From 58995581d71c75166f0f95344aa481e375d20947 Mon Sep 17 00:00:00 2001 From: Hanspeter Portner Date: Fri, 19 May 2023 23:16:24 +0200 Subject: [PATCH] Get rid of old nuklear ui --- .../nk_pugl/LICENSES => LICENSES}/ISC.txt | 0 include/moony.h | 3 +- meson.build | 60 +- meson_options.txt | 8 +- plugin/d2tk_ui.c | 4 +- plugin/manifest.ttl.in | 35 +- plugin/moony_ui.ttl | 45 +- plugin/nk_ui.c | 3946 --- subprojects/nk_pugl/.builds/alpine-latest.yml | 76 - subprojects/nk_pugl/.gitignore | 7 - subprojects/nk_pugl/.reuse/dep5 | 16 - subprojects/nk_pugl/COPYING | 201 - subprojects/nk_pugl/LICENSES/Artistic-2.0.txt | 85 - subprojects/nk_pugl/LICENSES/CC0-1.0.txt | 121 - subprojects/nk_pugl/LICENSES/MIT.txt | 9 - subprojects/nk_pugl/example/example.c | 107 - subprojects/nk_pugl/meson.build | 100 - subprojects/nk_pugl/meson_options.txt | 13 - subprojects/nk_pugl/nk_pugl/nk_pugl.h | 1365 - subprojects/nk_pugl/nuklear/.gitattributes | 3 - subprojects/nk_pugl/nuklear/.gitignore | 8 - subprojects/nk_pugl/nuklear/.gitmodules | 0 subprojects/nk_pugl/nuklear/.travis.yml | 16 - subprojects/nk_pugl/nuklear/Readme.md | 165 - .../demo/allegro5/KeyboardHandleriOS.h | 10 - .../demo/allegro5/KeyboardHandleriOS.m | 120 - .../nk_pugl/nuklear/demo/allegro5/Makefile | 22 - .../nk_pugl/nuklear/demo/allegro5/Readme.md | 35 - .../nk_pugl/nuklear/demo/allegro5/main.c | 165 - .../nuklear/demo/allegro5/nuklear_allegro5.h | 459 - subprojects/nk_pugl/nuklear/demo/calculator.c | 64 - .../nk_pugl/nuklear/demo/d3d11/build.bat | 9 - subprojects/nk_pugl/nuklear/demo/d3d11/main.c | 299 - .../nuklear/demo/d3d11/nuklear_d3d11.h | 622 - .../nuklear/demo/d3d11/nuklear_d3d11.hlsl | 36 - .../demo/d3d11/nuklear_d3d11_pixel_shader.h | 179 - .../demo/d3d11/nuklear_d3d11_vertex_shader.h | 350 - .../nk_pugl/nuklear/demo/d3d9/build.bat | 6 - subprojects/nk_pugl/nuklear/demo/d3d9/main.c | 313 - .../nk_pugl/nuklear/demo/d3d9/nuklear_d3d9.h | 543 - .../nk_pugl/nuklear/demo/gdi/build.bat | 6 - subprojects/nk_pugl/nuklear/demo/gdi/main.c | 184 - .../nk_pugl/nuklear/demo/gdi/nuklear_gdi.h | 842 - .../nk_pugl/nuklear/demo/gdip/build.bat | 5 - subprojects/nk_pugl/nuklear/demo/gdip/main.c | 178 - .../nk_pugl/nuklear/demo/gdip/nuklear_gdip.h | 1175 - .../nuklear/demo/glfw_opengl2/Makefile | 25 - .../nk_pugl/nuklear/demo/glfw_opengl2/main.c | 182 - .../demo/glfw_opengl2/nuklear_glfw_gl2.h | 381 - .../nuklear/demo/glfw_opengl3/Makefile | 26 - .../nk_pugl/nuklear/demo/glfw_opengl3/main.c | 200 - .../demo/glfw_opengl3/nuklear_glfw_gl3.h | 492 - .../nk_pugl/nuklear/demo/node_editor.c | 343 - subprojects/nk_pugl/nuklear/demo/overview.c | 1249 - .../nk_pugl/nuklear/demo/sdl_opengl2/Makefile | 25 - .../nk_pugl/nuklear/demo/sdl_opengl2/main.c | 198 - .../demo/sdl_opengl2/nuklear_sdl_gl2.h | 346 - .../nk_pugl/nuklear/demo/sdl_opengl3/Makefile | 25 - .../nk_pugl/nuklear/demo/sdl_opengl3/main.c | 208 - .../demo/sdl_opengl3/nuklear_sdl_gl3.h | 442 - .../nuklear/demo/sdl_opengles2/Makefile | 25 - .../nk_pugl/nuklear/demo/sdl_opengles2/main.c | 191 - .../demo/sdl_opengles2/nuklear_sdl_gles2.h | 443 - .../nuklear/demo/sfml_opengl2/Makefile | 33 - .../nuklear/demo/sfml_opengl2/Readme.md | 9 - .../nuklear/demo/sfml_opengl2/main.cpp | 181 - .../demo/sfml_opengl2/nuklear_sfml_gl2.h | 359 - .../nuklear/demo/sfml_opengl3/Makefile | 37 - .../nuklear/demo/sfml_opengl3/Readme.md | 11 - .../nuklear/demo/sfml_opengl3/main.cpp | 189 - .../demo/sfml_opengl3/nuklear_sfml_gl3.h | 463 - subprojects/nk_pugl/nuklear/demo/style.c | 132 - subprojects/nk_pugl/nuklear/demo/x11/Makefile | 13 - subprojects/nk_pugl/nuklear/demo/x11/main.c | 224 - .../nk_pugl/nuklear/demo/x11/nuklear_xlib.h | 957 - .../nk_pugl/nuklear/demo/x11_opengl2/Makefile | 26 - .../nk_pugl/nuklear/demo/x11_opengl2/main.c | 345 - .../demo/x11_opengl2/nuklear_xlib_gl2.h | 376 - .../nk_pugl/nuklear/demo/x11_opengl3/Makefile | 26 - .../nk_pugl/nuklear/demo/x11_opengl3/main.c | 342 - .../demo/x11_opengl3/nuklear_xlib_gl3.h | 743 - .../nk_pugl/nuklear/demo/x11_rawfb/Makefile | 13 - .../nk_pugl/nuklear/demo/x11_rawfb/main.c | 263 - .../nuklear/demo/x11_rawfb/nuklear_rawfb.h | 986 - .../nuklear/demo/x11_rawfb/nuklear_xlib.h | 283 - subprojects/nk_pugl/nuklear/doc/Makefile | 24 - subprojects/nk_pugl/nuklear/doc/build.sh | 4 - subprojects/nk_pugl/nuklear/doc/nuklear.html | 2533 -- subprojects/nk_pugl/nuklear/doc/stddoc.c | 141 - subprojects/nk_pugl/nuklear/example/Makefile | 42 - subprojects/nk_pugl/nuklear/example/canvas.c | 489 - .../nk_pugl/nuklear/example/extended.c | 906 - .../nk_pugl/nuklear/example/file_browser.c | 910 - .../nk_pugl/nuklear/example/icon/checked.png | Bin 1813 -> 0 bytes .../nk_pugl/nuklear/example/icon/cloud.png | Bin 7509 -> 0 bytes .../nk_pugl/nuklear/example/icon/computer.png | Bin 620 -> 0 bytes .../nk_pugl/nuklear/example/icon/copy.png | Bin 655 -> 0 bytes .../nk_pugl/nuklear/example/icon/default.png | Bin 460 -> 0 bytes .../nk_pugl/nuklear/example/icon/delete.png | Bin 11040 -> 0 bytes .../nk_pugl/nuklear/example/icon/desktop.png | Bin 583 -> 0 bytes .../nuklear/example/icon/directory.png | Bin 533 -> 0 bytes .../nk_pugl/nuklear/example/icon/edit.png | Bin 14998 -> 0 bytes .../nk_pugl/nuklear/example/icon/export.png | Bin 13336 -> 0 bytes .../nk_pugl/nuklear/example/icon/font.png | Bin 561 -> 0 bytes .../nk_pugl/nuklear/example/icon/home.png | Bin 819 -> 0 bytes .../nk_pugl/nuklear/example/icon/img.png | Bin 648 -> 0 bytes .../nk_pugl/nuklear/example/icon/movie.png | Bin 626 -> 0 bytes .../nk_pugl/nuklear/example/icon/music.png | Bin 610 -> 0 bytes .../nk_pugl/nuklear/example/icon/next.png | Bin 703 -> 0 bytes .../nk_pugl/nuklear/example/icon/pause.png | Bin 1338 -> 0 bytes .../nk_pugl/nuklear/example/icon/pen.png | Bin 5949 -> 0 bytes .../nk_pugl/nuklear/example/icon/phone.png | Bin 15778 -> 0 bytes .../nk_pugl/nuklear/example/icon/plane.png | Bin 13546 -> 0 bytes .../nk_pugl/nuklear/example/icon/play.png | Bin 566 -> 0 bytes .../nk_pugl/nuklear/example/icon/prev.png | Bin 701 -> 0 bytes .../nk_pugl/nuklear/example/icon/rocket.png | Bin 1121 -> 0 bytes .../nk_pugl/nuklear/example/icon/settings.png | Bin 15671 -> 0 bytes .../nk_pugl/nuklear/example/icon/stop.png | Bin 520 -> 0 bytes .../nk_pugl/nuklear/example/icon/text.png | Bin 601 -> 0 bytes .../nk_pugl/nuklear/example/icon/tools.png | Bin 24483 -> 0 bytes .../nuklear/example/icon/unchecked.png | Bin 1044 -> 0 bytes .../nk_pugl/nuklear/example/icon/volume.png | Bin 25438 -> 0 bytes .../nk_pugl/nuklear/example/icon/wifi.png | Bin 18857 -> 0 bytes .../nk_pugl/nuklear/example/images/image1.png | Bin 42882 -> 0 bytes .../nk_pugl/nuklear/example/images/image2.png | Bin 5671 -> 0 bytes .../nk_pugl/nuklear/example/images/image3.png | Bin 131502 -> 0 bytes .../nk_pugl/nuklear/example/images/image4.png | Bin 185821 -> 0 bytes .../nk_pugl/nuklear/example/images/image5.png | Bin 98475 -> 0 bytes .../nk_pugl/nuklear/example/images/image6.png | Bin 35633 -> 0 bytes .../nk_pugl/nuklear/example/images/image7.png | Bin 13960 -> 0 bytes .../nk_pugl/nuklear/example/images/image8.png | Bin 45987 -> 0 bytes .../nk_pugl/nuklear/example/images/image9.png | Bin 30759 -> 0 bytes .../nk_pugl/nuklear/example/skinning.c | 824 - .../nk_pugl/nuklear/example/skins/gwen.png | Bin 24565 -> 0 bytes .../nk_pugl/nuklear/example/stb_image.h | 6509 ---- .../nuklear/extra_font/Cousine-Regular.ttf | Bin 43912 -> 0 bytes .../nk_pugl/nuklear/extra_font/DroidSans.ttf | Bin 190044 -> 0 bytes .../nuklear/extra_font/Karla-Regular.ttf | Bin 16848 -> 0 bytes .../nuklear/extra_font/ProggyClean.ttf | Bin 41208 -> 0 bytes .../nk_pugl/nuklear/extra_font/ProggyTiny.ttf | Bin 35656 -> 0 bytes .../nuklear/extra_font/Raleway-Bold.ttf | Bin 176280 -> 0 bytes .../nuklear/extra_font/Roboto-Bold.ttf | Bin 135820 -> 0 bytes .../nuklear/extra_font/Roboto-Light.ttf | Bin 140276 -> 0 bytes .../nuklear/extra_font/Roboto-Regular.ttf | Bin 145348 -> 0 bytes .../nuklear/extra_font/kenvector_future.ttf | Bin 34136 -> 0 bytes .../extra_font/kenvector_future_thin.ttf | Bin 34100 -> 0 bytes subprojects/nk_pugl/nuklear/nuklear.h | 25596 ---------------- subprojects/nk_pugl/nuklear/package.json | 8 - subprojects/nk_pugl/pugl/.clang-format | 28 - subprojects/nk_pugl/pugl/.clang-tidy | 4 - subprojects/nk_pugl/pugl/.clant.json | 13 - subprojects/nk_pugl/pugl/.editorconfig | 19 - subprojects/nk_pugl/pugl/.gitattributes | 1 - subprojects/nk_pugl/pugl/.gitignore | 3 - subprojects/nk_pugl/pugl/.gitlab-ci.yml | 151 - subprojects/nk_pugl/pugl/.gitmodules | 0 subprojects/nk_pugl/pugl/.includes.imp | 4 - subprojects/nk_pugl/pugl/AUTHORS | 13 - subprojects/nk_pugl/pugl/COPYING | 13 - subprojects/nk_pugl/pugl/README.md | 97 - .../pugl/bindings/cxx/include/.clang-tidy | 14 - .../pugl/bindings/cxx/include/pugl/cairo.hpp | 45 - .../pugl/bindings/cxx/include/pugl/gl.hpp | 70 - .../pugl/bindings/cxx/include/pugl/pugl.hpp | 721 - .../pugl/bindings/cxx/include/pugl/stub.hpp | 45 - .../pugl/bindings/cxx/include/pugl/vulkan.hpp | 168 - .../nk_pugl/pugl/doc/_static/meson.build | 2 - subprojects/nk_pugl/pugl/doc/c/Doxyfile.in | 28 - .../nk_pugl/pugl/doc/c/api/meson.build | 5 - subprojects/nk_pugl/pugl/doc/c/event-loop.rst | 101 - subprojects/nk_pugl/pugl/doc/c/events.rst | 84 - subprojects/nk_pugl/pugl/doc/c/index.rst | 11 - subprojects/nk_pugl/pugl/doc/c/meson.build | 44 - subprojects/nk_pugl/pugl/doc/c/overview.rst | 26 - .../nk_pugl/pugl/doc/c/shutting-down.rst | 20 - subprojects/nk_pugl/pugl/doc/c/view.rst | 321 - subprojects/nk_pugl/pugl/doc/c/world.rst | 65 - .../nk_pugl/pugl/doc/c/xml/meson.build | 19 - subprojects/nk_pugl/pugl/doc/conf.py.in | 85 - subprojects/nk_pugl/pugl/doc/cpp/Doxyfile.in | 32 - .../nk_pugl/pugl/doc/cpp/api/meson.build | 5 - .../nk_pugl/pugl/doc/cpp/event-loop.rst | 37 - subprojects/nk_pugl/pugl/doc/cpp/events.rst | 43 - subprojects/nk_pugl/pugl/doc/cpp/index.rst | 12 - subprojects/nk_pugl/pugl/doc/cpp/meson.build | 43 - subprojects/nk_pugl/pugl/doc/cpp/overview.rst | 35 - subprojects/nk_pugl/pugl/doc/cpp/view.rst | 299 - subprojects/nk_pugl/pugl/doc/cpp/world.rst | 41 - .../nk_pugl/pugl/doc/cpp/xml/meson.build | 21 - subprojects/nk_pugl/pugl/doc/deployment.rst | 23 - subprojects/nk_pugl/pugl/doc/meson.build | 13 - subprojects/nk_pugl/pugl/doc/summary.rst | 22 - subprojects/nk_pugl/pugl/examples/.clang-tidy | 40 - subprojects/nk_pugl/pugl/examples/cube_view.h | 139 - .../nk_pugl/pugl/examples/demo_utils.h | 124 - .../nk_pugl/pugl/examples/file_utils.c | 68 - .../nk_pugl/pugl/examples/file_utils.h | 41 - subprojects/nk_pugl/pugl/examples/glad/glad.c | 1138 - subprojects/nk_pugl/pugl/examples/glad/glad.h | 2127 -- .../nk_pugl/pugl/examples/glad/khrplatform.h | 290 - subprojects/nk_pugl/pugl/examples/meson.build | 80 - .../nk_pugl/pugl/examples/pugl_cairo_demo.c | 261 - .../nk_pugl/pugl/examples/pugl_cursor_demo.c | 169 - .../nk_pugl/pugl/examples/pugl_cxx_demo.cpp | 148 - .../nk_pugl/pugl/examples/pugl_embed_demo.c | 354 - .../nk_pugl/pugl/examples/pugl_print_events.c | 79 - .../nk_pugl/pugl/examples/pugl_shader_demo.c | 470 - .../pugl/examples/pugl_vulkan_cxx_demo.cpp | 1826 -- .../nk_pugl/pugl/examples/pugl_vulkan_demo.c | 1127 - .../nk_pugl/pugl/examples/pugl_window_demo.c | 254 - subprojects/nk_pugl/pugl/examples/rects.h | 79 - .../nk_pugl/pugl/examples/shader_utils.h | 106 - .../pugl/examples/shaders/header_330.glsl | 4 - .../pugl/examples/shaders/header_420.glsl | 4 - .../nk_pugl/pugl/examples/shaders/meson.build | 35 - .../nk_pugl/pugl/examples/shaders/rect.frag | 33 - .../nk_pugl/pugl/examples/shaders/rect.vert | 36 - subprojects/nk_pugl/pugl/examples/sybok.hpp | 2325 -- subprojects/nk_pugl/pugl/include/.clang-tidy | 9 - subprojects/nk_pugl/pugl/include/pugl/cairo.h | 46 - subprojects/nk_pugl/pugl/include/pugl/gl.h | 107 - subprojects/nk_pugl/pugl/include/pugl/pugl.h | 1575 - subprojects/nk_pugl/pugl/include/pugl/stub.h | 47 - .../nk_pugl/pugl/include/pugl/vulkan.h | 156 - subprojects/nk_pugl/pugl/meson.build | 455 - subprojects/nk_pugl/pugl/meson/meson.build | 196 - subprojects/nk_pugl/pugl/meson_options.txt | 20 - subprojects/nk_pugl/pugl/pugl.pc.in | 11 - .../nk_pugl/pugl/resources/Info.plist.in | 20 - subprojects/nk_pugl/pugl/resources/pugl.ipe | 293 - subprojects/nk_pugl/pugl/resources/pugl.png | Bin 2641 -> 0 bytes subprojects/nk_pugl/pugl/resources/pugl.svg | 9 - subprojects/nk_pugl/pugl/scripts/cat.py | 7 - .../nk_pugl/pugl/scripts/dox_to_sphinx.py | 653 - subprojects/nk_pugl/pugl/src/.clang-tidy | 17 - subprojects/nk_pugl/pugl/src/implementation.c | 456 - subprojects/nk_pugl/pugl/src/implementation.h | 82 - subprojects/nk_pugl/pugl/src/mac.h | 55 - subprojects/nk_pugl/pugl/src/mac.m | 1468 - subprojects/nk_pugl/pugl/src/mac_cairo.m | 160 - subprojects/nk_pugl/pugl/src/mac_gl.m | 210 - subprojects/nk_pugl/pugl/src/mac_stub.m | 92 - subprojects/nk_pugl/pugl/src/mac_vulkan.m | 211 - subprojects/nk_pugl/pugl/src/stub.h | 72 - subprojects/nk_pugl/pugl/src/types.h | 112 - subprojects/nk_pugl/pugl/src/win.c | 1142 - subprojects/nk_pugl/pugl/src/win.h | 156 - subprojects/nk_pugl/pugl/src/win_cairo.c | 178 - subprojects/nk_pugl/pugl/src/win_gl.c | 327 - subprojects/nk_pugl/pugl/src/win_stub.c | 80 - subprojects/nk_pugl/pugl/src/win_vulkan.c | 126 - subprojects/nk_pugl/pugl/src/x11.c | 1431 - subprojects/nk_pugl/pugl/src/x11.h | 79 - subprojects/nk_pugl/pugl/src/x11_cairo.c | 163 - subprojects/nk_pugl/pugl/src/x11_gl.c | 235 - subprojects/nk_pugl/pugl/src/x11_stub.c | 58 - subprojects/nk_pugl/pugl/src/x11_vulkan.c | 130 - subprojects/nk_pugl/pugl/test/.clang-tidy | 16 - subprojects/nk_pugl/pugl/test/meson.build | 33 - subprojects/nk_pugl/pugl/test/test_build.c | 32 - subprojects/nk_pugl/pugl/test/test_build.cpp | 33 - .../nk_pugl/pugl/test/test_clipboard.c | 105 - subprojects/nk_pugl/pugl/test/test_gl_hints.c | 89 - subprojects/nk_pugl/pugl/test/test_realize.c | 100 - .../nk_pugl/pugl/test/test_redisplay.c | 141 - .../nk_pugl/pugl/test/test_show_hide.c | 148 - .../nk_pugl/pugl/test/test_stub_hints.c | 80 - subprojects/nk_pugl/pugl/test/test_timer.c | 159 - subprojects/nk_pugl/pugl/test/test_update.c | 125 - subprojects/nk_pugl/pugl/test/test_utils.h | 356 - 270 files changed, 24 insertions(+), 87053 deletions(-) rename {subprojects/nk_pugl/LICENSES => LICENSES}/ISC.txt (100%) delete mode 100644 plugin/nk_ui.c delete mode 100644 subprojects/nk_pugl/.builds/alpine-latest.yml delete mode 100644 subprojects/nk_pugl/.gitignore delete mode 100644 subprojects/nk_pugl/.reuse/dep5 delete mode 100644 subprojects/nk_pugl/COPYING delete mode 100644 subprojects/nk_pugl/LICENSES/Artistic-2.0.txt delete mode 100644 subprojects/nk_pugl/LICENSES/CC0-1.0.txt delete mode 100644 subprojects/nk_pugl/LICENSES/MIT.txt delete mode 100644 subprojects/nk_pugl/example/example.c delete mode 100644 subprojects/nk_pugl/meson.build delete mode 100644 subprojects/nk_pugl/meson_options.txt delete mode 100644 subprojects/nk_pugl/nk_pugl/nk_pugl.h delete mode 100644 subprojects/nk_pugl/nuklear/.gitattributes delete mode 100644 subprojects/nk_pugl/nuklear/.gitignore delete mode 100644 subprojects/nk_pugl/nuklear/.gitmodules delete mode 100644 subprojects/nk_pugl/nuklear/.travis.yml delete mode 100644 subprojects/nk_pugl/nuklear/Readme.md delete mode 100644 subprojects/nk_pugl/nuklear/demo/allegro5/KeyboardHandleriOS.h delete mode 100644 subprojects/nk_pugl/nuklear/demo/allegro5/KeyboardHandleriOS.m delete mode 100644 subprojects/nk_pugl/nuklear/demo/allegro5/Makefile delete mode 100644 subprojects/nk_pugl/nuklear/demo/allegro5/Readme.md delete mode 100644 subprojects/nk_pugl/nuklear/demo/allegro5/main.c delete mode 100644 subprojects/nk_pugl/nuklear/demo/allegro5/nuklear_allegro5.h delete mode 100644 subprojects/nk_pugl/nuklear/demo/calculator.c delete mode 100644 subprojects/nk_pugl/nuklear/demo/d3d11/build.bat delete mode 100644 subprojects/nk_pugl/nuklear/demo/d3d11/main.c delete mode 100644 subprojects/nk_pugl/nuklear/demo/d3d11/nuklear_d3d11.h delete mode 100644 subprojects/nk_pugl/nuklear/demo/d3d11/nuklear_d3d11.hlsl delete mode 100644 subprojects/nk_pugl/nuklear/demo/d3d11/nuklear_d3d11_pixel_shader.h delete mode 100644 subprojects/nk_pugl/nuklear/demo/d3d11/nuklear_d3d11_vertex_shader.h delete mode 100644 subprojects/nk_pugl/nuklear/demo/d3d9/build.bat delete mode 100644 subprojects/nk_pugl/nuklear/demo/d3d9/main.c delete mode 100644 subprojects/nk_pugl/nuklear/demo/d3d9/nuklear_d3d9.h delete mode 100644 subprojects/nk_pugl/nuklear/demo/gdi/build.bat delete mode 100644 subprojects/nk_pugl/nuklear/demo/gdi/main.c delete mode 100644 subprojects/nk_pugl/nuklear/demo/gdi/nuklear_gdi.h delete mode 100644 subprojects/nk_pugl/nuklear/demo/gdip/build.bat delete mode 100644 subprojects/nk_pugl/nuklear/demo/gdip/main.c delete mode 100644 subprojects/nk_pugl/nuklear/demo/gdip/nuklear_gdip.h delete mode 100644 subprojects/nk_pugl/nuklear/demo/glfw_opengl2/Makefile delete mode 100644 subprojects/nk_pugl/nuklear/demo/glfw_opengl2/main.c delete mode 100644 subprojects/nk_pugl/nuklear/demo/glfw_opengl2/nuklear_glfw_gl2.h delete mode 100644 subprojects/nk_pugl/nuklear/demo/glfw_opengl3/Makefile delete mode 100644 subprojects/nk_pugl/nuklear/demo/glfw_opengl3/main.c delete mode 100644 subprojects/nk_pugl/nuklear/demo/glfw_opengl3/nuklear_glfw_gl3.h delete mode 100644 subprojects/nk_pugl/nuklear/demo/node_editor.c delete mode 100644 subprojects/nk_pugl/nuklear/demo/overview.c delete mode 100644 subprojects/nk_pugl/nuklear/demo/sdl_opengl2/Makefile delete mode 100644 subprojects/nk_pugl/nuklear/demo/sdl_opengl2/main.c delete mode 100644 subprojects/nk_pugl/nuklear/demo/sdl_opengl2/nuklear_sdl_gl2.h delete mode 100644 subprojects/nk_pugl/nuklear/demo/sdl_opengl3/Makefile delete mode 100644 subprojects/nk_pugl/nuklear/demo/sdl_opengl3/main.c delete mode 100644 subprojects/nk_pugl/nuklear/demo/sdl_opengl3/nuklear_sdl_gl3.h delete mode 100644 subprojects/nk_pugl/nuklear/demo/sdl_opengles2/Makefile delete mode 100644 subprojects/nk_pugl/nuklear/demo/sdl_opengles2/main.c delete mode 100644 subprojects/nk_pugl/nuklear/demo/sdl_opengles2/nuklear_sdl_gles2.h delete mode 100644 subprojects/nk_pugl/nuklear/demo/sfml_opengl2/Makefile delete mode 100644 subprojects/nk_pugl/nuklear/demo/sfml_opengl2/Readme.md delete mode 100644 subprojects/nk_pugl/nuklear/demo/sfml_opengl2/main.cpp delete mode 100644 subprojects/nk_pugl/nuklear/demo/sfml_opengl2/nuklear_sfml_gl2.h delete mode 100644 subprojects/nk_pugl/nuklear/demo/sfml_opengl3/Makefile delete mode 100644 subprojects/nk_pugl/nuklear/demo/sfml_opengl3/Readme.md delete mode 100644 subprojects/nk_pugl/nuklear/demo/sfml_opengl3/main.cpp delete mode 100644 subprojects/nk_pugl/nuklear/demo/sfml_opengl3/nuklear_sfml_gl3.h delete mode 100644 subprojects/nk_pugl/nuklear/demo/style.c delete mode 100644 subprojects/nk_pugl/nuklear/demo/x11/Makefile delete mode 100644 subprojects/nk_pugl/nuklear/demo/x11/main.c delete mode 100644 subprojects/nk_pugl/nuklear/demo/x11/nuklear_xlib.h delete mode 100644 subprojects/nk_pugl/nuklear/demo/x11_opengl2/Makefile delete mode 100644 subprojects/nk_pugl/nuklear/demo/x11_opengl2/main.c delete mode 100644 subprojects/nk_pugl/nuklear/demo/x11_opengl2/nuklear_xlib_gl2.h delete mode 100644 subprojects/nk_pugl/nuklear/demo/x11_opengl3/Makefile delete mode 100644 subprojects/nk_pugl/nuklear/demo/x11_opengl3/main.c delete mode 100644 subprojects/nk_pugl/nuklear/demo/x11_opengl3/nuklear_xlib_gl3.h delete mode 100644 subprojects/nk_pugl/nuklear/demo/x11_rawfb/Makefile delete mode 100644 subprojects/nk_pugl/nuklear/demo/x11_rawfb/main.c delete mode 100644 subprojects/nk_pugl/nuklear/demo/x11_rawfb/nuklear_rawfb.h delete mode 100644 subprojects/nk_pugl/nuklear/demo/x11_rawfb/nuklear_xlib.h delete mode 100644 subprojects/nk_pugl/nuklear/doc/Makefile delete mode 100755 subprojects/nk_pugl/nuklear/doc/build.sh delete mode 100644 subprojects/nk_pugl/nuklear/doc/nuklear.html delete mode 100644 subprojects/nk_pugl/nuklear/doc/stddoc.c delete mode 100644 subprojects/nk_pugl/nuklear/example/Makefile delete mode 100644 subprojects/nk_pugl/nuklear/example/canvas.c delete mode 100644 subprojects/nk_pugl/nuklear/example/extended.c delete mode 100644 subprojects/nk_pugl/nuklear/example/file_browser.c delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/checked.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/cloud.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/computer.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/copy.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/default.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/delete.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/desktop.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/directory.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/edit.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/export.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/font.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/home.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/img.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/movie.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/music.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/next.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/pause.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/pen.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/phone.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/plane.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/play.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/prev.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/rocket.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/settings.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/stop.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/text.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/tools.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/unchecked.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/volume.png delete mode 100644 subprojects/nk_pugl/nuklear/example/icon/wifi.png delete mode 100644 subprojects/nk_pugl/nuklear/example/images/image1.png delete mode 100644 subprojects/nk_pugl/nuklear/example/images/image2.png delete mode 100644 subprojects/nk_pugl/nuklear/example/images/image3.png delete mode 100644 subprojects/nk_pugl/nuklear/example/images/image4.png delete mode 100644 subprojects/nk_pugl/nuklear/example/images/image5.png delete mode 100644 subprojects/nk_pugl/nuklear/example/images/image6.png delete mode 100644 subprojects/nk_pugl/nuklear/example/images/image7.png delete mode 100644 subprojects/nk_pugl/nuklear/example/images/image8.png delete mode 100644 subprojects/nk_pugl/nuklear/example/images/image9.png delete mode 100644 subprojects/nk_pugl/nuklear/example/skinning.c delete mode 100644 subprojects/nk_pugl/nuklear/example/skins/gwen.png delete mode 100644 subprojects/nk_pugl/nuklear/example/stb_image.h delete mode 100644 subprojects/nk_pugl/nuklear/extra_font/Cousine-Regular.ttf delete mode 100644 subprojects/nk_pugl/nuklear/extra_font/DroidSans.ttf delete mode 100644 subprojects/nk_pugl/nuklear/extra_font/Karla-Regular.ttf delete mode 100644 subprojects/nk_pugl/nuklear/extra_font/ProggyClean.ttf delete mode 100644 subprojects/nk_pugl/nuklear/extra_font/ProggyTiny.ttf delete mode 100644 subprojects/nk_pugl/nuklear/extra_font/Raleway-Bold.ttf delete mode 100644 subprojects/nk_pugl/nuklear/extra_font/Roboto-Bold.ttf delete mode 100644 subprojects/nk_pugl/nuklear/extra_font/Roboto-Light.ttf delete mode 100644 subprojects/nk_pugl/nuklear/extra_font/Roboto-Regular.ttf delete mode 100644 subprojects/nk_pugl/nuklear/extra_font/kenvector_future.ttf delete mode 100644 subprojects/nk_pugl/nuklear/extra_font/kenvector_future_thin.ttf delete mode 100644 subprojects/nk_pugl/nuklear/nuklear.h delete mode 100644 subprojects/nk_pugl/nuklear/package.json delete mode 100644 subprojects/nk_pugl/pugl/.clang-format delete mode 100644 subprojects/nk_pugl/pugl/.clang-tidy delete mode 100644 subprojects/nk_pugl/pugl/.clant.json delete mode 100644 subprojects/nk_pugl/pugl/.editorconfig delete mode 100644 subprojects/nk_pugl/pugl/.gitattributes delete mode 100644 subprojects/nk_pugl/pugl/.gitignore delete mode 100644 subprojects/nk_pugl/pugl/.gitlab-ci.yml delete mode 100644 subprojects/nk_pugl/pugl/.gitmodules delete mode 100644 subprojects/nk_pugl/pugl/.includes.imp delete mode 100644 subprojects/nk_pugl/pugl/AUTHORS delete mode 100644 subprojects/nk_pugl/pugl/COPYING delete mode 100644 subprojects/nk_pugl/pugl/README.md delete mode 100644 subprojects/nk_pugl/pugl/bindings/cxx/include/.clang-tidy delete mode 100644 subprojects/nk_pugl/pugl/bindings/cxx/include/pugl/cairo.hpp delete mode 100644 subprojects/nk_pugl/pugl/bindings/cxx/include/pugl/gl.hpp delete mode 100644 subprojects/nk_pugl/pugl/bindings/cxx/include/pugl/pugl.hpp delete mode 100644 subprojects/nk_pugl/pugl/bindings/cxx/include/pugl/stub.hpp delete mode 100644 subprojects/nk_pugl/pugl/bindings/cxx/include/pugl/vulkan.hpp delete mode 100644 subprojects/nk_pugl/pugl/doc/_static/meson.build delete mode 100644 subprojects/nk_pugl/pugl/doc/c/Doxyfile.in delete mode 100644 subprojects/nk_pugl/pugl/doc/c/api/meson.build delete mode 100644 subprojects/nk_pugl/pugl/doc/c/event-loop.rst delete mode 100644 subprojects/nk_pugl/pugl/doc/c/events.rst delete mode 100644 subprojects/nk_pugl/pugl/doc/c/index.rst delete mode 100644 subprojects/nk_pugl/pugl/doc/c/meson.build delete mode 100644 subprojects/nk_pugl/pugl/doc/c/overview.rst delete mode 100644 subprojects/nk_pugl/pugl/doc/c/shutting-down.rst delete mode 100644 subprojects/nk_pugl/pugl/doc/c/view.rst delete mode 100644 subprojects/nk_pugl/pugl/doc/c/world.rst delete mode 100644 subprojects/nk_pugl/pugl/doc/c/xml/meson.build delete mode 100644 subprojects/nk_pugl/pugl/doc/conf.py.in delete mode 100644 subprojects/nk_pugl/pugl/doc/cpp/Doxyfile.in delete mode 100644 subprojects/nk_pugl/pugl/doc/cpp/api/meson.build delete mode 100644 subprojects/nk_pugl/pugl/doc/cpp/event-loop.rst delete mode 100644 subprojects/nk_pugl/pugl/doc/cpp/events.rst delete mode 100644 subprojects/nk_pugl/pugl/doc/cpp/index.rst delete mode 100644 subprojects/nk_pugl/pugl/doc/cpp/meson.build delete mode 100644 subprojects/nk_pugl/pugl/doc/cpp/overview.rst delete mode 100644 subprojects/nk_pugl/pugl/doc/cpp/view.rst delete mode 100644 subprojects/nk_pugl/pugl/doc/cpp/world.rst delete mode 100644 subprojects/nk_pugl/pugl/doc/cpp/xml/meson.build delete mode 100644 subprojects/nk_pugl/pugl/doc/deployment.rst delete mode 100644 subprojects/nk_pugl/pugl/doc/meson.build delete mode 100644 subprojects/nk_pugl/pugl/doc/summary.rst delete mode 100644 subprojects/nk_pugl/pugl/examples/.clang-tidy delete mode 100644 subprojects/nk_pugl/pugl/examples/cube_view.h delete mode 100644 subprojects/nk_pugl/pugl/examples/demo_utils.h delete mode 100644 subprojects/nk_pugl/pugl/examples/file_utils.c delete mode 100644 subprojects/nk_pugl/pugl/examples/file_utils.h delete mode 100644 subprojects/nk_pugl/pugl/examples/glad/glad.c delete mode 100644 subprojects/nk_pugl/pugl/examples/glad/glad.h delete mode 100644 subprojects/nk_pugl/pugl/examples/glad/khrplatform.h delete mode 100644 subprojects/nk_pugl/pugl/examples/meson.build delete mode 100644 subprojects/nk_pugl/pugl/examples/pugl_cairo_demo.c delete mode 100644 subprojects/nk_pugl/pugl/examples/pugl_cursor_demo.c delete mode 100644 subprojects/nk_pugl/pugl/examples/pugl_cxx_demo.cpp delete mode 100644 subprojects/nk_pugl/pugl/examples/pugl_embed_demo.c delete mode 100644 subprojects/nk_pugl/pugl/examples/pugl_print_events.c delete mode 100644 subprojects/nk_pugl/pugl/examples/pugl_shader_demo.c delete mode 100644 subprojects/nk_pugl/pugl/examples/pugl_vulkan_cxx_demo.cpp delete mode 100644 subprojects/nk_pugl/pugl/examples/pugl_vulkan_demo.c delete mode 100644 subprojects/nk_pugl/pugl/examples/pugl_window_demo.c delete mode 100644 subprojects/nk_pugl/pugl/examples/rects.h delete mode 100644 subprojects/nk_pugl/pugl/examples/shader_utils.h delete mode 100644 subprojects/nk_pugl/pugl/examples/shaders/header_330.glsl delete mode 100644 subprojects/nk_pugl/pugl/examples/shaders/header_420.glsl delete mode 100644 subprojects/nk_pugl/pugl/examples/shaders/meson.build delete mode 100644 subprojects/nk_pugl/pugl/examples/shaders/rect.frag delete mode 100644 subprojects/nk_pugl/pugl/examples/shaders/rect.vert delete mode 100644 subprojects/nk_pugl/pugl/examples/sybok.hpp delete mode 100644 subprojects/nk_pugl/pugl/include/.clang-tidy delete mode 100644 subprojects/nk_pugl/pugl/include/pugl/cairo.h delete mode 100644 subprojects/nk_pugl/pugl/include/pugl/gl.h delete mode 100644 subprojects/nk_pugl/pugl/include/pugl/pugl.h delete mode 100644 subprojects/nk_pugl/pugl/include/pugl/stub.h delete mode 100644 subprojects/nk_pugl/pugl/include/pugl/vulkan.h delete mode 100644 subprojects/nk_pugl/pugl/meson.build delete mode 100644 subprojects/nk_pugl/pugl/meson/meson.build delete mode 100644 subprojects/nk_pugl/pugl/meson_options.txt delete mode 100644 subprojects/nk_pugl/pugl/pugl.pc.in delete mode 100644 subprojects/nk_pugl/pugl/resources/Info.plist.in delete mode 100644 subprojects/nk_pugl/pugl/resources/pugl.ipe delete mode 100644 subprojects/nk_pugl/pugl/resources/pugl.png delete mode 100644 subprojects/nk_pugl/pugl/resources/pugl.svg delete mode 100755 subprojects/nk_pugl/pugl/scripts/cat.py delete mode 100755 subprojects/nk_pugl/pugl/scripts/dox_to_sphinx.py delete mode 100644 subprojects/nk_pugl/pugl/src/.clang-tidy delete mode 100644 subprojects/nk_pugl/pugl/src/implementation.c delete mode 100644 subprojects/nk_pugl/pugl/src/implementation.h delete mode 100644 subprojects/nk_pugl/pugl/src/mac.h delete mode 100644 subprojects/nk_pugl/pugl/src/mac.m delete mode 100644 subprojects/nk_pugl/pugl/src/mac_cairo.m delete mode 100644 subprojects/nk_pugl/pugl/src/mac_gl.m delete mode 100644 subprojects/nk_pugl/pugl/src/mac_stub.m delete mode 100644 subprojects/nk_pugl/pugl/src/mac_vulkan.m delete mode 100644 subprojects/nk_pugl/pugl/src/stub.h delete mode 100644 subprojects/nk_pugl/pugl/src/types.h delete mode 100644 subprojects/nk_pugl/pugl/src/win.c delete mode 100644 subprojects/nk_pugl/pugl/src/win.h delete mode 100644 subprojects/nk_pugl/pugl/src/win_cairo.c delete mode 100644 subprojects/nk_pugl/pugl/src/win_gl.c delete mode 100644 subprojects/nk_pugl/pugl/src/win_stub.c delete mode 100644 subprojects/nk_pugl/pugl/src/win_vulkan.c delete mode 100644 subprojects/nk_pugl/pugl/src/x11.c delete mode 100644 subprojects/nk_pugl/pugl/src/x11.h delete mode 100644 subprojects/nk_pugl/pugl/src/x11_cairo.c delete mode 100644 subprojects/nk_pugl/pugl/src/x11_gl.c delete mode 100644 subprojects/nk_pugl/pugl/src/x11_stub.c delete mode 100644 subprojects/nk_pugl/pugl/src/x11_vulkan.c delete mode 100644 subprojects/nk_pugl/pugl/test/.clang-tidy delete mode 100644 subprojects/nk_pugl/pugl/test/meson.build delete mode 100644 subprojects/nk_pugl/pugl/test/test_build.c delete mode 100644 subprojects/nk_pugl/pugl/test/test_build.cpp delete mode 100644 subprojects/nk_pugl/pugl/test/test_clipboard.c delete mode 100644 subprojects/nk_pugl/pugl/test/test_gl_hints.c delete mode 100644 subprojects/nk_pugl/pugl/test/test_realize.c delete mode 100644 subprojects/nk_pugl/pugl/test/test_redisplay.c delete mode 100644 subprojects/nk_pugl/pugl/test/test_show_hide.c delete mode 100644 subprojects/nk_pugl/pugl/test/test_stub_hints.c delete mode 100644 subprojects/nk_pugl/pugl/test/test_timer.c delete mode 100644 subprojects/nk_pugl/pugl/test/test_update.c delete mode 100644 subprojects/nk_pugl/pugl/test/test_utils.h diff --git a/subprojects/nk_pugl/LICENSES/ISC.txt b/LICENSES/ISC.txt similarity index 100% rename from subprojects/nk_pugl/LICENSES/ISC.txt rename to LICENSES/ISC.txt diff --git a/include/moony.h b/include/moony.h index f492f92..c4ab22c 100644 --- a/include/moony.h +++ b/include/moony.h @@ -96,8 +96,7 @@ typedef struct _LV2_Canvas_Idisp LV2_Canvas_Idisp; #define MOONY_PARAM_COLS_URI MOONY_URI"#paramCols" #define MOONY_PARAM_ROWS_URI MOONY_URI"#paramRows" -#define MOONY_NK_URI MOONY_URI"#moony_ui" -#define MOONY_D2TK_URI MOONY_URI"#moony_d2tk" +#define MOONY_UI_URI MOONY_URI"#ui" #define MOONY_C1XC1_URI MOONY_URI"#c1xc1" #define MOONY_C2XC2_URI MOONY_URI"#c2xc2" diff --git a/meson.build b/meson.build index bfbc0ef..5e8bdda 100644 --- a/meson.build +++ b/meson.build @@ -9,7 +9,6 @@ project('moony.lv2', 'c', default_options : [ 'c_std=gnu11']) d2tk = subproject('d2tk') -nk_pugl = subproject('nk_pugl') canvas_lv2 = subproject('canvas.lv2') props_lv2 = subproject('props.lv2') ser_atom_lv2 = subproject('ser_atom.lv2') @@ -30,9 +29,6 @@ else error('no valid UI backend given') endif -nk_pugl_dep = nk_pugl.get_variable('nk_pugl_gl') -cousine_regular_ttf = nk_pugl.get_variable('cousine_regular_ttf') - canvas_lv2_dep = canvas_lv2.get_variable('canvas_lv2') canvas_idisp_lv2_dep = canvas_lv2.get_variable('canvas_idisp_lv2') props_lv2_dep = props_lv2.get_variable('props_lv2') @@ -43,8 +39,7 @@ varchunk_dep = varchunk.get_variable('varchunk') source_root = meson.source_root() build_root = meson.build_root() -build_opengl_ui = get_option('build-opengl-ui') -build_next_ui = get_option('build-next-ui') +build_ui = get_option('build-ui') build_inline_disp = get_option('build-inline-disp') cc = meson.get_compiler('c') @@ -54,8 +49,7 @@ lv2_dep = dependency('lv2', version : '>=1.14.0') thread_dep = dependency('threads') dsp_deps = [m_dep, lv2_dep, thread_dep, varchunk_dep, props_lv2_dep, timely_lv2_dep, canvas_lv2_dep, canvas_idisp_lv2_dep] -nk_ui_deps = [m_dep, lv2_dep, thread_dep, varchunk_dep, props_lv2_dep, canvas_lv2_dep, nk_pugl_dep] -d2tk_ui_deps = [m_dep, lv2_dep, varchunk_dep, props_lv2_dep, canvas_lv2_dep, ser_atom_lv2_dep, d2tk_dep] +ui_deps = [m_dep, lv2_dep, varchunk_dep, props_lv2_dep, canvas_lv2_dep, ser_atom_lv2_dep, d2tk_dep] if cc.has_member('LV2UI_Request_Value', 'request', prefix : '#include ') @@ -254,8 +248,6 @@ mod = shared_module('moony', dsp_srcs, suffix = mod.full_path().strip().split('.')[-1] conf_data.set('MODULE_SUFFIX', '.' + suffix) -conf_data.set('UI', '#') -conf_data.set('UI_TYPE', 'UI') if build_inline_disp conf_data.set('BUILD_INLINE_DISPLAY', '') @@ -263,53 +255,22 @@ else conf_data.set('BUILD_INLINE_DISPLAY', '#') endif -if build_opengl_ui - message('building OpenGL UI') - conf_data.set('UI', '') - conf_data.set('UI_OPENGL', '') -else - conf_data.set('UI_OPENGL', '#') -endif - -if build_next_ui +if build_ui message('building Simple UI') conf_data.set('UI', '') - conf_data.set('UI_NEXT', '') else - conf_data.set('UI_NEXT', '#') -endif - -if host_machine.system() == 'windows' - conf_data.set('UI_TYPE', 'WindowsUI') -elif host_machine.system() == 'darwin' - conf_data.set('UI_TYPE', 'CocoaUI') -else - conf_data.set('UI_TYPE', 'X11UI') -endif - -if build_opengl_ui - nk_ui_srcs = [ - join_paths('plugin', 'nk_ui.c')] - - nk_ui = shared_module('moony_ui', nk_ui_srcs, - c_args : [c_args, extra_args], - include_directories : inc_dir, - name_prefix : '', - dependencies : nk_ui_deps, - link_with : ui_with, - install : true, - install_dir : inst_dir) + conf_data.set('UI', '#') endif -if build_next_ui +if build_ui d2tk_ui_srcs = [ join_paths('plugin', 'd2tk_ui.c')] - d2tk_ui = shared_module('moony_d2tk', d2tk_ui_srcs, + d2tk_ui = shared_module('moony_ui', d2tk_ui_srcs, c_args : c_args, include_directories : inc_dir, name_prefix : '', - dependencies : d2tk_ui_deps, + dependencies : ui_deps, install : true, install_dir : inst_dir) @@ -399,13 +360,6 @@ pset_ttl = configure_file( install : true, install_dir : inst_dir) -configure_file( - input : cousine_regular_ttf, - output : 'Cousine-Regular.ttf', - copy : true, - install : true, - install_dir : inst_dir) - lexer_lua = configure_file( input : join_paths('plugin', 'lexer.lua'), output : 'lexer.lua', diff --git a/meson_options.txt b/meson_options.txt index 674b91b..4f2b30e 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -23,14 +23,10 @@ option('use-fontconfig', type : 'feature', value : 'enabled') -option('build-opengl-ui', +option('build-ui', type : 'boolean', value : true) -option('build-next-ui', - type : 'boolean', - value : false) - option('build-inline-disp', type : 'boolean', value : false) @@ -43,4 +39,4 @@ option('lv2libdir', type : 'string', value : 'lib/lv2') -option('version', type : 'string', value : '0.41.97') +option('version', type : 'string', value : '0.41.99') diff --git a/plugin/d2tk_ui.c b/plugin/d2tk_ui.c index b920a55..04c3c9a 100644 --- a/plugin/d2tk_ui.c +++ b/plugin/d2tk_ui.c @@ -2600,8 +2600,8 @@ _extension_data(const char *uri) return NULL; } -static const LV2UI_Descriptor moony_ui= { - .URI = MOONY_D2TK_URI, +static const LV2UI_Descriptor moony_ui = { + .URI = MOONY_UI_URI, .instantiate = instantiate, .cleanup = cleanup, .port_event = port_event, diff --git a/plugin/manifest.ttl.in b/plugin/manifest.ttl.in index c1e7fa0..76184cd 100644 --- a/plugin/manifest.ttl.in +++ b/plugin/manifest.ttl.in @@ -16,8 +16,7 @@ moony:c1xc1 lv2:minorVersion @MINOR_VERSION@ ; lv2:microVersion @MICRO_VERSION@ ; lv2:binary ; - @UI_OPENGL@ui:ui moony:moony_ui ; - @UI_NEXT@ui:ui moony:moony_d2tk ; + @UI@ui:ui moony:ui ; rdfs:seeAlso . moony:c2xc2 @@ -25,8 +24,7 @@ moony:c2xc2 lv2:minorVersion @MINOR_VERSION@ ; lv2:microVersion @MICRO_VERSION@ ; lv2:binary ; - @UI_OPENGL@ui:ui moony:moony_ui ; - @UI_NEXT@ui:ui moony:moony_d2tk ; + @UI@ui:ui moony:ui ; rdfs:seeAlso . moony:c4xc4 @@ -34,8 +32,7 @@ moony:c4xc4 lv2:minorVersion @MINOR_VERSION@ ; lv2:microVersion @MICRO_VERSION@ ; lv2:binary ; - @UI_OPENGL@ui:ui moony:moony_ui ; - @UI_NEXT@ui:ui moony:moony_d2tk ; + @UI@ui:ui moony:ui ; rdfs:seeAlso . # atom in, atom out @@ -44,8 +41,7 @@ moony:a1xa1 lv2:minorVersion @MINOR_VERSION@ ; lv2:microVersion @MICRO_VERSION@ ; lv2:binary ; - @UI_OPENGL@ui:ui moony:moony_ui ; - @UI_NEXT@ui:ui moony:moony_d2tk ; + @UI@ui:ui moony:ui ; rdfs:seeAlso . moony:a2xa2 @@ -53,8 +49,7 @@ moony:a2xa2 lv2:minorVersion @MINOR_VERSION@ ; lv2:microVersion @MICRO_VERSION@ ; lv2:binary ; - @UI_OPENGL@ui:ui moony:moony_ui ; - @UI_NEXT@ui:ui moony:moony_d2tk ; + @UI@ui:ui moony:ui ; rdfs:seeAlso . moony:a4xa4 @@ -62,8 +57,7 @@ moony:a4xa4 lv2:minorVersion @MINOR_VERSION@ ; lv2:microVersion @MICRO_VERSION@ ; lv2:binary ; - @UI_OPENGL@ui:ui moony:moony_ui ; - @UI_NEXT@ui:ui moony:moony_d2tk ; + @UI@ui:ui moony:ui ; rdfs:seeAlso . # control/atom in, control/atom out @@ -72,8 +66,7 @@ moony:c1a1xc1a1 lv2:minorVersion @MINOR_VERSION@ ; lv2:microVersion @MICRO_VERSION@ ; lv2:binary ; - @UI_OPENGL@ui:ui moony:moony_ui ; - @UI_NEXT@ui:ui moony:moony_d2tk ; + @UI@ui:ui moony:ui ; rdfs:seeAlso . moony:c2a1xc2a1 @@ -81,8 +74,7 @@ moony:c2a1xc2a1 lv2:minorVersion @MINOR_VERSION@ ; lv2:microVersion @MICRO_VERSION@ ; lv2:binary ; - @UI_OPENGL@ui:ui moony:moony_ui ; - @UI_NEXT@ui:ui moony:moony_d2tk ; + @UI@ui:ui moony:ui ; rdfs:seeAlso . moony:c4a1xc4a1 @@ -90,19 +82,14 @@ moony:c4a1xc4a1 lv2:minorVersion @MINOR_VERSION@ ; lv2:microVersion @MICRO_VERSION@ ; lv2:binary ; - @UI_OPENGL@ui:ui moony:moony_ui ; - @UI_NEXT@ui:ui moony:moony_d2tk ; + @UI@ui:ui moony:ui ; rdfs:seeAlso . # UI -@UI@moony:moony_ui -@UI@ a ui:@UI_TYPE@ ; +@UI@moony:ui +@UI@ a ui:X11UI ; @UI@ ui:binary ; @UI@ rdfs:seeAlso . -@UI@moony:moony_d2tk -@UI@ a ui:@UI_TYPE@ ; -@UI@ ui:binary ; -@UI@ rdfs:seeAlso . # Banks moony:bank-through diff --git a/plugin/moony_ui.ttl b/plugin/moony_ui.ttl index a6b425d..8651f08 100644 --- a/plugin/moony_ui.ttl +++ b/plugin/moony_ui.ttl @@ -11,50 +11,7 @@ @prefix moony: . -moony:moony_ui - ui:portNotification [ - ui:plugin moony:c1xc1 ; - lv2:symbol "notify" ; - ui:protocol atom:eventTransfer ; - ] , [ - ui:plugin moony:c2xc2 ; - lv2:symbol "notify" ; - ui:protocol atom:eventTransfer ; - ] , [ - ui:plugin moony:c4xc4 ; - lv2:symbol "notify" ; - ui:protocol atom:eventTransfer ; - ] , [ - ui:plugin moony:a1xa1 ; - lv2:symbol "notify" ; - ui:protocol atom:eventTransfer ; - ] , [ - ui:plugin moony:a2xa2 ; - lv2:symbol "notify" ; - ui:protocol atom:eventTransfer ; - ] , [ - ui:plugin moony:a4xa4 ; - lv2:symbol "notify" ; - ui:protocol atom:eventTransfer ; - ] , [ - ui:plugin moony:c1a1xc1a1 ; - lv2:symbol "notify" ; - ui:protocol atom:eventTransfer ; - ] , [ - ui:plugin moony:c2a1xc2a1 ; - lv2:symbol "notify" ; - ui:protocol atom:eventTransfer ; - ] , [ - ui:plugin moony:c4a1xc4a1 ; - lv2:symbol "notify" ; - ui:protocol atom:eventTransfer ; - ] ; - lv2:requiredFeature ui:idleInterface, ui:portMap, urid:map, urid:unmap, ui:parent ; - lv2:optionalFeature opts:options, log:log ; - opts:supportedOption ui:scaleFactor ; - lv2:extensionData ui:idleInterface . - -moony:moony_d2tk +moony:ui ui:portNotification [ ui:plugin moony:c1xc1 ; lv2:symbol "notify" ; diff --git a/plugin/nk_ui.c b/plugin/nk_ui.c deleted file mode 100644 index af2b81b..0000000 --- a/plugin/nk_ui.c +++ /dev/null @@ -1,3946 +0,0 @@ -/* - * SPDX-FileCopyrightText: Hanspeter Portner - * SPDX-License-Identifier: Artistic-2.0 - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define NK_PUGL_IMPLEMENTATION -#include "nk_pugl/nk_pugl.h" - -#include -#include -#include - -#if defined(BUILD_INLINE_DISP) -# include -#endif - -extern int luaopen_lpeg(lua_State *L); - -#ifdef Bool -# undef Bool // Xlib.h interferes with LV2_Atom_Forge.Bool -#endif - -#define RDF_PREFIX "http://www.w3.org/1999/02/22-rdf-syntax-ns#" -#define RDFS_PREFIX "http://www.w3.org/2000/01/rdf-schema#" - -#define RDF__value RDF_PREFIX"value" -#define RDFS__label RDFS_PREFIX"label" -#define RDFS__range RDFS_PREFIX"range" -#define RDFS__comment RDFS_PREFIX"comment" - -#define MAX_PATH_LEN 1024 - -#if defined(__WIN32) -static char * -_strndup(const char *s, size_t n) -{ - size_t len = strnlen(s, n); - char *new = (char *) malloc(len + 1); - - if(new == NULL) - return NULL; - - new[len] = '\0'; - return memcpy(new, s, len); -} -#else -# define _strndup strndup -#endif - -#ifdef __unix__ -#include -#include -#endif - -#ifndef _WIN32 -# include -#endif - -#ifdef _WIN32 -# define SLASH_CHAR '\\' -# define SLASH_STRING "\\" -#else -# define SLASH_CHAR '/' -# define SLASH_STRING "/" -#endif - -typedef struct _chunk_t chunk_t; -typedef struct _vec_t vec_t; -typedef union _body_t body_t; -typedef struct _prop_t prop_t; -typedef enum _browser_type_t browser_type_t; -typedef struct _browser_t browser_t; -typedef struct _plughandle_t plughandle_t; - -struct _chunk_t { - uint32_t size; - uint8_t *body; -}; - -struct _vec_t { - uint32_t child_num; - uint32_t child_type; - uint8_t *body; -}; - -union _body_t { - int32_t i; - int64_t h; - uint32_t u; - float f; - double d; - struct nk_text_edit editor; - chunk_t chunk; - vec_t vec; -}; - -struct _prop_t { - LV2_URID key; - uint32_t index; // for control ports only - LV2_URID range; - char *unit; - char *label; - char *comment; - body_t value; - body_t minimum; - body_t maximum; - LV2_Atom_Tuple *points; - struct nk_color color; - bool dirty; -}; - -enum _browser_type_t { - BROWSER_NONE = 0, - BROWSER_IMPORT_CODE, - BROWSER_EXPORT_CODE, - BROWSER_IMPORT_PROPERTY, - BROWSER_EXPORT_PROPERTY -}; - -struct _browser_t { - char file[MAX_PATH_LEN]; - char home[MAX_PATH_LEN]; - char directory[MAX_PATH_LEN]; - char export[MAX_PATH_LEN]; - - char **files; - char **directories; - size_t file_count; - size_t dir_count; - ssize_t selected; - int return_hidden; - int return_lua_only; - - struct { - struct nk_image home; - struct nk_image computer; - struct nk_image directory; - struct nk_image default_file; - struct nk_image checked; - struct nk_image run_all; - struct nk_image import_from; - struct nk_image export_to; - struct nk_image refresh; - struct nk_image editor; - struct nk_image log; - struct nk_image parameters; - struct nk_image plus; - struct nk_image clear; - struct nk_image bell; - struct nk_image panic; - struct nk_image about; - struct nk_image omk; - struct nk_image howl; - } icons; -}; - -struct _plughandle_t { - LV2_URID_Map *map; - LV2_URID_Unmap *unmap; - LV2_Atom_Forge forge; - - LV2_Log_Log *log; - LV2_Log_Logger logger; - - float scale; - - nk_pugl_window_t win; - struct nk_style_button bst; - -#if defined(BUILD_INLINE_DISP) - LV2_Canvas_URID canvas_urid; - LV2_Canvas_Idisp canvas_idisp; - struct nk_image canvas_img; - unsigned canvas_w; - unsigned canvas_h; - bool canvas_redraw; - LV2_Atom *canvas_value; -#endif - - LV2UI_Controller *controller; - LV2UI_Write_Function writer; - - uint32_t control; - uint32_t notify; - LV2_URID atom_eventTransfer; - LV2_URID ui_floatProtocol; - LV2_URID patch_self; - LV2_URID patch_Get; - LV2_URID patch_Set; - LV2_URID patch_Put; - LV2_URID patch_Patch; - LV2_URID patch_Ack; - LV2_URID patch_Error; - LV2_URID patch_writable; - LV2_URID patch_readable; - LV2_URID patch_add; - LV2_URID patch_remove; - LV2_URID patch_wildcard; - LV2_URID patch_property; - LV2_URID patch_body; - LV2_URID patch_value; - LV2_URID patch_subject; - LV2_URID patch_sequenceNumber; - LV2_URID moony_code; - LV2_URID moony_error; - LV2_URID moony_trace; - LV2_URID moony_panic; - LV2_URID moony_editorHidden; - LV2_URID moony_logHidden; - LV2_URID moony_logFollow; - LV2_URID moony_logReset; - LV2_URID moony_paramHidden; - LV2_URID moony_paramCols; - LV2_URID moony_paramRows; - LV2_URID moony_color; - LV2_URID moony_syntax; - LV2_URID lua_lang; - LV2_URID rdfs_label; - LV2_URID rdfs_range; - LV2_URID rdfs_comment; - LV2_URID rdf_value; - LV2_URID lv2_minimum; - LV2_URID lv2_maximum; - LV2_URID lv2_scalePoint; - LV2_URID units_symbol; - LV2_URID units_unit; - LV2_URID units_bar; - LV2_URID units_beat; - LV2_URID units_bpm; - LV2_URID units_cent; - LV2_URID units_cm; - LV2_URID units_db; - LV2_URID units_degree; - LV2_URID units_frame; - LV2_URID units_hz; - LV2_URID units_inch; - LV2_URID units_khz; - LV2_URID units_km; - LV2_URID units_m; - LV2_URID units_mhz; - LV2_URID units_midiNote; - LV2_URID units_mile; - LV2_URID units_min; - LV2_URID units_mm; - LV2_URID units_ms; - LV2_URID units_oct; - LV2_URID units_pc; - LV2_URID units_s; - LV2_URID units_semitone12TET; - - atom_ser_t ser; - - browser_type_t browser_type; - prop_t *browser_target; - - char code [MOONY_MAX_CHUNK_LEN]; - struct nk_text_edit editor; - bool dirty; - - bool has_control_a; - - char error [MOONY_MAX_ERROR_LEN]; - int error_sz; - - int n_trace; - char **traces; - - int n_writable; - prop_t *writables; - int n_readable; - prop_t *readables; - - prop_t controls_in [4]; - prop_t controls_out [4]; - - lua_State *L; - - browser_t browser; - const char *bundle_path; - char *manual; - - bool show_about; - - int32_t editor_hidden; - int32_t log_hidden; - int32_t log_follow; - int32_t log_reset; - int32_t param_hidden; - int32_t param_rows; - int32_t param_cols; - - bool has_initial_focus; - bool refocus_after_filedialog; - struct nk_text_edit *last_edit_focus; -}; - -static const char *default_script = - "-- Don't know how to code? Load a tutorial and visit the reference manual at:\n" - "-- https://openmusickontrollers.gitlab.io/moony.lv2/"; - -static void -_patch_set_code(plughandle_t *handle, uint32_t size, const char *body, bool user); - -static bool -_checkbox(struct nk_context *ctx, int32_t *state); - -#define URN_UUID_SIZE 49 -//tools.ietf.org/html/rfc4122 version 4 -static void -_urn_uuid_random(plughandle_t *handle) -{ - uint8_t bytes [0x10]; - - for(unsigned i=0x0; i<0x10; i++) - bytes[i] = rand() & 0xff; - - bytes[6] = (bytes[6] & 0b00001111) | 0b01000000; // set four most significant bits of 7th byte to 0b0100 - bytes[8] = (bytes[8] & 0b00111111) | 0b10000000; // set two most significant bits of 9th byte to 0b10 - - char uuid [URN_UUID_SIZE]; - snprintf(uuid, URN_UUID_SIZE, "'urn:uuid:%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x#'", - bytes[0x0], bytes[0x1], bytes[0x2], bytes[0x3], - bytes[0x4], bytes[0x5], - bytes[0x6], bytes[0x7], - bytes[0x8], bytes[0x9], - bytes[0xa], bytes[0xb], bytes[0xc], bytes[0xd], bytes[0xe], bytes[0xf]); - - nk_pugl_copy_to_clipboard(&handle->win, uuid, URN_UUID_SIZE); -} - -static uint8_t * -file_load(const char *path, size_t *siz) -{ - FILE *fd = fopen(path, "rb"); - if(!fd) - return NULL; - - fseek(fd, 0, SEEK_END); - *siz = ftell(fd); - fseek(fd, 0, SEEK_SET); - - uint8_t *buf = calloc(*siz, 1); - if(buf) - fread(buf, *siz, 1, fd); - - fclose(fd); - return buf; -} - -static void -dir_free_list(char **list, size_t size) -{ - size_t i; - for(i = 0; i < size; i++) - free(list[i]); - free(list); -} - -static int -_cmp(const void *a, const void *b) -{ - const char *const *A = a; - const char *const *B = b; - return strcasecmp(*A, *B); -} - -static char** -dir_list(const char *dir, int return_subdirs, int return_hidden, - int return_lua_only, size_t *count) -{ - size_t n = 0; - char buffer[MAX_PATH_LEN]; - char **results = NULL; - size_t capacity = 32; - size_t size; - DIR *z; - - assert(dir); - assert(count); - strncpy(buffer, dir, MAX_PATH_LEN - 1); - n = strlen(buffer); - - if(n > 0 && (buffer[n-1] != SLASH_CHAR)) - buffer[n++] = SLASH_CHAR; - - size = 0; - - z = opendir(dir); - if(z != NULL) - { - struct dirent *data = readdir(z); - if(data == NULL) - return NULL; - - do { - DIR *y; - char *p; - int is_subdir; - if( (data->d_name[0] == '.') - && (!return_hidden || ( (data->d_name[1] == '\0') || (data->d_name[1] == '.'))) ) - continue; - - if(return_lua_only) - { - char *point = strrchr(data->d_name, '.'); - if(!point) // no suffix - continue; - - if(strcmp(point, ".lua")) // no *.lua suffix - continue; - } - - strncpy(buffer + n, data->d_name, MAX_PATH_LEN-n); - y = opendir(buffer); - is_subdir = (y != NULL); - if (y != NULL) - closedir(y); - - if((return_subdirs && is_subdir) || (!is_subdir && !return_subdirs)) - { - if(!size) - { - results = (char**)calloc(sizeof(char*), capacity); - } - else if(size >= capacity) - { - void *old = results; - capacity = capacity * 2; - results = (char**)realloc(results, capacity * sizeof(char*)); - assert(results); - if(!results) - free(old); - } - p = strdup(data->d_name); - results[size++] = p; - } - } while ((data = readdir(z)) != NULL); - - qsort(results, size, sizeof(char *), _cmp); - } - - if(z) - closedir(z); - *count = size; - return results; -} - -static void -file_browser_reload_directory_content(browser_t *browser, const char *path) -{ - strncpy(browser->directory, path, MAX_PATH_LEN - 1); - dir_free_list(browser->files, browser->file_count); - dir_free_list(browser->directories, browser->dir_count); - browser->files = dir_list(path, 0, browser->return_hidden, browser->return_lua_only, &browser->file_count); - browser->directories = dir_list(path, 1, browser->return_hidden, 0, &browser->dir_count); - browser->selected = -1; -} - -static void -file_browser_init(browser_t *browser, int return_hidden, int return_lua_only, - struct nk_image (*icon_load)(void *data, const char *filename), void *data) -{ - memset(browser, 0, sizeof(*browser)); - - const char *home = getenv("HOME"); -#ifdef _WIN32 - if (!home) home = getenv("USERPROFILE"); -#else - if (!home) home = getpwuid(getuid())->pw_dir; -#endif - - size_t l; - strncpy(browser->home, home, MAX_PATH_LEN - 1); - l = strlen(browser->home); - strcpy(browser->home + l, SLASH_STRING); - strcpy(browser->directory, browser->home); - - browser->selected = -1; - browser->return_hidden = return_hidden; - browser->return_lua_only = return_lua_only; - - if(icon_load) - { - browser->icons.home = icon_load(data, "house.png"); - browser->icons.directory = icon_load(data, "layers.png"); - browser->icons.computer = icon_load(data, "user.png"); - browser->icons.default_file = icon_load(data, "envelope.png"); - browser->icons.checked = icon_load(data, "checked.png"); - browser->icons.run_all = icon_load(data, "next.png"); - browser->icons.import_from = icon_load(data, "upload.png"); - browser->icons.export_to = icon_load(data, "download.png"); - browser->icons.refresh = icon_load(data, "reload.png"); - browser->icons.editor = icon_load(data, "pencil.png"); - browser->icons.log = icon_load(data, "menu.png"); - browser->icons.parameters = icon_load(data, "settings.png"); - browser->icons.plus = icon_load(data, "plus.png"); - browser->icons.clear = icon_load(data, "cancel.png"); - browser->icons.bell = icon_load(data, "bell.png"); - browser->icons.panic= icon_load(data, "cancel-1.png"); - browser->icons.about= icon_load(data, "question.png"); - browser->icons.omk = icon_load(data, "omk_logo_256x256.png"); - browser->icons.howl = icon_load(data, "moony_logo.png"); - } -} - -static void -file_browser_free(browser_t *browser, - void (*icon_unload)(void *data, struct nk_image img), void *data) -{ - if(icon_unload) - { - icon_unload(data, browser->icons.home); - icon_unload(data, browser->icons.directory); - icon_unload(data, browser->icons.computer); - icon_unload(data, browser->icons.default_file); - icon_unload(data, browser->icons.checked); - icon_unload(data, browser->icons.run_all); - icon_unload(data, browser->icons.import_from); - icon_unload(data, browser->icons.export_to); - icon_unload(data, browser->icons.refresh); - icon_unload(data, browser->icons.editor); - icon_unload(data, browser->icons.log); - icon_unload(data, browser->icons.parameters); - icon_unload(data, browser->icons.plus); - icon_unload(data, browser->icons.clear); - icon_unload(data, browser->icons.bell); - icon_unload(data, browser->icons.panic); - icon_unload(data, browser->icons.about); - icon_unload(data, browser->icons.omk); - icon_unload(data, browser->icons.howl); - } - - if(browser->files) - dir_free_list(browser->files, browser->file_count); - browser->files = NULL; - - if(browser->directories) - dir_free_list(browser->directories, browser->dir_count); - browser->directories = NULL; - - memset(browser, 0, sizeof(*browser)); -} - -static int -file_browser_run(browser_t *browser, struct nk_context *ctx, float dy, - const char *title, browser_type_t browser_type, struct nk_rect bounds) -{ - int ret = 0; - bool commited = false; - const bool is_export = (browser_type == BROWSER_EXPORT_CODE) - || (browser_type == BROWSER_EXPORT_PROPERTY); - const struct nk_input *in = &ctx->input; - - // delayed initial loading - if(!browser->files) - browser->files = dir_list(browser->directory, 0, browser->return_hidden, browser->return_lua_only, &browser->file_count); - if(!browser->directories) - browser->directories = dir_list(browser->directory, 1, browser->return_hidden, 0, &browser->dir_count); - - if(nk_begin(ctx, title, bounds, - NK_WINDOW_BORDER | NK_WINDOW_TITLE | NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_CLOSABLE)) - { - static float ratio[] = {0.75f, 0.25f}; - float spacing_x = ctx->style.window.spacing.x; - - /* output path directory selector in the menubar */ - ctx->style.window.spacing.x = 0; - nk_menubar_begin(ctx); - { - char *d = browser->directory; - char *begin = d + 1; - nk_layout_row_dynamic(ctx, dy, 6); - while(*d++) - { - if(*d == SLASH_CHAR) - { - *d = '\0'; - if(nk_button_label(ctx, begin)) - { - *d++ = SLASH_CHAR; *d = '\0'; - file_browser_reload_directory_content(browser, browser->directory); - break; - } - *d = SLASH_CHAR; - begin = d + 1; - } - } - - nk_layout_row_dynamic(ctx, dy, 1); - nk_label(ctx, browser->directory, NK_TEXT_LEFT); - - if(is_export) - { - nk_flags flags = NK_EDIT_FIELD | NK_EDIT_SIG_ENTER; - const nk_flags state = nk_edit_string_zero_terminated(ctx, flags, - browser->export, MAX_PATH_LEN, nk_filter_ascii); - if( (state & NK_EDIT_COMMITED) && (strlen(browser->export) > 0) ) - { - commited = true; - } - } - } - nk_menubar_end(ctx); - ctx->style.window.spacing.x = spacing_x; - - /* window layout */ - struct nk_rect total_space = nk_window_get_content_region(ctx); - nk_layout_row(ctx, NK_DYNAMIC, total_space.h, 2, ratio); - - /* output directory content window */ - nk_group_begin(ctx, "Content", 0); - { - ssize_t count = browser->dir_count + browser->file_count; - - nk_layout_row_dynamic(ctx, dy, 1); - for(ssize_t j = 0; j < count; j++) - { - const bool odd = j % 2; - - if(odd) - nk_style_push_style_item(ctx, &ctx->style.selectable.normal, - nk_style_item_color(nk_rgb(0x37, 0x37, 0x37))); - if(j < (ssize_t)browser->dir_count) - { - if(nk_select_image_label(ctx, browser->icons.directory, browser->directories[j], NK_TEXT_LEFT, nk_false)) - { - browser->selected = j; - } - } - else - { - const int k = j - browser->dir_count; - if(nk_select_image_label(ctx, browser->icons.default_file, browser->files[k], NK_TEXT_LEFT, nk_false)) - { - if(browser->selected == j) - commited = true; // poor-man's double-click - - browser->selected = j; - strncpy(browser->export, browser->files[k], MAX_PATH_LEN - 1); - } - } - if(odd) - nk_style_pop_style_item(ctx); - } - - nk_group_end(ctx); - } - - /* special buttons */ - nk_group_begin(ctx, "Special", NK_WINDOW_NO_SCROLLBAR); - { - nk_layout_row_dynamic(ctx, dy, 1); - if(nk_button_image_label(ctx, browser->icons.home, "Home", NK_TEXT_RIGHT)) - file_browser_reload_directory_content(browser, browser->home); - if(nk_button_image_label(ctx, browser->icons.computer, "Computer", NK_TEXT_RIGHT)) -#ifdef _WIN32 - file_browser_reload_directory_content(browser, "C:\\"); -#else - file_browser_reload_directory_content(browser, SLASH_STRING); -#endif - - nk_spacing(ctx, 1); - - const float ratio2 [2] = {0.2, 0.8}; - nk_layout_row(ctx, NK_DYNAMIC, dy, 2, ratio2); - if(_checkbox(ctx, &browser->return_hidden)) - file_browser_reload_directory_content(browser, browser->directory); - nk_label(ctx, "Show hidden", NK_TEXT_LEFT); - - if(_checkbox(ctx, &browser->return_lua_only)) - file_browser_reload_directory_content(browser, browser->directory); - nk_label(ctx, "Show *.lua only", NK_TEXT_LEFT); - - nk_layout_row_dynamic(ctx, dy, 1); - // change directory - if( (browser->selected >= 0) && (browser->selected < (ssize_t)browser->dir_count) ) - { - const int j = browser->selected; - size_t n = strlen(browser->directory); - strncpy(browser->directory + n, browser->directories[j], MAX_PATH_LEN - n); - n = strlen(browser->directory); - if(n < MAX_PATH_LEN - 1) - { - browser->directory[n] = SLASH_CHAR; - browser->directory[n+1] = '\0'; - } - file_browser_reload_directory_content(browser, browser->directory); - } - - if(is_export) - { - nk_spacing(ctx, 2); - - //FIXME tooltip - if(nk_button_image_label(ctx, browser->icons.checked, "OK", NK_TEXT_RIGHT)) - { - commited = true; - } - } - - nk_group_end(ctx); - } - } - nk_end(ctx); - - if(is_export) - { - if( commited - || nk_input_is_key_pressed(in, NK_KEY_ENTER) ) - { - if(strlen(browser->export) > 0) - { - strncpy(browser->file, browser->directory, MAX_PATH_LEN); - const size_t n = strlen(browser->file); - strncpy(browser->file + n, browser->export, MAX_PATH_LEN - n); - ret = 1; - } - } - } - else // !is_export - { - // load selected file directly - if(browser->selected >= (ssize_t)browser->dir_count) - { - const int k = browser->selected - browser->dir_count; - strncpy(browser->file, browser->directory, MAX_PATH_LEN); - const size_t n = strlen(browser->file); - strncpy(browser->file + n, browser->files[k], MAX_PATH_LEN - n); - ret = 1; - browser->selected = -1; - } - } - - return ret; -} - -static inline void -_qsort(prop_t *a, unsigned n, LV2_URID_Unmap *unmap) -{ - if(n < 2) - return; - - const prop_t *p = &a[n/2]; - - unsigned i, j; - for(i=0, j=n-1; ; i++, j--) - { - while(strcmp(unmap->unmap(unmap->handle, a[i].key), unmap->unmap(unmap->handle, p->key)) < 0) - i++; - - while(strcmp(unmap->unmap(unmap->handle, p->key), unmap->unmap(unmap->handle, a[j].key)) < 0) - j--; - - if(i >= j) - break; - - const prop_t t = a[i]; - a[i] = a[j]; - a[j] = t; - } - - _qsort(a, i, unmap); - _qsort(&a[i], n - i, unmap); -} - -static prop_t * -_prop_get(prop_t **properties, int *n_properties, LV2_URID key) -{ - // we cannot easily speed this up, as properties are ordered according to URI, not URID - for(int i = 0; i < *n_properties; i++) - { - prop_t *prop = &(*properties)[i]; - - if(prop->key == key) - return prop; - } - - return NULL; -} - -static prop_t * -_prop_get_or_add(plughandle_t *handle, prop_t **properties, int *n_properties, LV2_URID key) -{ - prop_t *prop = _prop_get(properties, n_properties, key); - if(prop) - return prop; - - *properties = realloc(*properties, (*n_properties + 1)*sizeof(prop_t)); - prop = &(*properties)[*n_properties]; - memset(prop, 0x0, sizeof(prop_t)); - prop->key = key; - prop->color = nk_white; - *n_properties += 1; - - // sort properties according to URI string comparison - _qsort(*properties, *n_properties, handle->unmap); - - return _prop_get(properties, n_properties, key); -} - -static struct nk_image -_image_new(plughandle_t *handle, unsigned w, unsigned h, const void *data, - bool switch_context) -{ - GLuint tex = 0; - - if(switch_context) - { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - puglEnterContext(handle->win.view); -#pragma GCC diagnostic pop - } - - { - glGenTextures(1, &tex); - glBindTexture(GL_TEXTURE_2D, tex); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - if(!handle->win.glGenerateMipmap) // for GL >= 1.4 && < 3.1 - glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data); - if(handle->win.glGenerateMipmap) - handle->win.glGenerateMipmap(GL_TEXTURE_2D); - } - - if(switch_context) - { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - puglLeaveContext(handle->win.view); -#pragma GCC diagnostic pop - } - - return nk_image_id(tex); -} - -static void -_image_free(plughandle_t *handle, struct nk_image *img, bool switch_context) -{ - if(img->handle.id) - { - if(switch_context) - { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - puglEnterContext(handle->win.view); -#pragma GCC diagnostic pop - } - - { - glDeleteTextures(1, (const GLuint *)&img->handle.id); - img->handle.id = 0; - } - - if(switch_context) - { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - puglLeaveContext(handle->win.view); -#pragma GCC diagnostic pop - } - } -} - -static bool -_image_empty(struct nk_image *img) -{ - return (img->handle.id == 0); -} - -static void -_prop_free(plughandle_t *handle, prop_t *prop) -{ - if(prop->label) - free(prop->label); - - if(prop->comment) - free(prop->comment); - - if(prop->unit) - free(prop->unit); - - if( (prop->range == handle->forge.String) - || (prop->range == handle->forge.URID) ) - { - nk_textedit_free(&prop->value.editor); - } - else if(prop->range == handle->forge.Chunk) - { - if(prop->value.chunk.body) - free(prop->value.chunk.body); - } - else if(prop->range == handle->forge.Vector) - { - if(prop->value.vec.body) - free(prop->value.vec.body); - } - - if(prop->points) - free(prop->points); - - prop->key = 0; -} - -LV2_Atom_Forge_Ref -_sink_non_rt(LV2_Atom_Forge_Sink_Handle handle, const void *buf, uint32_t size) -{ - atom_ser_t *ser = handle; - - const LV2_Atom_Forge_Ref ref = ser->offset + 1; - - const uint32_t new_offset = ser->offset + size; - if(new_offset > ser->size) - { - uint32_t new_size = ser->size << 1; - while(new_offset > new_size) - new_size <<= 1; - - if(!(ser->buf = realloc(ser->buf, new_size))) - return 0; // realloc failed - - ser->size = new_size; - } - - memcpy(ser->buf + ser->offset, buf, size); - ser->offset = new_offset; - - return ref; -} - -LV2_Atom * -_deref(LV2_Atom_Forge_Sink_Handle handle, LV2_Atom_Forge_Ref ref) -{ - atom_ser_t *ser = handle; - - const uint32_t offset = ref - 1; - - return (LV2_Atom *)(ser->buf + offset); -} - -static void -_patch_ack(plughandle_t *handle, int32_t sequence_number) -{ - if(!sequence_number) - return; - - LV2_Atom_Forge *forge = &handle->forge; - atom_ser_t *ser = &handle->ser; - - ser->offset = 0; - lv2_atom_forge_set_sink(forge, _sink_non_rt, _deref, ser); - - LV2_Atom_Forge_Frame frame; - lv2_atom_forge_object(forge, &frame, 0, handle->patch_Ack); - - lv2_atom_forge_key(forge, handle->patch_subject); - lv2_atom_forge_urid(forge, handle->patch_self); - - lv2_atom_forge_key(forge, handle->patch_sequenceNumber); - lv2_atom_forge_int(forge, sequence_number); - - lv2_atom_forge_pop(forge, &frame); - - const uint32_t sz = lv2_atom_total_size(ser->atom); - handle->writer(handle->controller, handle->control, sz, handle->atom_eventTransfer, ser->atom); -} - -static void -_patch_error(plughandle_t *handle, int32_t sequence_number) -{ - if(!sequence_number) - return; - - LV2_Atom_Forge *forge = &handle->forge; - atom_ser_t *ser = &handle->ser; - - ser->offset = 0; - lv2_atom_forge_set_sink(forge, _sink_non_rt, _deref, ser); - - LV2_Atom_Forge_Frame frame; - lv2_atom_forge_object(forge, &frame, 0, handle->patch_Error); - - lv2_atom_forge_key(forge, handle->patch_subject); - lv2_atom_forge_urid(forge, handle->patch_self); - - lv2_atom_forge_key(forge, handle->patch_sequenceNumber); - lv2_atom_forge_int(forge, sequence_number); - - lv2_atom_forge_pop(forge, &frame); - - const uint32_t sz = lv2_atom_total_size(ser->atom); - handle->writer(handle->controller, handle->control, sz, handle->atom_eventTransfer, ser->atom); -} - -static void -_patch_get(plughandle_t *handle, LV2_URID property) -{ - LV2_Atom_Forge *forge = &handle->forge; - atom_ser_t *ser = &handle->ser; - - ser->offset = 0; - lv2_atom_forge_set_sink(forge, _sink_non_rt, _deref, ser); - - LV2_Atom_Forge_Frame frame; - lv2_atom_forge_object(forge, &frame, 0, handle->patch_Get); - if(property) - { - lv2_atom_forge_key(forge, handle->patch_subject); - lv2_atom_forge_urid(forge, handle->patch_self); - - lv2_atom_forge_key(forge, handle->patch_sequenceNumber); - lv2_atom_forge_int(forge, 0); - - lv2_atom_forge_key(forge, handle->patch_property); - lv2_atom_forge_urid(forge, property); - } - lv2_atom_forge_pop(forge, &frame); - - const uint32_t sz = lv2_atom_total_size(ser->atom); - handle->writer(handle->controller, handle->control, sz, handle->atom_eventTransfer, ser->atom); -} - -static void -_patch_set(plughandle_t *handle, LV2_URID property, uint32_t size, LV2_URID type, - const void *body) -{ - LV2_Atom_Forge *forge = &handle->forge; - atom_ser_t *ser = &handle->ser; - - ser->offset = 0; - lv2_atom_forge_set_sink(forge, _sink_non_rt, _deref, ser); - - LV2_Atom_Forge_Frame frame; - lv2_atom_forge_object(forge, &frame, 0, handle->patch_Set); - - lv2_atom_forge_key(forge, handle->patch_subject); - lv2_atom_forge_urid(forge, handle->patch_self); - - lv2_atom_forge_key(forge, handle->patch_sequenceNumber); - lv2_atom_forge_int(forge, 0); - - lv2_atom_forge_key(forge, handle->patch_property); - lv2_atom_forge_urid(forge, property); - - lv2_atom_forge_key(forge, handle->patch_value); - if(type == forge->String) - { - lv2_atom_forge_string(forge, body, size); - } - else // !String - { - lv2_atom_forge_atom(forge, size, type); - lv2_atom_forge_write(forge, body, size); - } - - lv2_atom_forge_pop(forge, &frame); - - const uint32_t sz = lv2_atom_total_size(ser->atom); - handle->writer(handle->controller, handle->control, sz, handle->atom_eventTransfer, ser->atom); -} - -static void -_control_set(plughandle_t *handle, uint32_t index, const float *value) -{ - const uint32_t sz = sizeof(float); - handle->writer(handle->controller, index, sz, 0, value); -} - -static void -_clear_error(plughandle_t *handle) -{ - handle->error[0] = '\0'; -} - -static void -_clear_log(plughandle_t *handle) -{ - for(int i = 0; i < handle->n_trace; i++) - free(handle->traces[i]); - free(handle->traces); - - handle->n_trace = 0; - handle->traces = NULL; - - nk_pugl_post_redisplay(&handle->win); -} - -static void -_submit_all(plughandle_t *handle) -{ - _clear_error(handle); - - struct nk_str *str = &handle->editor.string; - _patch_set(handle, handle->moony_code, - nk_str_len_char(str), handle->forge.String, nk_str_get_const(str)); - - handle->dirty = false; - - if(handle->log_reset) - _clear_log(handle); -} - -static void -_text_image_colored(struct nk_context *ctx, struct nk_image *img, - const char *str, nk_flags alignment, struct nk_color color) -{ - struct nk_window *win; - const struct nk_style *style; - - struct nk_vec2 item_padding; - struct nk_rect bounds; - struct nk_text text; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) return; - - win = ctx->current; - style = &ctx->style; - nk_panel_alloc_space(&bounds, ctx); - item_padding = style->text.padding; - - struct nk_rect bounds1 = bounds; - bounds1.w = bounds1.h; - nk_draw_image(&win->buffer, bounds1, img, nk_white); - - struct nk_rect bounds2 = bounds; - bounds2.x += bounds1.w + style->window.padding.x; - bounds2.w -= bounds1.w; - text.padding.x = item_padding.x; - text.padding.y = item_padding.y; - text.background = style->window.background; - text.text = color; - nk_widget_text(&win->buffer, bounds2, str, strlen(str), &text, alignment, style->font); -} - -static int -_dial_bool(struct nk_context *ctx, int32_t *val, struct nk_color color, bool editable) -{ - const int32_t tmp = *val; - struct nk_rect bounds = nk_layout_space_bounds(ctx); - const bool left_mouse_click_in_cursor = nk_widget_is_mouse_clicked(ctx, NK_BUTTON_LEFT); - const enum nk_widget_layout_states layout_states = nk_widget(&bounds, ctx); - - if(layout_states != NK_WIDGET_INVALID) - { - enum nk_widget_states states = NK_WIDGET_STATE_INACTIVE; - struct nk_input *in = (ctx->current->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - - if(in && editable) - { - bool mouse_has_scrolled = false; - - if(left_mouse_click_in_cursor) - { - states = NK_WIDGET_STATE_ACTIVED; - } - else if(nk_input_is_mouse_hovering_rect(in, bounds)) - { - if(in->mouse.scroll_delta.y != 0.f) // has scrolling - { - mouse_has_scrolled = true; - in->mouse.scroll_delta.y = 0.f; - } - - states = NK_WIDGET_STATE_HOVER; - } - - if(left_mouse_click_in_cursor || mouse_has_scrolled) - { - *val = !*val; - } - } - - const struct nk_style_item *fg = NULL; - - switch(states) - { - case NK_WIDGET_STATE_HOVER: - { - fg = &ctx->style.progress.cursor_hover; - } break; - case NK_WIDGET_STATE_ACTIVED: - { - fg = &ctx->style.progress.cursor_active; - } break; - default: - { - fg = &ctx->style.progress.cursor_normal; - } break; - } - - struct nk_color fg_color = fg->data.color; - - fg_color.r = (int)fg_color.r * color.r / 0xff; - fg_color.g = (int)fg_color.g * color.g / 0xff; - fg_color.b = (int)fg_color.b * color.b / 0xff; - fg_color.a = (int)fg_color.a * color.a / 0xff; - - struct nk_command_buffer *canv= nk_window_get_canvas(ctx); - const float w2 = bounds.w/2; - const float h2 = bounds.h/2; - const float r1 = NK_MIN(w2, h2); - const float r2 = r1 / 2; - const float cx = bounds.x + w2; - const float cy = bounds.y + h2; - - nk_stroke_arc(canv, cx, cy, r2 - 1, 0.f, 2*M_PI, 2.f, fg_color); - if(*val) - nk_fill_arc(canv, cx, cy, r2 - 4, 0.f, 2*M_PI, fg_color); - } - - return tmp != *val; -} - -static int32_t -_check(struct nk_context *ctx, int32_t state) -{ - _dial_bool(ctx, &state, nk_rgb(0xff, 0xff, 0xff), true); - - return state; -} - -static bool -_checkbox(struct nk_context *ctx, int32_t *state) -{ - const int32_t old = *state; - - _dial_bool(ctx, state, nk_rgb(0xff, 0xff, 0xff), true); - - return old != *state; -} - -static float -_dial_numeric_behavior(struct nk_context *ctx, struct nk_rect bounds, - enum nk_widget_states *states, int *divider, struct nk_input *in) -{ - const struct nk_mouse_button *btn = &in->mouse.buttons[NK_BUTTON_LEFT];; - const bool left_mouse_down = btn->down; - const bool left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in, - NK_BUTTON_LEFT, bounds, nk_true); - - float dd = 0.f; - if(left_mouse_down && left_mouse_click_in_cursor) - { - const float dx = in->mouse.delta.x; - const float dy = in->mouse.delta.y; - dd = fabs(dx) > fabs(dy) ? dx : -dy; - - *states = NK_WIDGET_STATE_ACTIVED; - } - else if(nk_input_is_mouse_hovering_rect(in, bounds)) - { - if(in->mouse.scroll_delta.y != 0.f) // has scrolling - { - dd = in->mouse.scroll_delta.y; - in->mouse.scroll_delta.y = 0.f; - } - - *states = NK_WIDGET_STATE_HOVER; - } - - if(nk_input_is_key_down(in, NK_KEY_CTRL)) - *divider *= 4; - if(nk_input_is_key_down(in, NK_KEY_SHIFT)) - *divider *= 4; - - return dd; -} - -static void -_dial_numeric_draw(struct nk_context *ctx, struct nk_rect bounds, - enum nk_widget_states states, float perc, struct nk_color color) -{ - struct nk_command_buffer *canv= nk_window_get_canvas(ctx); - const struct nk_style_item *bg = NULL; - const struct nk_style_item *fg = NULL; - - switch(states) - { - case NK_WIDGET_STATE_HOVER: - { - bg = &ctx->style.progress.hover; - fg = &ctx->style.progress.cursor_hover; - } break; - case NK_WIDGET_STATE_ACTIVED: - { - bg = &ctx->style.progress.active; - fg = &ctx->style.progress.cursor_active; - } break; - default: - { - bg = &ctx->style.progress.normal; - fg = &ctx->style.progress.cursor_normal; - } break; - } - - const struct nk_color bg_color = bg->data.color; - struct nk_color fg_color = fg->data.color; - - fg_color.r = (int)fg_color.r * color.r / 0xff; - fg_color.g = (int)fg_color.g * color.g / 0xff; - fg_color.b = (int)fg_color.b * color.b / 0xff; - fg_color.a = (int)fg_color.a * color.a / 0xff; - - const float w2 = bounds.w/2; - const float h2 = bounds.h/2; - const float r1 = NK_MIN(w2, h2); - const float r2 = r1 / 2; - const float cx = bounds.x + w2; - const float cy = bounds.y + h2; - const float aa = M_PI/6; - const float a1 = M_PI/2 + aa; - const float a2 = 2*M_PI + M_PI/2 - aa; - const float a3 = a1 + (a2 - a1)*perc; - - nk_stroke_arc(canv, cx, cy, (r1+r2)/2, a1, a2, r1-r2, bg_color); - nk_stroke_arc(canv, cx, cy, (r1+r2)/2, a1, a3, r1-r2, fg_color); -} - -static int -_dial_double(struct nk_context *ctx, double min, double *val, double max, float mul, - struct nk_color color, bool editable) -{ - const double tmp = *val; - struct nk_rect bounds = nk_layout_space_bounds(ctx); - const enum nk_widget_layout_states layout_states = nk_widget(&bounds, ctx); - - if(layout_states != NK_WIDGET_INVALID) - { - enum nk_widget_states states = NK_WIDGET_STATE_INACTIVE; - const double range = max - min; - struct nk_input *in = (ctx->current->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - - if(in && editable) - { - int divider = 1; - const float dd = _dial_numeric_behavior(ctx, bounds, &states, ÷r, in); - - if(dd != 0.f) // update value - { - const double per_pixel_inc = mul * range / bounds.w / divider; - - *val += dd * per_pixel_inc; - *val = NK_CLAMP(min, *val, max); - } - } - - const float perc = (*val - min) / range; - _dial_numeric_draw(ctx, bounds, states, perc, color); - } - - return tmp != *val; -} - -static int -_dial_long(struct nk_context *ctx, int64_t min, int64_t *val, int64_t max, float mul, - struct nk_color color, bool editable) -{ - const int64_t tmp = *val; - struct nk_rect bounds = nk_layout_space_bounds(ctx); - const enum nk_widget_layout_states layout_states = nk_widget(&bounds, ctx); - - if(layout_states != NK_WIDGET_INVALID) - { - enum nk_widget_states states = NK_WIDGET_STATE_INACTIVE; - const int64_t range = max - min; - struct nk_input *in = (ctx->current->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - - if(in && editable) - { - int divider = 1; - const float dd = _dial_numeric_behavior(ctx, bounds, &states, ÷r, in); - - if(dd != 0.f) // update value - { - const double per_pixel_inc = mul * range / bounds.w / divider; - - const double diff = dd * per_pixel_inc; - *val += diff < 0.0 ? floor(diff) : ceil(diff); - *val = NK_CLAMP(min, *val, max); - } - } - - const float perc = (float)(*val - min) / range; - _dial_numeric_draw(ctx, bounds, states, perc, color); - } - - return tmp != *val; -} - -static int -_dial_float(struct nk_context *ctx, float min, float *val, float max, float mul, - struct nk_color color, bool editable) -{ - double tmp = *val; - const int res = _dial_double(ctx, min, &tmp, max, mul, color, editable); - *val = tmp; - - return res; -} - -static int -_dial_int(struct nk_context *ctx, int32_t min, int32_t *val, int32_t max, float mul, - struct nk_color color, bool editable) -{ - int64_t tmp = *val; - const int res = _dial_long(ctx, min, &tmp, max, mul, color, editable); - *val = tmp; - - return res; -} - -static int -_lex_protected(lua_State *L) -{ - struct nk_token *tokens = NULL; - - lua_getglobal(L, "lexer"); - lua_getfield(L, -1, "lex"); - lua_getglobal(L, "moony"); - lua_pushvalue(L, 1); // code - lua_call(L, 2, 1); - - if(lua_type(L, -1) == LUA_TTABLE) - { - const int len = luaL_len(L, -1); - - tokens = calloc(len/2 + 1, sizeof(struct nk_token)); //FIXME use realloc - if(tokens) - { - for(int i = 0; i < len; i += 2) - { - struct nk_token *token = &tokens[i/2]; - - lua_rawgeti(L, -1, i + 1); - const nk_uint token_col = (lua_type(L, -1) == LUA_TNUMBER) - ? luaL_checkinteger(L, -1) - : 0xdddddd; - token->color = nk_rgb( - (token_col >> 16) & 0xff, - (token_col >> 8) & 0xff, - (token_col >> 0) & 0xff); - lua_pop(L, 1); - - lua_rawgeti(L, -1, i + 2); - const int token_offset = (lua_type(L, -1) == LUA_TNUMBER) - ? lua_tointeger(L, -1) - : token->offset + 1; - lua_pop(L, 1); - - token->offset = token_offset - 1; - } - - struct nk_token *token = &tokens[len/2]; - token->offset = INT32_MAX; - } - } - - lua_pushlightuserdata(L, tokens); - return 1; -} - -static struct nk_token * -_lex(void *data, const char *code, int code_sz) -{ - lua_State *L = data; - const int top = lua_gettop(L); - - struct nk_token *tokens = NULL; - - lua_pushcclosure(L, _lex_protected, 0); - lua_pushlstring(L, code, code_sz); - if(lua_pcall(L, 1, 1, 0)) - { - fprintf(stderr, "err: %s\n", lua_tostring(L, -1)); - } - else if(lua_type(L, -1) == LUA_TLIGHTUSERDATA) - { - tokens = lua_touserdata(L, -1); - } - - lua_settop(L, top); - return tokens; -} - -static bool -_tooltip_visible(struct nk_context *ctx) -{ - return nk_widget_has_mouse_click_down(ctx, NK_BUTTON_RIGHT, nk_true) - || (nk_widget_is_hovered(ctx) && nk_input_is_key_down(&ctx->input, NK_KEY_CTRL)); -} - -const char *lab = "#"; //FIXME - -static void -_parameter_widget_enum(plughandle_t *handle, struct nk_context *ctx, prop_t *prop, - bool editable, bool has_shift_enter, float dy, int ndy) -{ - const char *header = NULL; - float diff = HUGE_VAL; - LV2_ATOM_TUPLE_FOREACH(prop->points, itm) - { - const LV2_Atom_Object *obj = (const LV2_Atom_Object *)itm; - - if(!lv2_atom_forge_is_object_type(&handle->forge, obj->atom.type)) - continue; - - const LV2_Atom *label = NULL; - const LV2_Atom *value = NULL; - - lv2_atom_object_get(obj, - handle->rdfs_label, &label, - handle->rdf_value, &value, - 0); - - if(label && (label->type == handle->forge.String) - && value && (value->type == prop->range)) - { - float d = HUGE_VAL; - - if(value->type == handle->forge.Int) - d = abs(((const LV2_Atom_Int *)value)->body - prop->value.i); - else if(value->type == handle->forge.Bool) - d = abs(((const LV2_Atom_Bool *)value)->body - prop->value.i); - else if(value->type == handle->forge.Long) - d = labs(((const LV2_Atom_Long *)value)->body - prop->value.h); - else if(value->type == handle->forge.Float) - d = fabs(((const LV2_Atom_Float *)value)->body - prop->value.f); - else if(value->type == handle->forge.Double) - d = fabs(((const LV2_Atom_Double *)value)->body - prop->value.d); - - if(d < diff) - { - header = LV2_ATOM_BODY(label); - diff = d; - } - } - } - - nk_layout_row_dynamic(ctx, dy, 1); - if(header && nk_combo_begin_label(ctx, header, nk_vec2(nk_widget_width(ctx), 7*dy))) - { - nk_layout_row_dynamic(ctx, dy, 1); - LV2_ATOM_TUPLE_FOREACH(prop->points, itm) - { - const LV2_Atom_Object *obj = (const LV2_Atom_Object *)itm; - - if(!lv2_atom_forge_is_object_type(&handle->forge, obj->atom.type)) - continue; - - const LV2_Atom *label = NULL; - const LV2_Atom *value = NULL; - - lv2_atom_object_get(obj, - handle->rdfs_label, &label, - handle->rdf_value, &value, - 0); - - if(label && (label->type == handle->forge.String) - && value && (value->type == prop->range)) - { - if(nk_combo_item_label(ctx, LV2_ATOM_BODY_CONST(label), NK_TEXT_LEFT) && editable) - { - if(value->type == handle->forge.Int) - { - prop->value.i = ((const LV2_Atom_Int *)value)->body; - _patch_set(handle, prop->key, sizeof(int32_t), prop->range, &prop->value.i); - } - else if (value->type == handle->forge.Bool) - { - prop->value.i = ((const LV2_Atom_Bool *)value)->body; - _patch_set(handle, prop->key, sizeof(int32_t), prop->range, &prop->value.i); - } - else if (value->type == handle->forge.Long) - { - prop->value.h = ((const LV2_Atom_Long *)value)->body; - _patch_set(handle, prop->key, sizeof(int64_t), prop->range, &prop->value.h); - } - else if (value->type == handle->forge.Float) - { - prop->value.f = ((const LV2_Atom_Float *)value)->body; - _patch_set(handle, prop->key, sizeof(float), prop->range, &prop->value.f); - } - else if (value->type == handle->forge.Double) - { - prop->value.d = ((const LV2_Atom_Double *)value)->body; - _patch_set(handle, prop->key, sizeof(double), prop->range, &prop->value.d); - } - } - } - } - - nk_combo_end(ctx); - } -} - -static void -_parameter_widget_int(plughandle_t *handle, struct nk_context *ctx, prop_t *prop, - bool editable, bool has_shift_enter, float dy, int ndy) -{ - // draw dial - nk_layout_row_dynamic(ctx, dy*(ndy-1), 1); - if(_dial_int(ctx, prop->minimum.i, &prop->value.i, prop->maximum.i, 1.f, - prop->color, editable)) - { - _patch_set(handle, prop->key, sizeof(int32_t), prop->range, &prop->value.i); - } - - nk_layout_row_begin(ctx, NK_DYNAMIC, dy, 2); - nk_layout_row_push(ctx, 0.9); - if(editable) - { - const int32_t val = nk_propertyi(ctx, lab, - prop->minimum.i, prop->value.i, prop->maximum.i, 1.f, 0.f); - if(val != prop->value.i) - { - prop->value.i = val; - _patch_set(handle, prop->key, sizeof(int32_t), prop->range, &val); - } - } - else // !editable - { - nk_labelf(ctx, NK_TEXT_RIGHT, "%"PRIi32, prop->value.i); - } - nk_layout_row_push(ctx, 0.1); - if(prop->unit) - nk_label(ctx, prop->unit, NK_TEXT_RIGHT); - else - nk_spacing(ctx, 1); -} - -static void -_parameter_widget_long(plughandle_t *handle, struct nk_context *ctx, prop_t *prop, - bool editable, bool has_shift_enter, float dy, int ndy) -{ - nk_layout_row_dynamic(ctx, dy*(ndy-1), 1); - if(_dial_long(ctx, prop->minimum.h, &prop->value.h, prop->maximum.h, 1.f, - prop->color, editable)) - { - _patch_set(handle, prop->key, sizeof(int64_t), prop->range, &prop->value.h); - } - - nk_layout_row_begin(ctx, NK_DYNAMIC, dy, 2); - nk_layout_row_push(ctx, 0.9); - if(editable) - { - const int64_t val = nk_propertyi(ctx, lab, - prop->minimum.h, prop->value.h, prop->maximum.h, 1.f, 0.f); - if(val != prop->value.h) - { - prop->value.h = val; - _patch_set(handle, prop->key, sizeof(int64_t), prop->range, &val); - } - } - else // !editable - { - nk_labelf(ctx, NK_TEXT_RIGHT, "%"PRIi64, prop->value.h); - } - nk_layout_row_push(ctx, 0.1); - if(prop->unit) - nk_label(ctx, prop->unit, NK_TEXT_RIGHT); - else - nk_spacing(ctx, 1); -} - -static void -_parameter_widget_float(plughandle_t *handle, struct nk_context *ctx, prop_t *prop, - bool editable, bool has_shift_enter, float dy, int ndy) -{ - nk_layout_row_dynamic(ctx, dy*(ndy-1), 1); - if(_dial_float(ctx, prop->minimum.f, &prop->value.f, prop->maximum.f, 1.f, - prop->color, editable)) - { - if(prop->range == handle->ui_floatProtocol) - _control_set(handle, prop->index, &prop->value.f); - else - _patch_set(handle, prop->key, sizeof(float), prop->range, &prop->value.f); - } - - nk_layout_row_begin(ctx, NK_DYNAMIC, dy, 2); - nk_layout_row_push(ctx, 0.9); - if(editable) - { - const float val = nk_propertyf(ctx, lab, - prop->minimum.f, prop->value.f, prop->maximum.f, 0.05f, 0.f); - if(val != prop->value.f) - { - prop->value.f = val; - if(prop->range == handle->ui_floatProtocol) - _control_set(handle, prop->index, &prop->value.f); - else - _patch_set(handle, prop->key, sizeof(float), prop->range, &val); - } - } - else // !editable - { - nk_labelf(ctx, NK_TEXT_RIGHT, "%f", prop->value.f); - } - nk_layout_row_push(ctx, 0.1); - if(prop->unit) - nk_label(ctx, prop->unit, NK_TEXT_RIGHT); - else - nk_spacing(ctx, 1); -} - -static void -_parameter_widget_double(plughandle_t *handle, struct nk_context *ctx, prop_t *prop, - bool editable, bool has_shift_enter, float dy, int ndy) -{ - nk_layout_row_dynamic(ctx, dy*(ndy-1), 1); - if(_dial_double(ctx, prop->minimum.d, &prop->value.d, prop->maximum.d, 1.f, - prop->color, editable)) - { - _patch_set(handle, prop->key, sizeof(double), prop->range, &prop->value.d); - } - - nk_layout_row_begin(ctx, NK_DYNAMIC, dy, 2); - nk_layout_row_push(ctx, 0.9); - if(editable) - { - const double val = nk_propertyd(ctx, lab, - prop->minimum.d, prop->value.d, prop->maximum.d, 0.05f, 0.f); - if(val != prop->value.d) - { - prop->value.d = val; - _patch_set(handle, prop->key, sizeof(double), prop->range, &val); - } - } - else // !editable - { - nk_labelf(ctx, NK_TEXT_RIGHT, "%lf", prop->value.d); - } - nk_layout_row_push(ctx, 0.1); - if(prop->unit) - nk_label(ctx, prop->unit, NK_TEXT_RIGHT); - else - nk_spacing(ctx, 1); -} - -static void -_parameter_widget_bool(plughandle_t *handle, struct nk_context *ctx, prop_t *prop, - bool editable, bool has_shift_enter, float dy, int ndy) -{ - nk_layout_row_dynamic(ctx, dy*(ndy-1), 1); - if(_dial_bool(ctx, &prop->value.i, prop->color, editable)) - { - _patch_set(handle, prop->key, sizeof(int32_t), prop->range, &prop->value.i); - } -} - -static void -_parameter_widget_urid(plughandle_t *handle, struct nk_context *ctx, prop_t *prop, - bool editable, bool has_shift_enter, float dy, int ndy) -{ - bool prop_commited = false; - - nk_layout_row_dynamic(ctx, dy*(ndy-1), 1); - const int old_len = nk_str_len_char(&prop->value.editor.string); - nk_flags flags = NK_EDIT_BOX; - if(has_shift_enter) - flags |= NK_EDIT_SIG_ENTER; - if(!editable) - flags |= NK_EDIT_READ_ONLY; - if(handle->refocus_after_filedialog && (handle->last_edit_focus == &prop->value.editor) ) - { - nk_edit_focus(ctx, flags); - handle->refocus_after_filedialog = false; - } - const nk_flags state = nk_edit_buffer(ctx, flags, &prop->value.editor, nk_filter_default); - if(state & NK_EDIT_COMMITED) - prop_commited = true; - if(state & NK_EDIT_ACTIVE) - handle->last_edit_focus = &prop->value.editor; - if( (state & NK_EDIT_ACTIVE) && (old_len != nk_str_len_char(&prop->value.editor.string)) ) - prop->dirty = true; - if( (state & NK_EDIT_ACTIVE) && handle->has_control_a) - nk_textedit_select_all(&prop->value.editor); - - if(!editable) - return; - - nk_layout_row_dynamic(ctx, dy, 1); - nk_style_push_style_item(ctx, &ctx->style.button.normal, prop_commited - ? nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON_ACTIVE]) - : nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON])); - nk_style_push_color(ctx, &ctx->style.button.border_color, prop->dirty - ? nk_white - : nk_default_color_style[NK_COLOR_BORDER]); - if(nk_button_image_label(ctx, handle->browser.icons.run_all, "Send", NK_TEXT_RIGHT) || prop_commited) - { - struct nk_str *str = &prop->value.editor.string; - - LV2_URID urid = 0; - char *uri = _strndup(nk_str_get_const(str), nk_str_len_char(str)); - if(uri) - { - urid = handle->map->map(handle->map->handle, uri); - free(uri); - } - if(urid) - _patch_set(handle, prop->key, sizeof(uint32_t), prop->range, &urid); - prop->dirty = false; - } - nk_style_pop_color(ctx); - nk_style_pop_style_item(ctx); -} - -static void -_parameter_widget_string(plughandle_t *handle, struct nk_context *ctx, prop_t *prop, - bool editable, bool has_shift_enter, float dy, int ndy) -{ - bool prop_commited = false; - - nk_layout_row_dynamic(ctx, dy*(ndy-1), 1); - const int old_len = nk_str_len_char(&prop->value.editor.string); - nk_flags flags = NK_EDIT_BOX; - if(!editable) - flags |= NK_EDIT_READ_ONLY; - if(has_shift_enter) - flags |= NK_EDIT_SIG_ENTER; - if(handle->refocus_after_filedialog && (handle->last_edit_focus == &prop->value.editor) ) - { - nk_edit_focus(ctx, flags); - handle->refocus_after_filedialog = false; - } - const nk_flags state = nk_edit_buffer(ctx, flags, - &prop->value.editor, nk_filter_default); - if(state & NK_EDIT_COMMITED) - prop_commited = true; - if(state & NK_EDIT_ACTIVE) - handle->last_edit_focus = &prop->value.editor; - if( (state & NK_EDIT_ACTIVE) && (old_len != nk_str_len_char(&prop->value.editor.string)) ) - prop->dirty = true; - if( (state & NK_EDIT_ACTIVE) && handle->has_control_a) - nk_textedit_select_all(&prop->value.editor); - - if(!editable) - return; - - nk_layout_row_dynamic(ctx, dy, 3); - - //FIXME do this only once - struct nk_style *style = &ctx->style; - const float w1 = nk_widget_width(ctx) - 5*style->button.rounding; - const float w2= style->font->width(style->font->userdata, style->font->height, " ", 4); - - nk_style_push_style_item(ctx, &ctx->style.button.normal, prop_commited - ? nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON_ACTIVE]) - : nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON])); - nk_style_push_color(ctx, &ctx->style.button.border_color, prop->dirty - ? nk_white - : nk_default_color_style[NK_COLOR_BORDER]); - if(nk_button_image_label(ctx, handle->browser.icons.run_all, w1 > w2 ? "Send" : "", NK_TEXT_RIGHT) || prop_commited) - { - struct nk_str *str = &prop->value.editor.string; - - _patch_set(handle, prop->key, nk_str_len_char(str), prop->range, nk_str_get_const(str)); - prop->dirty = false; - //TODO needs refresh? - } - nk_style_pop_color(ctx); - nk_style_pop_style_item(ctx); - - if(nk_button_image_label(ctx, handle->browser.icons.import_from, w1 > w2 ? "Load" : "", NK_TEXT_RIGHT)) - { - handle->browser_type = BROWSER_IMPORT_PROPERTY; - handle->browser_target = prop; - } - - if(nk_button_image_label(ctx, handle->browser.icons.export_to, w1 > w2 ? "Save" : "", NK_TEXT_RIGHT)) - { - handle->browser_type = BROWSER_EXPORT_PROPERTY; - handle->browser_target = prop; - } -} - -static void -_parameter_widget_chunk(plughandle_t *handle, struct nk_context *ctx, prop_t *prop, - bool editable, bool has_shift_enter, float dy, int ndy) -{ - nk_layout_row_dynamic(ctx, dy*(ndy-1), 1); - nk_labelf(ctx, NK_TEXT_CENTERED, "%"PRIu32" bytes", prop->value.chunk.size); - - if(!editable) - return; - - nk_layout_row_dynamic(ctx, dy, 2); - - //FIXME do this only once - struct nk_style *style = &ctx->style; - const float w1 = nk_widget_width(ctx) - 5*style->button.rounding; - const float w2= style->font->width(style->font->userdata, style->font->height, " ", 4); - - if(nk_button_image_label(ctx, handle->browser.icons.import_from, w1 > w2 ? "Load" : "", NK_TEXT_RIGHT)) - { - handle->browser_type = BROWSER_IMPORT_PROPERTY; - handle->browser_target = prop; - } - if(nk_button_image_label(ctx, handle->browser.icons.export_to, w1 > w2 ? "Save" : "", NK_TEXT_RIGHT)) - { - handle->browser_type = BROWSER_EXPORT_PROPERTY; - handle->browser_target = prop; - } -} - -static inline void -_plot_i32(struct nk_context *ctx, prop_t *prop) -{ - const unsigned n = prop->value.vec.child_num; - - if(nk_chart_begin(ctx, NK_CHART_LINES, n, prop->minimum.i, prop->maximum.i)) - { - const int32_t *i32 = (int32_t *)prop->value.vec.body; - - for(unsigned i = 0; i < n; i++) - { - const nk_flags ret = nk_chart_push(ctx, i32[i]); - if(ret & NK_CHART_HOVERING) - { - char label [16]; - snprintf(label, 16, "%u: %"PRIi32, i, i32[i]); - nk_tooltip(ctx, label); - } - } - } - nk_chart_end(ctx); -} - -static inline void -_plot_i64(struct nk_context *ctx, prop_t *prop) -{ - const unsigned n = prop->value.vec.child_num; - - if(nk_chart_begin(ctx, NK_CHART_LINES, n, prop->minimum.h, prop->maximum.h)) - { - const int64_t *i64 = (int64_t *)prop->value.vec.body; - - for(unsigned i = 0; i < n; i++) - { - const nk_flags ret = nk_chart_push(ctx, i64[i]); - if(ret & NK_CHART_HOVERING) - { - char label [16]; - snprintf(label, 16, "%u: %"PRIi64, i, i64[i]); - nk_tooltip(ctx, label); - } - } - } - nk_chart_end(ctx); -} - -static inline void -_plot_f32(struct nk_context *ctx, prop_t *prop) -{ - const unsigned n = prop->value.vec.child_num; - - if(nk_chart_begin(ctx, NK_CHART_LINES, n, prop->minimum.f, prop->maximum.f)) - { - const float *f32 = (float *)prop->value.vec.body; - - for(unsigned i = 0; i < n; i++) - { - const nk_flags ret = nk_chart_push(ctx, f32[i]); - if(ret & NK_CHART_HOVERING) - { - char label [32]; - snprintf(label, sizeof(label), "%u: %f", i, f32[i]); - nk_tooltip(ctx, label); - } - } - } - nk_chart_end(ctx); -} - -static inline void -_plot_f64(struct nk_context *ctx, prop_t *prop) -{ - const unsigned n = prop->value.vec.child_num; - - if(nk_chart_begin(ctx, NK_CHART_LINES, n, prop->minimum.d, prop->maximum.d)) - { - const double *f64 = (double *)prop->value.vec.body; - - for(unsigned i = 0; i < n; i++) - { - const nk_flags ret = nk_chart_push(ctx, f64[i]); - if(ret & NK_CHART_HOVERING) - { - char label [32]; - snprintf(label, sizeof(label), "%u: %lf", i, f64[i]); - nk_tooltip(ctx, label); - } - } - } - nk_chart_end(ctx); -} - -static void -_parameter_widget_vector(plughandle_t *handle, struct nk_context *ctx, prop_t *prop, - bool editable, bool has_shift_enter, float dy, int ndy) -{ - nk_layout_row_dynamic(ctx, dy*(ndy-1), 1); - - if(prop->value.vec.child_type == handle->forge.Bool) - _plot_i32(ctx, prop); - else if(prop->value.vec.child_type == handle->forge.Int) - _plot_i32(ctx, prop); - else if(prop->value.vec.child_type == handle->forge.URID) - _plot_i32(ctx, prop); - else if(prop->value.vec.child_type == handle->forge.Long) - _plot_i64(ctx, prop); - else if(prop->value.vec.child_type == handle->forge.Float) - _plot_f32(ctx, prop); - else if(prop->value.vec.child_type == handle->forge.Double) - _plot_f64(ctx, prop); - else - nk_spacing(ctx, 1); // unsupported atom:childType -} - -static void -_parameter_widget_tuple(plughandle_t *handle, struct nk_context *ctx, prop_t *prop, - bool editable, bool has_shift_enter, float dy, int ndy) -{ -#if defined(BUILD_INLINE_DISP) - if(prop->key == handle->canvas_idisp.canvas.urid.Canvas_graph) - { - nk_layout_row_dynamic(ctx, dy*(ndy-1), 1); - const struct nk_rect bnd = nk_widget_bounds(ctx); - nk_spacing(ctx, 1); - - //FIXME implement aspect ratio - const float aspect_ratio = 1.f; - unsigned w = bnd.w; - unsigned h = bnd.h; - - if(w < h) - { - h = w; - } - else - { - w = h; - } - - if( (w != handle->canvas_w) || (h != handle->canvas_h) ) - { - handle->canvas_w = w; - handle->canvas_h = h; - handle->canvas_redraw = true; - } - - if(handle->canvas_redraw) - { - LV2_Inline_Display_Image_Surface *surf = - lv2_canvas_idisp_surf_configure(&handle->canvas_idisp, w, h, aspect_ratio); - - const LV2_Atom *value = handle->canvas_value; - - const LV2_Atom fake = { - .size = 0, - .type = handle->forge.Tuple - }; - - if(!value) - { - value = &fake; - } - - lv2_canvas_idisp_render_body(&handle->canvas_idisp, value->type, - value->size, (const LV2_Atom *)LV2_ATOM_BODY_CONST(value)); - - _image_free(handle, &handle->canvas_img, false); - handle->canvas_img = _image_new(handle, surf->width, surf->height, - surf->data, false); - - handle->canvas_redraw = false; - } - - const struct nk_rect bnd2 = { - .x = bnd.x + bnd.w/2 - w/2, - .y = bnd.y + bnd.h/2 - h/2, - .w = w, - .h = h - }; - - struct nk_command_buffer *canvas = nk_window_get_canvas(ctx); - struct nk_style_button *style = &ctx->style.button; - - nk_draw_image(canvas, bnd2, &handle->canvas_img, nk_rgb(0xff, 0xff, 0xff)); - nk_stroke_rect(canvas, bnd2, style->rounding, style->border, style->border_color); - } - else -#endif - { - nk_layout_row_dynamic(ctx, dy*(ndy-1), 1); - nk_label(ctx, "unsupported", NK_TEXT_CENTERED); - } -} - -static void -_parameter_widget_nil(plughandle_t *handle, struct nk_context *ctx, prop_t *prop, - bool editable, bool has_shift_enter, float dy, int ndy) -{ - nk_layout_row_dynamic(ctx, dy*(ndy-1), 1); - nk_spacing(ctx, 1); -} - -static void -_parameter_widget_unsupported(plughandle_t *handle, struct nk_context *ctx, prop_t *prop, - bool editable, bool has_shift_enter, float dy, int ndy) -{ - nk_layout_row_dynamic(ctx, dy*(ndy-1), 1); - nk_label(ctx, "unsupported", NK_TEXT_CENTERED); -} - -static void -_parameter_widget(plughandle_t *handle, struct nk_context *ctx, prop_t *prop, - bool editable, bool has_shift_enter, float dy, int ndy) -{ - const char *label = prop->label ? prop->label : "Unknown"; - if(prop->comment && _tooltip_visible(ctx)) - nk_tooltip(ctx, prop->comment); - if(nk_group_begin(ctx, label, NK_WINDOW_TITLE | NK_WINDOW_BORDER | NK_WINDOW_NO_SCROLLBAR)) - { - if(prop->points) // an Enumerator - { - _parameter_widget_enum(handle, ctx, prop, editable, has_shift_enter, dy, ndy); - } - else if(prop->range == handle->forge.Int) - { - _parameter_widget_int(handle, ctx, prop, editable, has_shift_enter, dy, ndy); - } - else if(prop->range == handle->forge.Long) - { - _parameter_widget_long(handle, ctx, prop, editable, has_shift_enter, dy, ndy); - } - else if(prop->range == handle->forge.Float) - { - _parameter_widget_float(handle, ctx, prop, editable, has_shift_enter, dy, ndy); - } - else if(prop->range == handle->forge.Double) - { - _parameter_widget_double(handle, ctx, prop, editable, has_shift_enter, dy, ndy); - } - else if(prop->range == handle->forge.Bool) - { - _parameter_widget_bool(handle, ctx, prop, editable, has_shift_enter, dy, ndy); - } - else if(prop->range == handle->forge.URID) - { - _parameter_widget_urid(handle, ctx, prop, editable, has_shift_enter, dy, ndy); - } - else if(prop->range == handle->forge.String) - { - _parameter_widget_string(handle, ctx, prop, editable, has_shift_enter, dy, ndy); - } - else if(prop->range == handle->forge.Chunk) - { - _parameter_widget_chunk(handle, ctx, prop, editable, has_shift_enter, dy, ndy); - } - else if(prop->range == handle->forge.Tuple) - { - _parameter_widget_tuple(handle, ctx, prop, editable, has_shift_enter, dy, ndy); - } - else if(prop->range == handle->forge.Vector) - { - _parameter_widget_vector(handle, ctx, prop, editable, has_shift_enter, dy, ndy); - } - else if(prop->range == 0) - { - _parameter_widget_nil(handle, ctx, prop, editable, has_shift_enter, dy, ndy); - } - else if(prop->range == handle->ui_floatProtocol) - { - _parameter_widget_float(handle, ctx, prop, editable, has_shift_enter, dy, ndy); - } - else - { - _parameter_widget_unsupported(handle, ctx, prop, editable, has_shift_enter, dy, ndy); - } - - nk_group_end(ctx); - } -} - -static void -_set_string(struct nk_str *str, uint32_t size, const char *body) -{ - nk_str_clear(str); - - // replace tab with 2 spaces - const char *end = (size > 0) && ( (body[size - 1] == '\n') || (body[size - 1] == '\0') ) - ? body + size - 1 // ignore newline in sane files - : body + size; // handle non-sane files without a newline - const char *from = body; - for(const char *to = strchr(from, '\t'); - to && (to < end); - from = to + 1, to = strchr(from, '\t')) - { - nk_str_append_text_utf8(str, from, to-from); - nk_str_append_text_utf8(str, " ", 2); - } - nk_str_append_text_utf8(str, from, end-from); -} - -static void -_patch_set_string(plughandle_t *handle, prop_t *prop, uint32_t size, const char *body) -{ - struct nk_str *str = &prop->value.editor.string; - - _set_string(str, size, body); - - if(prop->value.editor.lexer.lex) - prop->value.editor.lexer.needs_refresh = 1; - - nk_pugl_post_redisplay(&handle->win); -} - -static void -_expose(struct nk_context *ctx, struct nk_rect wbounds, void *data) -{ - plughandle_t *handle = data; - - const float dy = 20.f * handle->scale; - - // modify default button style - struct nk_style_button *bst = &handle->win.ctx.style.button; - bst->rounding = (dy - 2*bst->border) / 2; - - struct nk_input *in = &ctx->input; - const struct nk_vec2 window_padding = ctx->style.window.padding; - const struct nk_vec2 group_padding = ctx->style.window.group_padding; - const float header_h = 1*dy + 2*window_padding.y; - const float footer_h = 1*dy + 2*window_padding.y; - const float body_h = wbounds.h - header_h - footer_h; - const float header_height = ctx->style.font->height + 2*ctx->style.window.header.padding.y - + 2*ctx->style.window.header.label_padding.y; - - const char *window_name = "Moony"; - if(nk_begin(ctx, window_name, wbounds, NK_WINDOW_NO_SCROLLBAR)) - { - const bool has_control_down = nk_input_is_key_down(in, NK_KEY_CTRL); - const bool has_shift_down = nk_input_is_key_down(in, NK_KEY_SHIFT); - const bool has_enter_pressed = nk_input_is_key_pressed(in, NK_KEY_ENTER); - const bool has_shift_enter = has_shift_down && has_enter_pressed; - const bool has_control_enter = has_control_down && has_enter_pressed; - const bool has_control_l = nk_pugl_is_shortcut_pressed(in, 'l', true); - const bool has_control_d = nk_pugl_is_shortcut_pressed(in, 'd', true); - const bool has_control_e = nk_pugl_is_shortcut_pressed(in, 'e', true); - const bool has_control_p = nk_pugl_is_shortcut_pressed(in, 'p', true); - const bool has_control_f = nk_pugl_is_shortcut_pressed(in, 'f', true); - const bool has_control_n = nk_pugl_is_shortcut_pressed(in, 'n', true); - const bool has_control_t = nk_pugl_is_shortcut_pressed(in, 't', true); - const bool has_control_k = nk_pugl_is_shortcut_pressed(in, 'k', true); - const bool has_control_u = nk_pugl_is_shortcut_pressed(in, 'u', true); - handle->has_control_a = nk_pugl_is_shortcut_pressed(in, 'a', true); - bool has_commited = false; - - if(has_control_u) - _urn_uuid_random(handle); // copy UUIDv4 into clipboard - - nk_layout_row_begin(ctx, NK_DYNAMIC, dy, 3); - { - //FIXME remove duplicate code - nk_layout_row_push(ctx, 0.6); - if(_tooltip_visible(ctx)) - nk_tooltip(ctx, "Ctrl-E"); - if(has_control_e) - handle->editor_hidden = !handle->editor_hidden; - const bool editor_hidden = handle->editor_hidden; - nk_style_push_style_item(ctx, &ctx->style.button.normal, handle->editor_hidden - ? nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON]) - : nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON_ACTIVE])); - nk_style_push_color(ctx, &ctx->style.button.text_normal, handle->editor_hidden - ? nk_default_color_style[NK_COLOR_TEXT] - : nk_white); - if(nk_button_image_label(ctx, handle->browser.icons.editor, ":: Editor ::", NK_TEXT_LEFT)) - handle->editor_hidden = !handle->editor_hidden; - nk_style_pop_color(ctx); - nk_style_pop_style_item(ctx); - if( (editor_hidden != handle->editor_hidden) || has_control_e) - _patch_set(handle, handle->moony_editorHidden, sizeof(int32_t), handle->forge.Bool, &handle->editor_hidden); - - nk_layout_row_push(ctx, 0.2); - if(_tooltip_visible(ctx)) - nk_tooltip(ctx, "Ctrl-L"); - if(has_control_l) - handle->log_hidden = !handle->log_hidden; - const bool log_hidden = handle->log_hidden; - nk_style_push_style_item(ctx, &ctx->style.button.normal, handle->log_hidden - ? nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON]) - : nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON_ACTIVE])); - nk_style_push_color(ctx, &ctx->style.button.text_normal, handle->log_hidden - ? nk_default_color_style[NK_COLOR_TEXT] - : nk_white); - if(nk_button_image_label(ctx, handle->browser.icons.log, ":: Log ::", NK_TEXT_LEFT)) - handle->log_hidden = !handle->log_hidden; - nk_style_pop_color(ctx); - nk_style_pop_style_item(ctx); - if( (log_hidden != handle->log_hidden) || has_control_l) - _patch_set(handle, handle->moony_logHidden, sizeof(int32_t), handle->forge.Bool, &handle->log_hidden); - - nk_layout_row_push(ctx, 0.2); - if(_tooltip_visible(ctx)) - nk_tooltip(ctx, "Ctrl-P"); - if(has_control_p) - handle->param_hidden = !handle->param_hidden; - const bool param_hidden = handle->param_hidden; - nk_style_push_style_item(ctx, &ctx->style.button.normal, handle->param_hidden - ? nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON]) - : nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON_ACTIVE])); - nk_style_push_color(ctx, &ctx->style.button.text_normal, handle->param_hidden - ? nk_default_color_style[NK_COLOR_TEXT] - : nk_white); - if(nk_button_image_label(ctx, handle->browser.icons.parameters, ":: Parameters ::", NK_TEXT_LEFT)) - handle->param_hidden = !handle->param_hidden; - nk_style_pop_color(ctx); - nk_style_pop_style_item(ctx); - if( (param_hidden != handle->param_hidden) || has_control_p) - _patch_set(handle, handle->moony_paramHidden, sizeof(int32_t), handle->forge.Bool, &handle->param_hidden); - } - nk_layout_row_end(ctx); - - nk_layout_row_begin(ctx, NK_DYNAMIC, body_h, !handle->editor_hidden + !handle->log_hidden + !handle->param_hidden); - { - const struct nk_style *style = &ctx->style; - const float box_h = body_h - 1*dy - 3*group_padding.y; - - if(!handle->editor_hidden) - { - nk_layout_row_push(ctx, (handle->log_hidden && handle->param_hidden) ? 1.0 : 0.6); - if(nk_group_begin(ctx, "Logic", NK_WINDOW_NO_SCROLLBAR)) - { - const float left_width = style->font->width(style->font->userdata, - style->font->height, " ", 5); //TODO calculate only once? - const float left_rel = left_width / nk_window_get_content_region_size(ctx).x; - - const float ratio [2] = {left_rel, NK_UNDEFINED}; - nk_layout_row(ctx, NK_DYNAMIC, box_h, 2, ratio); - - // reserve space for line numbers - struct nk_rect ln_bounds = nk_layout_space_bounds(ctx); - const enum nk_widget_layout_states ln_states = nk_widget(&ln_bounds, ctx); - - // draw bracket around line numbers - { - struct nk_command_buffer *canvas = nk_window_get_canvas(ctx); - nk_stroke_line(canvas, ln_bounds.x, ln_bounds.y, - ln_bounds.x + ln_bounds.w, ln_bounds.y, - style->edit.border, style->edit.border_color); - nk_stroke_line(canvas, ln_bounds.x, ln_bounds.y + ln_bounds.h, - ln_bounds.x + ln_bounds.w, ln_bounds.y + ln_bounds.h, - style->edit.border, style->edit.border_color); - nk_stroke_line(canvas, ln_bounds.x, ln_bounds.y, - ln_bounds.x, ln_bounds.y + ln_bounds.h, - style->edit.border, style->edit.border_color); - } - - const int old_len = nk_str_len_char(&handle->editor.string); - nk_flags flags = NK_EDIT_BOX; - if(has_shift_enter || has_control_enter) - flags |= NK_EDIT_SIG_ENTER; - if(!handle->has_initial_focus) - { - nk_edit_focus(ctx, flags); - handle->has_initial_focus = true; - } - if(handle->refocus_after_filedialog && (handle->last_edit_focus == &handle->editor) ) - { - nk_edit_focus(ctx, flags); - handle->refocus_after_filedialog = false; - } - const nk_flags state = nk_edit_buffer(ctx, flags, - &handle->editor, nk_filter_default); - if(state & NK_EDIT_ACTIVE) - handle->last_edit_focus = &handle->editor; - if(state & NK_EDIT_COMMITED) - { - if(has_shift_down) - _submit_all(handle); - - has_commited = true; - } - if( (state & NK_EDIT_ACTIVE) && (old_len != nk_str_len_char(&handle->editor.string)) ) - handle->dirty = true; - if( (state & NK_EDIT_ACTIVE) && handle->has_control_a) - nk_textedit_select_all(&handle->editor); - - // actually draw line numbers (after editor window) - if(ln_states != NK_WIDGET_INVALID) - { - const float y0 = ln_bounds.y + style->edit.padding.y + style->edit.border - handle->editor.scrollbar.y; - struct nk_command_buffer *canv = nk_window_get_canvas(ctx); - - struct nk_rect old_clip = canv->clip; - nk_push_scissor(canv, ln_bounds); - for(int i = 0; ; i++) - { - struct nk_rect bb = ln_bounds; - bb.h = style->font->height + style->edit.row_padding; - bb.y = y0 + bb.h * i; - - if(bb.y + bb.h < ln_bounds.y) - continue; // skip, not visible - else if(bb.y > ln_bounds.y + ln_bounds.h) - break; // break out of loop, rest not visible - - struct nk_window *win = ctx->current; - struct nk_vec2 item_padding = style->text.padding; - struct nk_text text; - text.padding.x = item_padding.x; - text.padding.y = item_padding.y; - text.background = style->window.background; - text.text = style->text.color; - - char tmp [16]; - snprintf(tmp, 16, "%i", i + 1); - nk_widget_text(&win->buffer, bb, tmp, strlen(tmp), &text, NK_TEXT_RIGHT, style->font); - } - nk_push_scissor(canv, old_clip); - } - - nk_layout_row_dynamic(ctx, dy, 4); - - if(_tooltip_visible(ctx)) - nk_tooltip(ctx, "Shift-Enter"); - nk_style_push_style_item(ctx, &ctx->style.button.normal, has_shift_enter && has_commited - ? nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON_ACTIVE]) - : nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON])); - nk_style_push_color(ctx, &ctx->style.button.border_color, handle->dirty - ? nk_white - : nk_default_color_style[NK_COLOR_BORDER]); - if(nk_button_image_label(ctx, handle->browser.icons.run_all, "Send", NK_TEXT_RIGHT)) - _submit_all(handle); - nk_style_pop_color(ctx); - nk_style_pop_style_item(ctx); - - if(_tooltip_visible(ctx)) - nk_tooltip(ctx, "Ctrl-N"); - nk_style_push_style_item(ctx, &ctx->style.button.normal, has_control_n - ? nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON_ACTIVE]) - : nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON])); - if(nk_button_image_label(ctx, handle->browser.icons.plus, "New", NK_TEXT_RIGHT) || has_control_n) - _patch_set_code(handle, strlen(default_script) + 1, default_script, true); //TODO should we send it, too? - nk_style_pop_style_item(ctx); - - if(_tooltip_visible(ctx)) - nk_tooltip(ctx, "Ctrl-F"); - nk_style_push_style_item(ctx, &ctx->style.button.normal, has_control_f - ? nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON_ACTIVE]) - : nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON])); - if(nk_button_image_label(ctx, handle->browser.icons.import_from, "Load", NK_TEXT_RIGHT) || has_control_f) - handle->browser_type = BROWSER_IMPORT_CODE; - nk_style_pop_style_item(ctx); - - if(_tooltip_visible(ctx)) - nk_tooltip(ctx, "Ctrl-T"); - nk_style_push_style_item(ctx, &ctx->style.button.normal, has_control_t - ? nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON_ACTIVE]) - : nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON])); - if(nk_button_image_label(ctx, handle->browser.icons.export_to, "Save", NK_TEXT_RIGHT) || has_control_t) - handle->browser_type = BROWSER_EXPORT_CODE; - nk_style_pop_style_item(ctx); - - nk_group_end(ctx); - } - } - - if(!handle->log_hidden) - { - nk_layout_row_push(ctx, (handle->param_hidden ? 0.4 : 0.2) * (handle->editor_hidden ? 2.5 : 1) ); - if(nk_group_begin(ctx, "Utils", NK_WINDOW_NO_SCROLLBAR)) - { - nk_layout_row_dynamic(ctx, box_h, 1); - struct nk_list_view lview; - const float dh = style->font->height + style->edit.row_padding; - nk_flags flags = NK_WINDOW_BORDER; - if(handle->log_follow) - flags |= NK_WINDOW_NO_SCROLLBAR; - if(nk_list_view_begin(ctx, &lview, "Traces", flags, dh, handle->n_trace)) - { - if(handle->log_follow) - { - lview.end = NK_MAX(handle->n_trace, 0); - lview.begin = NK_MAX(lview.end - lview.count, 0); - } - nk_layout_row_dynamic(ctx, dh, 1); - for(int l = lview.begin; (l < lview.end) && (l < handle->n_trace); l++) - { - if(l % 2) - { - struct nk_command_buffer *canvas = nk_window_get_canvas(ctx); - struct nk_rect b1 = nk_widget_bounds(ctx); - nk_fill_rect(canvas, b1, 0.f, nk_rgb(0x37, 0x37, 0x37)); - } - nk_label(ctx, handle->traces[l], NK_TEXT_LEFT); - } - - nk_list_view_end(&lview); - } - - const float footer [5] = {0.3, 0.1, 0.25, 0.1, 0.25}; - nk_layout_row(ctx, NK_DYNAMIC, dy, 5, footer); - if(_tooltip_visible(ctx)) - nk_tooltip(ctx, "Ctrl-D"); - nk_style_push_style_item(ctx, &ctx->style.button.normal, has_control_d - ? nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON_ACTIVE]) - : nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON])); - if(nk_button_image_label(ctx, handle->browser.icons.clear, "Clear", NK_TEXT_RIGHT) || has_control_d) - _clear_log(handle); - nk_style_pop_style_item(ctx); - - const int log_follow = handle->log_follow; - handle->log_follow = _check(ctx, handle->log_follow); - if(log_follow != handle->log_follow) - _patch_set(handle, handle->moony_logFollow, sizeof(int32_t), handle->forge.Bool, &handle->log_follow); - nk_label(ctx, "Follow", NK_TEXT_LEFT); - - const int log_reset = handle->log_reset; - handle->log_reset = _check(ctx, handle->log_reset); - if(log_reset != handle->log_reset) - _patch_set(handle, handle->moony_logReset, sizeof(int32_t), handle->forge.Bool, &handle->log_reset); - nk_label(ctx, "Reset", NK_TEXT_LEFT); - - nk_group_end(ctx); - } - } - - if(!handle->param_hidden) - { - nk_layout_row_push(ctx, (handle->log_hidden ? 0.4 : 0.2) * (handle->editor_hidden ? 2.5 : 1) ); - if(nk_group_begin(ctx, "Parameters", NK_WINDOW_NO_SCROLLBAR)) - { - const float prop_h = (box_h - (handle->param_rows + 1) * group_padding.y) / handle->param_rows; - const float rest = header_height + 3*group_padding.y + 2*ctx->style.window.border; - const int ndy = ceilf(prop_h - rest) / dy; - const float prop_h_2 = ndy*dy + rest; - - nk_layout_row_dynamic(ctx, box_h, 1); - if(nk_group_begin(ctx, "Widgets", 0)) - { - nk_layout_row_dynamic(ctx, prop_h_2, handle->param_cols); - for(int p = 0; p < 4; p++) - { - prop_t *prop = &handle->controls_in[p]; - if(prop->index != LV2UI_INVALID_PORT_INDEX) - _parameter_widget(handle, ctx, prop, true, has_shift_enter, dy, ndy); - } - for(int p = 0; p < 4; p++) - { - prop_t *prop = &handle->controls_out[p]; - if(prop->index != LV2UI_INVALID_PORT_INDEX) - _parameter_widget(handle, ctx, prop, false, has_shift_enter, dy, ndy); - } - for(int p = 0; p < handle->n_writable; p++) - { - prop_t *prop = &handle->writables[p]; - if(!prop->key) // marked for removal - continue; - - _parameter_widget(handle, ctx, prop, true, has_shift_enter, dy, ndy); - } - for(int p = 0; p < handle->n_readable; p++) - { - prop_t *prop = &handle->readables[p]; - if(!prop->key) // marked for removal - continue; - - _parameter_widget(handle, ctx, prop, false, has_shift_enter, dy, ndy); - } - - nk_group_end(ctx); - } - - nk_layout_row_dynamic(ctx, dy, 2); - - const int param_rows = handle->param_rows; - handle->param_rows = nk_propertyi(ctx, "Rows", 1, handle->param_rows, 16, 1, 0.f); - if(param_rows != handle->param_rows) - _patch_set(handle, handle->moony_paramRows, sizeof(int32_t), handle->forge.Int, &handle->param_rows); - - const int param_cols = handle->param_cols; - handle->param_cols = nk_propertyi(ctx, "Columns", 1, handle->param_cols, 16, 1, 0.f); - if(param_cols != handle->param_cols) - _patch_set(handle, handle->moony_paramCols, sizeof(int32_t), handle->forge.Int, &handle->param_cols); - - nk_group_end(ctx); - } - } - } - nk_layout_row_end(ctx); - - nk_layout_row_begin(ctx, NK_DYNAMIC, dy, 4); - { - nk_layout_row_push(ctx, 0.15); - if(_tooltip_visible(ctx)) - nk_tooltip(ctx, "Ctrl-K"); - nk_style_push_style_item(ctx, &ctx->style.button.normal, has_control_k - ? nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON_ACTIVE]) - : nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON])); - if(nk_button_image_label(ctx, handle->browser.icons.panic, "Panic", NK_TEXT_RIGHT) || has_control_k) - { - const int32_t i32 = 1; - _patch_set(handle, handle->moony_panic, sizeof(int32_t), handle->forge.Bool, &i32); - } - nk_style_pop_style_item(ctx); - - nk_layout_row_push(ctx, 0.55); - if(handle->error[0] == 0) - nk_spacing(ctx, 1); - else - _text_image_colored(ctx, &handle->browser.icons.bell, handle->error, NK_TEXT_LEFT, nk_yellow); - - nk_layout_row_push(ctx, 0.15); - if(nk_button_image_label(ctx, handle->browser.icons.about, "Manual", NK_TEXT_RIGHT)) - { - char *cmd; -#if defined(_WIN32) - if(asprintf(&cmd, "cmd /c start %s", handle->manual) != -1) -#elif defined(__APPLE__) - if(asprintf(&cmd, "open %s", handle->manual) != -1) -#else - if(asprintf(&cmd, "xdg-open %s &", handle->manual) != -1) -#endif - { - system(cmd); - free(cmd); - } - } - - nk_layout_row_push(ctx, 0.15); - if(nk_button_image_label(ctx, handle->browser.icons.about, "About", NK_TEXT_RIGHT)) - handle->show_about = true; - } - nk_layout_row_end(ctx); - } - nk_end(ctx); - - if(handle->browser_type != BROWSER_NONE) - { - const struct nk_vec2 browser_padding = nk_vec2(wbounds.w/8, wbounds.h/8); - if(file_browser_run(&handle->browser, ctx, dy, "File browser", - handle->browser_type, nk_pad_rect(wbounds, browser_padding))) - { - switch(handle->browser_type) - { - case BROWSER_NONE: - break; - case BROWSER_IMPORT_CODE: - { - size_t sz; - uint8_t *chunk = file_load(handle->browser.file, &sz); - if(chunk) - { - _patch_set_code(handle, sz, (const char *)chunk, true); - free(chunk); - } - } break; - case BROWSER_EXPORT_CODE: - { - FILE *f = fopen(handle->browser.file, "wb"); - if(f) - { - // write text - struct nk_str *str = &handle->editor.string; - if(fwrite(nk_str_get_const(str), nk_str_len_char(str), 1, f) != 1) - { - //TODO handle error - } - - // write end-of-file line break - const char lb = '\n'; - if(fwrite(&lb, sizeof(lb), 1, f) != 1) - { - //TODO handle error - } - - fclose(f); - } - } break; - case BROWSER_IMPORT_PROPERTY: - { - prop_t *prop = handle->browser_target; - if(prop) - { - size_t sz; - uint8_t *chunk = file_load(handle->browser.file, &sz); - if(chunk) - { - if(prop->range == handle->forge.String) - { - _patch_set_string(handle, prop, sz, (const char *)chunk); - prop->dirty = true; // user needs to resend - } - else if(prop->range == handle->forge.Chunk) - { - prop->value.chunk.size = sz; - prop->value.chunk.body = realloc(prop->value.chunk.body, sz); - if(prop->value.chunk.body) - { - memcpy(prop->value.chunk.body, chunk, sz); - } - else - { - //TODO handle error - } - _patch_set(handle, prop->key, sz, prop->range, chunk); - } - free(chunk); - } - } - } break; - case BROWSER_EXPORT_PROPERTY: - { - prop_t *prop = handle->browser_target; - if(prop) - { - FILE *f = fopen(handle->browser.file, "wb"); - if(f) - { - if(prop->range == handle->forge.String) - { - // write text - struct nk_str *str = &prop->value.editor.string; - if(fwrite(nk_str_get_const(str), nk_str_len_char(str), 1, f) != 1) - { - //TODO handle error - } - - // write end-of-file line break - const char lb = '\n'; - if(fwrite(&lb, sizeof(lb), 1, f) != 1) - { - //TODO handle error - } - } - else if(prop->range == handle->forge.Chunk) - { - if(fwrite(prop->value.chunk.body, prop->value.chunk.size, 1, f) != 1) - { - //TODO handle error - } - } - - fclose(f); - } - } - } break; - } - - nk_window_close(ctx, "File browser"); - } - - if( !nk_window_is_active(ctx, "File browser") - || nk_input_is_key_pressed(in, NK_KEY_TEXT_RESET_MODE)) // or escape - { - nk_window_close(ctx, "File browser"); - handle->refocus_after_filedialog = true; - } - - if(nk_window_is_closed(ctx, "File browser")) - { - // reset browser type and target - handle->browser_type = BROWSER_NONE; - handle->browser_target = NULL; - } - } - - if(handle->show_about) - { - const struct nk_vec2 about_padding = nk_vec2(wbounds.w/3, wbounds.h/8); - if(nk_begin(ctx, "About", nk_pad_rect(wbounds, about_padding), - NK_WINDOW_BORDER | NK_WINDOW_TITLE | NK_WINDOW_CLOSABLE)) - { - nk_layout_row_dynamic(ctx, dy, 1); - const float w = nk_widget_width(ctx); - - nk_spacing(ctx, 1); - nk_label_colored(ctx, "Moony.lv2", NK_TEXT_CENTERED, nk_white); - nk_label(ctx, MOONY_VERSION, NK_TEXT_CENTERED); - - nk_spacing(ctx, 1); - const float ratio_howl [3] = {0.25, 0.5, 0.25}; - nk_layout_row(ctx, NK_DYNAMIC, w/2, 3, ratio_howl); - nk_spacing(ctx, 1); - nk_image(ctx, handle->browser.icons.howl); - - nk_layout_row_dynamic(ctx, dy, 1); - nk_spacing(ctx, 1); - nk_label(ctx, "Copyright © 2015-2021 Hanspeter Portner", NK_TEXT_CENTERED); - - //nk_spacing(ctx, 1); - nk_label(ctx, "This is free, libre and open source software", NK_TEXT_CENTERED); - nk_label(ctx, "Released under Artistic License 2.0", NK_TEXT_CENTERED); - nk_label(ctx, "By Open Music Kontrollers", NK_TEXT_CENTERED); - - nk_spacing(ctx, 1); - const float ratio_omk [3] = {0.375, 0.25, 0.375}; - nk_layout_row(ctx, NK_DYNAMIC, w/4, 3, ratio_omk); - nk_spacing(ctx, 1); - nk_image(ctx, handle->browser.icons.omk); - - nk_layout_row_dynamic(ctx, dy, 1); - nk_spacing(ctx, 1); - nk_label(ctx, "https://open-music-kontrollers.ch/lv2/moony", NK_TEXT_CENTERED); - nk_label(ctx, "dev@open-music-kontrollers.ch", NK_TEXT_CENTERED); - nk_spacing(ctx, 1); - } - nk_end(ctx); - - if( !nk_window_is_active(ctx, "About") - || nk_input_is_key_pressed(in, NK_KEY_TEXT_RESET_MODE)) // or escape - { - nk_window_close(ctx, "About"); - } - - if(nk_window_is_closed(ctx, "About")) - { - handle->show_about = false; - } - } -} - -static struct nk_image -_icon_load(void *data, const char *file) -{ - plughandle_t *handle = data; - - struct nk_image img; - char *path; - if(asprintf(&path, "%s%s", handle->bundle_path, file) != -1) - { - img = nk_pugl_icon_load(&handle->win, path); - free(path); - } - else - img = nk_image_id(0); - - return img; -} - -static void -_icon_unload(void *data, struct nk_image img) -{ - plughandle_t *handle = data; - - nk_pugl_icon_unload(&handle->win, img); -} - -static LV2UI_Handle -instantiate(const LV2UI_Descriptor *descriptor, const char *plugin_uri, - const char *bundle_path, LV2UI_Write_Function write_function, - LV2UI_Controller controller, LV2UI_Widget *widget, - const LV2_Feature *const *features) -{ - plughandle_t *handle = calloc(1, sizeof(plughandle_t)); - if(!handle) - return NULL; - - handle->bundle_path = bundle_path; - - srand(time(NULL)); - - void *parent = NULL; - LV2UI_Port_Map *port_map = NULL; - LV2_Options_Option *opts = NULL; - for(int i=0; features[i]; i++) - { - if(!strcmp(features[i]->URI, LV2_UI__parent)) - { - parent = features[i]->data; - } - else if(!strcmp(features[i]->URI, LV2_UI__portMap)) - { - port_map = features[i]->data; - } - else if(!strcmp(features[i]->URI, LV2_URID__map)) - { - handle->map = features[i]->data; - } - else if(!strcmp(features[i]->URI, LV2_URID__unmap)) - { - handle->unmap = features[i]->data; - } - else if(!strcmp(features[i]->URI, LV2_LOG__log)) - { - handle->log = features[i]->data; - } - else if(!strcmp(features[i]->URI, LV2_OPTIONS__options)) - { - opts = features[i]->data; - } - } - - if(!parent) - { - fprintf(stderr, - "%s: Host does not support ui:parent\n", descriptor->URI); - free(handle); - return NULL; - } - if(!port_map) - { - fprintf(stderr, - "%s: Host does not support ui:portMap\n", descriptor->URI); - free(handle); - return NULL; - } - if(!handle->map || !handle->unmap) - { - fprintf(stderr, - "%s: Host does not support urid:map/unmap\n", descriptor->URI); - free(handle); - return NULL; - } - - if(handle->log) - lv2_log_logger_init(&handle->logger, handle->map, handle->log); - - lv2_atom_forge_init(&handle->forge, handle->map); - - handle->atom_eventTransfer = handle->map->map(handle->map->handle, LV2_ATOM__eventTransfer); - handle->ui_floatProtocol = handle->map->map(handle->map->handle, LV2_UI__floatProtocol); - - handle->patch_self = handle->map->map(handle->map->handle, plugin_uri); - handle->patch_Get = handle->map->map(handle->map->handle, LV2_PATCH__Get); - handle->patch_Set = handle->map->map(handle->map->handle, LV2_PATCH__Set); - handle->patch_Put = handle->map->map(handle->map->handle, LV2_PATCH__Put); - handle->patch_Patch = handle->map->map(handle->map->handle, LV2_PATCH__Patch); - handle->patch_Ack = handle->map->map(handle->map->handle, LV2_PATCH__Ack); - handle->patch_Error = handle->map->map(handle->map->handle, LV2_PATCH__Error); - handle->patch_writable = handle->map->map(handle->map->handle, LV2_PATCH__writable); - handle->patch_readable = handle->map->map(handle->map->handle, LV2_PATCH__readable); - handle->patch_add = handle->map->map(handle->map->handle, LV2_PATCH__add); - handle->patch_remove = handle->map->map(handle->map->handle, LV2_PATCH__remove); - handle->patch_wildcard = handle->map->map(handle->map->handle, LV2_PATCH__wildcard); - handle->patch_property = handle->map->map(handle->map->handle, LV2_PATCH__property); - handle->patch_body = handle->map->map(handle->map->handle, LV2_PATCH__body); - handle->patch_value = handle->map->map(handle->map->handle, LV2_PATCH__value); - handle->patch_subject = handle->map->map(handle->map->handle, LV2_PATCH__subject); - handle->patch_sequenceNumber = handle->map->map(handle->map->handle, LV2_PATCH__sequenceNumber); - handle->moony_code = handle->map->map(handle->map->handle, MOONY_CODE_URI); - handle->moony_error = handle->map->map(handle->map->handle, MOONY_ERROR_URI); - handle->moony_trace = handle->map->map(handle->map->handle, MOONY_TRACE_URI); - handle->moony_panic = handle->map->map(handle->map->handle, MOONY_PANIC_URI); - handle->moony_editorHidden = handle->map->map(handle->map->handle, MOONY_EDITOR_HIDDEN_URI); - handle->moony_logHidden = handle->map->map(handle->map->handle, MOONY_LOG_HIDDEN_URI); - handle->moony_logFollow = handle->map->map(handle->map->handle, MOONY_LOG_FOLLOW_URI); - handle->moony_logReset = handle->map->map(handle->map->handle, MOONY_LOG_RESET_URI); - handle->moony_paramHidden = handle->map->map(handle->map->handle, MOONY_PARAM_HIDDEN_URI); - handle->moony_paramCols = handle->map->map(handle->map->handle, MOONY_PARAM_COLS_URI); - handle->moony_paramRows = handle->map->map(handle->map->handle, MOONY_PARAM_ROWS_URI); - handle->moony_color = handle->map->map(handle->map->handle, MOONY__color); - handle->moony_syntax = handle->map->map(handle->map->handle, MOONY__syntax); - handle->lua_lang = handle->map->map(handle->map->handle, LUA__lang); - handle->rdfs_label = handle->map->map(handle->map->handle, RDFS__label); - handle->rdfs_range= handle->map->map(handle->map->handle, RDFS__range); - handle->rdfs_comment = handle->map->map(handle->map->handle, RDFS__comment); - handle->rdf_value = handle->map->map(handle->map->handle, RDF__value); - handle->lv2_minimum = handle->map->map(handle->map->handle, LV2_CORE__minimum); - handle->lv2_maximum = handle->map->map(handle->map->handle, LV2_CORE__maximum); - handle->lv2_scalePoint = handle->map->map(handle->map->handle, LV2_CORE__scalePoint); - - handle->units_symbol = handle->map->map(handle->map->handle, LV2_UNITS__symbol); - handle->units_unit = handle->map->map(handle->map->handle, LV2_UNITS__unit); - handle->units_bar = handle->map->map(handle->map->handle, LV2_UNITS__bar); - handle->units_beat = handle->map->map(handle->map->handle, LV2_UNITS__beat); - handle->units_bpm = handle->map->map(handle->map->handle, LV2_UNITS__bpm); - handle->units_cent = handle->map->map(handle->map->handle, LV2_UNITS__cent); - handle->units_cm = handle->map->map(handle->map->handle, LV2_UNITS__cm); - handle->units_db = handle->map->map(handle->map->handle, LV2_UNITS__db); - handle->units_degree = handle->map->map(handle->map->handle, LV2_UNITS__degree); - handle->units_frame = handle->map->map(handle->map->handle, LV2_UNITS__frame); - handle->units_hz = handle->map->map(handle->map->handle, LV2_UNITS__hz); - handle->units_inch = handle->map->map(handle->map->handle, LV2_UNITS__inch); - handle->units_khz = handle->map->map(handle->map->handle, LV2_UNITS__khz); - handle->units_km = handle->map->map(handle->map->handle, LV2_UNITS__km); - handle->units_m = handle->map->map(handle->map->handle, LV2_UNITS__m); - handle->units_mhz = handle->map->map(handle->map->handle, LV2_UNITS__mhz); - handle->units_midiNote = handle->map->map(handle->map->handle, LV2_UNITS__midiNote); - handle->units_mile = handle->map->map(handle->map->handle, LV2_UNITS__mile); - handle->units_min = handle->map->map(handle->map->handle, LV2_UNITS__min); - handle->units_mm = handle->map->map(handle->map->handle, LV2_UNITS__mm); - handle->units_ms = handle->map->map(handle->map->handle, LV2_UNITS__ms); - handle->units_oct = handle->map->map(handle->map->handle, LV2_UNITS__oct); - handle->units_pc = handle->map->map(handle->map->handle, LV2_UNITS__pc); - handle->units_s = handle->map->map(handle->map->handle, LV2_UNITS__s); - handle->units_semitone12TET = handle->map->map(handle->map->handle, LV2_UNITS__semitone12TET); - - handle->controller = controller; - handle->writer = write_function; - - handle->control = port_map->port_index(port_map->handle, "control"); - handle->notify = port_map->port_index(port_map->handle, "notify"); - - for(int i = 0; i < 4; i++) - { - char symbol [16]; - char label [16]; - char uri [64]; - prop_t *prop; - - snprintf(symbol, 16, "input_%i", i + 1); - snprintf(label , 16, "Input %i", i + 1); - snprintf(uri, 64, MOONY_URI"#%s", symbol); - - prop = &handle->controls_in[i]; - prop->index = port_map->port_index(port_map->handle, symbol); - if(prop->index != LV2UI_INVALID_PORT_INDEX) - { - prop->key = handle->map->map(handle->map->handle, uri); - prop->label = strdup(label); - prop->range = handle->ui_floatProtocol; - prop->minimum.f = 0.f; - prop->maximum.f = 1.f; - prop->value.f = 0.f; - prop->color = nk_white; - } - - snprintf(symbol, 16, "output_%i", i + 1); - snprintf(label , 16, "Output %i", i + 1); - snprintf(uri, 64, MOONY_URI"#%s", symbol); - - prop = &handle->controls_out[i]; - prop->index = port_map->port_index(port_map->handle, symbol); - if(prop->index != LV2UI_INVALID_PORT_INDEX) - { - prop->key = handle->map->map(handle->map->handle, uri); - prop->label = strdup(label); - prop->range = handle->ui_floatProtocol; - prop->minimum.f = 0.f; - prop->maximum.f = 1.f; - prop->value.f = 0.f; - prop->color = nk_white; - } - } - - const LV2_URID ui_scaleFactor = handle->map->map(handle->map->handle, - LV2_UI__scaleFactor); - - for(LV2_Options_Option *opt = opts; - opt && (opt->key != 0) && (opt->value != NULL); - opt++) - { - if( (opt->key == ui_scaleFactor) && (opt->type == handle->forge.Float) ) - { - handle->scale = *(float*)opt->value; - } - } - - if(handle->scale == 0.f) - { - handle->scale = nk_pugl_get_scale(); - } - - nk_pugl_config_t *cfg = &handle->win.cfg; - cfg->width = 1280 * handle->scale; - cfg->height = 720 * handle->scale; - cfg->min_width = cfg->width / 4; - cfg->min_height = cfg->height / 4; - cfg->resizable = true; - cfg->ignore = false; - cfg->class = "moony"; - cfg->title = "Moony"; - cfg->parent = (intptr_t)parent; - cfg->host_resize = NULL; - cfg->data = handle; - cfg->expose = _expose; - - if(asprintf(&cfg->font.face, "%sCousine-Regular.ttf", bundle_path) == -1) - cfg->font.face = NULL; - cfg->font.size = 13 * handle->scale; - - if(asprintf(&handle->manual, "%smanual.html", bundle_path) == -1) - handle->manual = NULL; - - *(intptr_t *)widget = nk_pugl_init(&handle->win); - - nk_pugl_show(&handle->win); - - handle->ser.data = NULL; - handle->ser.size = 1024; - handle->ser.buf = malloc(1024); - handle->ser.offset = 0; - - nk_textedit_init_fixed(&handle->editor, handle->code, MOONY_MAX_CHUNK_LEN); - handle->editor.single_line = nk_false; - - _patch_get(handle, handle->moony_code); - _patch_get(handle, handle->moony_error); - _patch_get(handle, handle->moony_editorHidden); - _patch_get(handle, handle->moony_logHidden); - _patch_get(handle, handle->moony_logFollow); - _patch_get(handle, handle->moony_logReset); - _patch_get(handle, handle->moony_paramHidden); - _patch_get(handle, handle->moony_paramCols); - _patch_get(handle, handle->moony_paramRows); - _patch_get(handle, 0); - - handle->L = luaL_newstate(); - if(handle->L) - { - luaL_requiref(handle->L, "base", luaopen_base, 0); - luaL_requiref(handle->L, "coroutine", luaopen_coroutine, 1); - luaL_requiref(handle->L, "table", luaopen_table, 1); - luaL_requiref(handle->L, "string", luaopen_string, 1); - luaL_requiref(handle->L, "math", luaopen_math, 1); - luaL_requiref(handle->L, "utf8", luaopen_utf8, 1); - luaL_requiref(handle->L, "debug", luaopen_debug, 1); - luaL_requiref(handle->L, "lpeg", luaopen_lpeg, 1); - lua_pop(handle->L, 8); - - //luaL_requiref(handle->L, "io", luaopen_io, 1); - //luaL_requiref(handle->L, "os", luaopen_os, 1); - //luaL_requiref(handle->L, "bit32", luaopen_bit32, 1); - luaL_requiref(handle->L, "package", luaopen_package, 1); - - // generational garbage collector - lua_gc(handle->L, LUA_GCRESTART, 0); // enable automatic garbage collection - // next minor collection when memory increased by 5% - // next major collection when memory increased by 100% - lua_gc(handle->L, LUA_GCGEN, 5, 100); - - // set package.path - lua_getglobal(handle->L, "package"); - lua_pushfstring(handle->L, "%s?.lua", bundle_path); - lua_setfield(handle->L, -2, "path"); - lua_pop(handle->L, 1); // package - - char *path = NULL; - if(asprintf(&path, "%s%s", bundle_path, "lexer.lua") != -1) - { - if(luaL_dofile(handle->L, path)) - { - fprintf(stderr, "err: %s\n", lua_tostring(handle->L, -1)); - lua_pop(handle->L, 1); // err - } - else - { - lua_setglobal(handle->L, "lexer"); - } - free(path); - } - - lua_getglobal(handle->L, "lexer"); - lua_getfield(handle->L, -1, "load"); - lua_pushstring(handle->L, "moony"); - if(lua_pcall(handle->L, 1, 1, 0)) - { - fprintf(stderr, "err: %s\n", lua_tostring(handle->L, -1)); - lua_pop(handle->L, 1); - } - else - { - lua_setglobal(handle->L, "moony"); - } - lua_pop(handle->L, 1); // lexer - } - - handle->editor.lexer.lex = _lex; - handle->editor.lexer.data = handle->L; - - file_browser_init(&handle->browser, 0, 1, _icon_load, handle); - - // modify default button style - struct nk_style_button *bst = &handle->win.ctx.style.button; - //bst->rounding = (dy - 2*bst->border) / 2; // in _expose, depends on scaling - bst->image_padding.x = -bst->padding.x - bst->border - 1; - bst->image_padding.y = -bst->padding.y - bst->border - 1; - bst->text_hover = nk_white; - bst->text_active = nk_white; - - // modify default selectable style - struct nk_style_selectable *sst = &handle->win.ctx.style.selectable; - sst->hover = nk_style_item_color(nk_default_color_style[NK_COLOR_BUTTON_HOVER]); - sst->text_hover = nk_white; - sst->text_pressed= nk_white; - sst->text_normal_active = nk_white; - sst->text_hover_active = nk_white; - sst->text_pressed_active = nk_white; - - // modify default selectable style - struct nk_style_toggle *tst = &handle->win.ctx.style.checkbox; - tst->text_hover = nk_white; - - // modify default combo style - struct nk_style_combo *cst = &handle->win.ctx.style.combo; - cst->label_hover = nk_white; - -#if defined(BUILD_INLINE_DISP) - lv2_canvas_idisp_init(&handle->canvas_idisp, NULL, handle->map); -#endif - - return handle; -} - -static void -cleanup(LV2UI_Handle instance) -{ - plughandle_t *handle = instance; - nk_pugl_config_t *cfg = &handle->win.cfg; - -#if defined(BUILD_INLINE_DISP) - free(handle->canvas_value); - _image_free(handle, &handle->canvas_img, true); - lv2_canvas_idisp_deinit(&handle->canvas_idisp); -#endif - - file_browser_free(&handle->browser, _icon_unload, handle); - - if(handle->L) - lua_close(handle->L); - - nk_textedit_free(&handle->editor); - - if(handle->editor.lexer.tokens) - free(handle->editor.lexer.tokens); - - _clear_log(handle); - - for(int p = 0; p < handle->n_writable; p++) - _prop_free(handle, &handle->writables[p]); - if(handle->writables) - free(handle->writables); - - for(int p = 0; p < handle->n_readable; p++) - _prop_free(handle, &handle->readables[p]); - if(handle->readables) - free(handle->readables); - - for(int p = 0; p < 4; p++) - { - _prop_free(handle, &handle->controls_in[p]); - _prop_free(handle, &handle->controls_out[p]); - } - - if(handle->ser.buf) - free(handle->ser.buf); - - if(handle->manual) - free(handle->manual); - - if(cfg->font.face) - free(cfg->font.face); - - nk_pugl_hide(&handle->win); - nk_pugl_shutdown(&handle->win); - - free(handle); -} - -static void -_patch_set_parameter_value(plughandle_t *handle, LV2_URID property, - const LV2_Atom *value) -{ - prop_t *prop = _prop_get(&handle->readables, &handle->n_readable, property); - if(!prop) - prop = _prop_get(&handle->writables, &handle->n_writable, property); - if(prop && (prop->range == value->type) ) - { - if(prop->range == handle->forge.Int) - { - prop->value.i = ((const LV2_Atom_Int *)value)->body; - prop->value.i = NK_CLAMP(prop->minimum.i, prop->value.i, prop->maximum.i); - } - else if(prop->range == handle->forge.Long) - { - prop->value.h = ((const LV2_Atom_Long *)value)->body; - prop->value.h = NK_CLAMP(prop->minimum.h, prop->value.h, prop->maximum.h); - } - else if(prop->range == handle->forge.Float) - { - prop->value.f = ((const LV2_Atom_Float *)value)->body; - prop->value.f = NK_CLAMP(prop->minimum.f, prop->value.f, prop->maximum.f); - } - else if(prop->range == handle->forge.Double) - { - prop->value.d = ((const LV2_Atom_Double *)value)->body; - prop->value.d = NK_CLAMP(prop->minimum.d, prop->value.d, prop->maximum.d); - } - else if(prop->range == handle->forge.Bool) - { - prop->value.i = ((const LV2_Atom_Bool *)value)->body; - prop->minimum.i = 0; - prop->maximum.i = 1; - } - else if(prop->range == handle->forge.URID) - { - const LV2_URID urid = ((const LV2_Atom_URID *)value)->body; - const char *uri = handle->unmap->unmap(handle->unmap->handle, urid); - - struct nk_str *str = &prop->value.editor.string; - nk_str_clear(str); - nk_str_append_text_utf8(str, uri, strlen(uri)); - } - else if(prop->range == handle->forge.String) - { - struct nk_str *str = &prop->value.editor.string; - nk_str_clear(str); - nk_str_append_text_utf8(str, LV2_ATOM_BODY_CONST(value), value->size - 1); - - if(prop->value.editor.lexer.lex) - prop->value.editor.lexer.needs_refresh = 1; - } - else if(prop->range == handle->forge.Chunk) - { - prop->value.chunk.size = value->size; - prop->value.chunk.body = realloc(prop->value.chunk.body, value->size); - if(prop->value.chunk.body) - { - memcpy(prop->value.chunk.body, LV2_ATOM_BODY_CONST(value), value->size); - } - else - { - //TODO handle error - } - } - else if(prop->range == handle->forge.Tuple) - { -#if defined(BUILD_INLINE_DISP) - if(prop->key == handle->canvas_idisp.canvas.urid.Canvas_graph) - { - const size_t total_sz = lv2_atom_total_size(value); - - // copy graph atom tuple - handle->canvas_value = realloc(handle->canvas_value, total_sz); - memcpy(handle->canvas_value, value, total_sz); - - // force redraw - handle->canvas_redraw = true; - } -#endif - } - else if(prop->range == handle->forge.Vector) - { - const LV2_Atom_Vector *vec = (const LV2_Atom_Vector *)value; - const uint32_t vec_body_size = vec->atom.size - sizeof(LV2_Atom_Vector_Body); - const void *vec_body = LV2_ATOM_CONTENTS_CONST(LV2_Atom_Vector, value); - - prop->value.vec.child_num = vec->body.child_size - ? vec_body_size / vec->body.child_size - : 0; - prop->value.vec.child_type = vec->body.child_type; - prop->value.vec.body = realloc(prop->value.vec.body, vec_body_size); - if(prop->value.vec.body) - { - memcpy(prop->value.vec.body, vec_body, vec_body_size); - } - else - { - //TODO handle error - } - } - else - { - //FIXME - } - - nk_pugl_post_redisplay(&handle->win); - } -} - -static void -_patch_set_parameter_property(plughandle_t *handle, LV2_URID subject, LV2_URID property, - const LV2_Atom *value) -{ - prop_t *prop = _prop_get(&handle->readables, &handle->n_readable, subject); - if(!prop) - prop = _prop_get(&handle->writables, &handle->n_writable, subject); - if(prop) - { - if( (property == handle->rdfs_range) - && (value->type == handle->forge.URID) ) - { - const LV2_Atom_URID *range = (const LV2_Atom_URID *)value; - - prop->range = range->body; - - if( (prop->range == handle->forge.String) - || (prop->range == handle->forge.URID) ) - { - nk_textedit_init_default(&prop->value.editor); - prop->value.editor.single_line = nk_false; - } - - _patch_get(handle, subject); // rdfs:range is mandatory, so will always be sent - } - else if( (property == handle->rdfs_label) - && (value->type == handle->forge.String) ) - { - prop->label = strdup(LV2_ATOM_BODY_CONST(value)); - } - else if( (property == handle->rdfs_comment) - && (value->type == handle->forge.String) ) - { - prop->comment= strdup(LV2_ATOM_BODY_CONST(value)); - } - else if( (property == handle->units_symbol) - && (value->type == handle->forge.String) ) - { - prop->unit= strdup(LV2_ATOM_BODY_CONST(value)); - } - else if( (property == handle->units_unit) - && (value->type == handle->forge.URID) ) - { - const LV2_Atom_URID *unit = (const LV2_Atom_URID *)value; - - //TODO use binary lookup - if(unit->body == handle->units_bar) - prop->unit = strdup("bars"); - else if(unit->body == handle->units_beat) - prop->unit = strdup("beats"); - else if(unit->body == handle->units_bpm) - prop->unit = strdup("BPM"); - else if(unit->body == handle->units_cent) - prop->unit = strdup("ct"); - else if(unit->body == handle->units_cm) - prop->unit = strdup("cm"); - else if(unit->body == handle->units_db) - prop->unit = strdup("dB"); - else if(unit->body == handle->units_degree) - prop->unit = strdup("deg"); - else if(unit->body == handle->units_frame) - prop->unit = strdup("frames"); - else if(unit->body == handle->units_hz) - prop->unit = strdup("Hz"); - else if(unit->body == handle->units_inch) - prop->unit = strdup("in"); - else if(unit->body == handle->units_khz) - prop->unit = strdup("kHz"); - else if(unit->body == handle->units_km) - prop->unit = strdup("km"); - else if(unit->body == handle->units_m) - prop->unit = strdup("m"); - else if(unit->body == handle->units_mhz) - prop->unit = strdup("MHz"); - else if(unit->body == handle->units_midiNote) - prop->unit = strdup("note"); - else if(unit->body == handle->units_mile) - prop->unit = strdup("mi"); - else if(unit->body == handle->units_min) - prop->unit = strdup("min"); - else if(unit->body == handle->units_mm) - prop->unit = strdup("mm"); - else if(unit->body == handle->units_ms) - prop->unit = strdup("ms"); - else if(unit->body == handle->units_oct) - prop->unit = strdup("oct"); - else if(unit->body == handle->units_pc) - prop->unit = strdup("%"); - else if(unit->body == handle->units_s) - prop->unit = strdup("s"); - else if(unit->body == handle->units_semitone12TET) - prop->unit = strdup("semi"); - } - else if( (property == handle->moony_color) - && (value->type == handle->forge.Long) ) - { - const LV2_Atom_Long *style = (const LV2_Atom_Long *)value; - - prop->color = nk_rgba( - (style->body >> 24) & 0xff, - (style->body >> 16) & 0xff, - (style->body >> 8) & 0xff, - (style->body >> 0) & 0xff); - } - else if( (property == handle->moony_syntax) - && (value->type == handle->forge.URID) ) - { - const LV2_Atom_URID *syntax = (const LV2_Atom_URID *)value; - - if(syntax->body == handle->lua_lang) - { - prop->value.editor.lexer.lex = _lex; - prop->value.editor.lexer.data = handle->L; - } - } - else if( (property == handle->lv2_minimum) - && (!prop->range || (prop->range == handle->forge.Vector) || (prop->range == value->type)) ) - { - if(value->type == handle->forge.Int) - prop->minimum.i = ((const LV2_Atom_Int *)(value))->body; - else if(value->type == handle->forge.Bool) - prop->minimum.i = 0; // overwrite - else if(value->type == handle->forge.URID) - prop->minimum.u = ((const LV2_Atom_URID *)(value))->body; - else if(value->type == handle->forge.Long) - prop->minimum.h = ((const LV2_Atom_Long *)(value))->body; - else if(value->type == handle->forge.Float) - prop->minimum.f = ((const LV2_Atom_Float *)(value))->body; - else if(value->type == handle->forge.Double) - prop->minimum.d = ((const LV2_Atom_Double *)(value))->body; - //FIXME handle more types? - } - else if( (property == handle->lv2_maximum) - && (!prop->range || (prop->range == handle->forge.Vector) || (prop->range == value->type)) ) - { - if(value->type == handle->forge.Int) - prop->maximum.i = ((const LV2_Atom_Int *)(value))->body; - else if(value->type == handle->forge.Bool) - prop->maximum.i = 1; // overwrite - else if(value->type == handle->forge.URID) - prop->maximum.u = ((const LV2_Atom_URID *)(value))->body; - else if(value->type == handle->forge.Long) - prop->maximum.h = ((const LV2_Atom_Long *)(value))->body; - else if(value->type == handle->forge.Float) - prop->maximum.f = ((const LV2_Atom_Float *)(value))->body; - else if(value->type == handle->forge.Double) - prop->maximum.d = ((const LV2_Atom_Double *)(value))->body; - //FIXME handle more types? - } - else if( (property == handle->lv2_scalePoint) - && (value->type == handle->forge.Tuple) ) - { - const LV2_Atom_Tuple *points = (const LV2_Atom_Tuple *)value; - - const uint32_t sz = lv2_atom_total_size(&points->atom); - prop->points = malloc(sz); - if(prop->points) - memcpy(prop->points, points, sz); - } - - nk_pugl_post_redisplay(&handle->win); - } -} - -static void -_patch_set_code(plughandle_t *handle, uint32_t size, const char *body, bool user) -{ - if(size <= MOONY_MAX_CHUNK_LEN) - { - struct nk_str *str = &handle->editor.string; - - _set_string(str, size, body); - - handle->editor.lexer.needs_refresh = 1; - - if(user) - handle->dirty = true; // user needs to resend - - nk_pugl_post_redisplay(&handle->win); - } -} - -static void -_patch_set_self(plughandle_t *handle, LV2_URID property, const LV2_Atom *value) -{ - const char *body = LV2_ATOM_BODY_CONST(value); - - if(property == handle->moony_code) - { - _clear_error(handle); // is safe, as moony:code is always received before a moony:error - _patch_set_code(handle, value->size, body, false); - - // new state may have these differently, so request them - _patch_get(handle, handle->moony_editorHidden); - _patch_get(handle, handle->moony_logHidden); - _patch_get(handle, handle->moony_logFollow); - _patch_get(handle, handle->moony_logReset); - _patch_get(handle, handle->moony_paramHidden); - _patch_get(handle, handle->moony_paramCols); - _patch_get(handle, handle->moony_paramRows); - } - else if(property == handle->moony_trace) - { - if(value->size <= MOONY_MAX_TRACE_LEN) - { - char *trace = strdup(body); - if(trace) - { - handle->traces = realloc(handle->traces, (handle->n_trace + 1)*sizeof(char *)); - handle->traces[handle->n_trace++] = trace; - - // replace tab with 1 space - const char *end = trace + value->size - 1; - const char *from = trace; - for(char *to = strchr(from, '\t'); - to && (to < end); - from = to + 1, to = strchr(from, '\t')) - { - *to = ' '; - } - } - - nk_pugl_post_redisplay(&handle->win); - } - } - else if(property == handle->moony_error) - { - if(value->size <= MOONY_MAX_ERROR_LEN) - { - if(handle->error[0] == 0) // do not overwrite previously received error message - { - strncpy(handle->error, body, value->size); - handle->error_sz = value->size - 1; - - if(handle->error_sz) - handle->dirty = true; // user needs to resend - - nk_pugl_post_redisplay(&handle->win); - } - } - } - else if(property == handle->moony_editorHidden) - { - if(value->type == handle->forge.Bool) - { - handle->editor_hidden = ((const LV2_Atom_Bool *)value)->body; - - nk_pugl_post_redisplay(&handle->win); - } - } - else if(property == handle->moony_logHidden) - { - if(value->type == handle->forge.Bool) - { - handle->log_hidden = ((const LV2_Atom_Bool *)value)->body; - - nk_pugl_post_redisplay(&handle->win); - } - } - else if(property == handle->moony_logFollow) - { - if(value->type == handle->forge.Bool) - { - handle->log_follow = ((const LV2_Atom_Bool *)value)->body; - - nk_pugl_post_redisplay(&handle->win); - } - } - else if(property == handle->moony_logReset) - { - if(value->type == handle->forge.Bool) - { - handle->log_reset = ((const LV2_Atom_Bool *)value)->body; - - nk_pugl_post_redisplay(&handle->win); - } - } - else if(property == handle->moony_paramHidden) - { - if(value->type == handle->forge.Bool) - { - handle->param_hidden = ((const LV2_Atom_Bool *)value)->body; - - nk_pugl_post_redisplay(&handle->win); - } - } - else if(property == handle->moony_paramCols) - { - if(value->type == handle->forge.Int) - { - handle->param_cols = ((const LV2_Atom_Int *)value)->body; - - nk_pugl_post_redisplay(&handle->win); - } - } - else if(property == handle->moony_paramRows) - { - if(value->type == handle->forge.Int) - { - handle->param_rows = ((const LV2_Atom_Int *)value)->body; - - nk_pugl_post_redisplay(&handle->win); - } - } - else - { - _patch_set_parameter_value(handle, property, value); - } -} - -static void -port_event(LV2UI_Handle instance, uint32_t index, uint32_t size, - uint32_t protocol, const void *buf) -{ - plughandle_t *handle = instance; - - if( ( (index == handle->notify) || (index == handle->control) ) - && (protocol == handle->atom_eventTransfer) ) - { - const LV2_Atom_Object *obj = buf; - - if(lv2_atom_forge_is_object_type(&handle->forge, obj->atom.type)) - { - if(obj->body.otype == handle->patch_Set) - { - const LV2_Atom_URID *subj = NULL; - const LV2_Atom_Int *seqn = NULL; - const LV2_Atom_URID *property = NULL; - const LV2_Atom *value = NULL; - - lv2_atom_object_get(obj, - handle->patch_subject, &subj, - handle->patch_sequenceNumber, &seqn, - handle->patch_property, &property, - handle->patch_value, &value, - 0); - - int32_t sequence_number = 0; - if(seqn && (seqn->atom.type == handle->forge.Int) ) - sequence_number = seqn->body; - - if( property && (property->atom.type == handle->forge.URID) - && (!subj || (subj->atom.type == handle->forge.URID)) - && value) - { - if(!subj || (subj->body == handle->patch_self) ) // destined for plugin - { - _patch_set_self(handle, property->body, value); - } - else // destined for parameter - { - _patch_set_parameter_property(handle, subj->body, property->body, value); - } - - _patch_ack(handle, sequence_number); //TODO handle errors in _patch_set_* - } - else - { - _patch_error(handle, sequence_number); - } - } - else if(obj->body.otype == handle->patch_Put) - { - const LV2_Atom_URID *subj = NULL; - const LV2_Atom_Int *seqn = NULL; - const LV2_Atom_Object *body= NULL; - - lv2_atom_object_get(obj, - handle->patch_subject, &subj, - handle->patch_sequenceNumber, &seqn, - handle->patch_body, &body, - 0); - - int32_t sequence_number = 0; - if(seqn && (seqn->atom.type == handle->forge.Int) ) - sequence_number = seqn->body; - - if( (!subj || (subj->atom.type == handle->forge.URID)) - && body && lv2_atom_forge_is_object_type(&handle->forge, body->atom.type) ) - { - if(!subj || (subj->body == handle->patch_self) ) // destined for plugin - { - LV2_ATOM_OBJECT_FOREACH(body, pro) - { - _patch_set_self(handle, pro->key, &pro->value); - } - } - else // destined for parameter - { - LV2_ATOM_OBJECT_FOREACH(body, pro) - { - _patch_set_parameter_property(handle, subj->body, pro->key, &pro->value); - } - } - - _patch_ack(handle, sequence_number); //TODO handle errors in _patch_set_* - } - else - { - _patch_error(handle, sequence_number); - } - } - else if(obj->body.otype == handle->patch_Patch) - { - const LV2_Atom_URID *subj = NULL; - const LV2_Atom_Int *seqn = NULL; - const LV2_Atom_Object *add = NULL; - const LV2_Atom_Object *rem = NULL; - - lv2_atom_object_get(obj, - handle->patch_subject, &subj, - handle->patch_sequenceNumber, &seqn, - handle->patch_add, &add, - handle->patch_remove, &rem, - 0); - - int32_t sequence_number = 0; - if(seqn && (seqn->atom.type == handle->forge.Int) ) - sequence_number = seqn->body; - - if( (!subj || (subj->atom.type == handle->forge.URID)) - && add && lv2_atom_forge_is_object_type(&handle->forge, add->atom.type) - && rem && lv2_atom_forge_is_object_type(&handle->forge, rem->atom.type) ) - { - LV2_ATOM_OBJECT_FOREACH(rem, pro) - { - if(!subj || (subj->body == handle->patch_self)) - { - const LV2_Atom_URID *property = (const LV2_Atom_URID *)&pro->value; - - if( (pro->key == handle->patch_writable) - && (property->body == handle->patch_wildcard) ) - { - //printf("clearing patch:writable\n"); - for(int p = 0; p < handle->n_writable; p++) - _prop_free(handle, &handle->writables[p]); - - if(handle->writables) - free(handle->writables); - - handle->writables = NULL; - handle->n_writable = 0; - - nk_pugl_post_redisplay(&handle->win); - } - else if( (pro->key == handle->patch_readable) - && (property->body == handle->patch_wildcard) ) - { - //printf("clearing patch:readable\n"); - for(int p = 0; p < handle->n_readable; p++) - _prop_free(handle, &handle->readables[p]); - - if(handle->readables) - free(handle->readables); - - handle->readables = NULL; - handle->n_readable = 0; - - nk_pugl_post_redisplay(&handle->win); - } - } - } - - LV2_ATOM_OBJECT_FOREACH(add, pro) - { - if(!subj || (subj->body == handle->patch_self)) - { - const LV2_Atom_URID *property = (const LV2_Atom_URID *)&pro->value; //FIXME check atom.type - - if(pro->key == handle->patch_writable) - { - prop_t *prop = _prop_get_or_add(handle, &handle->writables, &handle->n_writable, property->body); - (void)prop; - } - else if(pro->key == handle->patch_readable) - { - prop_t *prop = _prop_get_or_add(handle, &handle->readables, &handle->n_readable, property->body); - (void)prop; - } - } - else - { - _patch_set_parameter_property(handle, subj->body, pro->key, &pro->value); - } - } - - _patch_ack(handle, sequence_number); //TODO handle errors in _patch_get/set_* - } - else - { - _patch_error(handle, sequence_number); - } - } - } - } - else if( (protocol == 0) || (protocol == handle->ui_floatProtocol) ) // check for control port updates - { - for(int p = 0; p < 4; p++) - { - if(index == handle->controls_in[p].index) - { - prop_t *prop = &handle->controls_in[p]; - prop->value.f = *(const float *)buf; - - nk_pugl_post_redisplay(&handle->win); - break; - } - else if(index == handle->controls_out[p].index) - { - prop_t *prop = &handle->controls_out[p]; - prop->value.f = *(const float *)buf; - - // widen range if necessary - // TODO should we set range back after code update? - if(prop->value.f < prop->minimum.f) - prop->minimum.f = prop->value.f; - if(prop->value.f > prop->maximum.f) - prop->maximum.f = prop->value.f; - - nk_pugl_post_redisplay(&handle->win); - break; - } - } - } -} - -static int -_idle(LV2UI_Handle instance) -{ - plughandle_t *handle = instance; - - return nk_pugl_process_events(&handle->win); -} - -static const LV2UI_Idle_Interface idle_ext = { - .idle = _idle -}; - -static const void * -ext_data(const char *uri) -{ - if(!strcmp(uri, LV2_UI__idleInterface)) - { - return &idle_ext; - } - - return NULL; -} - -const LV2UI_Descriptor nk_ui= { - .URI = MOONY_NK_URI, - .instantiate = instantiate, - .cleanup = cleanup, - .port_event = port_event, - .extension_data = ext_data -}; - -LV2_SYMBOL_EXPORT const LV2UI_Descriptor* -lv2ui_descriptor(uint32_t index) -{ - switch(index) - { - case 0: - return &nk_ui; - default: - return NULL; - } -} diff --git a/subprojects/nk_pugl/.builds/alpine-latest.yml b/subprojects/nk_pugl/.builds/alpine-latest.yml deleted file mode 100644 index b07f370..0000000 --- a/subprojects/nk_pugl/.builds/alpine-latest.yml +++ /dev/null @@ -1,76 +0,0 @@ -# SPDX-FileCopyrightText: Hanspeter Portner -# SPDX-License-Identifier: CC0-1.0 - ---- - -image: alpine/latest - -packages: - - clang15-analyzer - - llvm15 - - reuse - - meson - - git-subtree - - hut - - jq - - valgrind - - - lv2-dev - - glew-dev - - glu-dev - - libx11-dev - - libxext-dev - -environment: - project: nk_pugl - CI_SCAN_BUILD_OPTS: -disable-checker security.insecureAPI.vfork -disable-checker unix.Vfork --exclude nanovg --exclude pugl --exclude nuklear - -secrets: - - 0545580c-42ac-4700-b322-4e9df924eb07 # runner-ssh - - 5fe806cd-3af4-4588-9898-8115d9262144 # hut-config - - d6d10b2a-542a-4b45-b1be-6ef30a8ab558 # git-config - -sources: - - https://git.open-music-kontrollers.ch/~hp/ci - -tasks: - - gcc: | - . ~/ci/activate - - ci-meson gcc setup \ - -Dbuild-examples=true - ci-meson gcc build - ci-meson gcc test - ci-meson gcc memcheck - - - clang: | - . ~/ci/activate - - ci-meson clang setup \ - -Dbuild-examples=true - ci-meson clang build - ci-meson clang test - ci-meson clang memcheck - - - analyzer: | - . ~/ci/activate - - ci-meson analyzer setup \ - -Dbuild-examples=true - ci-meson analyzer build - ci-meson analyzer test - - - deploy: | - . ~/ci/activate - - if ! ci-isrelease; then - complete-build - fi - - ci-subtreemerge - -triggers: - - action: email - condition: failure - to: "" -... diff --git a/subprojects/nk_pugl/.gitignore b/subprojects/nk_pugl/.gitignore deleted file mode 100644 index 6187fa8..0000000 --- a/subprojects/nk_pugl/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-FileCopyrightText: (c) Hanspeter Portner (dev@open-music-kontrollers.ch) -# SPDX-License-Identifier: CC0-1.0 - -tags -*.taghl -doc -configure diff --git a/subprojects/nk_pugl/.reuse/dep5 b/subprojects/nk_pugl/.reuse/dep5 deleted file mode 100644 index 2707630..0000000 --- a/subprojects/nk_pugl/.reuse/dep5 +++ /dev/null @@ -1,16 +0,0 @@ -Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: nk_pugl -Upstream-Contact: Hanspeter Portner -Source: https://git.open-music-kontrollers.ch/~hp/nk_pugl/ - -Files: pugl/* -Copyright: David Robillard -License: ISC - -Files: linenoise/* -Copyright: Salvatore Sanfilippo -License: BSD-2-Clause - -Files: nuklear/* -Copyright: MIcha Mettke -License: MIT diff --git a/subprojects/nk_pugl/COPYING b/subprojects/nk_pugl/COPYING deleted file mode 100644 index ddb9a46..0000000 --- a/subprojects/nk_pugl/COPYING +++ /dev/null @@ -1,201 +0,0 @@ - The Artistic License 2.0 - - Copyright (c) 2000-2006, The Perl Foundation. - - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -Preamble - -This license establishes the terms under which a given free software -Package may be copied, modified, distributed, and/or redistributed. -The intent is that the Copyright Holder maintains some artistic -control over the development of that Package while still keeping the -Package available as open source and free software. - -You are always permitted to make arrangements wholly outside of this -license directly with the Copyright Holder of a given Package. If the -terms of this license do not permit the full use that you propose to -make of the Package, you should contact the Copyright Holder and seek -a different licensing arrangement. - -Definitions - - "Copyright Holder" means the individual(s) or organization(s) - named in the copyright notice for the entire Package. - - "Contributor" means any party that has contributed code or other - material to the Package, in accordance with the Copyright Holder's - procedures. - - "You" and "your" means any person who would like to copy, - distribute, or modify the Package. - - "Package" means the collection of files distributed by the - Copyright Holder, and derivatives of that collection and/or of - those files. A given Package may consist of either the Standard - Version, or a Modified Version. - - "Distribute" means providing a copy of the Package or making it - accessible to anyone else, or in the case of a company or - organization, to others outside of your company or organization. - - "Distributor Fee" means any fee that you charge for Distributing - this Package or providing support for this Package to another - party. It does not mean licensing fees. - - "Standard Version" refers to the Package if it has not been - modified, or has been modified only in ways explicitly requested - by the Copyright Holder. - - "Modified Version" means the Package, if it has been changed, and - such changes were not explicitly requested by the Copyright - Holder. - - "Original License" means this Artistic License as Distributed with - the Standard Version of the Package, in its current version or as - it may be modified by The Perl Foundation in the future. - - "Source" form means the source code, documentation source, and - configuration files for the Package. - - "Compiled" form means the compiled bytecode, object code, binary, - or any other form resulting from mechanical transformation or - translation of the Source form. - - -Permission for Use and Modification Without Distribution - -(1) You are permitted to use the Standard Version and create and use -Modified Versions for any purpose without restriction, provided that -you do not Distribute the Modified Version. - - -Permissions for Redistribution of the Standard Version - -(2) You may Distribute verbatim copies of the Source form of the -Standard Version of this Package in any medium without restriction, -either gratis or for a Distributor Fee, provided that you duplicate -all of the original copyright notices and associated disclaimers. At -your discretion, such verbatim copies may or may not include a -Compiled form of the Package. - -(3) You may apply any bug fixes, portability changes, and other -modifications made available from the Copyright Holder. The resulting -Package will still be considered the Standard Version, and as such -will be subject to the Original License. - - -Distribution of Modified Versions of the Package as Source - -(4) You may Distribute your Modified Version as Source (either gratis -or for a Distributor Fee, and with or without a Compiled form of the -Modified Version) provided that you clearly document how it differs -from the Standard Version, including, but not limited to, documenting -any non-standard features, executables, or modules, and provided that -you do at least ONE of the following: - - (a) make the Modified Version available to the Copyright Holder - of the Standard Version, under the Original License, so that the - Copyright Holder may include your modifications in the Standard - Version. - - (b) ensure that installation of your Modified Version does not - prevent the user installing or running the Standard Version. In - addition, the Modified Version must bear a name that is different - from the name of the Standard Version. - - (c) allow anyone who receives a copy of the Modified Version to - make the Source form of the Modified Version available to others - under - - (i) the Original License or - - (ii) a license that permits the licensee to freely copy, - modify and redistribute the Modified Version using the same - licensing terms that apply to the copy that the licensee - received, and requires that the Source form of the Modified - Version, and of any works derived from it, be made freely - available in that license fees are prohibited but Distributor - Fees are allowed. - - -Distribution of Compiled Forms of the Standard Version -or Modified Versions without the Source - -(5) You may Distribute Compiled forms of the Standard Version without -the Source, provided that you include complete instructions on how to -get the Source of the Standard Version. Such instructions must be -valid at the time of your distribution. If these instructions, at any -time while you are carrying out such distribution, become invalid, you -must provide new instructions on demand or cease further distribution. -If you provide valid instructions or cease distribution within thirty -days after you become aware that the instructions are invalid, then -you do not forfeit any of your rights under this license. - -(6) You may Distribute a Modified Version in Compiled form without -the Source, provided that you comply with Section 4 with respect to -the Source of the Modified Version. - - -Aggregating or Linking the Package - -(7) You may aggregate the Package (either the Standard Version or -Modified Version) with other packages and Distribute the resulting -aggregation provided that you do not charge a licensing fee for the -Package. Distributor Fees are permitted, and licensing fees for other -components in the aggregation are permitted. The terms of this license -apply to the use and Distribution of the Standard or Modified Versions -as included in the aggregation. - -(8) You are permitted to link Modified and Standard Versions with -other works, to embed the Package in a larger work of your own, or to -build stand-alone binary or bytecode versions of applications that -include the Package, and Distribute the result without restriction, -provided the result does not expose a direct interface to the Package. - - -Items That are Not Considered Part of a Modified Version - -(9) Works (including, but not limited to, modules and scripts) that -merely extend or make use of the Package, do not, by themselves, cause -the Package to be a Modified Version. In addition, such works are not -considered parts of the Package itself, and are not subject to the -terms of this license. - - -General Provisions - -(10) Any use, modification, and distribution of the Standard or -Modified Versions is governed by this Artistic License. By using, -modifying or distributing the Package, you accept this license. Do not -use, modify, or distribute the Package, if you do not accept this -license. - -(11) If your Modified Version has been derived from a Modified -Version made by someone other than you, you are nevertheless required -to ensure that your Modified Version complies with the requirements of -this license. - -(12) This license does not grant you the right to use any trademark, -service mark, tradename, or logo of the Copyright Holder. - -(13) This license includes the non-exclusive, worldwide, -free-of-charge patent license to make, have made, use, offer to sell, -sell, import and otherwise transfer the Package with respect to any -patent claims licensable by the Copyright Holder that are necessarily -infringed by the Package. If you institute patent litigation -(including a cross-claim or counterclaim) against any party alleging -that the Package constitutes direct or contributory patent -infringement, then this Artistic License to you shall terminate on the -date that such litigation is filed. - -(14) Disclaimer of Warranty: -THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS -IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED -WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR -NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL -LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/subprojects/nk_pugl/LICENSES/Artistic-2.0.txt b/subprojects/nk_pugl/LICENSES/Artistic-2.0.txt deleted file mode 100644 index eb2e968..0000000 --- a/subprojects/nk_pugl/LICENSES/Artistic-2.0.txt +++ /dev/null @@ -1,85 +0,0 @@ -The Artistic License 2.0 - -Copyright (c) 2000-2006, The Perl Foundation. - -Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - -Preamble - -This license establishes the terms under which a given free software Package may be copied, modified, distributed, and/or redistributed. The intent is that the Copyright Holder maintains some artistic control over the development of that Package while still keeping the Package available as open source and free software. - -You are always permitted to make arrangements wholly outside of this license directly with the Copyright Holder of a given Package. If the terms of this license do not permit the full use that you propose to make of the Package, you should contact the Copyright Holder and seek a different licensing arrangement. - -Definitions - - "Copyright Holder" means the individual(s) or organization(s) named in the copyright notice for the entire Package. - - "Contributor" means any party that has contributed code or other material to the Package, in accordance with the Copyright Holder's procedures. - - "You" and "your" means any person who would like to copy, distribute, or modify the Package. - - "Package" means the collection of files distributed by the Copyright Holder, and derivatives of that collection and/or of those files. A given Package may consist of either the Standard Version, or a Modified Version. - - "Distribute" means providing a copy of the Package or making it accessible to anyone else, or in the case of a company or organization, to others outside of your company or organization. - - "Distributor Fee" means any fee that you charge for Distributing this Package or providing support for this Package to another party. It does not mean licensing fees. - - "Standard Version" refers to the Package if it has not been modified, or has been modified only in ways explicitly requested by the Copyright Holder. - - "Modified Version" means the Package, if it has been changed, and such changes were not explicitly requested by the Copyright Holder. - - "Original License" means this Artistic License as Distributed with the Standard Version of the Package, in its current version or as it may be modified by The Perl Foundation in the future. - - "Source" form means the source code, documentation source, and configuration files for the Package. - - "Compiled" form means the compiled bytecode, object code, binary, or any other form resulting from mechanical transformation or translation of the Source form. - -Permission for Use and Modification Without Distribution - -(1) You are permitted to use the Standard Version and create and use Modified Versions for any purpose without restriction, provided that you do not Distribute the Modified Version. - -Permissions for Redistribution of the Standard Version - -(2) You may Distribute verbatim copies of the Source form of the Standard Version of this Package in any medium without restriction, either gratis or for a Distributor Fee, provided that you duplicate all of the original copyright notices and associated disclaimers. At your discretion, such verbatim copies may or may not include a Compiled form of the Package. - -(3) You may apply any bug fixes, portability changes, and other modifications made available from the Copyright Holder. The resulting Package will still be considered the Standard Version, and as such will be subject to the Original License. - -Distribution of Modified Versions of the Package as Source - -(4) You may Distribute your Modified Version as Source (either gratis or for a Distributor Fee, and with or without a Compiled form of the Modified Version) provided that you clearly document how it differs from the Standard Version, including, but not limited to, documenting any non-standard features, executables, or modules, and provided that you do at least ONE of the following: - - (a) make the Modified Version available to the Copyright Holder of the Standard Version, under the Original License, so that the Copyright Holder may include your modifications in the Standard Version. - (b) ensure that installation of your Modified Version does not prevent the user installing or running the Standard Version. In addition, the Modified Version must bear a name that is different from the name of the Standard Version. - (c) allow anyone who receives a copy of the Modified Version to make the Source form of the Modified Version available to others under - - (i) the Original License or - (ii) a license that permits the licensee to freely copy, modify and redistribute the Modified Version using the same licensing terms that apply to the copy that the licensee received, and requires that the Source form of the Modified Version, and of any works derived from it, be made freely available in that license fees are prohibited but Distributor Fees are allowed. - -Distribution of Compiled Forms of the Standard Version or Modified Versions without the Source - -(5) You may Distribute Compiled forms of the Standard Version without the Source, provided that you include complete instructions on how to get the Source of the Standard Version. Such instructions must be valid at the time of your distribution. If these instructions, at any time while you are carrying out such distribution, become invalid, you must provide new instructions on demand or cease further distribution. If you provide valid instructions or cease distribution within thirty days after you become aware that the instructions are invalid, then you do not forfeit any of your rights under this license. - -(6) You may Distribute a Modified Version in Compiled form without the Source, provided that you comply with Section 4 with respect to the Source of the Modified Version. - -Aggregating or Linking the Package - -(7) You may aggregate the Package (either the Standard Version or Modified Version) with other packages and Distribute the resulting aggregation provided that you do not charge a licensing fee for the Package. Distributor Fees are permitted, and licensing fees for other components in the aggregation are permitted. The terms of this license apply to the use and Distribution of the Standard or Modified Versions as included in the aggregation. - -(8) You are permitted to link Modified and Standard Versions with other works, to embed the Package in a larger work of your own, or to build stand-alone binary or bytecode versions of applications that include the Package, and Distribute the result without restriction, provided the result does not expose a direct interface to the Package. - -Items That are Not Considered Part of a Modified Version - -(9) Works (including, but not limited to, modules and scripts) that merely extend or make use of the Package, do not, by themselves, cause the Package to be a Modified Version. In addition, such works are not considered parts of the Package itself, and are not subject to the terms of this license. - -General Provisions - -(10) Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license. - -(11) If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license. - -(12) This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder. - -(13) This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed. - -(14) Disclaimer of Warranty: -THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/subprojects/nk_pugl/LICENSES/CC0-1.0.txt b/subprojects/nk_pugl/LICENSES/CC0-1.0.txt deleted file mode 100644 index 0e259d4..0000000 --- a/subprojects/nk_pugl/LICENSES/CC0-1.0.txt +++ /dev/null @@ -1,121 +0,0 @@ -Creative Commons Legal Code - -CC0 1.0 Universal - - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE - LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN - ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS - INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES - REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS - PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM - THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED - HEREUNDER. - -Statement of Purpose - -The laws of most jurisdictions throughout the world automatically confer -exclusive Copyright and Related Rights (defined below) upon the creator -and subsequent owner(s) (each and all, an "owner") of an original work of -authorship and/or a database (each, a "Work"). - -Certain owners wish to permanently relinquish those rights to a Work for -the purpose of contributing to a commons of creative, cultural and -scientific works ("Commons") that the public can reliably and without fear -of later claims of infringement build upon, modify, incorporate in other -works, reuse and redistribute as freely as possible in any form whatsoever -and for any purposes, including without limitation commercial purposes. -These owners may contribute to the Commons to promote the ideal of a free -culture and the further production of creative, cultural and scientific -works, or to gain reputation or greater distribution for their Work in -part through the use and efforts of others. - -For these and/or other purposes and motivations, and without any -expectation of additional consideration or compensation, the person -associating CC0 with a Work (the "Affirmer"), to the extent that he or she -is an owner of Copyright and Related Rights in the Work, voluntarily -elects to apply CC0 to the Work and publicly distribute the Work under its -terms, with knowledge of his or her Copyright and Related Rights in the -Work and the meaning and intended legal effect of CC0 on those rights. - -1. Copyright and Related Rights. A Work made available under CC0 may be -protected by copyright and related or neighboring rights ("Copyright and -Related Rights"). Copyright and Related Rights include, but are not -limited to, the following: - - i. the right to reproduce, adapt, distribute, perform, display, - communicate, and translate a Work; - ii. moral rights retained by the original author(s) and/or performer(s); -iii. publicity and privacy rights pertaining to a person's image or - likeness depicted in a Work; - iv. rights protecting against unfair competition in regards to a Work, - subject to the limitations in paragraph 4(a), below; - v. rights protecting the extraction, dissemination, use and reuse of data - in a Work; - vi. database rights (such as those arising under Directive 96/9/EC of the - European Parliament and of the Council of 11 March 1996 on the legal - protection of databases, and under any national implementation - thereof, including any amended or successor version of such - directive); and -vii. other similar, equivalent or corresponding rights throughout the - world based on applicable law or treaty, and any national - implementations thereof. - -2. Waiver. To the greatest extent permitted by, but not in contravention -of, applicable law, Affirmer hereby overtly, fully, permanently, -irrevocably and unconditionally waives, abandons, and surrenders all of -Affirmer's Copyright and Related Rights and associated claims and causes -of action, whether now known or unknown (including existing as well as -future claims and causes of action), in the Work (i) in all territories -worldwide, (ii) for the maximum duration provided by applicable law or -treaty (including future time extensions), (iii) in any current or future -medium and for any number of copies, and (iv) for any purpose whatsoever, -including without limitation commercial, advertising or promotional -purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each -member of the public at large and to the detriment of Affirmer's heirs and -successors, fully intending that such Waiver shall not be subject to -revocation, rescission, cancellation, termination, or any other legal or -equitable action to disrupt the quiet enjoyment of the Work by the public -as contemplated by Affirmer's express Statement of Purpose. - -3. Public License Fallback. Should any part of the Waiver for any reason -be judged legally invalid or ineffective under applicable law, then the -Waiver shall be preserved to the maximum extent permitted taking into -account Affirmer's express Statement of Purpose. In addition, to the -extent the Waiver is so judged Affirmer hereby grants to each affected -person a royalty-free, non transferable, non sublicensable, non exclusive, -irrevocable and unconditional license to exercise Affirmer's Copyright and -Related Rights in the Work (i) in all territories worldwide, (ii) for the -maximum duration provided by applicable law or treaty (including future -time extensions), (iii) in any current or future medium and for any number -of copies, and (iv) for any purpose whatsoever, including without -limitation commercial, advertising or promotional purposes (the -"License"). The License shall be deemed effective as of the date CC0 was -applied by Affirmer to the Work. Should any part of the License for any -reason be judged legally invalid or ineffective under applicable law, such -partial invalidity or ineffectiveness shall not invalidate the remainder -of the License, and in such case Affirmer hereby affirms that he or she -will not (i) exercise any of his or her remaining Copyright and Related -Rights in the Work or (ii) assert any associated claims and causes of -action with respect to the Work, in either case contrary to Affirmer's -express Statement of Purpose. - -4. Limitations and Disclaimers. - - a. No trademark or patent rights held by Affirmer are waived, abandoned, - surrendered, licensed or otherwise affected by this document. - b. Affirmer offers the Work as-is and makes no representations or - warranties of any kind concerning the Work, express, implied, - statutory or otherwise, including without limitation warranties of - title, merchantability, fitness for a particular purpose, non - infringement, or the absence of latent or other defects, accuracy, or - the present or absence of errors, whether or not discoverable, all to - the greatest extent permissible under applicable law. - c. Affirmer disclaims responsibility for clearing rights of other persons - that may apply to the Work or any use thereof, including without - limitation any person's Copyright and Related Rights in the Work. - Further, Affirmer disclaims responsibility for obtaining any necessary - consents, permissions or other rights required for any use of the - Work. - d. Affirmer understands and acknowledges that Creative Commons is not a - party to this document and has no duty or obligation with respect to - this CC0 or use of the Work. diff --git a/subprojects/nk_pugl/LICENSES/MIT.txt b/subprojects/nk_pugl/LICENSES/MIT.txt deleted file mode 100644 index 2071b23..0000000 --- a/subprojects/nk_pugl/LICENSES/MIT.txt +++ /dev/null @@ -1,9 +0,0 @@ -MIT License - -Copyright (c) - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/subprojects/nk_pugl/example/example.c b/subprojects/nk_pugl/example/example.c deleted file mode 100644 index fbde5f3..0000000 --- a/subprojects/nk_pugl/example/example.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * SPDX-FileCopyrightText: Hanspeter Portner - * SPDX-License-Identifier: Artistic-2.0 - */ - -#include -#include -#include -#include - -#define LEN NK_LEN -#define MAX NK_MAX - -#define NK_PUGL_IMPLEMENTATION -#include - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" -#pragma GCC diagnostic ignored "-Wunused-variable" -#include "nuklear/demo/overview.c" -#pragma GCC diagnostic pop - -static volatile sig_atomic_t done = 0; - -static void -_sigint(int signum __attribute__((unused))) -{ - done = 1; -} - -static void -_expose(struct nk_context *ctx, struct nk_rect wbounds __attribute__((unused)), - void *data __attribute__((unused))) -{ - overview(ctx); -} - -int -main(int argc __attribute__((unused)), char **argv __attribute__((unused))) -{ - static nk_pugl_window_t win; - nk_pugl_config_t *cfg = &win.cfg; - - const float scale = nk_pugl_get_scale(); - - cfg->width = 1280 * scale; - cfg->height = 720 * scale; - cfg->resizable = true; - cfg->parent = 0; - cfg->threads = false; - cfg->ignore = false; - cfg->class = "nk_pugl_example"; - cfg->title = "Nk Pugl Example"; - cfg->expose = _expose; - cfg->data = NULL; - cfg->font.face = "./Cousine-Regular.ttf"; - cfg->font.size = 13 * scale; - - signal(SIGTERM, _sigint); - signal(SIGINT, _sigint); -#if !defined(_WIN32) - signal(SIGQUIT, _sigint); - signal(SIGKILL, _sigint); -#endif - - const intptr_t widget = nk_pugl_init(&win); - if(!widget) - { - return 1; - } - - nk_pugl_show(&win); - -#if !defined(_WIN32) && !defined(__APPLE__) - struct timespec tm; - clock_gettime(CLOCK_MONOTONIC, &tm); -#endif - - while(!done) - { -#if !defined(_WIN32) && !defined(__APPLE__) - if(clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tm, NULL) != 0) - { - continue; - } - -#define NANOS 1000000000 - tm.tv_nsec += NANOS / 25; - while(tm.tv_nsec >= NANOS) - { - tm.tv_sec += 1; - tm.tv_nsec -= NANOS; - } -#undef NANOS -#else - usleep(1000000 / 25); -#endif - - done = nk_pugl_process_events(&win); - } - - nk_pugl_hide(&win); - - nk_pugl_shutdown(&win); - - return 0; -} diff --git a/subprojects/nk_pugl/meson.build b/subprojects/nk_pugl/meson.build deleted file mode 100644 index 606d17b..0000000 --- a/subprojects/nk_pugl/meson.build +++ /dev/null @@ -1,100 +0,0 @@ -# SPDX-FileCopyrightText: Hanspeter Portner -# SPDX-License-Identifier: CC0-1.0 - -project('nk_pugl', 'c', default_options : [ - 'buildtype=release', - 'warning_level=3', - 'werror=false', - 'b_lto=false', - 'c_std=gnu11']) - -build_examples = get_option('build-examples') -build_tests = get_option('build-tests') - -static_link = false #meson.is_cross_build() - -cc = meson.get_compiler('c') - -m_dep = cc.find_library('m') -lv2_dep = dependency('lv2', - version : '>=1.14.0') -glew_dep = dependency('glew', - version : '>=2.0.0', - static : static_link) -glu_dep = dependency('glu', - version : '>=9.0.0', - static : static_link) -reuse = find_program('reuse', - required : false) - -deps = [m_dep, lv2_dep, glu_dep, glew_dep] -links = [] - -nk_pugl_inc = include_directories('') -pugl_inc = include_directories(join_paths('pugl', 'include')) -inc_dir = [nk_pugl_inc, pugl_inc] - -add_project_arguments('-D_GNU_SOURCE', language : 'c') - -bin_srcs = [ - join_paths('example', 'example.c') -] - -lib_srcs = [ - join_paths('pugl', 'src', 'implementation.c') -] - -c_args = [ - '-Wno-unknown-warning-option', - '-Wno-null-pointer-subtraction' -] - -if host_machine.system() == 'windows' - deps += cc.find_library('opengl32') - deps += cc.find_library('gdi32') - deps += cc.find_library('ws2_32') - lib_srcs += join_paths('pugl', 'src', 'win.c') - lib_srcs += join_paths('pugl', 'src', 'win_gl.c') -elif host_machine.system() == 'darwin' - add_languages('objc') - links += ['-framework', 'OpenGL'] - links += ['-framework', 'Cocoa'] - lib_srcs += join_paths('pugl', 'src', 'mac.m') - lib_srcs += join_paths('pugl', 'src', 'mac_gl.m') -else - deps += dependency('gl') - deps += dependency('x11', version : '>=1.6.0') - deps += dependency('xext', version : '>=1.3.0') - lib_srcs += join_paths('pugl', 'src', 'x11.c') - lib_srcs += join_paths('pugl', 'src', 'x11_gl.c') -endif - -nk_pugl_gl = declare_dependency( - compile_args : ['-DPUGL_STATIC'], - include_directories : inc_dir, - dependencies : deps, - link_args : links, - sources : lib_srcs) - -cousine_regular_ttf = configure_file( - input : join_paths('nuklear', 'extra_font', 'Cousine-Regular.ttf'), - output : 'Cousine-Regular.ttf', - copy : true, - install : false) - -if build_examples - executable('nk_pugl.gl', [bin_srcs], - c_args : c_args, - include_directories : inc_dir, - dependencies: nk_pugl_gl, - install : false) -endif - -if build_tests - if reuse.found() - test('REUSE', reuse, args : [ - '--root', meson.current_source_dir(), - 'lint' - ]) - endif -endif diff --git a/subprojects/nk_pugl/meson_options.txt b/subprojects/nk_pugl/meson_options.txt deleted file mode 100644 index 8e39ab5..0000000 --- a/subprojects/nk_pugl/meson_options.txt +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-FileCopyrightText: Hanspeter Portner -# SPDX-License-Identifier: CC0-1.0 - -option('build-tests', - type : 'boolean', - value : true, - yield : true) -option('build-examples', - type : 'boolean', - value : false, - yield : true) - -option('version', type : 'string', value : '0.2.0') diff --git a/subprojects/nk_pugl/nk_pugl/nk_pugl.h b/subprojects/nk_pugl/nk_pugl/nk_pugl.h deleted file mode 100644 index 9ca0ef4..0000000 --- a/subprojects/nk_pugl/nk_pugl/nk_pugl.h +++ /dev/null @@ -1,1365 +0,0 @@ -/* - * SPDX-FileCopyrightText: Hanspeter Portner - * SPDX-License-Identifier: Artistic-2.0 - */ - -#ifndef _NK_PUGL_H -#define _NK_PUGL_H - -#include -#include // isalpha -#include // isalpha - -#ifdef __cplusplus -extern C { -#endif - -#if defined(__APPLE__) -# include -# include -#else -# include -# ifdef _WIN32 -# include -# else -# include -# endif -#endif - -#include "pugl/pugl.h" -#include "pugl/gl.h" - -#include - -#define KEY_TAB '\t' -#define KEY_NEWLINE '\n' -#define KEY_RETURN '\r' -#define KEY_PLUS '+' -#define KEY_MINUS '-' -#define KEY_C 'c' -#define KEY_V 'v' -#define KEY_X 'x' -#define KEY_Z 'z' - -#define NK_ZERO_COMMAND_MEMORY -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_STANDARD_VARARGS -#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT -#define NK_INCLUDE_FONT_BAKING -#define NK_INCLUDE_DEFAULT_FONT -#define NK_SIN sinf -#define NK_COS cosf -#define NK_SQRT sqrtf - -#include "nuklear/nuklear.h" -#include "nuklear/example/stb_image.h" - -#ifndef NK_PUGL_API -# define NK_PUGL_API static inline -#endif - -typedef struct _nk_pugl_config_t nk_pugl_config_t; -typedef struct _nk_pugl_window_t nk_pugl_window_t; -typedef void (*nkglGenerateMipmap)(GLenum target); -typedef void (*nk_pugl_expose_t)(struct nk_context *ctx, - struct nk_rect wbounds, void *data); - -struct _nk_pugl_config_t { - unsigned width; - unsigned height; - unsigned min_width; - unsigned min_height; - - bool resizable; - bool fixed_aspect; - bool ignore; - const char *class; - const char *title; - - struct { - char *face; - int size; - } font; - - intptr_t parent; - bool threads; - - LV2UI_Resize *host_resize; - - void *data; - nk_pugl_expose_t expose; -}; - -struct _nk_pugl_window_t { - nk_pugl_config_t cfg; - char urn [46]; - - PuglWorld *world; - PuglView *view; - int quit; - - struct nk_buffer cmds; - struct nk_buffer vbuf; - struct nk_buffer ebuf; - struct nk_draw_null_texture null; - struct nk_context ctx; - struct nk_font_atlas atlas; - struct nk_convert_config conv; - struct { - void *buffer; - size_t size; - } last; - bool has_left; - bool has_entered; - - GLuint font_tex; - nkglGenerateMipmap glGenerateMipmap; - - intptr_t widget; - PuglMod state; -#if !defined(__APPLE__) && !defined(_WIN32) - atomic_flag async; -#endif -}; - -NK_PUGL_API intptr_t -nk_pugl_init(nk_pugl_window_t *win); - -NK_PUGL_API void -nk_pugl_show(nk_pugl_window_t *win); - -NK_PUGL_API void -nk_pugl_hide(nk_pugl_window_t *win); - -NK_PUGL_API void -nk_pugl_shutdown(nk_pugl_window_t *win); - -NK_PUGL_API void -nk_pugl_wait_for_event(nk_pugl_window_t *win); - -NK_PUGL_API int -nk_pugl_process_events(nk_pugl_window_t *win); - -NK_PUGL_API int -nk_pugl_resize(nk_pugl_window_t *win, int width, int height); - -NK_PUGL_API void -nk_pugl_post_redisplay(nk_pugl_window_t *win); - -NK_PUGL_API void -nk_pugl_async_redisplay(nk_pugl_window_t *win); - -NK_PUGL_API void -nk_pugl_quit(nk_pugl_window_t *win); - -NK_PUGL_API struct nk_image -nk_pugl_icon_load(nk_pugl_window_t *win, const char *filename); - -NK_PUGL_API void -nk_pugl_icon_unload(nk_pugl_window_t *win, struct nk_image img); - -NK_PUGL_API bool -nk_pugl_is_shortcut_pressed(struct nk_input *in, char letter, bool clear); - -NK_PUGL_API void -nk_pugl_copy_to_clipboard(nk_pugl_window_t *win, const char *selection, size_t len); - -NK_PUGL_API const char * -nk_pugl_paste_from_clipboard(nk_pugl_window_t *win, size_t *len); - -NK_PUGL_API float -nk_pugl_get_scale(void); - -#ifdef __cplusplus -} -#endif - -#endif // _NK_PUGL_H - -#ifdef NK_PUGL_IMPLEMENTATION - -#ifdef __cplusplus -extern C { -#endif - -#define NK_ZERO_COMMAND_MEMORY -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_STANDARD_VARARGS -#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT -#define NK_INCLUDE_FONT_BAKING -#define NK_INCLUDE_DEFAULT_FONT -#define NK_SIN sinf -#define NK_COS cosf -#define NK_SQRT sqrtf - -#define NK_IMPLEMENTATION -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" -#include "nuklear/nuklear.h" -#pragma GCC diagnostic pop - -#define STB_IMAGE_IMPLEMENTATION -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmisleading-indentation" -#pragma GCC diagnostic ignored "-Wshift-negative-value" -#include "nuklear/example/stb_image.h" -#pragma GCC diagnostic pop - -typedef struct _nk_pugl_vertex_t nk_pugl_vertex_t; - -struct _nk_pugl_vertex_t { - float position [2]; - float uv [2]; - nk_byte col [4]; -}; - -static const struct nk_draw_vertex_layout_element vertex_layout [] = { - {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(nk_pugl_vertex_t, position)}, - {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(nk_pugl_vertex_t, uv)}, - {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(nk_pugl_vertex_t, col)}, - {NK_VERTEX_LAYOUT_END} -}; - -#if defined(__APPLE__) -# define GL_EXT(name) name - -#elif defined(_WIN32) -static void * -_nk_pugl_gl_ext(const char *name) -{ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" - void *p = wglGetProcAddress(name); -#pragma GCC diagnostic pop - - if( (p == 0) || (p == (void *)-1) - || (p == (void *)0x1) || (p == (void *)0x2) || (p == (void *)0x3) ) - { - HMODULE module = LoadLibraryA("opengl32.dll"); - p = (void *)GetProcAddress(module, name); - } - - if(!p) - { - fprintf(stderr, "[GL]: failed to load extension: %s", name); - } - - return p; -} -# define GL_EXT(name) (nk##name)_nk_pugl_gl_ext(#name) - -#else -static void * -_nk_pugl_gl_ext(const char *name) -{ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" - void *p = puglGetProcAddress(name); -#pragma GCC diagnostic pop - - if(!p) - { - fprintf(stderr, "[GL]: failed to load extension: %s", name); - } - - return p; -} -# define GL_EXT(name) (nk##name)_nk_pugl_gl_ext(#name) -#endif - -static inline void -_nk_pugl_device_upload_atlas(nk_pugl_window_t *win, const void *image, - int width, int height) -{ - glGenTextures(1, &win->font_tex); - glBindTexture(GL_TEXTURE_2D, win->font_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, image); -} - -static inline void -_nk_pugl_render_gl2_push(unsigned width, unsigned height) -{ - glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT); - - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glEnable(GL_SCISSOR_TEST); - glEnable(GL_BLEND); - glEnable(GL_TEXTURE_2D); - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glViewport(0, 0, width, height); - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(0.f, width, height, 0.f, -1.f, 1.f); - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); -} - -static inline void -_nk_pugl_render_gl2_pop(void) -{ - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - - glBindTexture(GL_TEXTURE_2D, 0); - - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - - glPopAttrib(); -} - -static inline void -_nk_pugl_render_gl2(nk_pugl_window_t *win) -{ - nk_pugl_config_t *cfg = &win->cfg; - bool has_changes = win->has_left || win->has_entered; - - // compare current command buffer with last one to defer any changes - if(!has_changes) - { - const size_t size = win->ctx.memory.allocated; - const void *commands = nk_buffer_memory_const(&win->ctx.memory); - - if( (size != win->last.size) || memcmp(commands, win->last.buffer, size) ) - { - // swap last buffer with current one for next comparison - win->last.buffer = realloc(win->last.buffer, size); - if(win->last.buffer) - { - win->last.size = size; - memcpy(win->last.buffer, commands, size); - } - else - { - win->last.size = 0; - } - has_changes = true; - } - } - - if(has_changes) - { - // clear command/vertex buffers of last stable view - nk_buffer_clear(&win->cmds); - nk_buffer_clear(&win->vbuf); - nk_buffer_clear(&win->ebuf); - nk_draw_list_clear(&win->ctx.draw_list); - - // convert shapes into vertexes if there were changes - nk_convert(&win->ctx, &win->cmds, &win->vbuf, &win->ebuf, &win->conv); - } - - _nk_pugl_render_gl2_push(cfg->width, cfg->height); - - // setup vertex buffer pointers - const GLsizei vs = sizeof(nk_pugl_vertex_t); - const size_t vp = offsetof(nk_pugl_vertex_t, position); - const size_t vt = offsetof(nk_pugl_vertex_t, uv); - const size_t vc = offsetof(nk_pugl_vertex_t, col); - const nk_byte *vertices = nk_buffer_memory_const(&win->vbuf); - glVertexPointer(2, GL_FLOAT, vs, &vertices[vp]); - glTexCoordPointer(2, GL_FLOAT, vs, &vertices[vt]); - glColorPointer(4, GL_UNSIGNED_BYTE, vs, &vertices[vc]); - - // iterate over and execute each draw command - const nk_draw_index *offset = nk_buffer_memory_const(&win->ebuf); - const struct nk_draw_command *cmd; - nk_draw_foreach(cmd, &win->ctx, &win->cmds) - { - if(!cmd->elem_count) - { - continue; - } - - glBindTexture(GL_TEXTURE_2D, cmd->texture.id); - glScissor( - cmd->clip_rect.x, - cfg->height - (cmd->clip_rect.y + cmd->clip_rect.h), - cmd->clip_rect.w, - cmd->clip_rect.h); - glDrawElements(GL_TRIANGLES, cmd->elem_count, GL_UNSIGNED_SHORT, offset); - - offset += cmd->elem_count; - } - - _nk_pugl_render_gl2_pop(); - - win->has_entered = false; - - nk_clear(&win->ctx); -} - -static void -_nk_pugl_glew_init(void) -{ -#if defined(__APPLE__) -//FIXME -#else - glewExperimental = GL_TRUE; - const GLenum err = glewInit(); - if(err != GLEW_OK) - { - fprintf(stderr, "glewInit failed: %s\n", glewGetErrorString(err)); - return; - } -#endif -} - -static void -_nk_pugl_font_init(nk_pugl_window_t *win) -{ - nk_pugl_config_t *cfg = &win->cfg; - - const int font_size = cfg->font.size; - - // init nuklear font - struct nk_font *ttf = NULL; - struct nk_font_config fcfg = nk_font_config(font_size); - static const nk_rune range [] = { - 0x0020, 0x007F, // Basic Latin - 0x00A0, 0x00FF, // Latin-1 Supplement - 0x0100, 0x017F, // Latin Extended-A - 0x0180, 0x024F, // Latin Extended-B - 0x0300, 0x036F, // Combining Diacritical Marks - 0x0370, 0x03FF, // Greek and Coptic - 0x0400, 0x04FF, // Cyrillic - 0x0500, 0x052F, // Cyrillic Supplementary - 0 - }; - fcfg.range = range; - fcfg.oversample_h = 8; - fcfg.oversample_v = 8; - - struct nk_font_atlas *atlas = &win->atlas; - nk_font_atlas_init_default(atlas); - nk_font_atlas_begin(atlas); - - if(cfg->font.face && font_size) - { - ttf = nk_font_atlas_add_from_file(&win->atlas, cfg->font.face, font_size, &fcfg); - } - - int w = 0; - int h = 0; - struct nk_draw_null_texture null; - const void *image = nk_font_atlas_bake(atlas, &w, &h, NK_FONT_ATLAS_RGBA32); - _nk_pugl_device_upload_atlas(win, image, w, h); - nk_font_atlas_end(atlas, nk_handle_id(win->font_tex), &null); - - if(atlas->default_font) - { - nk_style_set_font(&win->ctx, &atlas->default_font->handle); - } - - if(ttf) - { - nk_style_set_font(&win->ctx, &ttf->handle); - } - - // to please compiler - (void)nk_cos; - (void)nk_sin; - (void)nk_sqrt; -} - -static void -_nk_pugl_font_deinit(nk_pugl_window_t *win) -{ - nk_font_atlas_clear(&win->atlas); - - if(win->font_tex) - { - glDeleteTextures(1, (const GLuint *)&win->font_tex); - } -} - -static void -_nk_pugl_host_resize(nk_pugl_window_t *win) -{ - nk_pugl_config_t *cfg = &win->cfg; - - if(cfg->host_resize) - { - cfg->host_resize->ui_resize(cfg->host_resize->handle, - cfg->width, cfg->height); - } -} - -static void -_nk_pugl_key_press(struct nk_context *ctx, enum nk_keys key) -{ - nk_input_key(ctx, key, nk_true); - nk_input_key(ctx, key, nk_false); -} - -static void -_nk_pugl_modifiers(nk_pugl_window_t *win, PuglMod state) -{ - struct nk_context *ctx = &win->ctx; - - if(win->state != state) // modifiers changed - { - if( (win->state & PUGL_MOD_SHIFT) != (state & PUGL_MOD_SHIFT)) - { - nk_input_key(ctx, NK_KEY_SHIFT, (state & PUGL_MOD_SHIFT) == PUGL_MOD_SHIFT); - } - - if( (win->state & PUGL_MOD_CTRL) != (state & PUGL_MOD_CTRL)) - { - nk_input_key(ctx, NK_KEY_CTRL, (state & PUGL_MOD_CTRL) == PUGL_MOD_CTRL); - } - - if( (win->state & PUGL_MOD_ALT) != (state & PUGL_MOD_ALT)) - { - // not yet supported in nuklear - } - - if( (win->state & PUGL_MOD_SUPER) != (state & PUGL_MOD_SUPER)) - { - // not yet supported in nuklear - } - - win->state = state; // switch old and new modifier states - } -} - -static bool -_nk_pugl_key_down(nk_pugl_window_t *win, const PuglEventKey *ev) -{ - struct nk_context *ctx = &win->ctx; -#if defined(__APPLE__) - const bool control = ev->state & PUGL_MOD_SUPER; -#else - const bool control = ev->state & PUGL_MOD_CTRL; -#endif - const bool shift = ev->state & PUGL_MOD_SHIFT; - - switch(ev->key) - { - case PUGL_KEY_LEFT: - { - _nk_pugl_key_press(ctx, control ? NK_KEY_TEXT_WORD_LEFT : NK_KEY_LEFT); - } break; - case PUGL_KEY_RIGHT: - { - _nk_pugl_key_press(ctx, control ? NK_KEY_TEXT_WORD_RIGHT : NK_KEY_RIGHT); - } break; - case PUGL_KEY_UP: - { - _nk_pugl_key_press(ctx, NK_KEY_UP); - } break; - case PUGL_KEY_DOWN: - { - _nk_pugl_key_press(ctx, NK_KEY_DOWN); - } break; - case PUGL_KEY_PAGE_UP: - { - _nk_pugl_key_press(ctx, NK_KEY_SCROLL_UP); - } break; - case PUGL_KEY_PAGE_DOWN: - { - _nk_pugl_key_press(ctx, NK_KEY_SCROLL_DOWN); - } break; - case PUGL_KEY_HOME: - { - if(control) - { - _nk_pugl_key_press(ctx, NK_KEY_TEXT_START); - _nk_pugl_key_press(ctx, NK_KEY_SCROLL_START); - } - else - { - _nk_pugl_key_press(ctx, NK_KEY_TEXT_LINE_START); - } - } break; - case PUGL_KEY_END: - { - if(control) - { - _nk_pugl_key_press(ctx, NK_KEY_TEXT_END); - _nk_pugl_key_press(ctx, NK_KEY_SCROLL_END); - } - else - { - _nk_pugl_key_press(ctx, NK_KEY_TEXT_LINE_END); - } - } break; - case PUGL_KEY_INSERT: - { - _nk_pugl_key_press(ctx, NK_KEY_TEXT_INSERT_MODE); - } break; - case PUGL_KEY_SHIFT: - { - win->state |= PUGL_MOD_SHIFT; - nk_input_key(ctx, NK_KEY_SHIFT, nk_true); - } return true; - case PUGL_KEY_CTRL: - { - win->state |= PUGL_MOD_CTRL; - nk_input_key(ctx, NK_KEY_CTRL, nk_true); - } return true; - case KEY_NEWLINE: - // fall-through - case KEY_RETURN: - { - _nk_pugl_key_press(ctx, NK_KEY_ENTER); - } break; - case KEY_TAB: - { - _nk_pugl_key_press(ctx, NK_KEY_TAB); - } break; - case PUGL_KEY_DELETE: - { -#if defined(__APPLE__) // quirk around Apple's Delete key strangeness - _nk_pugl_key_press(ctx, NK_KEY_BACKSPACE); -#else - _nk_pugl_key_press(ctx, NK_KEY_DEL); -#endif - } break; - case PUGL_KEY_BACKSPACE: - { -#if defined(__APPLE__) // quirk around Apple's Delete key strangeness - _nk_pugl_key_press(ctx, NK_KEY_DEL); -#else - _nk_pugl_key_press(ctx, NK_KEY_BACKSPACE); -#endif - } break; - case PUGL_KEY_ESCAPE: - { - _nk_pugl_key_press(ctx, NK_KEY_TEXT_RESET_MODE); - } break; - - default: - { - if(control) - { - switch(ev->key) - { - case KEY_C: - { - _nk_pugl_key_press(ctx, NK_KEY_COPY); - } break; - case KEY_V: - { - _nk_pugl_key_press(ctx, NK_KEY_PASTE); - } break; - case KEY_X: - { - _nk_pugl_key_press(ctx, NK_KEY_CUT); - } break; - case KEY_Z: - { - _nk_pugl_key_press(ctx, shift ? NK_KEY_TEXT_REDO : NK_KEY_TEXT_UNDO); - } break; - } - } - } - } - - return false; -} - -static bool -_nk_pugl_key_up(nk_pugl_window_t *win, const PuglEventKey *ev) -{ - struct nk_context *ctx = &win->ctx; - - switch(ev->key) - { - case PUGL_KEY_SHIFT: - { - nk_input_key(ctx, NK_KEY_SHIFT, nk_false); - win->state &= ~PUGL_MOD_SHIFT; - } return true; - case PUGL_KEY_CTRL: - { - nk_input_key(ctx, NK_KEY_CTRL, nk_false); - win->state &= ~PUGL_MOD_CTRL; - } return true; - } - - return false; -} - -static inline void -_nk_pugl_expose(PuglView *view) -{ - nk_pugl_window_t *win = puglGetHandle(view); - nk_pugl_config_t *cfg = &win->cfg; - struct nk_context *ctx = &win->ctx; - - const struct nk_rect wbounds = nk_rect(0, 0, cfg->width, cfg->height); - - if(nk_begin(ctx, "__bg__", wbounds, 0)) - { - const struct nk_rect obounds = nk_window_get_bounds(ctx); - - if( (obounds.x != wbounds.x) || (obounds.y != wbounds.y) - || (obounds.w != wbounds.w) || (obounds.h != wbounds.h) ) - { - // size has changed - puglPostRedisplay(view); - } - - // clears window with widget background color - } - nk_end(ctx); - - if(cfg->expose) - { - cfg->expose(ctx, wbounds, cfg->data); - } - - _nk_pugl_render_gl2(win); -} - -static PuglStatus -_nk_pugl_event_func(PuglView *view, const PuglEvent *e) -{ - nk_pugl_window_t *win = puglGetHandle(view); - nk_pugl_config_t *cfg = &win->cfg; - struct nk_context *ctx = &win->ctx; - - switch(e->type) - { - case PUGL_LOOP_ENTER: - { - // TODO - } break; - case PUGL_LOOP_LEAVE: - { - // TODO - } break; - case PUGL_BUTTON_PRESS: - { - const PuglEventButton *ev = (const PuglEventButton *)e; - - _nk_pugl_modifiers(win, ev->state); - nk_input_button(ctx, ev->button - 1, ev->x, ev->y, 1); - - puglPostRedisplay(win->view); - } break; - case PUGL_BUTTON_RELEASE: - { - const PuglEventButton *ev = (const PuglEventButton *)e; - - _nk_pugl_modifiers(win, ev->state); - nk_input_button(ctx, ev->button - 1, ev->x, ev->y, 0); - - puglPostRedisplay(win->view); - } break; - case PUGL_CONFIGURE: - { - const PuglEventConfigure *ev = (const PuglEventConfigure *)e; - - // only redisplay if size has changed - if( (cfg->width == ev->width) && (cfg->height == ev->height) ) - { - break; - } - - cfg->width = ev->width; - cfg->height = ev->height; - - puglPostRedisplay(win->view); - } break; - case PUGL_EXPOSE: - { - nk_input_end(ctx); - _nk_pugl_expose(win->view); - nk_input_begin(ctx); - } break; - case PUGL_CLOSE: - { - nk_pugl_quit(win); - } break; - case PUGL_KEY_PRESS: - { - const PuglEventKey *ev = (const PuglEventKey *)e; - - if(!_nk_pugl_key_down(win, ev)) // no modifier change - { - _nk_pugl_modifiers(win, ev->state); - } - - puglPostRedisplay(win->view); - } break; - case PUGL_KEY_RELEASE: - { - const PuglEventKey *ev = (const PuglEventKey *)e; - - if(!_nk_pugl_key_up(win, ev)) // no modifier change - { - _nk_pugl_modifiers(win, ev->state); - } - - puglPostRedisplay(win->view); - } break; - case PUGL_MOTION: - { - const PuglEventMotion *ev = (const PuglEventMotion *)e; - - _nk_pugl_modifiers(win, ev->state); - nk_input_motion(ctx, ev->x, ev->y); - - puglPostRedisplay(win->view); - } break; - case PUGL_SCROLL: - { - const PuglEventScroll *ev = (const PuglEventScroll *)e; - - _nk_pugl_modifiers(win, ev->state); - nk_input_scroll(ctx, nk_vec2(0.f, ev->dy)); - - puglPostRedisplay(win->view); - } break; - - case PUGL_POINTER_OUT: - { - const PuglEventCrossing *ev = (const PuglEventCrossing *)e; - - _nk_pugl_modifiers(win, ev->state); - win->has_left = true; - puglPostRedisplay(win->view); - } break; - case PUGL_POINTER_IN: - { - const PuglEventCrossing *ev = (const PuglEventCrossing *)e; - - _nk_pugl_modifiers(win, ev->state); - win->has_left = false; - win->has_entered = true; - puglPostRedisplay(win->view); - } break; - - case PUGL_FOCUS_OUT: - case PUGL_FOCUS_IN: - { - // nothing - } break; - - case PUGL_TEXT: - { - const PuglEventText *ev = (const PuglEventText *)e; - - const bool control = ev->state & PUGL_MOD_CTRL; - - const int ch = control ? ev->character | 0x60 : ev->character; - - if(isprint(ch)) - { - _nk_pugl_key_press(ctx, NK_KEY_TEXT_INSERT_MODE); - nk_input_unicode(ctx, ch); - } - } break; - - case PUGL_CREATE: - { - // init glew - _nk_pugl_glew_init(); - - // init font system - _nk_pugl_font_init(win); - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" - win->glGenerateMipmap = GL_EXT(glGenerateMipmap); -#pragma GCC diagnostic pop - } break; - case PUGL_DESTROY: - { - // deinit font system - _nk_pugl_font_deinit(win); - } break; - - case PUGL_MAP: - { - //nothing - } break; - case PUGL_UNMAP: - { - //nothing - } break; - case PUGL_UPDATE: - { - //nothing - } break; - case PUGL_CLIENT: - { - //nothing - } break; - case PUGL_TIMER: - { - //nothing - } break; - case PUGL_NOTHING: - { - // nothing - } break; - } - - return PUGL_SUCCESS; -} - -static void -_nk_pugl_editor_paste(nk_handle userdata, struct nk_text_edit* editor) -{ - nk_pugl_window_t *win = userdata.ptr; - - size_t len; - const char *selection = nk_pugl_paste_from_clipboard(win, &len); - if(selection) - { - nk_textedit_paste(editor, selection, len); - } -} - -static void -_nk_pugl_editor_copy(nk_handle userdata, const char *buf, int len) -{ - nk_pugl_window_t *win = userdata.ptr; - - nk_pugl_copy_to_clipboard(win, buf, len); -} - -NK_PUGL_API intptr_t -nk_pugl_init(nk_pugl_window_t *win) -{ - nk_pugl_config_t *cfg = &win->cfg; - struct nk_convert_config *conv = &win->conv; - - win->has_left = true; - - // init pugl - win->world = puglNewWorld(cfg->parent ? PUGL_MODULE : PUGL_PROGRAM, - cfg->threads ? PUGL_WORLD_THREADS : 0); - -#if defined(__APPLE__) || defined(_WIN32) - uint8_t bytes [0x10]; - - srand(time(NULL)); - for(unsigned i=0x0; i<0x10; i++) - bytes[i] = rand() & 0xff; - - bytes[6] = (bytes[6] & 0b00001111) | 0b01000000; // set four most significant bits of 7th byte to 0b0100 - bytes[8] = (bytes[8] & 0b00111111) | 0b10000000; // set two most significant bits of 9th byte to 0b10 - - snprintf(win->urn, sizeof(win->urn), - "urn:uuid:%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", - bytes[0x0], bytes[0x1], bytes[0x2], bytes[0x3], - bytes[0x4], bytes[0x5], - bytes[0x6], bytes[0x7], - bytes[0x8], bytes[0x9], - bytes[0xa], bytes[0xb], bytes[0xc], bytes[0xd], bytes[0xe], bytes[0xf]); - fprintf(stderr, "%s\n", win->urn); - puglSetClassName(win->world, win->urn); -#else - puglSetClassName(win->world, cfg->class ? cfg->class : "nuklear"); -#endif - - // init nuklear - nk_buffer_init_default(&win->cmds); - nk_buffer_init_default(&win->vbuf); - nk_buffer_init_default(&win->ebuf); - nk_init_default(&win->ctx, 0); - - // fill convert configuration - conv->vertex_layout = vertex_layout; - conv->vertex_size = sizeof(nk_pugl_vertex_t); - conv->vertex_alignment = NK_ALIGNOF(nk_pugl_vertex_t); - conv->null = win->null; - conv->circle_segment_count = 22; - conv->curve_segment_count = 22; - conv->arc_segment_count = 22; - conv->global_alpha = 1.0f; - conv->shape_AA = NK_ANTI_ALIASING_ON; - conv->line_AA = NK_ANTI_ALIASING_ON; - - nk_input_begin(&win->ctx); - - win->ctx.clip.paste = _nk_pugl_editor_paste; - win->ctx.clip.copy = _nk_pugl_editor_copy; - win->ctx.clip.userdata.ptr = win; - - win->view = puglNewView(win->world); - - const PuglRect frame = { - .x = 0, - .y = 0, - .width = cfg->width, - .height = cfg->height - }; - - puglSetFrame(win->view, frame); - if(cfg->min_width && cfg->min_height) - { - puglSetMinSize(win->view, cfg->min_width, cfg->min_height); - } - if(cfg->parent) - { - puglSetParentWindow(win->view, cfg->parent); -#if 0 // not yet implemented for mingw, darwin - puglSetTransientFor(win->view, cfg->parent); -#endif - } - if(cfg->fixed_aspect) - { - puglSetAspectRatio(win->view, cfg->width, cfg->height, - cfg->width, cfg->height); - } - puglSetViewHint(win->view, PUGL_RESIZABLE, cfg->resizable); - puglSetViewHint(win->view, PUGL_DOUBLE_BUFFER, true); - puglSetViewHint(win->view, PUGL_SWAP_INTERVAL, 1); - puglSetHandle(win->view, win); - puglSetEventFunc(win->view, _nk_pugl_event_func); - puglSetBackend(win->view, puglGlBackend()); - puglSetWindowTitle(win->view, - cfg->title ? cfg->title : "Nuklear"); - const int stat = puglRealize(win->view); - assert(stat == 0); - - win->widget = puglGetNativeWindow(win->view); - return win->widget; -} - -NK_PUGL_API void -nk_pugl_show(nk_pugl_window_t *win) -{ - if(!win->view) - { - return; - } - - puglShow(win->view); - _nk_pugl_host_resize(win); -} - -NK_PUGL_API void -nk_pugl_hide(nk_pugl_window_t *win) -{ - if(!win->view) - { - return; - } - - puglHide(win->view); -} - -NK_PUGL_API void -nk_pugl_shutdown(nk_pugl_window_t *win) -{ - if(!win->view) - { - return; - } - - nk_input_end(&win->ctx); - - if(win->last.buffer) - { - free(win->last.buffer); - } - - // shutdown nuklear - nk_buffer_free(&win->cmds); - nk_buffer_free(&win->vbuf); - nk_buffer_free(&win->ebuf); - nk_free(&win->ctx); - - // shutdown pugl - if(win->world) - { - if(win->view) - { - puglFreeView(win->view); - } - - puglFreeWorld(win->world); - } -} - -NK_PUGL_API void -nk_pugl_wait_for_event(nk_pugl_window_t *win) -{ - if(!win->view) - { - return; - } - - puglUpdate(win->world, -1.0); // blocking pooll -} - -NK_PUGL_API int -nk_pugl_process_events(nk_pugl_window_t *win) -{ - if(!win->view) - { - return 1; // quit - } - - PuglStatus stat = puglUpdate(win->world, 0.0); - (void)stat; - - return win->quit; -} - -NK_PUGL_API int -nk_pugl_resize(nk_pugl_window_t *win, int width, int height) -{ - if(!win->view) - { - return 1; // quit - } - - win->cfg.width = width; - win->cfg.height = height; - - puglPostRedisplay(win->view); - - return 0; -} - -NK_PUGL_API void -nk_pugl_post_redisplay(nk_pugl_window_t *win) -{ - if(!win->view) - { - return; - } - - puglPostRedisplay(win->view); -} - -NK_PUGL_API void -nk_pugl_async_redisplay(nk_pugl_window_t *win) -{ - if(!win->view) - { - return; - } - -#if defined(__APPLE__) -// TODO -#elif defined(_WIN32) - const HWND widget = (HWND)win->widget; - const int status = SendNotifyMessage(widget, WM_PAINT, 0, 0); - (void)status; -#else - Display *disp = puglGetNativeWorld(win->world); - const Window widget = (Window)win->widget; - XExposeEvent xevent = { - .type = Expose, - .display = disp, - .window = widget - }; - - while(atomic_flag_test_and_set_explicit(&win->async, memory_order_acquire)) - { - // spin - } - - const Status status = XSendEvent(disp, widget, false, ExposureMask, - (XEvent *)&xevent); - (void)status; - XFlush(disp); - - atomic_flag_clear_explicit(&win->async, memory_order_release); -#endif -} - -NK_PUGL_API void -nk_pugl_quit(nk_pugl_window_t *win) -{ - win->quit = 1; -} - -NK_PUGL_API struct nk_image -nk_pugl_icon_load(nk_pugl_window_t *win, const char *filename) -{ - GLuint tex = 0; - - if(!win->view) - { - return nk_image_id(tex); - } - - int w, h, n; - uint8_t *data = stbi_load(filename, &w, &h, &n, 4); - if(data) - { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - puglEnterContext(win->view); -#pragma GCC diagnostic pop - { - glGenTextures(1, &tex); - glBindTexture(GL_TEXTURE_2D, tex); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - if(!win->glGenerateMipmap) // for GL >= 1.4 && < 3.1 - { - glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); - } - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - if(win->glGenerateMipmap) // for GL >= 3.1 - { - win->glGenerateMipmap(GL_TEXTURE_2D); - } - } -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - puglLeaveContext(win->view); -#pragma GCC diagnostic pop - - stbi_image_free(data); - } - - return nk_image_id(tex); -} - -NK_PUGL_API void -nk_pugl_icon_unload(nk_pugl_window_t *win, struct nk_image img) -{ - if(!win->view) - { - return; - } - - if(img.handle.id) - { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - puglEnterContext(win->view); -#pragma GCC diagnostic pop - { - glDeleteTextures(1, (const GLuint *)&img.handle.id); - } -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - puglLeaveContext(win->view); -#pragma GCC diagnostic pop - } -} - -NK_PUGL_API bool -nk_pugl_is_shortcut_pressed(struct nk_input *in, char letter, bool clear) -{ - const bool control = nk_input_is_key_down(in, NK_KEY_CTRL); - - if(control && (in->keyboard.text_len == 1) ) - { - if(in->keyboard.text[0] == letter) - { - if(clear) - { - in->keyboard.text_len = 0; - } - - return true; // matching shortcut - } - } - - return false; -} - -NK_PUGL_API void -nk_pugl_copy_to_clipboard(nk_pugl_window_t *win, const char *selection, size_t len) -{ - const char *type = "text/plain"; - - puglSetClipboard(win->view, type, selection, len); -} - -NK_PUGL_API const char * -nk_pugl_paste_from_clipboard(nk_pugl_window_t *win, size_t *len) -{ - const char *type = NULL; - - return puglGetClipboard(win->view, &type, len); -} - -NK_PUGL_API float -nk_pugl_get_scale(void) -{ - const char *NK_SCALE = getenv("NK_SCALE"); - const float scale = NK_SCALE ? atof(NK_SCALE) : 1.f; - const float dpi0 = 96.f; // reference DPI we're designing for - float dpi1 = dpi0; - -#if defined(__APPLE__) - // FIXME -#elif defined(_WIN32) - // GetDpiForSystem/Monitor/Window is Win10 only - HDC screen = GetDC(NULL); - dpi1 = GetDeviceCaps(screen, LOGPIXELSX); - ReleaseDC(NULL, screen); -#else - Display *disp = XOpenDisplay(0); - if(disp) - { - // modern X actually lies here, but proprietary nvidia - dpi1 = XDisplayWidth(disp, 0) * 25.4f / XDisplayWidthMM(disp, 0); - - // read DPI from users's ~/.Xresources - char *resource_string = XResourceManagerString(disp); - XrmInitialize(); - if(resource_string) - { - XrmDatabase db = XrmGetStringDatabase(resource_string); - if(db) - { - char *type = NULL; - XrmValue value; - - XrmGetResource(db, "Xft.dpi", "String", &type, &value); - if(value.addr) - { - dpi1 = atof(value.addr); - } - - XrmDestroyDatabase(db); - } - } - - XCloseDisplay(disp); - } -#endif - - return scale * dpi1 / dpi0; -} - -#ifdef __cplusplus -} -#endif - -#endif // NK_PUGL_IMPLEMENTATION diff --git a/subprojects/nk_pugl/nuklear/.gitattributes b/subprojects/nk_pugl/nuklear/.gitattributes deleted file mode 100644 index 5a5328c..0000000 --- a/subprojects/nk_pugl/nuklear/.gitattributes +++ /dev/null @@ -1,3 +0,0 @@ -# Github language settings -*.h linguist-language=c -*.c linguist-language=c diff --git a/subprojects/nk_pugl/nuklear/.gitignore b/subprojects/nk_pugl/nuklear/.gitignore deleted file mode 100644 index 6b06b55..0000000 --- a/subprojects/nk_pugl/nuklear/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -demo/*/*.exe -demo/*/*.obj -demo/*/bin/* -example/bin/* -docs/xml -docs/build -docs/src -*.tmp diff --git a/subprojects/nk_pugl/nuklear/.gitmodules b/subprojects/nk_pugl/nuklear/.gitmodules deleted file mode 100644 index e69de29..0000000 diff --git a/subprojects/nk_pugl/nuklear/.travis.yml b/subprojects/nk_pugl/nuklear/.travis.yml deleted file mode 100644 index 80a5ad5..0000000 --- a/subprojects/nk_pugl/nuklear/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -language: c - -os: - - linux - -compiler: - - gcc - - clang - -before_install: - - if [ $TRAVIS_OS_NAME == linux ]; then sudo add-apt-repository -y ppa:pyglfw/pyglfw && sudo apt-get update -qq && sudo apt-get install -y --no-install-recommends libglfw3 libglfw3-dev libglew-dev; fi - -script: - - make -C demo/glfw_opengl3 CFLAGS="-Wall -DINCLUDE_ALL" - - make -C demo/glfw_opengl2 - - make -C example diff --git a/subprojects/nk_pugl/nuklear/Readme.md b/subprojects/nk_pugl/nuklear/Readme.md deleted file mode 100644 index d097e35..0000000 --- a/subprojects/nk_pugl/nuklear/Readme.md +++ /dev/null @@ -1,165 +0,0 @@ -# Nuklear - -[![Build Status](https://travis-ci.org/vurtun/nuklear.svg)](https://travis-ci.org/vurtun/nuklear) - -This is a minimal state immediate mode graphical user interface toolkit -written in ANSI C and licensed under public domain. It was designed as a simple -embeddable user interface for application and does not have any dependencies, -a default render backend or OS window and input handling but instead provides a very modular -library approach by using simple input state for input and draw -commands describing primitive shapes as output. So instead of providing a -layered library that tries to abstract over a number of platform and -render backends it only focuses on the actual UI. - -## Features - -- Immediate mode graphical user interface toolkit -- Single header library -- Written in C89 (ANSI C) -- Small codebase (~18kLOC) -- Focus on portability, efficiency and simplicity -- No dependencies (not even the standard library if not wanted) -- Fully skinnable and customizable -- Low memory footprint with total memory control if needed or wanted -- UTF-8 support -- No global or hidden state -- Customizable library modules (you can compile and use only what you need) -- Optional font baker and vertex buffer output -- [Documentation](https://rawgit.com/vurtun/nuklear/master/doc/nuklear.html) - -## Building - -This library is self contained in one single header file and can be used either -in header only mode or in implementation mode. The header only mode is used -by default when included and allows including this header in other headers -and does not contain the actual implementation. - -The implementation mode requires to define the preprocessor macro -`NK_IMPLEMENTATION` in *one* .c/.cpp file before `#include`ing this file, e.g.: -```c -#define NK_IMPLEMENTATION -#include "nuklear.h" -``` -IMPORTANT: Every time you include "nuklear.h" you have to define the same optional flags. -This is very important not doing it either leads to compiler errors or even worse stack corruptions. - -## Gallery - -![screenshot](https://cloud.githubusercontent.com/assets/8057201/11761525/ae06f0ca-a0c6-11e5-819d-5610b25f6ef4.gif) -![screen](https://cloud.githubusercontent.com/assets/8057201/13538240/acd96876-e249-11e5-9547-5ac0b19667a0.png) -![screen2](https://cloud.githubusercontent.com/assets/8057201/13538243/b04acd4c-e249-11e5-8fd2-ad7744a5b446.png) -![node](https://cloud.githubusercontent.com/assets/8057201/9976995/e81ac04a-5ef7-11e5-872b-acd54fbeee03.gif) -![skinning](https://cloud.githubusercontent.com/assets/8057201/15991632/76494854-30b8-11e6-9555-a69840d0d50b.png) -![gamepad](https://cloud.githubusercontent.com/assets/8057201/14902576/339926a8-0d9c-11e6-9fee-a8b73af04473.png) - -## Example - -```c -/* init gui state */ -struct nk_context ctx; -nk_init_fixed(&ctx, calloc(1, MAX_MEMORY), MAX_MEMORY, &font); - -enum {EASY, HARD}; -static int op = EASY; -static float value = 0.6f; -static int i = 20; - -if (nk_begin(&ctx, "Show", nk_rect(50, 50, 220, 220), - NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE)) { - /* fixed widget pixel width */ - nk_layout_row_static(&ctx, 30, 80, 1); - if (nk_button_label(&ctx, "button")) { - /* event handling */ - } - - /* fixed widget window ratio width */ - nk_layout_row_dynamic(&ctx, 30, 2); - if (nk_option_label(&ctx, "easy", op == EASY)) op = EASY; - if (nk_option_label(&ctx, "hard", op == HARD)) op = HARD; - - /* custom widget pixel width */ - nk_layout_row_begin(&ctx, NK_STATIC, 30, 2); - { - nk_layout_row_push(&ctx, 50); - nk_label(&ctx, "Volume:", NK_TEXT_LEFT); - nk_layout_row_push(&ctx, 110); - nk_slider_float(&ctx, 0, &value, 1.0f, 0.1f); - } - nk_layout_row_end(&ctx); -} -nk_end(&ctx); -``` -![example](https://cloud.githubusercontent.com/assets/8057201/10187981/584ecd68-675c-11e5-897c-822ef534a876.png) - -## Bindings -There are a number of nuklear bindings for different languges created by other authors. -I cannot atest for their quality since I am not necessarily proficient in either of these -languages. Furthermore there are no guarantee that all bindings will always be kept up to date: - -- [Java](https://github.com/glegris/nuklear4j) by Guillaume Legris -- [Golang](https://github.com/golang-ui/nuklear) by golang-ui@github.com -- [Rust](https://github.com/snuk182/nuklear-rust) by snuk182@github.com -- [Chicken](https://github.com/wasamasa/nuklear) by wasamasa@github.com -- [Nim](https://github.com/zacharycarter/nuklear-nim) by zacharycarter@github.com -- [Lua/Löve2d](https://github.com/keharriso/love-nuklear) by Kevin Harrison -- Python - - [pyNuklear](https://github.com/billsix/pyNuklear) by William Emerison Six (ctypes-based wrapper) - - [pynk](https://github.com/nathanrw/nuklear-cffi) by nathanrw@github.com (cffi binding) -- [CSharp/.NET](https://github.com/cartman300/NuklearDotNet) by cartman300@github.com - -## Credits -Developed by Micha Mettke and every direct or indirect contributor to the GitHub. - - -Embeds `stb_texedit`, `stb_truetype` and `stb_rectpack` by Sean Barrett (public domain) -Embeds `ProggyClean.ttf` font by Tristan Grimmer (MIT license). - - -Big thank you to Omar Cornut (ocornut@github) for his [imgui](https://github.com/ocornut/imgui) library and -giving me the inspiration for this library, Casey Muratori for handmade hero -and his original immediate mode graphical user interface idea and Sean -Barrett for his amazing single header [libraries](https://github.com/nothings/stb) which restored my faith -in libraries and brought me to create some of my own. - -## License -``` ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2017 Micha Mettke -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, -commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to -this software under copyright law. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------ -``` diff --git a/subprojects/nk_pugl/nuklear/demo/allegro5/KeyboardHandleriOS.h b/subprojects/nk_pugl/nuklear/demo/allegro5/KeyboardHandleriOS.h deleted file mode 100644 index 2664d2e..0000000 --- a/subprojects/nk_pugl/nuklear/demo/allegro5/KeyboardHandleriOS.h +++ /dev/null @@ -1,10 +0,0 @@ -#import - -#include - -@interface KeyboardHandleriOS : UIView --(void)setCustomKeyboardEventSource:(ALLEGRO_EVENT_SOURCE*)ev_src; --(void)show; --(void)hide; -@end - diff --git a/subprojects/nk_pugl/nuklear/demo/allegro5/KeyboardHandleriOS.m b/subprojects/nk_pugl/nuklear/demo/allegro5/KeyboardHandleriOS.m deleted file mode 100644 index 206f9e4..0000000 --- a/subprojects/nk_pugl/nuklear/demo/allegro5/KeyboardHandleriOS.m +++ /dev/null @@ -1,120 +0,0 @@ -#ifdef __OBJC__ -#import -#endif -#import "KeyboardHandleriOS.h" -#include -#include -@interface KeyboardHandleriOS() -{ - ALLEGRO_EVENT_SOURCE *event_source; - ALLEGRO_DISPLAY *current_display; -} -@end -@implementation KeyboardHandleriOS -- (id)init { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil]; - self = [self initWithFrame:CGRectMake(-100, -100, 0, 0)]; - event_source = NULL; - current_display = al_get_current_display(); - UIView* v = al_iphone_get_view(current_display); - [v addSubview:self]; - return self; -} - -- (void)setCustomKeyboardEventSource:(ALLEGRO_EVENT_SOURCE *)ev_src { - event_source = ev_src; -} - -- (UIKeyboardType) keyboardType -{ - return UIKeyboardTypeASCIICapable; -} - -- (UITextAutocorrectionType) autocorrectionType -{ - return UITextAutocorrectionTypeNo; -} - --(BOOL)canBecomeFirstResponder { - return YES; -} - -- (void)deleteBackward { - - if (!event_source) { - NSLog(@"deleteBackward(): No event source found, not sending events"); - return; - } - - ALLEGRO_EVENT *event_down = (ALLEGRO_EVENT*)calloc(1, sizeof(ALLEGRO_EVENT)); - ALLEGRO_EVENT *event_up = (ALLEGRO_EVENT*)calloc(1, sizeof(ALLEGRO_EVENT)); - - event_down->type = ALLEGRO_EVENT_KEY_DOWN; - event_down->keyboard.display = current_display; - event_down->keyboard.keycode = ALLEGRO_KEY_BACKSPACE; - event_up->type = ALLEGRO_EVENT_KEY_UP; - event_up->keyboard.display = current_display; - event_up->keyboard.keycode = ALLEGRO_KEY_BACKSPACE; - al_emit_user_event(event_source, event_down, NULL); - al_emit_user_event(event_source, event_up, NULL); - - free(event_down); - free(event_up); -} - -- (BOOL)hasText { - return YES; -} - -- (void)insertText:(NSString *)text -{ - if (!event_source) { - NSLog(@"insertText(): No event source found, not sending events"); - return; - } - - ALLEGRO_EVENT *event_down = (ALLEGRO_EVENT*)calloc(1, sizeof(ALLEGRO_EVENT)); - ALLEGRO_EVENT *event_up = (ALLEGRO_EVENT*)calloc(1, sizeof(ALLEGRO_EVENT)); - - if([text isEqualToString:@"\n"]) - { - event_down->type = ALLEGRO_EVENT_KEY_DOWN; - event_down->keyboard.display = current_display; - event_down->keyboard.keycode = ALLEGRO_KEY_ENTER; - event_up->type = ALLEGRO_EVENT_KEY_UP; - event_up->keyboard.display = current_display; - event_up->keyboard.keycode = ALLEGRO_KEY_ENTER; - al_emit_user_event(event_source, event_down, NULL); - al_emit_user_event(event_source, event_up, NULL); - [self hide]; - //m_kb->setDonePressed(); - } - else { - event_down->type = ALLEGRO_EVENT_KEY_CHAR; - event_down->keyboard.display = current_display; - event_down->keyboard.unichar = [text characterAtIndex:0]; - // doesn't matter what keycode is, nuklear backend ignores it as long as it - // isn't a special key - event_down->keyboard.keycode = ALLEGRO_KEY_A; - al_emit_user_event(event_source, event_down, NULL); - } - free(event_down); - free(event_up); -} - --(void)show { - NSLog(@"Should be showing!"); - [self performSelectorOnMainThread:@selector(becomeFirstResponder) withObject:nil waitUntilDone:YES]; -} --(void)hide { - NSLog(@"Should be hiding!"); - [self performSelectorOnMainThread:@selector(resignFirstResponder) withObject:nil waitUntilDone:YES]; -} -- (void)keyboardDidHide:(NSNotification *)notification { - NSLog(@"keyboardDidHide called"); -} - --(void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil]; -} -@end diff --git a/subprojects/nk_pugl/nuklear/demo/allegro5/Makefile b/subprojects/nk_pugl/nuklear/demo/allegro5/Makefile deleted file mode 100644 index 090a126..0000000 --- a/subprojects/nk_pugl/nuklear/demo/allegro5/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -# Install -BIN = demo - -# Flags -CFLAGS += -std=c99 -pedantic -O2 - -SRC = main.c -OBJ = $(SRC:.c=.o) - -# TODO: Handle Windows build -#ifeq ($(OS),Windows_NT) -#BIN := $(BIN).exe -#LIBS = -lglfw3 -lopengl32 -lm -lGLU32 -lGLEW32 -#else -LIBS = -lallegro -lallegro_main -lallegro_image -lallegro_font \ - -lallegro_ttf -lallegro_primitives -lm -#endif - -$(BIN): - @mkdir -p bin - rm -f bin/$(BIN) $(OBJS) - $(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS) diff --git a/subprojects/nk_pugl/nuklear/demo/allegro5/Readme.md b/subprojects/nk_pugl/nuklear/demo/allegro5/Readme.md deleted file mode 100644 index 71a4840..0000000 --- a/subprojects/nk_pugl/nuklear/demo/allegro5/Readme.md +++ /dev/null @@ -1,35 +0,0 @@ -# Allegro v5 nuklear backend - -This backend provides support for [Allegro version 5](http://liballeg.org/). It works on on all supported platforms with an OpenGL backend, including iOS and Android. - -Touch support is provided by handling the first touch (ignoring any extra simultaneous touches) and emitting nuklear mouse events. nuklear will handle only the first touch like a single left-mouse click. Dragging the touch screen emits mouse-move events. - -## Compiling -You must link with image, font, ttf, and primitives Allegro addons. See the `Makefile`. - -## Resolutions - -Like every nuklear backend, handling many different resolutions and resolution densities can be tricky. 14px font on a desktop may be perfect, but extremely small on a retina iPad. I recommend writing a middleware that will detect what kind of screen is being used, and modify the sizes of widgets accordingly. - -## Soft Keyboard for Touch Screen Devices - -Information on how to implement soft keyboard callbacks for Android can be on the Allegro community wiki: https://wiki.allegro.cc/index.php?title=Running_Allegro_applications_on_Android#Displaying_the_Android_keyboard - -To display a soft keyboard on iOS, you must create a `UIView` subclass that implements the `UIKeyInput` interface. See `KeyboardHandleriOS.h` and `KeyboardHandleriOS.m` Objective-C source code files for an example on how to do this. As the Allegro keyboard driver does not currently listen for iOS events, we use a custom event emitter to emit keyboard events, which is passed in after initialization with `(void)setCustomKeyboardEventSource:(ALLEGRO_EVENT_SOURCE *)ev_src`. This causes normal keyboard events to be emitted and properly caught by the nuklear backend. The provided `main.c` demo file does not implement this, but with the provided source code files it is not difficult to do. See this Allegro community forum thread for more information: https://www.allegro.cc/forums/thread/616672 - -To know when nuklear wants to open and close the keyboard, you can check edit widget flags: - -``` -nk_flags ed_flags = nk_edit_string(ctx, NK_EDIT_FIELD, field_buffer, &field_len, 64, nk_filter_default); -if (ed_flags & NK_EDIT_ACTIVATED) - open_ios_soft_keyboard(); -if (ed_flags & NK_EDIT_DEACTIVATED) - close_ios_soft_keyboard(); -``` - -### Manual Soft Keyboard Dismissal -As the user can dismiss a keyboard manually, nuklear will not be aware when this occurs, and the text edit cursor will think the entry field is still active. I recommend catching the dismiss event, then emitting `ALLEGRO_EVENT_TOUCH_BEGIN` and `ALLEGRO_EVENT_TOUCH_END` events in an unused portion of the screen (like the bottom-right corner). This will simulate the user touching outside of the text entry widget, which will make the edit field inactive. - -### The Keyboard Covers Widgets - -If you have a widget near the bottom of the screen, the keyboard opening woll cover it, and the user won't see what they are entering. One way to handle this is to make all text edit widgets view-only, and when tapped you dynamically create a new widget above the keyboard that receives all the key strokes. When the user dismisses the keyboard, copy the result from the new widget into the existing read-only text view and destroy the dynamic one. \ No newline at end of file diff --git a/subprojects/nk_pugl/nuklear/demo/allegro5/main.c b/subprojects/nk_pugl/nuklear/demo/allegro5/main.c deleted file mode 100644 index 624e7c9..0000000 --- a/subprojects/nk_pugl/nuklear/demo/allegro5/main.c +++ /dev/null @@ -1,165 +0,0 @@ -/* nuklear - 1.32.0 - public domain */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define WINDOW_WIDTH 1200 -#define WINDOW_HEIGHT 800 - -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_STANDARD_VARARGS -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_IMPLEMENTATION -#define NK_ALLEGRO5_IMPLEMENTATION -#include "../../nuklear.h" -#include "nuklear_allegro5.h" - - -#define UNUSED(a) (void)a -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#define MAX(a,b) ((a) < (b) ? (b) : (a)) -#define LEN(a) (sizeof(a)/sizeof(a)[0]) - -/* =============================================================== - * - * EXAMPLE - * - * ===============================================================*/ -/* This are some code examples to provide a small overview of what can be - * done with this library. To try out an example uncomment the include - * and the corresponding function. */ -/*#include "../style.c"*/ -/*#include "../calculator.c"*/ -#include "../overview.c" -/*#include "../node_editor.c"*/ - -/* =============================================================== - * - * DEMO - * - * ===============================================================*/ -static void error_callback(int e, const char *d) -{printf("Error %d: %s\n", e, d);} - -int main(void) -{ - /* Platform */ - ALLEGRO_DISPLAY *display = NULL; - ALLEGRO_EVENT_QUEUE *event_queue = NULL; - - if (!al_init()) { - fprintf(stdout, "failed to initialize allegro5!\n"); - exit(1); - } - - al_install_mouse(); - al_set_mouse_wheel_precision(150); - al_install_keyboard(); - - al_set_new_display_flags(ALLEGRO_WINDOWED|ALLEGRO_RESIZABLE|ALLEGRO_OPENGL); - al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 1, ALLEGRO_SUGGEST); - al_set_new_display_option(ALLEGRO_SAMPLES, 8, ALLEGRO_SUGGEST); - display = al_create_display(WINDOW_WIDTH, WINDOW_HEIGHT); - if (!display) { - fprintf(stdout, "failed to create display!\n"); - exit(1); - } - - event_queue = al_create_event_queue(); - if (!event_queue) { - fprintf(stdout, "failed to create event_queue!\n"); - al_destroy_display(display); - exit(1); - } - - al_register_event_source(event_queue, al_get_display_event_source(display)); - al_register_event_source(event_queue, al_get_mouse_event_source()); - al_register_event_source(event_queue, al_get_keyboard_event_source()); - - NkAllegro5Font *font; - font = nk_allegro5_font_create_from_file("../../../extra_font/Roboto-Regular.ttf", 12, 0); - struct nk_context *ctx; - - ctx = nk_allegro5_init(font, display, WINDOW_WIDTH, WINDOW_HEIGHT); - - /* style.c */ - /*set_style(ctx, THEME_WHITE);*/ - /*set_style(ctx, THEME_RED);*/ - /*set_style(ctx, THEME_BLUE);*/ - /*set_style(ctx, THEME_DARK);*/ - - while(1) - { - ALLEGRO_EVENT ev; - ALLEGRO_TIMEOUT timeout; - al_init_timeout(&timeout, 0.06); - - bool get_event = al_wait_for_event_until(event_queue, &ev, &timeout); - - if (get_event && ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { - break; - } - - /* Very Important: Always do nk_input_begin / nk_input_end even if - there are no events, otherwise internal nuklear state gets messed up */ - nk_input_begin(ctx); - if (get_event) { - while (get_event) { - nk_allegro5_handle_event(&ev); - get_event = al_get_next_event(event_queue, &ev); - } - } - nk_input_end(ctx); - - /* GUI */ - if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200), - NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE| - NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) - { - enum {EASY, HARD}; - static int op = EASY; - static int property = 20; - - nk_layout_row_static(ctx, 30, 80, 1); - if (nk_button_label(ctx, "button")) - fprintf(stdout, "button pressed\n"); - nk_layout_row_dynamic(ctx, 30, 2); - if (nk_option_label(ctx, "easy", op == EASY)) op = EASY; - if (nk_option_label(ctx, "hard", op == HARD)) op = HARD; - nk_layout_row_dynamic(ctx, 22, 1); - nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1); - } - nk_end(ctx); - - /* -------------- EXAMPLES ---------------- */ - /*calculator(ctx);*/ - overview(ctx); - /*node_editor(ctx);*/ - /* ----------------------------------------- */ - - /* Draw */ - al_clear_to_color(al_map_rgb(19, 43, 81)); - /* IMPORTANT: `nk_allegro5_render` changes the target backbuffer - to the display set at initialization and does not restore it. - Change it if you want to draw somewhere else. */ - nk_allegro5_render(); - al_flip_display(); - } - - nk_allegro5_font_del(font); - nk_allegro5_shutdown(); - al_destroy_display(display); - al_destroy_event_queue(event_queue); - return 0; -} - diff --git a/subprojects/nk_pugl/nuklear/demo/allegro5/nuklear_allegro5.h b/subprojects/nk_pugl/nuklear/demo/allegro5/nuklear_allegro5.h deleted file mode 100644 index f396600..0000000 --- a/subprojects/nk_pugl/nuklear/demo/allegro5/nuklear_allegro5.h +++ /dev/null @@ -1,459 +0,0 @@ -/* - * Nuklear - 1.32.0 - public domain - * no warrenty implied; use at your own risk. - * authored from 2015-2016 by Micha Mettke - */ -/* - * ============================================================== - * - * API - * - * =============================================================== - */ -#ifndef NK_ALLEGRO5_H_ -#define NK_ALLEGRO5_H_ - -#include -#include -#include -#include -#include -#include - -typedef struct NkAllegro5Font NkAllegro5Font; -NK_API struct nk_context* nk_allegro5_init(NkAllegro5Font *font, ALLEGRO_DISPLAY *dsp, - unsigned int width, unsigned int height); -NK_API void nk_allegro5_handle_event(ALLEGRO_EVENT *ev); -NK_API void nk_allegro5_shutdown(void); -NK_API void nk_allegro5_render(void); - -/* Fonts. We wrap normal allegro fonts in some nuklear book keeping */ -NK_API NkAllegro5Font* nk_allegro5_font_create_from_file(const char *file_name, int font_size, int flags); -NK_API void nk_allegro5_font_del(NkAllegro5Font *font); -NK_API void nk_allegro5_font_set_font(NkAllegro5Font *font); - -#endif -/* - * ============================================================== - * - * IMPLEMENTATION - * - * =============================================================== - */ -#ifdef NK_ALLEGRO5_IMPLEMENTATION - -#ifndef NK_ALLEGRO5_TEXT_MAX -#define NK_ALLEGRO5_TEXT_MAX 256 -#endif - - -struct NkAllegro5Font { - struct nk_user_font nk; - int height; - ALLEGRO_FONT *font; -}; - -static struct nk_allegro5 { - ALLEGRO_DISPLAY *dsp; - unsigned int width; - unsigned int height; - int is_touch_down; - int touch_down_id; - struct nk_context ctx; - struct nk_buffer cmds; -} allegro5; - - -/* Flags are identical to al_load_font() flags argument */ -NK_API NkAllegro5Font* -nk_allegro5_font_create_from_file(const char *file_name, int font_size, int flags) -{ - if (!al_init_image_addon()) { - fprintf(stdout, "Unable to initialize required allegro5 image addon\n"); - exit(1); - } - if (!al_init_font_addon()) { - fprintf(stdout, "Unable to initialize required allegro5 font addon\n"); - exit(1); - } - if (!al_init_ttf_addon()) { - fprintf(stdout, "Unable to initialize required allegro5 TTF font addon\n"); - exit(1); - } - NkAllegro5Font *font = (NkAllegro5Font*)calloc(1, sizeof(NkAllegro5Font)); - - font->font = al_load_font(file_name, font_size, flags); - if (font->font == NULL) { - fprintf(stdout, "Unable to load font file: %s\n", file_name); - return NULL; - } - font->height = al_get_font_line_height(font->font); - return font; -} - -static float -nk_allegro5_font_get_text_width(nk_handle handle, float height, const char *text, int len) -{ - NkAllegro5Font *font = (NkAllegro5Font*)handle.ptr; - if (!font || !text) { - return 0; - } - /* We must copy into a new buffer with exact length null-terminated - as nuklear uses variable size buffers and al_get_text_width doesn't - accept a length, it infers length from null-termination - (which is unsafe API design by allegro devs!) */ - char strcpy[len+1]; - strncpy((char*)&strcpy, text, len); - strcpy[len] = '\0'; - return al_get_text_width(font->font, strcpy); -} - -NK_API void -nk_allegro5_font_set_font(NkAllegro5Font *allegro5font) -{ - struct nk_user_font *font = &allegro5font->nk; - font->userdata = nk_handle_ptr(allegro5font); - font->height = (float)allegro5font->height; - font->width = nk_allegro5_font_get_text_width; - nk_style_set_font(&allegro5.ctx, font); -} - -NK_API void -nk_allegro5_font_del(NkAllegro5Font *font) -{ - if(!font) return; - al_destroy_font(font->font); - free(font); -} - -static ALLEGRO_COLOR -nk_color_to_allegro_color(struct nk_color color) -{ - return al_map_rgba((unsigned char)color.r, (unsigned char)color.g, - (unsigned char)color.b, (unsigned char)color.a); -} - -NK_API void -nk_allegro5_render() -{ - const struct nk_command *cmd; - - al_set_target_backbuffer(allegro5.dsp); - - nk_foreach(cmd, &allegro5.ctx) - { - ALLEGRO_COLOR color; - switch (cmd->type) { - case NK_COMMAND_NOP: break; - case NK_COMMAND_SCISSOR: { - const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd; - al_set_clipping_rectangle((int)s->x, (int)s->y, (int)s->w, (int)s->h); - } break; - case NK_COMMAND_LINE: { - const struct nk_command_line *l = (const struct nk_command_line *)cmd; - color = nk_color_to_allegro_color(l->color); - al_draw_line((float)l->begin.x, (float)l->begin.y, (float)l->end.x, - (float)l->end.y, color, (float)l->line_thickness); - } break; - case NK_COMMAND_RECT: { - const struct nk_command_rect *r = (const struct nk_command_rect *)cmd; - color = nk_color_to_allegro_color(r->color); - al_draw_rounded_rectangle((float)r->x, (float)r->y, (float)(r->x + r->w), - (float)(r->y + r->h), (float)r->rounding, (float)r->rounding, color, - (float)r->line_thickness); - } break; - case NK_COMMAND_RECT_FILLED: { - const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd; - color = nk_color_to_allegro_color(r->color); - al_draw_filled_rounded_rectangle((float)r->x, (float)r->y, - (float)(r->x + r->w), (float)(r->y + r->h), (float)r->rounding, - (float)r->rounding, color); - } break; - case NK_COMMAND_CIRCLE: { - const struct nk_command_circle *c = (const struct nk_command_circle *)cmd; - color = nk_color_to_allegro_color(c->color); - float xr, yr; - xr = (float)c->w/2; - yr = (float)c->h/2; - al_draw_ellipse(((float)(c->x)) + xr, ((float)c->y) + yr, - xr, yr, color, (float)c->line_thickness); - } break; - case NK_COMMAND_CIRCLE_FILLED: { - const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd; - color = nk_color_to_allegro_color(c->color); - float xr, yr; - xr = (float)c->w/2; - yr = (float)c->h/2; - al_draw_filled_ellipse(((float)(c->x)) + xr, ((float)c->y) + yr, - xr, yr, color); - } break; - case NK_COMMAND_TRIANGLE: { - const struct nk_command_triangle*t = (const struct nk_command_triangle*)cmd; - color = nk_color_to_allegro_color(t->color); - al_draw_triangle((float)t->a.x, (float)t->a.y, (float)t->b.x, (float)t->b.y, - (float)t->c.x, (float)t->c.y, color, (float)t->line_thickness); - } break; - case NK_COMMAND_TRIANGLE_FILLED: { - const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd; - color = nk_color_to_allegro_color(t->color); - al_draw_filled_triangle((float)t->a.x, (float)t->a.y, (float)t->b.x, - (float)t->b.y, (float)t->c.x, (float)t->c.y, color); - } break; - case NK_COMMAND_POLYGON: { - const struct nk_command_polygon *p = (const struct nk_command_polygon*)cmd; - color = nk_color_to_allegro_color(p->color); - int i; - float vertices[p->point_count * 2]; - for (i = 0; i < p->point_count; i++) { - vertices[i*2] = p->points[i].x; - vertices[(i*2) + 1] = p->points[i].y; - } - al_draw_polyline((const float*)&vertices, (2 * sizeof(float)), - (int)p->point_count, ALLEGRO_LINE_JOIN_ROUND, ALLEGRO_LINE_CAP_CLOSED, - color, (float)p->line_thickness, 0.0); - } break; - case NK_COMMAND_POLYGON_FILLED: { - const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd; - color = nk_color_to_allegro_color(p->color); - int i; - float vertices[p->point_count * 2]; - for (i = 0; i < p->point_count; i++) { - vertices[i*2] = p->points[i].x; - vertices[(i*2) + 1] = p->points[i].y; - } - al_draw_filled_polygon((const float*)&vertices, (int)p->point_count, color); - } break; - case NK_COMMAND_POLYLINE: { - const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd; - color = nk_color_to_allegro_color(p->color); - int i; - float vertices[p->point_count * 2]; - for (i = 0; i < p->point_count; i++) { - vertices[i*2] = p->points[i].x; - vertices[(i*2) + 1] = p->points[i].y; - } - al_draw_polyline((const float*)&vertices, (2 * sizeof(float)), - (int)p->point_count, ALLEGRO_LINE_JOIN_ROUND, ALLEGRO_LINE_CAP_ROUND, - color, (float)p->line_thickness, 0.0); - } break; - case NK_COMMAND_TEXT: { - const struct nk_command_text *t = (const struct nk_command_text*)cmd; - color = nk_color_to_allegro_color(t->foreground); - NkAllegro5Font *font = (NkAllegro5Font*)t->font->userdata.ptr; - al_draw_text(font->font, - color, (float)t->x, (float)t->y, 0, - (const char*)t->string); - } break; - case NK_COMMAND_CURVE: { - const struct nk_command_curve *q = (const struct nk_command_curve *)cmd; - color = nk_color_to_allegro_color(q->color); - float points[8]; - points[0] = (float)q->begin.x; - points[1] = (float)q->begin.y; - points[2] = (float)q->ctrl[0].x; - points[3] = (float)q->ctrl[0].y; - points[4] = (float)q->ctrl[1].x; - points[5] = (float)q->ctrl[1].y; - points[6] = (float)q->end.x; - points[7] = (float)q->end.y; - al_draw_spline(points, color, (float)q->line_thickness); - } break; - case NK_COMMAND_ARC: { - const struct nk_command_arc *a = (const struct nk_command_arc *)cmd; - color = nk_color_to_allegro_color(a->color); - al_draw_arc((float)a->cx, (float)a->cy, (float)a->r, a->a[0], - a->a[1], color, (float)a->line_thickness); - } break; - case NK_COMMAND_RECT_MULTI_COLOR: - case NK_COMMAND_IMAGE: - case NK_COMMAND_ARC_FILLED: - default: break; - } - } - nk_clear(&allegro5.ctx); -} - -NK_API void -nk_allegro5_handle_event(ALLEGRO_EVENT *ev) -{ - struct nk_context *ctx = &allegro5.ctx; - switch (ev->type) { - case ALLEGRO_EVENT_DISPLAY_RESIZE: { - allegro5.width = (unsigned int)ev->display.width; - allegro5.height = (unsigned int)ev->display.height; - al_acknowledge_resize(ev->display.source); - } break; - case ALLEGRO_EVENT_MOUSE_AXES: { - nk_input_motion(ctx, ev->mouse.x, ev->mouse.y); - if (ev->mouse.dz != 0) { - nk_input_scroll(ctx, nk_vec2(0,(float)ev->mouse.dz / al_get_mouse_wheel_precision())); - } - } break; - case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN: - case ALLEGRO_EVENT_MOUSE_BUTTON_UP: { - int button = NK_BUTTON_LEFT; - if (ev->mouse.button == 2) { - button = NK_BUTTON_RIGHT; - } - else if (ev->mouse.button == 3) { - button = NK_BUTTON_MIDDLE; - } - nk_input_button(ctx, button, ev->mouse.x, ev->mouse.y, ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN); - } break; - /* This essentially converts touch events to mouse events */ - case ALLEGRO_EVENT_TOUCH_BEGIN: - case ALLEGRO_EVENT_TOUCH_END: { - /* We only acknowledge one touch at a time. Otherwise, each touch - would be manipulating multiple nuklear elements, as if there - were multiple mouse cursors */ - if (allegro5.is_touch_down && allegro5.touch_down_id != ev->touch.id) { - return; - } - if (ev->type == ALLEGRO_EVENT_TOUCH_BEGIN) { - allegro5.is_touch_down = 1; - allegro5.touch_down_id = ev->touch.id; - /* FIXME: This is a hack to properly simulate - touches as a mouse with nuklear. If you instantly jump - from one place to another without an nk_input_end(), it - confuses the nuklear state. nuklear expects smooth mouse - movements, which is unlike a touch screen */ - nk_input_motion(ctx, (int)ev->touch.x, (int)ev->touch.y); - nk_input_end(ctx); - nk_input_begin(ctx); - } - else { - allegro5.is_touch_down = 0; - allegro5.touch_down_id = -1; - } - nk_input_button(ctx, NK_BUTTON_LEFT, (int)ev->touch.x, (int)ev->touch.y, ev->type == ALLEGRO_EVENT_TOUCH_BEGIN); - } break; - case ALLEGRO_EVENT_TOUCH_MOVE: { - /* Only acknowledge movements of a single touch, we are - simulating a mouse cursor */ - if (!allegro5.is_touch_down || allegro5.touch_down_id != ev->touch.id) { - return; - } - nk_input_motion(ctx, (int)ev->touch.x, (int)ev->touch.y); - } break; - case ALLEGRO_EVENT_KEY_DOWN: - case ALLEGRO_EVENT_KEY_UP: { - int kc = ev->keyboard.keycode; - int down = ev->type == ALLEGRO_EVENT_KEY_DOWN; - - if (kc == ALLEGRO_KEY_LSHIFT || kc == ALLEGRO_KEY_RSHIFT) nk_input_key(ctx, NK_KEY_SHIFT, down); - else if (kc == ALLEGRO_KEY_DELETE) nk_input_key(ctx, NK_KEY_DEL, down); - else if (kc == ALLEGRO_KEY_ENTER) nk_input_key(ctx, NK_KEY_ENTER, down); - else if (kc == ALLEGRO_KEY_TAB) nk_input_key(ctx, NK_KEY_TAB, down); - else if (kc == ALLEGRO_KEY_LEFT) nk_input_key(ctx, NK_KEY_LEFT, down); - else if (kc == ALLEGRO_KEY_RIGHT) nk_input_key(ctx, NK_KEY_RIGHT, down); - else if (kc == ALLEGRO_KEY_UP) nk_input_key(ctx, NK_KEY_UP, down); - else if (kc == ALLEGRO_KEY_DOWN) nk_input_key(ctx, NK_KEY_DOWN, down); - else if (kc == ALLEGRO_KEY_BACKSPACE) nk_input_key(ctx, NK_KEY_BACKSPACE, down); - else if (kc == ALLEGRO_KEY_ESCAPE) nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, down); - else if (kc == ALLEGRO_KEY_PGUP) nk_input_key(ctx, NK_KEY_SCROLL_UP, down); - else if (kc == ALLEGRO_KEY_PGDN) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down); - else if (kc == ALLEGRO_KEY_HOME) { - nk_input_key(ctx, NK_KEY_TEXT_START, down); - nk_input_key(ctx, NK_KEY_SCROLL_START, down); - } else if (kc == ALLEGRO_KEY_END) { - nk_input_key(ctx, NK_KEY_TEXT_END, down); - nk_input_key(ctx, NK_KEY_SCROLL_END, down); - } - } break; - case ALLEGRO_EVENT_KEY_CHAR: { - int kc = ev->keyboard.keycode; - int control_mask = (ev->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL) || - (ev->keyboard.modifiers & ALLEGRO_KEYMOD_COMMAND); - - if (kc == ALLEGRO_KEY_C && control_mask) { - nk_input_key(ctx, NK_KEY_COPY, 1); - } else if (kc == ALLEGRO_KEY_V && control_mask) { - nk_input_key(ctx, NK_KEY_PASTE, 1); - } else if (kc == ALLEGRO_KEY_X && control_mask) { - nk_input_key(ctx, NK_KEY_CUT, 1); - } else if (kc == ALLEGRO_KEY_Z && control_mask) { - nk_input_key(ctx, NK_KEY_TEXT_UNDO, 1); - } else if (kc == ALLEGRO_KEY_R && control_mask) { - nk_input_key(ctx, NK_KEY_TEXT_REDO, 1); - } else if (kc == ALLEGRO_KEY_A && control_mask) { - nk_input_key(ctx, NK_KEY_TEXT_SELECT_ALL, 1); - } else { - if (kc != ALLEGRO_KEY_BACKSPACE && - kc != ALLEGRO_KEY_LEFT && - kc != ALLEGRO_KEY_RIGHT && - kc != ALLEGRO_KEY_UP && - kc != ALLEGRO_KEY_DOWN && - kc != ALLEGRO_KEY_HOME && - kc != ALLEGRO_KEY_DELETE && - kc != ALLEGRO_KEY_ENTER && - kc != ALLEGRO_KEY_END && - kc != ALLEGRO_KEY_ESCAPE && - kc != ALLEGRO_KEY_PGDN && - kc != ALLEGRO_KEY_PGUP) { - nk_input_unicode(ctx, ev->keyboard.unichar); - } - } - } break; - default: break; - } -} - -NK_INTERN void -nk_allegro5_clipboard_paste(nk_handle usr, struct nk_text_edit *edit) -{ - char *text = al_get_clipboard_text(allegro5.dsp); - if (text) nk_textedit_paste(edit, text, nk_strlen(text)); - (void)usr; - al_free(text); -} - -NK_INTERN void -nk_allegro5_clipboard_copy(nk_handle usr, const char *text, int len) -{ - char *str = 0; - (void)usr; - if (!len) return; - str = (char*)malloc((size_t)len+1); - if (!str) return; - memcpy(str, text, (size_t)len); - str[len] = '\0'; - al_set_clipboard_text(allegro5.dsp, str); - free(str); -} - -NK_API struct nk_context* -nk_allegro5_init(NkAllegro5Font *allegro5font, ALLEGRO_DISPLAY *dsp, - unsigned int width, unsigned int height) -{ - if (!al_init_primitives_addon()) { - fprintf(stdout, "Unable to initialize required allegro5 primitives addon\n"); - exit(1); - } - - struct nk_user_font *font = &allegro5font->nk; - font->userdata = nk_handle_ptr(allegro5font); - font->height = (float)allegro5font->height; - font->width = nk_allegro5_font_get_text_width; - - allegro5.dsp = dsp; - allegro5.width = width; - allegro5.height = height; - allegro5.is_touch_down = 0; - allegro5.touch_down_id = -1; - - nk_init_default(&allegro5.ctx, font); - allegro5.ctx.clip.copy = nk_allegro5_clipboard_copy; - allegro5.ctx.clip.paste = nk_allegro5_clipboard_paste; - allegro5.ctx.clip.userdata = nk_handle_ptr(0); - return &allegro5.ctx; -} - -NK_API -void nk_allegro5_shutdown(void) -{ - nk_free(&allegro5.ctx); - memset(&allegro5, 0, sizeof(allegro5)); -} - -#endif /* NK_ALLEGRO5_IMPLEMENTATION */ - diff --git a/subprojects/nk_pugl/nuklear/demo/calculator.c b/subprojects/nk_pugl/nuklear/demo/calculator.c deleted file mode 100644 index b871301..0000000 --- a/subprojects/nk_pugl/nuklear/demo/calculator.c +++ /dev/null @@ -1,64 +0,0 @@ -/* nuklear - v1.00 - public domain */ -static void -calculator(struct nk_context *ctx) -{ - if (nk_begin(ctx, "Calculator", nk_rect(10, 10, 180, 250), - NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_MOVABLE)) - { - static int set = 0, prev = 0, op = 0; - static const char numbers[] = "789456123"; - static const char ops[] = "+-*/"; - static double a = 0, b = 0; - static double *current = &a; - - size_t i = 0; - int solve = 0; - {int len; char buffer[256]; - nk_layout_row_dynamic(ctx, 35, 1); - len = snprintf(buffer, 256, "%.2f", *current); - nk_edit_string(ctx, NK_EDIT_SIMPLE, buffer, &len, 255, nk_filter_float); - buffer[len] = 0; - *current = atof(buffer);} - - nk_layout_row_dynamic(ctx, 35, 4); - for (i = 0; i < 16; ++i) { - if (i >= 12 && i < 15) { - if (i > 12) continue; - if (nk_button_label(ctx, "C")) { - a = b = op = 0; current = &a; set = 0; - } if (nk_button_label(ctx, "0")) { - *current = *current*10.0f; set = 0; - } if (nk_button_label(ctx, "=")) { - solve = 1; prev = op; op = 0; - } - } else if (((i+1) % 4)) { - if (nk_button_text(ctx, &numbers[(i/4)*3+i%4], 1)) { - *current = *current * 10.0f + numbers[(i/4)*3+i%4] - '0'; - set = 0; - } - } else if (nk_button_text(ctx, &ops[i/4], 1)) { - if (!set) { - if (current != &b) { - current = &b; - } else { - prev = op; - solve = 1; - } - } - op = ops[i/4]; - set = 1; - } - } - if (solve) { - if (prev == '+') a = a + b; - if (prev == '-') a = a - b; - if (prev == '*') a = a * b; - if (prev == '/') a = a / b; - current = &a; - if (set) current = &b; - b = 0; set = 0; - } - } - nk_end(ctx); -} - diff --git a/subprojects/nk_pugl/nuklear/demo/d3d11/build.bat b/subprojects/nk_pugl/nuklear/demo/d3d11/build.bat deleted file mode 100644 index 31bd0e0..0000000 --- a/subprojects/nk_pugl/nuklear/demo/d3d11/build.bat +++ /dev/null @@ -1,9 +0,0 @@ -@echo off - -rem This will use VS2015 for compiler -call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86 - -fxc.exe /nologo /T vs_4_0_level_9_0 /E vs /O3 /Zpc /Ges /Fh nuklear_d3d11_vertex_shader.h /Vn nk_d3d11_vertex_shader /Qstrip_reflect /Qstrip_debug /Qstrip_priv nuklear_d3d11.hlsl -fxc.exe /nologo /T ps_4_0_level_9_0 /E ps /O3 /Zpc /Ges /Fh nuklear_d3d11_pixel_shader.h /Vn nk_d3d11_pixel_shader /Qstrip_reflect /Qstrip_debug /Qstrip_priv nuklear_d3d11.hlsl - -cl /D_CRT_SECURE_NO_DEPRECATE /nologo /W3 /O2 /fp:fast /Gm- /Fedemo.exe main.c user32.lib dxguid.lib d3d11.lib /link /incremental:no diff --git a/subprojects/nk_pugl/nuklear/demo/d3d11/main.c b/subprojects/nk_pugl/nuklear/demo/d3d11/main.c deleted file mode 100644 index a7abf1d..0000000 --- a/subprojects/nk_pugl/nuklear/demo/d3d11/main.c +++ /dev/null @@ -1,299 +0,0 @@ -/* nuklear - 1.32.0 - public domain */ -#define COBJMACROS -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include -#include - -#define WINDOW_WIDTH 800 -#define WINDOW_HEIGHT 600 - -#define MAX_VERTEX_BUFFER 512 * 1024 -#define MAX_INDEX_BUFFER 128 * 1024 - -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_STANDARD_VARARGS -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT -#define NK_INCLUDE_FONT_BAKING -#define NK_INCLUDE_DEFAULT_FONT -#define NK_IMPLEMENTATION -#define NK_D3D11_IMPLEMENTATION -#include "../../nuklear.h" -#include "nuklear_d3d11.h" - -/* =============================================================== - * - * EXAMPLE - * - * ===============================================================*/ -/* This are some code examples to provide a small overview of what can be - * done with this library. To try out an example uncomment the defines */ -/*#define INCLUDE_ALL */ -/*#define INCLUDE_STYLE */ -/*#define INCLUDE_CALCULATOR */ -/*#define INCLUDE_OVERVIEW */ -/*#define INCLUDE_NODE_EDITOR */ - -#ifdef INCLUDE_ALL - #define INCLUDE_STYLE - #define INCLUDE_CALCULATOR - #define INCLUDE_OVERVIEW - #define INCLUDE_NODE_EDITOR -#endif - -#ifdef INCLUDE_STYLE - #include "../style.c" -#endif -#ifdef INCLUDE_CALCULATOR - #include "../calculator.c" -#endif -#ifdef INCLUDE_OVERVIEW - #include "../overview.c" -#endif -#ifdef INCLUDE_NODE_EDITOR - #include "../node_editor.c" -#endif - -/* =============================================================== - * - * DEMO - * - * ===============================================================*/ -static IDXGISwapChain *swap_chain; -static ID3D11Device *device; -static ID3D11DeviceContext *context; -static ID3D11RenderTargetView* rt_view; - -static void -set_swap_chain_size(int width, int height) -{ - ID3D11Texture2D *back_buffer; - D3D11_RENDER_TARGET_VIEW_DESC desc; - HRESULT hr; - - if (rt_view) - ID3D11RenderTargetView_Release(rt_view); - - ID3D11DeviceContext_OMSetRenderTargets(context, 0, NULL, NULL); - - hr = IDXGISwapChain_ResizeBuffers(swap_chain, 0, width, height, DXGI_FORMAT_UNKNOWN, 0); - if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET || hr == DXGI_ERROR_DRIVER_INTERNAL_ERROR) - { - /* to recover from this, you'll need to recreate device and all the resources */ - MessageBoxW(NULL, L"DXGI device is removed or reset!", L"Error", 0); - exit(0); - } - assert(SUCCEEDED(hr)); - - memset(&desc, 0, sizeof(desc)); - desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - - hr = IDXGISwapChain_GetBuffer(swap_chain, 0, &IID_ID3D11Texture2D, (void **)&back_buffer); - assert(SUCCEEDED(hr)); - - hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)back_buffer, &desc, &rt_view); - assert(SUCCEEDED(hr)); - - ID3D11Texture2D_Release(back_buffer); -} - -static LRESULT CALLBACK -WindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) -{ - switch (msg) - { - case WM_DESTROY: - PostQuitMessage(0); - return 0; - - case WM_SIZE: - if (swap_chain) - { - int width = LOWORD(lparam); - int height = HIWORD(lparam); - set_swap_chain_size(width, height); - nk_d3d11_resize(context, width, height); - } - break; - } - - if (nk_d3d11_handle_event(wnd, msg, wparam, lparam)) - return 0; - - return DefWindowProcW(wnd, msg, wparam, lparam); -} - -int main(void) -{ - struct nk_context *ctx; - struct nk_colorf bg; - - WNDCLASSW wc; - RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT }; - DWORD style = WS_OVERLAPPEDWINDOW; - DWORD exstyle = WS_EX_APPWINDOW; - HWND wnd; - int running = 1; - HRESULT hr; - D3D_FEATURE_LEVEL feature_level; - DXGI_SWAP_CHAIN_DESC swap_chain_desc; - - /* Win32 */ - memset(&wc, 0, sizeof(wc)); - wc.style = CS_DBLCLKS; - wc.lpfnWndProc = WindowProc; - wc.hInstance = GetModuleHandleW(0); - wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.lpszClassName = L"NuklearWindowClass"; - RegisterClassW(&wc); - - AdjustWindowRectEx(&rect, style, FALSE, exstyle); - - wnd = CreateWindowExW(exstyle, wc.lpszClassName, L"Nuklear Demo", - style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, - rect.right - rect.left, rect.bottom - rect.top, - NULL, NULL, wc.hInstance, NULL); - - /* D3D11 setup */ - memset(&swap_chain_desc, 0, sizeof(swap_chain_desc)); - swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - swap_chain_desc.BufferDesc.RefreshRate.Numerator = 60; - swap_chain_desc.BufferDesc.RefreshRate.Denominator = 1; - swap_chain_desc.SampleDesc.Count = 1; - swap_chain_desc.SampleDesc.Quality = 0; - swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swap_chain_desc.BufferCount = 1; - swap_chain_desc.OutputWindow = wnd; - swap_chain_desc.Windowed = TRUE; - swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - swap_chain_desc.Flags = 0; - if (FAILED(D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, - NULL, 0, NULL, 0, D3D11_SDK_VERSION, &swap_chain_desc, - &swap_chain, &device, &feature_level, &context))) - { - /* if hardware device fails, then try WARP high-performance - software rasterizer, this is useful for RDP sessions */ - hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_WARP, - NULL, 0, NULL, 0, D3D11_SDK_VERSION, &swap_chain_desc, - &swap_chain, &device, &feature_level, &context); - assert(SUCCEEDED(hr)); - } - set_swap_chain_size(WINDOW_WIDTH, WINDOW_HEIGHT); - - /* GUI */ - ctx = nk_d3d11_init(device, WINDOW_WIDTH, WINDOW_HEIGHT, MAX_VERTEX_BUFFER, MAX_INDEX_BUFFER); - /* Load Fonts: if none of these are loaded a default font will be used */ - /* Load Cursor: if you uncomment cursor loading please hide the cursor */ - {struct nk_font_atlas *atlas; - nk_d3d11_font_stash_begin(&atlas); - /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../extra_font/DroidSans.ttf", 14, 0);*/ - /*struct nk_font *robot = nk_font_atlas_add_from_file(atlas, "../../extra_font/Roboto-Regular.ttf", 14, 0);*/ - /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../extra_font/kenvector_future_thin.ttf", 13, 0);*/ - /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../extra_font/ProggyClean.ttf", 12, 0);*/ - /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../extra_font/ProggyTiny.ttf", 10, 0);*/ - /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../extra_font/Cousine-Regular.ttf", 13, 0);*/ - nk_d3d11_font_stash_end(); - /*nk_style_load_all_cursors(ctx, atlas->cursors);*/ - /*nk_style_set_font(ctx, &droid->handle)*/;} - - /* style.c */ - #ifdef INCLUDE_STYLE - /*set_style(ctx, THEME_WHITE);*/ - /*set_style(ctx, THEME_RED);*/ - /*set_style(ctx, THEME_BLUE);*/ - /*set_style(ctx, THEME_DARK);*/ - #endif - - bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f; - while (running) - { - /* Input */ - MSG msg; - nk_input_begin(ctx); - while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) - { - if (msg.message == WM_QUIT) - running = 0; - TranslateMessage(&msg); - DispatchMessageW(&msg); - } - nk_input_end(ctx); - - /* GUI */ - if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250), - NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE| - NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) - { - enum {EASY, HARD}; - static int op = EASY; - static int property = 20; - - nk_layout_row_static(ctx, 30, 80, 1); - if (nk_button_label(ctx, "button")) - fprintf(stdout, "button pressed\n"); - nk_layout_row_dynamic(ctx, 30, 2); - if (nk_option_label(ctx, "easy", op == EASY)) op = EASY; - if (nk_option_label(ctx, "hard", op == HARD)) op = HARD; - nk_layout_row_dynamic(ctx, 22, 1); - nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1); - - nk_layout_row_dynamic(ctx, 20, 1); - nk_label(ctx, "background:", NK_TEXT_LEFT); - nk_layout_row_dynamic(ctx, 25, 1); - if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) { - nk_layout_row_dynamic(ctx, 120, 1); - bg = nk_color_picker(ctx, bg, NK_RGBA); - nk_layout_row_dynamic(ctx, 25, 1); - bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f); - bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f); - bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f); - bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f); - nk_combo_end(ctx); - } - } - nk_end(ctx); - - /* -------------- EXAMPLES ---------------- */ - #ifdef INCLUDE_CALCULATOR - calculator(ctx); - #endif - #ifdef INCLUDE_OVERVIEW - overview(ctx); - #endif - #ifdef INCLUDE_NODE_EDITOR - node_editor(ctx); - #endif - /* ----------------------------------------- */ - - /* Draw */ - ID3D11DeviceContext_ClearRenderTargetView(context, rt_view, &bg.r); - ID3D11DeviceContext_OMSetRenderTargets(context, 1, &rt_view, NULL); - nk_d3d11_render(context, NK_ANTI_ALIASING_ON); - hr = IDXGISwapChain_Present(swap_chain, 1, 0); - if (hr == DXGI_ERROR_DEVICE_RESET || hr == DXGI_ERROR_DEVICE_REMOVED) { - /* to recover from this, you'll need to recreate device and all the resources */ - MessageBoxW(NULL, L"D3D11 device is lost or removed!", L"Error", 0); - break; - } else if (hr == DXGI_STATUS_OCCLUDED) { - /* window is not visible, so vsync won't work. Let's sleep a bit to reduce CPU usage */ - Sleep(10); - } - assert(SUCCEEDED(hr)); - } - - ID3D11DeviceContext_ClearState(context); - nk_d3d11_shutdown(); - ID3D11ShaderResourceView_Release(rt_view); - ID3D11DeviceContext_Release(context); - ID3D11Device_Release(device); - IDXGISwapChain_Release(swap_chain); - UnregisterClassW(wc.lpszClassName, wc.hInstance); - return 0; -} diff --git a/subprojects/nk_pugl/nuklear/demo/d3d11/nuklear_d3d11.h b/subprojects/nk_pugl/nuklear/demo/d3d11/nuklear_d3d11.h deleted file mode 100644 index 7097d98..0000000 --- a/subprojects/nk_pugl/nuklear/demo/d3d11/nuklear_d3d11.h +++ /dev/null @@ -1,622 +0,0 @@ -/* - * Nuklear - 1.32.0 - public domain - * no warrenty implied; use at your own risk. - * authored from 2015-2016 by Micha Mettke - */ -/* - * ============================================================== - * - * API - * - * =============================================================== - */ -#ifndef NK_D3D11_H_ -#define NK_D3D11_H_ - -#define WIN32_LEAN_AND_MEAN -#include - -typedef struct ID3D11Device ID3D11Device; -typedef struct ID3D11DeviceContext ID3D11DeviceContext; - -NK_API struct nk_context *nk_d3d11_init(ID3D11Device *device, int width, int height, unsigned int max_vertex_buffer, unsigned int max_index_buffer); -NK_API void nk_d3d11_font_stash_begin(struct nk_font_atlas **atlas); -NK_API void nk_d3d11_font_stash_end(void); -NK_API int nk_d3d11_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); -NK_API void nk_d3d11_render(ID3D11DeviceContext *context, enum nk_anti_aliasing); -NK_API void nk_d3d11_resize(ID3D11DeviceContext *context, int width, int height); -NK_API void nk_d3d11_shutdown(void); - -#endif -/* - * ============================================================== - * - * IMPLEMENTATION - * - * =============================================================== - */ -#ifdef NK_D3D11_IMPLEMENTATION - -#define WIN32_LEAN_AND_MEAN -#define COBJMACROS -#include - -#include -#include -#include -#include - -#include "nuklear_d3d11_vertex_shader.h" -#include "nuklear_d3d11_pixel_shader.h" - -struct nk_d3d11_vertex { - float position[2]; - float uv[2]; - nk_byte col[4]; -}; - -static struct -{ - struct nk_context ctx; - struct nk_font_atlas atlas; - struct nk_buffer cmds; - - struct nk_draw_null_texture null; - unsigned int max_vertex_buffer; - unsigned int max_index_buffer; - - D3D11_VIEWPORT viewport; - ID3D11Device *device; - ID3D11RasterizerState *rasterizer_state; - ID3D11VertexShader *vertex_shader; - ID3D11InputLayout *input_layout; - ID3D11Buffer *const_buffer; - ID3D11PixelShader *pixel_shader; - ID3D11BlendState *blend_state; - ID3D11Buffer *index_buffer; - ID3D11Buffer *vertex_buffer; - ID3D11ShaderResourceView *font_texture_view; - ID3D11SamplerState *sampler_state; -} d3d11; - -NK_API void -nk_d3d11_render(ID3D11DeviceContext *context, enum nk_anti_aliasing AA) -{ - const float blend_factor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; - const UINT stride = sizeof(struct nk_d3d11_vertex); - const UINT offset = 0; - - ID3D11DeviceContext_IASetInputLayout(context, d3d11.input_layout); - ID3D11DeviceContext_IASetVertexBuffers(context, 0, 1, &d3d11.vertex_buffer, &stride, &offset); - ID3D11DeviceContext_IASetIndexBuffer(context, d3d11.index_buffer, DXGI_FORMAT_R16_UINT, 0); - ID3D11DeviceContext_IASetPrimitiveTopology(context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - - ID3D11DeviceContext_VSSetShader(context, d3d11.vertex_shader, NULL, 0); - ID3D11DeviceContext_VSSetConstantBuffers(context, 0, 1, &d3d11.const_buffer); - - ID3D11DeviceContext_PSSetShader(context, d3d11.pixel_shader, NULL, 0); - ID3D11DeviceContext_PSSetSamplers(context, 0, 1, &d3d11.sampler_state); - - ID3D11DeviceContext_OMSetBlendState(context, d3d11.blend_state, blend_factor, 0xffffffff); - ID3D11DeviceContext_RSSetState(context, d3d11.rasterizer_state); - ID3D11DeviceContext_RSSetViewports(context, 1, &d3d11.viewport); - - /* Convert from command queue into draw list and draw to screen */ - {/* load draw vertices & elements directly into vertex + element buffer */ - D3D11_MAPPED_SUBRESOURCE vertices; - D3D11_MAPPED_SUBRESOURCE indices; - const struct nk_draw_command *cmd; - UINT offset = 0; - HRESULT hr; - - hr = ID3D11DeviceContext_Map(context, (ID3D11Resource *)d3d11.vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &vertices); - NK_ASSERT(SUCCEEDED(hr)); - hr = ID3D11DeviceContext_Map(context, (ID3D11Resource *)d3d11.index_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &indices); - NK_ASSERT(SUCCEEDED(hr)); - - {/* fill converting configuration */ - struct nk_convert_config config; - NK_STORAGE const struct nk_draw_vertex_layout_element vertex_layout[] = { - {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_d3d11_vertex, position)}, - {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_d3d11_vertex, uv)}, - {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_d3d11_vertex, col)}, - {NK_VERTEX_LAYOUT_END} - }; - memset(&config, 0, sizeof(config)); - config.vertex_layout = vertex_layout; - config.vertex_size = sizeof(struct nk_d3d11_vertex); - config.vertex_alignment = NK_ALIGNOF(struct nk_d3d11_vertex); - config.global_alpha = 1.0f; - config.shape_AA = AA; - config.line_AA = AA; - config.circle_segment_count = 22; - config.curve_segment_count = 22; - config.arc_segment_count = 22; - config.null = d3d11.null; - - {/* setup buffers to load vertices and elements */ - struct nk_buffer vbuf, ibuf; - nk_buffer_init_fixed(&vbuf, vertices.pData, (size_t)d3d11.max_vertex_buffer); - nk_buffer_init_fixed(&ibuf, indices.pData, (size_t)d3d11.max_index_buffer); - nk_convert(&d3d11.ctx, &d3d11.cmds, &vbuf, &ibuf, &config);} - } - - ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)d3d11.vertex_buffer, 0); - ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)d3d11.index_buffer, 0); - - /* iterate over and execute each draw command */ - nk_draw_foreach(cmd, &d3d11.ctx, &d3d11.cmds) - { - D3D11_RECT scissor; - ID3D11ShaderResourceView *texture_view = (ID3D11ShaderResourceView *)cmd->texture.ptr; - if (!cmd->elem_count) continue; - - scissor.left = (LONG)cmd->clip_rect.x; - scissor.right = (LONG)(cmd->clip_rect.x + cmd->clip_rect.w); - scissor.top = (LONG)cmd->clip_rect.y; - scissor.bottom = (LONG)(cmd->clip_rect.y + cmd->clip_rect.h); - - ID3D11DeviceContext_PSSetShaderResources(context, 0, 1, &texture_view); - ID3D11DeviceContext_RSSetScissorRects(context, 1, &scissor); - ID3D11DeviceContext_DrawIndexed(context, (UINT)cmd->elem_count, offset, 0); - offset += cmd->elem_count; - } - nk_clear(&d3d11.ctx);} -} - -static void -nk_d3d11_get_projection_matrix(int width, int height, float *result) -{ - const float L = 0.0f; - const float R = (float)width; - const float T = 0.0f; - const float B = (float)height; - float matrix[4][4] = - { - { 2.0f / (R - L), 0.0f, 0.0f, 0.0f }, - { 0.0f, 2.0f / (T - B), 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.5f, 0.0f }, - { (R + L) / (L - R), (T + B) / (B - T), 0.5f, 1.0f }, - }; - memcpy(result, matrix, sizeof(matrix)); -} - -NK_API void -nk_d3d11_resize(ID3D11DeviceContext *context, int width, int height) -{ - D3D11_MAPPED_SUBRESOURCE mapped; - if (SUCCEEDED(ID3D11DeviceContext_Map(context, (ID3D11Resource *)d3d11.const_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped))) - { - nk_d3d11_get_projection_matrix(width, height, (float *)mapped.pData); - ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)d3d11.const_buffer, 0); - - d3d11.viewport.Width = (float)width; - d3d11.viewport.Height = (float)height; - } -} - -NK_API int -nk_d3d11_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) -{ - switch (msg) - { - case WM_KEYDOWN: - case WM_KEYUP: - case WM_SYSKEYDOWN: - case WM_SYSKEYUP: - { - int down = !((lparam >> 31) & 1); - int ctrl = GetKeyState(VK_CONTROL) & (1 << 15); - - switch (wparam) - { - case VK_SHIFT: - case VK_LSHIFT: - case VK_RSHIFT: - nk_input_key(&d3d11.ctx, NK_KEY_SHIFT, down); - return 1; - - case VK_DELETE: - nk_input_key(&d3d11.ctx, NK_KEY_DEL, down); - return 1; - - case VK_RETURN: - nk_input_key(&d3d11.ctx, NK_KEY_ENTER, down); - return 1; - - case VK_TAB: - nk_input_key(&d3d11.ctx, NK_KEY_TAB, down); - return 1; - - case VK_LEFT: - if (ctrl) - nk_input_key(&d3d11.ctx, NK_KEY_TEXT_WORD_LEFT, down); - else - nk_input_key(&d3d11.ctx, NK_KEY_LEFT, down); - return 1; - - case VK_RIGHT: - if (ctrl) - nk_input_key(&d3d11.ctx, NK_KEY_TEXT_WORD_RIGHT, down); - else - nk_input_key(&d3d11.ctx, NK_KEY_RIGHT, down); - return 1; - - case VK_BACK: - nk_input_key(&d3d11.ctx, NK_KEY_BACKSPACE, down); - return 1; - - case VK_HOME: - nk_input_key(&d3d11.ctx, NK_KEY_TEXT_START, down); - nk_input_key(&d3d11.ctx, NK_KEY_SCROLL_START, down); - return 1; - - case VK_END: - nk_input_key(&d3d11.ctx, NK_KEY_TEXT_END, down); - nk_input_key(&d3d11.ctx, NK_KEY_SCROLL_END, down); - return 1; - - case VK_NEXT: - nk_input_key(&d3d11.ctx, NK_KEY_SCROLL_DOWN, down); - return 1; - - case VK_PRIOR: - nk_input_key(&d3d11.ctx, NK_KEY_SCROLL_UP, down); - return 1; - - case 'C': - if (ctrl) { - nk_input_key(&d3d11.ctx, NK_KEY_COPY, down); - return 1; - } - break; - - case 'V': - if (ctrl) { - nk_input_key(&d3d11.ctx, NK_KEY_PASTE, down); - return 1; - } - break; - - case 'X': - if (ctrl) { - nk_input_key(&d3d11.ctx, NK_KEY_CUT, down); - return 1; - } - break; - - case 'Z': - if (ctrl) { - nk_input_key(&d3d11.ctx, NK_KEY_TEXT_UNDO, down); - return 1; - } - break; - - case 'R': - if (ctrl) { - nk_input_key(&d3d11.ctx, NK_KEY_TEXT_REDO, down); - return 1; - } - break; - } - return 0; - } - - case WM_CHAR: - if (wparam >= 32) - { - nk_input_unicode(&d3d11.ctx, (nk_rune)wparam); - return 1; - } - break; - - case WM_LBUTTONDOWN: - nk_input_button(&d3d11.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1); - SetCapture(wnd); - return 1; - - case WM_LBUTTONUP: - nk_input_button(&d3d11.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0); - nk_input_button(&d3d11.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0); - ReleaseCapture(); - return 1; - - case WM_RBUTTONDOWN: - nk_input_button(&d3d11.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1); - SetCapture(wnd); - return 1; - - case WM_RBUTTONUP: - nk_input_button(&d3d11.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0); - ReleaseCapture(); - return 1; - - case WM_MBUTTONDOWN: - nk_input_button(&d3d11.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1); - SetCapture(wnd); - return 1; - - case WM_MBUTTONUP: - nk_input_button(&d3d11.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0); - ReleaseCapture(); - return 1; - - case WM_MOUSEWHEEL: - nk_input_scroll(&d3d11.ctx, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA)); - return 1; - - case WM_MOUSEMOVE: - nk_input_motion(&d3d11.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam)); - return 1; - - case WM_LBUTTONDBLCLK: - nk_input_button(&d3d11.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1); - return 1; - } - - return 0; -} - -static void -nk_d3d11_clipbard_paste(nk_handle usr, struct nk_text_edit *edit) -{ - (void)usr; - if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL)) - { - HGLOBAL mem = GetClipboardData(CF_UNICODETEXT); - if (mem) - { - SIZE_T size = GlobalSize(mem) - 1; - if (size) - { - LPCWSTR wstr = (LPCWSTR)GlobalLock(mem); - if (wstr) - { - int utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, size / sizeof(wchar_t), NULL, 0, NULL, NULL); - if (utf8size) - { - char* utf8 = (char*)malloc(utf8size); - if (utf8) - { - WideCharToMultiByte(CP_UTF8, 0, wstr, size / sizeof(wchar_t), utf8, utf8size, NULL, NULL); - nk_textedit_paste(edit, utf8, utf8size); - free(utf8); - } - } - GlobalUnlock(mem); - } - } - } - CloseClipboard(); - } -} - -static void -nk_d3d11_clipbard_copy(nk_handle usr, const char *text, int len) -{ - (void)usr; - if (OpenClipboard(NULL)) - { - int wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0); - if (wsize) - { - HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t)); - if (mem) - { - wchar_t* wstr = (wchar_t*)GlobalLock(mem); - if (wstr) - { - MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize); - wstr[wsize] = 0; - GlobalUnlock(mem); - SetClipboardData(CF_UNICODETEXT, mem); - } - } - } - CloseClipboard(); - } -} - -NK_API struct nk_context* -nk_d3d11_init(ID3D11Device *device, int width, int height, unsigned int max_vertex_buffer, unsigned int max_index_buffer) -{ - HRESULT hr; - d3d11.max_vertex_buffer = max_vertex_buffer; - d3d11.max_index_buffer = max_index_buffer; - d3d11.device = device; - ID3D11Device_AddRef(device); - - nk_init_default(&d3d11.ctx, 0); - d3d11.ctx.clip.copy = nk_d3d11_clipbard_copy; - d3d11.ctx.clip.paste = nk_d3d11_clipbard_paste; - d3d11.ctx.clip.userdata = nk_handle_ptr(0); - - nk_buffer_init_default(&d3d11.cmds); - - {/* rasterizer state */ - D3D11_RASTERIZER_DESC desc; - memset(&desc, 0, sizeof(desc)); - desc.FillMode = D3D11_FILL_SOLID; - desc.CullMode = D3D11_CULL_NONE; - desc.FrontCounterClockwise = FALSE; - desc.DepthBias = 0; - desc.DepthBiasClamp = 0; - desc.SlopeScaledDepthBias = 0.0f; - desc.DepthClipEnable = TRUE; - desc.ScissorEnable = TRUE; - desc.MultisampleEnable = FALSE; - desc.AntialiasedLineEnable = FALSE; - hr = ID3D11Device_CreateRasterizerState(device,&desc, &d3d11.rasterizer_state); - NK_ASSERT(SUCCEEDED(hr));} - - /* vertex shader */ - {hr = ID3D11Device_CreateVertexShader(device,nk_d3d11_vertex_shader, sizeof(nk_d3d11_vertex_shader), NULL, &d3d11.vertex_shader); - NK_ASSERT(SUCCEEDED(hr));} - - /* input layout */ - {const D3D11_INPUT_ELEMENT_DESC layout[] = { - { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(struct nk_d3d11_vertex, position), D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(struct nk_d3d11_vertex, uv), D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(struct nk_d3d11_vertex, col), D3D11_INPUT_PER_VERTEX_DATA, 0 }, - }; - hr = ID3D11Device_CreateInputLayout(device,layout, ARRAYSIZE(layout), nk_d3d11_vertex_shader, sizeof(nk_d3d11_vertex_shader), &d3d11.input_layout); - NK_ASSERT(SUCCEEDED(hr));} - - /* constant buffer */ - {float matrix[4*4]; - D3D11_BUFFER_DESC desc; - memset(&desc, 0, sizeof(desc)); - desc.ByteWidth = sizeof(matrix); - desc.Usage = D3D11_USAGE_DYNAMIC; - desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - desc.MiscFlags = 0; - - {D3D11_SUBRESOURCE_DATA data; - data.pSysMem = matrix; - data.SysMemPitch = 0; - data.SysMemSlicePitch = 0; - - nk_d3d11_get_projection_matrix(width, height, matrix); - hr = ID3D11Device_CreateBuffer(device, &desc, &data, &d3d11.const_buffer); - NK_ASSERT(SUCCEEDED(hr));}} - - /* pixel shader */ - {hr = ID3D11Device_CreatePixelShader(device, nk_d3d11_pixel_shader, sizeof(nk_d3d11_pixel_shader), NULL, &d3d11.pixel_shader); - NK_ASSERT(SUCCEEDED(hr));} - - {/* blend state */ - D3D11_BLEND_DESC desc; - memset(&desc, 0, sizeof(desc)); - desc.AlphaToCoverageEnable = FALSE; - desc.RenderTarget[0].BlendEnable = TRUE; - desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; - desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; - desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; - desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; - desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; - desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; - desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - hr = ID3D11Device_CreateBlendState(device, &desc, &d3d11.blend_state); - NK_ASSERT(SUCCEEDED(hr));} - - /* vertex buffer */ - {D3D11_BUFFER_DESC desc; - memset(&desc, 0, sizeof(desc)); - desc.Usage = D3D11_USAGE_DYNAMIC; - desc.ByteWidth = max_vertex_buffer; - desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - desc.MiscFlags = 0; - hr = ID3D11Device_CreateBuffer(device, &desc, NULL, &d3d11.vertex_buffer); - NK_ASSERT(SUCCEEDED(hr));} - - /* index buffer */ - {D3D11_BUFFER_DESC desc; - memset(&desc, 0, sizeof(desc)); - desc.Usage = D3D11_USAGE_DYNAMIC; - desc.ByteWidth = max_index_buffer; - desc.BindFlags = D3D11_BIND_INDEX_BUFFER; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - hr = ID3D11Device_CreateBuffer(device, &desc, NULL, &d3d11.index_buffer); - NK_ASSERT(SUCCEEDED(hr));} - - /* sampler state */ - {D3D11_SAMPLER_DESC desc; - memset(&desc, 0, sizeof(desc)); - desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; - desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; - desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - desc.MipLODBias = 0.0f; - desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; - desc.MinLOD = 0.0f; - desc.MaxLOD = FLT_MAX; - hr = ID3D11Device_CreateSamplerState(device, &desc, &d3d11.sampler_state); - NK_ASSERT(SUCCEEDED(hr));} - - /* viewport */ - {d3d11.viewport.TopLeftX = 0.0f; - d3d11.viewport.TopLeftY = 0.0f; - d3d11.viewport.Width = (float)width; - d3d11.viewport.Height = (float)height; - d3d11.viewport.MinDepth = 0.0f; - d3d11.viewport.MaxDepth = 1.0f;} - return &d3d11.ctx; -} - -NK_API void -nk_d3d11_font_stash_begin(struct nk_font_atlas **atlas) -{ - nk_font_atlas_init_default(&d3d11.atlas); - nk_font_atlas_begin(&d3d11.atlas); - *atlas = &d3d11.atlas; -} - -NK_API void -nk_d3d11_font_stash_end(void) -{ - const void *image; int w, h; - image = nk_font_atlas_bake(&d3d11.atlas, &w, &h, NK_FONT_ATLAS_RGBA32); - - /* upload font to texture and create texture view */ - {ID3D11Texture2D *font_texture; - HRESULT hr; - - D3D11_TEXTURE2D_DESC desc; - memset(&desc, 0, sizeof(desc)); - desc.Width = (UINT)w; - desc.Height = (UINT)h; - desc.MipLevels = 1; - desc.ArraySize = 1; - desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - desc.CPUAccessFlags = 0; - - {D3D11_SUBRESOURCE_DATA data; - data.pSysMem = image; - data.SysMemPitch = (UINT)(w * 4); - data.SysMemSlicePitch = 0; - hr = ID3D11Device_CreateTexture2D(d3d11.device, &desc, &data, &font_texture); - assert(SUCCEEDED(hr));} - - {D3D11_SHADER_RESOURCE_VIEW_DESC srv; - memset(&srv, 0, sizeof(srv)); - srv.Format = desc.Format; - srv.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - srv.Texture2D.MipLevels = 1; - srv.Texture2D.MostDetailedMip = 0; - hr = ID3D11Device_CreateShaderResourceView(d3d11.device, (ID3D11Resource *)font_texture, &srv, &d3d11.font_texture_view); - assert(SUCCEEDED(hr));} - ID3D11Texture2D_Release(font_texture);} - - nk_font_atlas_end(&d3d11.atlas, nk_handle_ptr(d3d11.font_texture_view), &d3d11.null); - if (d3d11.atlas.default_font) - nk_style_set_font(&d3d11.ctx, &d3d11.atlas.default_font->handle); -} - -NK_API -void nk_d3d11_shutdown(void) -{ - nk_font_atlas_clear(&d3d11.atlas); - nk_buffer_free(&d3d11.cmds); - nk_free(&d3d11.ctx); - - ID3D11SamplerState_Release(d3d11.sampler_state); - ID3D11ShaderResourceView_Release(d3d11.font_texture_view); - ID3D11Buffer_Release(d3d11.vertex_buffer); - ID3D11Buffer_Release(d3d11.index_buffer); - ID3D11BlendState_Release(d3d11.blend_state); - ID3D11PixelShader_Release(d3d11.pixel_shader); - ID3D11Buffer_Release(d3d11.const_buffer); - ID3D11VertexShader_Release(d3d11.vertex_shader); - ID3D11InputLayout_Release(d3d11.input_layout); - ID3D11RasterizerState_Release(d3d11.rasterizer_state); - ID3D11Device_Release(d3d11.device); -} - -#endif - diff --git a/subprojects/nk_pugl/nuklear/demo/d3d11/nuklear_d3d11.hlsl b/subprojects/nk_pugl/nuklear/demo/d3d11/nuklear_d3d11.hlsl deleted file mode 100644 index a932dca..0000000 --- a/subprojects/nk_pugl/nuklear/demo/d3d11/nuklear_d3d11.hlsl +++ /dev/null @@ -1,36 +0,0 @@ -// -cbuffer buffer0 : register(b0) -{ - float4x4 ProjectionMatrix; -}; - -sampler sampler0 : register(s0); -Texture2D texture0 : register(t0); - -struct VS_INPUT -{ - float2 pos : POSITION; - float4 col : COLOR0; - float2 uv : TEXCOORD0; -}; - -struct PS_INPUT -{ - float4 pos : SV_POSITION; - float4 col : COLOR0; - float2 uv : TEXCOORD0; -}; - -PS_INPUT vs(VS_INPUT input) -{ - PS_INPUT output; - output.pos = mul(ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f)); - output.col = input.col; - output.uv = input.uv; - return output; -} - -float4 ps(PS_INPUT input) : SV_Target -{ - return input.col * texture0.Sample(sampler0, input.uv); -} diff --git a/subprojects/nk_pugl/nuklear/demo/d3d11/nuklear_d3d11_pixel_shader.h b/subprojects/nk_pugl/nuklear/demo/d3d11/nuklear_d3d11_pixel_shader.h deleted file mode 100644 index 1447559..0000000 --- a/subprojects/nk_pugl/nuklear/demo/d3d11/nuklear_d3d11_pixel_shader.h +++ /dev/null @@ -1,179 +0,0 @@ -#if 0 -// -// Generated by Microsoft (R) D3D Shader Disassembler -// -// -// Input signature: -// -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_POSITION 0 xyzw 0 POS float -// COLOR 0 xyzw 1 NONE float xyzw -// TEXCOORD 0 xy 2 NONE float xy -// -// -// Output signature: -// -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Target 0 xyzw 0 TARGET float xyzw -// -// -// Sampler/Resource to DX9 shader sampler mappings: -// -// Target Sampler Source Sampler Source Resource -// -------------- --------------- ---------------- -// s0 s0 t0 -// -// -// Level9 shader bytecode: -// - ps_2_0 - dcl t0 - dcl t1.xy - dcl_2d s0 - texld r0, t1, s0 - mul r0, r0, t0 - mov oC0, r0 - -// approximately 3 instruction slots used (1 texture, 2 arithmetic) -// -// Sampler/Resource to DX9 shader sampler mappings: -// -// Target Sampler Source Sampler Source Resource -// -------------- --------------- ---------------- -// s0 s0 t0 -// -// -// XNA shader bytecode: -// - ps_2_0 - dcl t0 - dcl t1.xy - dcl_2d s0 - texld r0, r2, s0 - mul oC0, r0, r1 - -// approximately 2 instruction slots used (1 texture, 1 arithmetic) -ps_4_0 -dcl_sampler s0, mode_default -dcl_resource_texture2d (float,float,float,float) t0 -dcl_input_ps linear v1.xyzw -dcl_input_ps linear v2.xy -dcl_output o0.xyzw -dcl_temps 1 -sample r0.xyzw, v2.xyxx, t0.xyzw, s0 -mul o0.xyzw, r0.xyzw, v1.xyzw -ret -// Approximately 0 instruction slots used -#endif - -const BYTE nk_d3d11_pixel_shader[] = -{ - 68, 88, 66, 67, 249, 46, - 26, 75, 111, 182, 161, 241, - 199, 179, 191, 89, 44, 229, - 245, 103, 1, 0, 0, 0, - 124, 2, 0, 0, 5, 0, - 0, 0, 52, 0, 0, 0, - 176, 0, 0, 0, 56, 1, - 0, 0, 212, 1, 0, 0, - 72, 2, 0, 0, 88, 78, - 65, 83, 116, 0, 0, 0, - 116, 0, 0, 0, 0, 2, - 255, 255, 76, 0, 0, 0, - 40, 0, 0, 0, 0, 0, - 40, 0, 0, 0, 40, 0, - 0, 0, 40, 0, 1, 0, - 36, 0, 0, 0, 40, 0, - 0, 0, 0, 0, 0, 2, - 255, 255, 31, 0, 0, 2, - 0, 0, 0, 128, 0, 0, - 15, 176, 31, 0, 0, 2, - 0, 0, 0, 128, 1, 0, - 3, 176, 31, 0, 0, 2, - 0, 0, 0, 144, 0, 8, - 15, 160, 66, 0, 0, 3, - 0, 0, 15, 128, 2, 0, - 228, 128, 0, 8, 228, 160, - 5, 0, 0, 3, 0, 8, - 15, 128, 0, 0, 228, 128, - 1, 0, 228, 128, 255, 255, - 0, 0, 65, 111, 110, 57, - 128, 0, 0, 0, 128, 0, - 0, 0, 0, 2, 255, 255, - 88, 0, 0, 0, 40, 0, - 0, 0, 0, 0, 40, 0, - 0, 0, 40, 0, 0, 0, - 40, 0, 1, 0, 36, 0, - 0, 0, 40, 0, 0, 0, - 0, 0, 0, 2, 255, 255, - 31, 0, 0, 2, 0, 0, - 0, 128, 0, 0, 15, 176, - 31, 0, 0, 2, 0, 0, - 0, 128, 1, 0, 3, 176, - 31, 0, 0, 2, 0, 0, - 0, 144, 0, 8, 15, 160, - 66, 0, 0, 3, 0, 0, - 15, 128, 1, 0, 228, 176, - 0, 8, 228, 160, 5, 0, - 0, 3, 0, 0, 15, 128, - 0, 0, 228, 128, 0, 0, - 228, 176, 1, 0, 0, 2, - 0, 8, 15, 128, 0, 0, - 228, 128, 255, 255, 0, 0, - 83, 72, 68, 82, 148, 0, - 0, 0, 64, 0, 0, 0, - 37, 0, 0, 0, 90, 0, - 0, 3, 0, 96, 16, 0, - 0, 0, 0, 0, 88, 24, - 0, 4, 0, 112, 16, 0, - 0, 0, 0, 0, 85, 85, - 0, 0, 98, 16, 0, 3, - 242, 16, 16, 0, 1, 0, - 0, 0, 98, 16, 0, 3, - 50, 16, 16, 0, 2, 0, - 0, 0, 101, 0, 0, 3, - 242, 32, 16, 0, 0, 0, - 0, 0, 104, 0, 0, 2, - 1, 0, 0, 0, 69, 0, - 0, 9, 242, 0, 16, 0, - 0, 0, 0, 0, 70, 16, - 16, 0, 2, 0, 0, 0, - 70, 126, 16, 0, 0, 0, - 0, 0, 0, 96, 16, 0, - 0, 0, 0, 0, 56, 0, - 0, 7, 242, 32, 16, 0, - 0, 0, 0, 0, 70, 14, - 16, 0, 0, 0, 0, 0, - 70, 30, 16, 0, 1, 0, - 0, 0, 62, 0, 0, 1, - 73, 83, 71, 78, 108, 0, - 0, 0, 3, 0, 0, 0, - 8, 0, 0, 0, 80, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 15, 0, 0, 0, 92, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 1, 0, 0, 0, - 15, 15, 0, 0, 98, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 2, 0, 0, 0, - 3, 3, 0, 0, 83, 86, - 95, 80, 79, 83, 73, 84, - 73, 79, 78, 0, 67, 79, - 76, 79, 82, 0, 84, 69, - 88, 67, 79, 79, 82, 68, - 0, 171, 79, 83, 71, 78, - 44, 0, 0, 0, 1, 0, - 0, 0, 8, 0, 0, 0, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 15, 0, 0, 0, - 83, 86, 95, 84, 97, 114, - 103, 101, 116, 0, 171, 171 -}; diff --git a/subprojects/nk_pugl/nuklear/demo/d3d11/nuklear_d3d11_vertex_shader.h b/subprojects/nk_pugl/nuklear/demo/d3d11/nuklear_d3d11_vertex_shader.h deleted file mode 100644 index 770d2dd..0000000 --- a/subprojects/nk_pugl/nuklear/demo/d3d11/nuklear_d3d11_vertex_shader.h +++ /dev/null @@ -1,350 +0,0 @@ -#if 0 -// -// Generated by Microsoft (R) D3D Shader Disassembler -// -// -// Input signature: -// -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// POSITION 0 xy 0 NONE float xy -// COLOR 0 xyzw 1 NONE float xyzw -// TEXCOORD 0 xy 2 NONE float xy -// -// -// Output signature: -// -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_POSITION 0 xyzw 0 POS float xyzw -// COLOR 0 xyzw 1 NONE float xyzw -// TEXCOORD 0 xy 2 NONE float xy -// -// -// Constant buffer to DX9 shader constant mappings: -// -// Target Reg Buffer Start Reg # of Regs Data Conversion -// ---------- ------- --------- --------- ---------------------- -// c1 cb0 0 4 ( FLT, FLT, FLT, FLT) -// -// -// Runtime generated constant mappings: -// -// Target Reg Constant Description -// ---------- -------------------------------------------------- -// c0 Vertex Shader position offset -// -// -// Level9 shader bytecode: -// - vs_2_0 - def c5, 0, 1, 0, 0 - dcl_texcoord v0 - dcl_texcoord1 v1 - dcl_texcoord2 v2 - mul r0, v0.x, c1 - mad r0, c2, v0.y, r0 - mov r1.xy, c5 - mad r0, c3, r1.x, r0 - mad r0, c4, r1.y, r0 - mul r1.xy, r0.w, c0 - add oPos.xy, r0, r1 - mov oPos.zw, r0 - mov oT0, v1 - mov oT1.xy, v2 - -// approximately 10 instruction slots used -// -// Constant buffer to DX9 shader constant mappings: -// -// Target Reg Buffer Start Reg # of Regs Data Conversion -// ---------- ------- --------- --------- ---------------------- -// c0 cb0 0 4 ( FLT, FLT, FLT, FLT) -// -// -// XNA Prepass shader bytecode: -// - vs_2_0 - def c4, 0, 1, 0, 0 - dcl_texcoord v0 - mul r1, r0.x, c0 - mad r0, c1, r0.y, r1 - mov r1.xy, c4 - mad r0, c2, r1.x, r0 - mad r0, c3, r1.y, r0 - mov oPos, r0 - -// approximately 6 instruction slots used -// -// Constant buffer to DX9 shader constant mappings: -// -// Target Reg Buffer Start Reg # of Regs Data Conversion -// ---------- ------- --------- --------- ---------------------- -// c0 cb0 0 4 ( FLT, FLT, FLT, FLT) -// -// -// XNA shader bytecode: -// - vs_2_0 - def c4, 0, 1, 0, 0 - dcl_texcoord v0 - dcl_texcoord1 v1 - dcl_texcoord2 v2 - mov oT0, r1 - mov oT1.xy, r2 - mul r1, r0.x, c0 - mad r0, c1, r0.y, r1 - mov r1.xy, c4 - mad r0, c2, r1.x, r0 - mad r0, c3, r1.y, r0 - mov oPos, r0 - -// approximately 8 instruction slots used -vs_4_0 -dcl_constantbuffer cb0[4], immediateIndexed -dcl_input v0.xy -dcl_input v1.xyzw -dcl_input v2.xy -dcl_output_siv o0.xyzw, position -dcl_output o1.xyzw -dcl_output o2.xy -dcl_temps 1 -mul r0.xyzw, v0.xxxx, cb0[0].xyzw -mad r0.xyzw, cb0[1].xyzw, v0.yyyy, r0.xyzw -mad r0.xyzw, cb0[2].xyzw, l(0.000000, 0.000000, 0.000000, 0.000000), r0.xyzw -mad o0.xyzw, cb0[3].xyzw, l(1.000000, 1.000000, 1.000000, 1.000000), r0.xyzw -mov o1.xyzw, v1.xyzw -mov o2.xy, v2.xyxx -ret -// Approximately 0 instruction slots used -#endif - -const BYTE nk_d3d11_vertex_shader[] = -{ - 68, 88, 66, 67, 215, 245, - 86, 155, 188, 117, 37, 118, - 193, 207, 209, 90, 160, 153, - 246, 188, 1, 0, 0, 0, - 72, 5, 0, 0, 6, 0, - 0, 0, 56, 0, 0, 0, - 48, 1, 0, 0, 248, 1, - 0, 0, 20, 3, 0, 0, - 100, 4, 0, 0, 212, 4, - 0, 0, 88, 78, 65, 83, - 240, 0, 0, 0, 240, 0, - 0, 0, 0, 2, 254, 255, - 192, 0, 0, 0, 48, 0, - 0, 0, 1, 0, 36, 0, - 0, 0, 48, 0, 0, 0, - 48, 0, 0, 0, 36, 0, - 0, 0, 48, 0, 0, 0, - 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 0, 2, - 254, 255, 81, 0, 0, 5, - 4, 0, 15, 160, 0, 0, - 0, 0, 0, 0, 128, 63, - 0, 0, 0, 0, 0, 0, - 0, 0, 31, 0, 0, 2, - 5, 0, 0, 128, 0, 0, - 15, 144, 31, 0, 0, 2, - 5, 0, 1, 128, 1, 0, - 15, 144, 31, 0, 0, 2, - 5, 0, 2, 128, 2, 0, - 15, 144, 1, 0, 0, 2, - 0, 0, 15, 224, 1, 0, - 228, 128, 1, 0, 0, 2, - 1, 0, 3, 224, 2, 0, - 228, 128, 5, 0, 0, 3, - 1, 0, 15, 128, 0, 0, - 0, 128, 0, 0, 228, 160, - 4, 0, 0, 4, 0, 0, - 15, 128, 1, 0, 228, 160, - 0, 0, 85, 128, 1, 0, - 228, 128, 1, 0, 0, 2, - 1, 0, 3, 128, 4, 0, - 228, 160, 4, 0, 0, 4, - 0, 0, 15, 128, 2, 0, - 228, 160, 1, 0, 0, 128, - 0, 0, 228, 128, 4, 0, - 0, 4, 0, 0, 15, 128, - 3, 0, 228, 160, 1, 0, - 85, 128, 0, 0, 228, 128, - 1, 0, 0, 2, 0, 0, - 15, 192, 0, 0, 228, 128, - 255, 255, 0, 0, 88, 78, - 65, 80, 192, 0, 0, 0, - 192, 0, 0, 0, 0, 2, - 254, 255, 144, 0, 0, 0, - 48, 0, 0, 0, 1, 0, - 36, 0, 0, 0, 48, 0, - 0, 0, 48, 0, 0, 0, - 36, 0, 0, 0, 48, 0, - 0, 0, 0, 0, 4, 0, - 0, 0, 0, 0, 0, 0, - 0, 2, 254, 255, 81, 0, - 0, 5, 4, 0, 15, 160, - 0, 0, 0, 0, 0, 0, - 128, 63, 0, 0, 0, 0, - 0, 0, 0, 0, 31, 0, - 0, 2, 5, 0, 0, 128, - 0, 0, 15, 144, 5, 0, - 0, 3, 1, 0, 15, 128, - 0, 0, 0, 128, 0, 0, - 228, 160, 4, 0, 0, 4, - 0, 0, 15, 128, 1, 0, - 228, 160, 0, 0, 85, 128, - 1, 0, 228, 128, 1, 0, - 0, 2, 1, 0, 3, 128, - 4, 0, 228, 160, 4, 0, - 0, 4, 0, 0, 15, 128, - 2, 0, 228, 160, 1, 0, - 0, 128, 0, 0, 228, 128, - 4, 0, 0, 4, 0, 0, - 15, 128, 3, 0, 228, 160, - 1, 0, 85, 128, 0, 0, - 228, 128, 1, 0, 0, 2, - 0, 0, 15, 192, 0, 0, - 228, 128, 255, 255, 0, 0, - 65, 111, 110, 57, 20, 1, - 0, 0, 20, 1, 0, 0, - 0, 2, 254, 255, 224, 0, - 0, 0, 52, 0, 0, 0, - 1, 0, 36, 0, 0, 0, - 48, 0, 0, 0, 48, 0, - 0, 0, 36, 0, 1, 0, - 48, 0, 0, 0, 0, 0, - 4, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 2, 254, 255, 81, 0, - 0, 5, 5, 0, 15, 160, - 0, 0, 0, 0, 0, 0, - 128, 63, 0, 0, 0, 0, - 0, 0, 0, 0, 31, 0, - 0, 2, 5, 0, 0, 128, - 0, 0, 15, 144, 31, 0, - 0, 2, 5, 0, 1, 128, - 1, 0, 15, 144, 31, 0, - 0, 2, 5, 0, 2, 128, - 2, 0, 15, 144, 5, 0, - 0, 3, 0, 0, 15, 128, - 0, 0, 0, 144, 1, 0, - 228, 160, 4, 0, 0, 4, - 0, 0, 15, 128, 2, 0, - 228, 160, 0, 0, 85, 144, - 0, 0, 228, 128, 1, 0, - 0, 2, 1, 0, 3, 128, - 5, 0, 228, 160, 4, 0, - 0, 4, 0, 0, 15, 128, - 3, 0, 228, 160, 1, 0, - 0, 128, 0, 0, 228, 128, - 4, 0, 0, 4, 0, 0, - 15, 128, 4, 0, 228, 160, - 1, 0, 85, 128, 0, 0, - 228, 128, 5, 0, 0, 3, - 1, 0, 3, 128, 0, 0, - 255, 128, 0, 0, 228, 160, - 2, 0, 0, 3, 0, 0, - 3, 192, 0, 0, 228, 128, - 1, 0, 228, 128, 1, 0, - 0, 2, 0, 0, 12, 192, - 0, 0, 228, 128, 1, 0, - 0, 2, 0, 0, 15, 224, - 1, 0, 228, 144, 1, 0, - 0, 2, 1, 0, 3, 224, - 2, 0, 228, 144, 255, 255, - 0, 0, 83, 72, 68, 82, - 72, 1, 0, 0, 64, 0, - 1, 0, 82, 0, 0, 0, - 89, 0, 0, 4, 70, 142, - 32, 0, 0, 0, 0, 0, - 4, 0, 0, 0, 95, 0, - 0, 3, 50, 16, 16, 0, - 0, 0, 0, 0, 95, 0, - 0, 3, 242, 16, 16, 0, - 1, 0, 0, 0, 95, 0, - 0, 3, 50, 16, 16, 0, - 2, 0, 0, 0, 103, 0, - 0, 4, 242, 32, 16, 0, - 0, 0, 0, 0, 1, 0, - 0, 0, 101, 0, 0, 3, - 242, 32, 16, 0, 1, 0, - 0, 0, 101, 0, 0, 3, - 50, 32, 16, 0, 2, 0, - 0, 0, 104, 0, 0, 2, - 1, 0, 0, 0, 56, 0, - 0, 8, 242, 0, 16, 0, - 0, 0, 0, 0, 6, 16, - 16, 0, 0, 0, 0, 0, - 70, 142, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 50, 0, 0, 10, 242, 0, - 16, 0, 0, 0, 0, 0, - 70, 142, 32, 0, 0, 0, - 0, 0, 1, 0, 0, 0, - 86, 21, 16, 0, 0, 0, - 0, 0, 70, 14, 16, 0, - 0, 0, 0, 0, 50, 0, - 0, 13, 242, 0, 16, 0, - 0, 0, 0, 0, 70, 142, - 32, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 2, 64, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 70, 14, 16, 0, 0, 0, - 0, 0, 50, 0, 0, 13, - 242, 32, 16, 0, 0, 0, - 0, 0, 70, 142, 32, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 2, 64, 0, 0, - 0, 0, 128, 63, 0, 0, - 128, 63, 0, 0, 128, 63, - 0, 0, 128, 63, 70, 14, - 16, 0, 0, 0, 0, 0, - 54, 0, 0, 5, 242, 32, - 16, 0, 1, 0, 0, 0, - 70, 30, 16, 0, 1, 0, - 0, 0, 54, 0, 0, 5, - 50, 32, 16, 0, 2, 0, - 0, 0, 70, 16, 16, 0, - 2, 0, 0, 0, 62, 0, - 0, 1, 73, 83, 71, 78, - 104, 0, 0, 0, 3, 0, - 0, 0, 8, 0, 0, 0, - 80, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 0, 0, - 0, 0, 3, 3, 0, 0, - 89, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 1, 0, - 0, 0, 15, 15, 0, 0, - 95, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 2, 0, - 0, 0, 3, 3, 0, 0, - 80, 79, 83, 73, 84, 73, - 79, 78, 0, 67, 79, 76, - 79, 82, 0, 84, 69, 88, - 67, 79, 79, 82, 68, 0, - 79, 83, 71, 78, 108, 0, - 0, 0, 3, 0, 0, 0, - 8, 0, 0, 0, 80, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 15, 0, 0, 0, 92, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 1, 0, 0, 0, - 15, 0, 0, 0, 98, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 2, 0, 0, 0, - 3, 12, 0, 0, 83, 86, - 95, 80, 79, 83, 73, 84, - 73, 79, 78, 0, 67, 79, - 76, 79, 82, 0, 84, 69, - 88, 67, 79, 79, 82, 68, - 0, 171 -}; diff --git a/subprojects/nk_pugl/nuklear/demo/d3d9/build.bat b/subprojects/nk_pugl/nuklear/demo/d3d9/build.bat deleted file mode 100644 index 726b6f6..0000000 --- a/subprojects/nk_pugl/nuklear/demo/d3d9/build.bat +++ /dev/null @@ -1,6 +0,0 @@ -@echo off - -rem This will use VS2015 for compiler -call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86 - -cl /D_CRT_SECURE_NO_DEPRECATE /nologo /W3 /O2 /fp:fast /Gm- /Fedemo.exe main.c user32.lib d3d9.lib /link /incremental:no diff --git a/subprojects/nk_pugl/nuklear/demo/d3d9/main.c b/subprojects/nk_pugl/nuklear/demo/d3d9/main.c deleted file mode 100644 index b329e2b..0000000 --- a/subprojects/nk_pugl/nuklear/demo/d3d9/main.c +++ /dev/null @@ -1,313 +0,0 @@ -/* nuklear - 1.32.0 - public domain */ -#define COBJMACROS -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include -#include - -#define WINDOW_WIDTH 800 -#define WINDOW_HEIGHT 600 - -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_STANDARD_VARARGS -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT -#define NK_INCLUDE_FONT_BAKING -#define NK_INCLUDE_DEFAULT_FONT -#define NK_IMPLEMENTATION -#define NK_D3D9_IMPLEMENTATION -#include "../../nuklear.h" -#include "nuklear_d3d9.h" - -/* =============================================================== - * - * EXAMPLE - * - * ===============================================================*/ -/* This are some code examples to provide a small overview of what can be - * done with this library. To try out an example uncomment the defines */ -/*#define INCLUDE_ALL */ -/*#define INCLUDE_STYLE */ -/*#define INCLUDE_CALCULATOR */ -/*#define INCLUDE_OVERVIEW */ -/*#define INCLUDE_NODE_EDITOR */ - -#ifdef INCLUDE_ALL - #define INCLUDE_STYLE - #define INCLUDE_CALCULATOR - #define INCLUDE_OVERVIEW - #define INCLUDE_NODE_EDITOR -#endif - -#ifdef INCLUDE_STYLE - #include "../style.c" -#endif -#ifdef INCLUDE_CALCULATOR - #include "../calculator.c" -#endif -#ifdef INCLUDE_OVERVIEW - #include "../overview.c" -#endif -#ifdef INCLUDE_NODE_EDITOR - #include "../node_editor.c" -#endif - -/* =============================================================== - * - * DEMO - * - * ===============================================================*/ -static IDirect3DDevice9 *device; -static IDirect3DDevice9Ex *deviceEx; -static D3DPRESENT_PARAMETERS present; - -static LRESULT CALLBACK -WindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) -{ - switch (msg) - { - case WM_DESTROY: - PostQuitMessage(0); - return 0; - - case WM_SIZE: - if (device) - { - UINT width = LOWORD(lparam); - UINT height = HIWORD(lparam); - if (width != 0 && height != 0 && - (width != present.BackBufferWidth || height != present.BackBufferHeight)) - { - nk_d3d9_release(); - present.BackBufferWidth = width; - present.BackBufferHeight = height; - HRESULT hr = IDirect3DDevice9_Reset(device, &present); - NK_ASSERT(SUCCEEDED(hr)); - nk_d3d9_resize(width, height); - } - } - break; - } - - if (nk_d3d9_handle_event(wnd, msg, wparam, lparam)) - return 0; - - return DefWindowProcW(wnd, msg, wparam, lparam); -} - -static void create_d3d9_device(HWND wnd) -{ - HRESULT hr; - - present.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; - present.BackBufferWidth = WINDOW_WIDTH; - present.BackBufferHeight = WINDOW_HEIGHT; - present.BackBufferFormat = D3DFMT_X8R8G8B8; - present.BackBufferCount = 1; - present.MultiSampleType = D3DMULTISAMPLE_NONE; - present.SwapEffect = D3DSWAPEFFECT_DISCARD; - present.hDeviceWindow = wnd; - present.EnableAutoDepthStencil = TRUE; - present.AutoDepthStencilFormat = D3DFMT_D24S8; - present.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL; - present.Windowed = TRUE; - - {/* first try to create Direct3D9Ex device if possible (on Windows 7+) */ - typedef HRESULT WINAPI Direct3DCreate9ExPtr(UINT, IDirect3D9Ex**); - Direct3DCreate9ExPtr *Direct3DCreate9Ex = (void *)GetProcAddress(GetModuleHandleA("d3d9.dll"), "Direct3DCreate9Ex"); - if (Direct3DCreate9Ex) { - IDirect3D9Ex *d3d9ex; - if (SUCCEEDED(Direct3DCreate9Ex(D3D_SDK_VERSION, &d3d9ex))) { - hr = IDirect3D9Ex_CreateDeviceEx(d3d9ex, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, - D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_FPU_PRESERVE, - &present, NULL, &deviceEx); - if (SUCCEEDED(hr)) { - device = (IDirect3DDevice9 *)deviceEx; - } else { - /* hardware vertex processing not supported, no big deal - retry with software vertex processing */ - hr = IDirect3D9Ex_CreateDeviceEx(d3d9ex, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, - D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_FPU_PRESERVE, - &present, NULL, &deviceEx); - if (SUCCEEDED(hr)) { - device = (IDirect3DDevice9 *)deviceEx; - } - } - IDirect3D9Ex_Release(d3d9ex); - } - } - } - - if (!device) { - /* otherwise do regular D3D9 setup */ - IDirect3D9 *d3d9 = Direct3DCreate9(D3D_SDK_VERSION); - - hr = IDirect3D9_CreateDevice(d3d9, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, - D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_FPU_PRESERVE, - &present, &device); - if (FAILED(hr)) { - /* hardware vertex processing not supported, no big deal - retry with software vertex processing */ - hr = IDirect3D9_CreateDevice(d3d9, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, - D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_FPU_PRESERVE, - &present, &device); - NK_ASSERT(SUCCEEDED(hr)); - } - IDirect3D9_Release(d3d9); - } -} - -int main(void) -{ - struct nk_context *ctx; - struct nk_colorf bg; - - WNDCLASSW wc; - RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT }; - DWORD style = WS_OVERLAPPEDWINDOW; - DWORD exstyle = WS_EX_APPWINDOW; - HWND wnd; - int running = 1; - - /* Win32 */ - memset(&wc, 0, sizeof(wc)); - wc.style = CS_DBLCLKS; - wc.lpfnWndProc = WindowProc; - wc.hInstance = GetModuleHandleW(0); - wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.lpszClassName = L"NuklearWindowClass"; - RegisterClassW(&wc); - - AdjustWindowRectEx(&rect, style, FALSE, exstyle); - - wnd = CreateWindowExW(exstyle, wc.lpszClassName, L"Nuklear Demo", - style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, - rect.right - rect.left, rect.bottom - rect.top, - NULL, NULL, wc.hInstance, NULL); - - create_d3d9_device(wnd); - - /* GUI */ - ctx = nk_d3d9_init(device, WINDOW_WIDTH, WINDOW_HEIGHT); - /* Load Fonts: if none of these are loaded a default font will be used */ - /* Load Cursor: if you uncomment cursor loading please hide the cursor */ - {struct nk_font_atlas *atlas; - nk_d3d9_font_stash_begin(&atlas); - /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../extra_font/DroidSans.ttf", 14, 0);*/ - /*struct nk_font *robot = nk_font_atlas_add_from_file(atlas, "../../extra_font/Roboto-Regular.ttf", 14, 0);*/ - /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../extra_font/kenvector_future_thin.ttf", 13, 0);*/ - /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../extra_font/ProggyClean.ttf", 12, 0);*/ - /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../extra_font/ProggyTiny.ttf", 10, 0);*/ - /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../extra_font/Cousine-Regular.ttf", 13, 0);*/ - nk_d3d9_font_stash_end(); - /*nk_style_load_all_cursors(ctx, atlas->cursors);*/ - /*nk_style_set_font(ctx, &droid->handle)*/;} - - /* style.c */ - #ifdef INCLUDE_STYLE - /*set_style(ctx, THEME_WHITE);*/ - /*set_style(ctx, THEME_RED);*/ - /*set_style(ctx, THEME_BLUE);*/ - /*set_style(ctx, THEME_DARK);*/ - #endif - - bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f; - while (running) - { - /* Input */ - MSG msg; - nk_input_begin(ctx); - while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) { - if (msg.message == WM_QUIT) - running = 0; - TranslateMessage(&msg); - DispatchMessageW(&msg); - } - nk_input_end(ctx); - - /* GUI */ - if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250), - NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE| - NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) - { - enum {EASY, HARD}; - static int op = EASY; - static int property = 20; - - nk_layout_row_static(ctx, 30, 80, 1); - if (nk_button_label(ctx, "button")) - fprintf(stdout, "button pressed\n"); - nk_layout_row_dynamic(ctx, 30, 2); - if (nk_option_label(ctx, "easy", op == EASY)) op = EASY; - if (nk_option_label(ctx, "hard", op == HARD)) op = HARD; - nk_layout_row_dynamic(ctx, 22, 1); - nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1); - - nk_layout_row_dynamic(ctx, 20, 1); - nk_label(ctx, "background:", NK_TEXT_LEFT); - nk_layout_row_dynamic(ctx, 25, 1); - if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) { - nk_layout_row_dynamic(ctx, 120, 1); - bg = nk_color_picker(ctx, bg, NK_RGBA); - nk_layout_row_dynamic(ctx, 25, 1); - bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f); - bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f); - bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f); - bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f); - nk_combo_end(ctx); - } - } - nk_end(ctx); - - /* -------------- EXAMPLES ---------------- */ - #ifdef INCLUDE_CALCULATOR - calculator(ctx); - #endif - #ifdef INCLUDE_OVERVIEW - overview(ctx); - #endif - #ifdef INCLUDE_NODE_EDITOR - node_editor(ctx); - #endif - /* ----------------------------------------- */ - - /* Draw */ - { - HRESULT hr; - hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, - D3DCOLOR_COLORVALUE(bg.a, bg.r, bg.g, bg.b), 0.0f, 0); - NK_ASSERT(SUCCEEDED(hr)); - - hr = IDirect3DDevice9_BeginScene(device); - NK_ASSERT(SUCCEEDED(hr)); - nk_d3d9_render(NK_ANTI_ALIASING_ON); - hr = IDirect3DDevice9_EndScene(device); - NK_ASSERT(SUCCEEDED(hr)); - - if (deviceEx) { - hr = IDirect3DDevice9Ex_PresentEx(deviceEx, NULL, NULL, NULL, NULL, 0); - } else { - hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); - } - if (hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICEHUNG || hr == D3DERR_DEVICEREMOVED) { - /* to recover from this, you'll need to recreate device and all the resources */ - MessageBoxW(NULL, L"D3D9 device is lost or removed!", L"Error", 0); - break; - } else if (hr == S_PRESENT_OCCLUDED) { - /* window is not visible, so vsync won't work. Let's sleep a bit to reduce CPU usage */ - Sleep(10); - } - NK_ASSERT(SUCCEEDED(hr)); - } - } - nk_d3d9_shutdown(); - if (deviceEx)IDirect3DDevice9Ex_Release(deviceEx); - else IDirect3DDevice9_Release(device); - UnregisterClassW(wc.lpszClassName, wc.hInstance); - return 0; -} diff --git a/subprojects/nk_pugl/nuklear/demo/d3d9/nuklear_d3d9.h b/subprojects/nk_pugl/nuklear/demo/d3d9/nuklear_d3d9.h deleted file mode 100644 index fd8d176..0000000 --- a/subprojects/nk_pugl/nuklear/demo/d3d9/nuklear_d3d9.h +++ /dev/null @@ -1,543 +0,0 @@ -/* - * Nuklear - 1.32.0 - public domain - * no warrenty implied; use at your own risk. - * authored from 2015-2016 by Micha Mettke - */ -/* - * ============================================================== - * - * API - * - * =============================================================== - */ -#ifndef NK_D3D9_H_ -#define NK_D3D9_H_ - -#define WIN32_LEAN_AND_MEAN -#include - -typedef struct IDirect3DDevice9 IDirect3DDevice9; - -NK_API struct nk_context *nk_d3d9_init(IDirect3DDevice9 *device, int width, int height); -NK_API void nk_d3d9_font_stash_begin(struct nk_font_atlas **atlas); -NK_API void nk_d3d9_font_stash_end(void); -NK_API int nk_d3d9_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); -NK_API void nk_d3d9_render(enum nk_anti_aliasing); -NK_API void nk_d3d9_release(void); -NK_API void nk_d3d9_resize(int width, int height); -NK_API void nk_d3d9_shutdown(void); - -#endif -/* - * ============================================================== - * - * IMPLEMENTATION - * - * =============================================================== - */ -#ifdef NK_D3D9_IMPLEMENTATION - -#define WIN32_LEAN_AND_MEAN -#define COBJMACROS -#include - -#include -#include - -struct nk_d3d9_vertex { - /* D3d9 FFP requires three coordinate position, but nuklear writes only 2 elements - projection matrix doesn't use z coordinate => so it can be any value. - Member order here is important! Do not rearrange them! */ - float position[3]; - nk_uchar col[4]; - float uv[2]; -}; - -static struct { - struct nk_context ctx; - struct nk_font_atlas atlas; - struct nk_buffer cmds; - - struct nk_draw_null_texture null; - - D3DVIEWPORT9 viewport; - D3DMATRIX projection; - IDirect3DDevice9 *device; - IDirect3DTexture9 *texture; - IDirect3DStateBlock9 *state; -} d3d9; - -NK_API void -nk_d3d9_create_state() -{ - HRESULT hr; - - hr = IDirect3DDevice9_BeginStateBlock(d3d9.device); - NK_ASSERT(SUCCEEDED(hr)); - - /* vertex format */ - IDirect3DDevice9_SetFVF(d3d9.device, D3DFVF_XYZ + D3DFVF_DIFFUSE + D3DFVF_TEX1); - - /* blend state */ - IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); - IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); - IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_ALPHABLENDENABLE, TRUE); - IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_BLENDOP, D3DBLENDOP_ADD); - - /* render state */ - IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_LIGHTING, FALSE); - IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_ZENABLE, FALSE); - IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_ZWRITEENABLE, FALSE); - IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_CULLMODE, D3DCULL_NONE); - IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_SCISSORTESTENABLE, TRUE); - - /* sampler state */ - IDirect3DDevice9_SetSamplerState(d3d9.device, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - IDirect3DDevice9_SetSamplerState(d3d9.device, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - IDirect3DDevice9_SetSamplerState(d3d9.device, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - IDirect3DDevice9_SetSamplerState(d3d9.device, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - - /* texture stage state */ - IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_COLOROP, D3DTOP_MODULATE); - IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE); - IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); - IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); - IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); - IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); - - hr = IDirect3DDevice9_EndStateBlock(d3d9.device, &d3d9.state); - NK_ASSERT(SUCCEEDED(hr)); -} - -NK_API void -nk_d3d9_render(enum nk_anti_aliasing AA) -{ - HRESULT hr; - - nk_d3d9_create_state(); - - hr = IDirect3DStateBlock9_Apply(d3d9.state); - NK_ASSERT(SUCCEEDED(hr)); - - /* projection matrix */ - IDirect3DDevice9_SetTransform(d3d9.device, D3DTS_PROJECTION, &d3d9.projection); - - /* viewport */ - IDirect3DDevice9_SetViewport(d3d9.device, &d3d9.viewport); - - /* convert from command queue into draw list and draw to screen */ - { - struct nk_buffer vbuf, ebuf; - const struct nk_draw_command *cmd; - const nk_draw_index *offset = NULL; - UINT vertex_count; - - /* fill converting configuration */ - struct nk_convert_config config; - NK_STORAGE const struct nk_draw_vertex_layout_element vertex_layout[] = { - {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_d3d9_vertex, position)}, - {NK_VERTEX_COLOR, NK_FORMAT_B8G8R8A8, NK_OFFSETOF(struct nk_d3d9_vertex, col)}, - {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_d3d9_vertex, uv)}, - {NK_VERTEX_LAYOUT_END} - }; - memset(&config, 0, sizeof(config)); - config.vertex_layout = vertex_layout; - config.vertex_size = sizeof(struct nk_d3d9_vertex); - config.vertex_alignment = NK_ALIGNOF(struct nk_d3d9_vertex); - config.global_alpha = 1.0f; - config.shape_AA = AA; - config.line_AA = AA; - config.circle_segment_count = 22; - config.curve_segment_count = 22; - config.arc_segment_count = 22; - config.null = d3d9.null; - - /* convert shapes into vertexes */ - nk_buffer_init_default(&vbuf); - nk_buffer_init_default(&ebuf); - nk_convert(&d3d9.ctx, &d3d9.cmds, &vbuf, &ebuf, &config); - - /* iterate over and execute each draw command */ - offset = (const nk_draw_index *)nk_buffer_memory_const(&ebuf); - vertex_count = (UINT)vbuf.needed / sizeof(struct nk_d3d9_vertex); - - nk_draw_foreach(cmd, &d3d9.ctx, &d3d9.cmds) - { - RECT scissor; - if (!cmd->elem_count) continue; - - hr = IDirect3DDevice9_SetTexture(d3d9.device, 0, (IDirect3DBaseTexture9 *)cmd->texture.ptr); - NK_ASSERT(SUCCEEDED(hr)); - - scissor.left = (LONG)cmd->clip_rect.x; - scissor.right = (LONG)(cmd->clip_rect.x + cmd->clip_rect.w); - scissor.top = (LONG)cmd->clip_rect.y; - scissor.bottom = (LONG)(cmd->clip_rect.y + cmd->clip_rect.h); - - hr = IDirect3DDevice9_SetScissorRect(d3d9.device, &scissor); - NK_ASSERT(SUCCEEDED(hr)); - - NK_ASSERT(sizeof(nk_draw_index) == sizeof(NK_UINT16)); - hr = IDirect3DDevice9_DrawIndexedPrimitiveUP(d3d9.device, D3DPT_TRIANGLELIST, - 0, vertex_count, cmd->elem_count/3, offset, D3DFMT_INDEX16, - nk_buffer_memory_const(&vbuf), sizeof(struct nk_d3d9_vertex)); - NK_ASSERT(SUCCEEDED(hr)); - offset += cmd->elem_count; - } - - nk_buffer_free(&vbuf); - nk_buffer_free(&ebuf); - } - - nk_clear(&d3d9.ctx); - - IDirect3DStateBlock9_Apply(d3d9.state); - IDirect3DStateBlock9_Release(d3d9.state); -} - -static void -nk_d3d9_get_projection_matrix(int width, int height, float *result) -{ - const float L = 0.5f; - const float R = (float)width + 0.5f; - const float T = 0.5f; - const float B = (float)height + 0.5f; - float matrix[4][4] = { - { 2.0f / (R - L), 0.0f, 0.0f, 0.0f }, - { 0.0f, 2.0f / (T - B), 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 0.0f }, - { (R + L) / (L - R), (T + B) / (B - T), 0.0f, 1.0f }, - }; - memcpy(result, matrix, sizeof(matrix)); -} - -NK_API void -nk_d3d9_release(void) -{ - IDirect3DTexture9_Release(d3d9.texture); -} - -static void -nk_d3d9_create_font_texture() -{ - int w, h, y; - const void *image; - - HRESULT hr; - D3DLOCKED_RECT locked; - - image = nk_font_atlas_bake(&d3d9.atlas, &w, &h, NK_FONT_ATLAS_RGBA32); - - hr = IDirect3DDevice9_CreateTexture(d3d9.device, w, h, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d9.texture, NULL); - NK_ASSERT(SUCCEEDED(hr)); - - hr = IDirect3DTexture9_LockRect(d3d9.texture, 0, &locked, NULL, 0); - NK_ASSERT(SUCCEEDED(hr)); - - for (y = 0; y < h; y++) { - void *src = (char *)image + y * w * 4; - void *dst = (char *)locked.pBits + y * locked.Pitch; - memcpy(dst, src, w * 4); - } - - hr = IDirect3DTexture9_UnlockRect(d3d9.texture, 0); - NK_ASSERT(SUCCEEDED(hr)); - - nk_font_atlas_end(&d3d9.atlas, nk_handle_ptr(d3d9.texture), &d3d9.null); -} - -NK_API void -nk_d3d9_resize(int width, int height) -{ - if (d3d9.texture) { - nk_d3d9_create_font_texture(); - } - - nk_d3d9_create_state(); - - nk_d3d9_get_projection_matrix(width, height, &d3d9.projection.m[0][0]); - d3d9.viewport.Width = width; - d3d9.viewport.Height = height; -} - -NK_API int -nk_d3d9_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) -{ - switch (msg) - { - case WM_KEYDOWN: - case WM_KEYUP: - case WM_SYSKEYDOWN: - case WM_SYSKEYUP: - { - int down = !((lparam >> 31) & 1); - int ctrl = GetKeyState(VK_CONTROL) & (1 << 15); - - switch (wparam) - { - case VK_SHIFT: - case VK_LSHIFT: - case VK_RSHIFT: - nk_input_key(&d3d9.ctx, NK_KEY_SHIFT, down); - return 1; - - case VK_DELETE: - nk_input_key(&d3d9.ctx, NK_KEY_DEL, down); - return 1; - - case VK_RETURN: - nk_input_key(&d3d9.ctx, NK_KEY_ENTER, down); - return 1; - - case VK_TAB: - nk_input_key(&d3d9.ctx, NK_KEY_TAB, down); - return 1; - - case VK_LEFT: - if (ctrl) - nk_input_key(&d3d9.ctx, NK_KEY_TEXT_WORD_LEFT, down); - else - nk_input_key(&d3d9.ctx, NK_KEY_LEFT, down); - return 1; - - case VK_RIGHT: - if (ctrl) - nk_input_key(&d3d9.ctx, NK_KEY_TEXT_WORD_RIGHT, down); - else - nk_input_key(&d3d9.ctx, NK_KEY_RIGHT, down); - return 1; - - case VK_BACK: - nk_input_key(&d3d9.ctx, NK_KEY_BACKSPACE, down); - return 1; - - case VK_HOME: - nk_input_key(&d3d9.ctx, NK_KEY_TEXT_START, down); - nk_input_key(&d3d9.ctx, NK_KEY_SCROLL_START, down); - return 1; - - case VK_END: - nk_input_key(&d3d9.ctx, NK_KEY_TEXT_END, down); - nk_input_key(&d3d9.ctx, NK_KEY_SCROLL_END, down); - return 1; - - case VK_NEXT: - nk_input_key(&d3d9.ctx, NK_KEY_SCROLL_DOWN, down); - return 1; - - case VK_PRIOR: - nk_input_key(&d3d9.ctx, NK_KEY_SCROLL_UP, down); - return 1; - - case 'C': - if (ctrl) { - nk_input_key(&d3d9.ctx, NK_KEY_COPY, down); - return 1; - } - break; - - case 'V': - if (ctrl) { - nk_input_key(&d3d9.ctx, NK_KEY_PASTE, down); - return 1; - } - break; - - case 'X': - if (ctrl) { - nk_input_key(&d3d9.ctx, NK_KEY_CUT, down); - return 1; - } - break; - - case 'Z': - if (ctrl) { - nk_input_key(&d3d9.ctx, NK_KEY_TEXT_UNDO, down); - return 1; - } - break; - - case 'R': - if (ctrl) { - nk_input_key(&d3d9.ctx, NK_KEY_TEXT_REDO, down); - return 1; - } - break; - } - return 0; - } - - case WM_CHAR: - if (wparam >= 32) - { - nk_input_unicode(&d3d9.ctx, (nk_rune)wparam); - return 1; - } - break; - - case WM_LBUTTONDOWN: - nk_input_button(&d3d9.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1); - SetCapture(wnd); - return 1; - - case WM_LBUTTONUP: - nk_input_button(&d3d9.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0); - nk_input_button(&d3d9.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0); - ReleaseCapture(); - return 1; - - case WM_RBUTTONDOWN: - nk_input_button(&d3d9.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1); - SetCapture(wnd); - return 1; - - case WM_RBUTTONUP: - nk_input_button(&d3d9.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0); - ReleaseCapture(); - return 1; - - case WM_MBUTTONDOWN: - nk_input_button(&d3d9.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1); - SetCapture(wnd); - return 1; - - case WM_MBUTTONUP: - nk_input_button(&d3d9.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0); - ReleaseCapture(); - return 1; - - case WM_MOUSEWHEEL: - nk_input_scroll(&d3d9.ctx, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA)); - return 1; - - case WM_MOUSEMOVE: - nk_input_motion(&d3d9.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam)); - return 1; - - case WM_LBUTTONDBLCLK: - nk_input_button(&d3d9.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1); - return 1; - } - - return 0; -} - -static void -nk_d3d9_clipboard_paste(nk_handle usr, struct nk_text_edit *edit) -{ - (void)usr; - if (!IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL)) { - return; - } - - HGLOBAL mem = GetClipboardData(CF_UNICODETEXT); - if (!mem) { - CloseClipboard(); - return; - } - - SIZE_T size = GlobalSize(mem) - 1; - if (!size) { - CloseClipboard(); - return; - } - - LPCWSTR wstr = (LPCWSTR)GlobalLock(mem); - if (!wstr) { - CloseClipboard(); - return; - } - - int utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, (int)size / sizeof(wchar_t), NULL, 0, NULL, NULL); - if (utf8size) { - char *utf8 = (char *)malloc(utf8size); - if (utf8) { - WideCharToMultiByte(CP_UTF8, 0, wstr, (int)size / sizeof(wchar_t), utf8, utf8size, NULL, NULL); - nk_textedit_paste(edit, utf8, utf8size); - free(utf8); - } - } - - GlobalUnlock(mem); - CloseClipboard(); -} - -static void -nk_d3d9_clipboard_copy(nk_handle usr, const char *text, int len) -{ - (void)usr; - if (!OpenClipboard(NULL)) { - return; - } - - int wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0); - if (wsize) { - HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t)); - if (mem) { - wchar_t *wstr = (wchar_t*)GlobalLock(mem); - if (wstr) { - MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize); - wstr[wsize] = 0; - GlobalUnlock(mem); - SetClipboardData(CF_UNICODETEXT, mem); - } - } - } - - CloseClipboard(); -} - -NK_API struct nk_context* -nk_d3d9_init(IDirect3DDevice9 *device, int width, int height) -{ - d3d9.device = device; - IDirect3DDevice9_AddRef(device); - - nk_init_default(&d3d9.ctx, 0); - d3d9.state = NULL; - d3d9.texture = NULL; - d3d9.ctx.clip.copy = nk_d3d9_clipboard_copy; - d3d9.ctx.clip.paste = nk_d3d9_clipboard_paste; - d3d9.ctx.clip.userdata = nk_handle_ptr(0); - - nk_buffer_init_default(&d3d9.cmds); - - /* viewport */ - d3d9.viewport.X = 0; - d3d9.viewport.Y = 0; - d3d9.viewport.MinZ = 0.0f; - d3d9.viewport.MaxZ = 1.0f; - - nk_d3d9_resize(width, height); - - return &d3d9.ctx; -} - -NK_API void -nk_d3d9_font_stash_begin(struct nk_font_atlas **atlas) -{ - nk_font_atlas_init_default(&d3d9.atlas); - nk_font_atlas_begin(&d3d9.atlas); - *atlas = &d3d9.atlas; -} - -NK_API void -nk_d3d9_font_stash_end(void) -{ - nk_d3d9_create_font_texture(); - - if (d3d9.atlas.default_font) - nk_style_set_font(&d3d9.ctx, &d3d9.atlas.default_font->handle); -} - -NK_API -void nk_d3d9_shutdown(void) -{ - nk_d3d9_release(); - - nk_font_atlas_clear(&d3d9.atlas); - nk_buffer_free(&d3d9.cmds); - nk_free(&d3d9.ctx); -} - -#endif diff --git a/subprojects/nk_pugl/nuklear/demo/gdi/build.bat b/subprojects/nk_pugl/nuklear/demo/gdi/build.bat deleted file mode 100644 index 3884317..0000000 --- a/subprojects/nk_pugl/nuklear/demo/gdi/build.bat +++ /dev/null @@ -1,6 +0,0 @@ -@echo off - -rem This will use VS2015 for compiler -call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86 - -cl /nologo /W3 /O2 /fp:fast /Gm- /Fedemo.exe main.c user32.lib gdi32.lib /link /incremental:no diff --git a/subprojects/nk_pugl/nuklear/demo/gdi/main.c b/subprojects/nk_pugl/nuklear/demo/gdi/main.c deleted file mode 100644 index 1755b9c..0000000 --- a/subprojects/nk_pugl/nuklear/demo/gdi/main.c +++ /dev/null @@ -1,184 +0,0 @@ -/* nuklear - 1.32.0 - public domain */ -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include - -#define WINDOW_WIDTH 800 -#define WINDOW_HEIGHT 600 - -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_STANDARD_VARARGS -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_IMPLEMENTATION -#define NK_GDI_IMPLEMENTATION -#include "../../nuklear.h" -#include "nuklear_gdi.h" - -/* =============================================================== - * - * EXAMPLE - * - * ===============================================================*/ -/* This are some code examples to provide a small overview of what can be - * done with this library. To try out an example uncomment the defines */ -/*#define INCLUDE_ALL */ -/*#define INCLUDE_STYLE */ -/*#define INCLUDE_CALCULATOR */ -/*#define INCLUDE_OVERVIEW */ -/*#define INCLUDE_NODE_EDITOR */ - -#ifdef INCLUDE_ALL - #define INCLUDE_STYLE - #define INCLUDE_CALCULATOR - #define INCLUDE_OVERVIEW - #define INCLUDE_NODE_EDITOR -#endif - -#ifdef INCLUDE_STYLE - #include "../style.c" -#endif -#ifdef INCLUDE_CALCULATOR - #include "../calculator.c" -#endif -#ifdef INCLUDE_OVERVIEW - #include "../overview.c" -#endif -#ifdef INCLUDE_NODE_EDITOR - #include "../node_editor.c" -#endif - -/* =============================================================== - * - * DEMO - * - * ===============================================================*/ -static LRESULT CALLBACK -WindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) -{ - switch (msg) - { - case WM_DESTROY: - PostQuitMessage(0); - return 0; - } - - if (nk_gdi_handle_event(wnd, msg, wparam, lparam)) - return 0; - - return DefWindowProcW(wnd, msg, wparam, lparam); -} - -int main(void) -{ - GdiFont* font; - struct nk_context *ctx; - - WNDCLASSW wc; - ATOM atom; - RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT }; - DWORD style = WS_OVERLAPPEDWINDOW; - DWORD exstyle = WS_EX_APPWINDOW; - HWND wnd; - HDC dc; - int running = 1; - int needs_refresh = 1; - - /* Win32 */ - memset(&wc, 0, sizeof(wc)); - wc.style = CS_DBLCLKS; - wc.lpfnWndProc = WindowProc; - wc.hInstance = GetModuleHandleW(0); - wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.lpszClassName = L"NuklearWindowClass"; - atom = RegisterClassW(&wc); - - AdjustWindowRectEx(&rect, style, FALSE, exstyle); - wnd = CreateWindowExW(exstyle, wc.lpszClassName, L"Nuklear Demo", - style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, - rect.right - rect.left, rect.bottom - rect.top, - NULL, NULL, wc.hInstance, NULL); - dc = GetDC(wnd); - - /* GUI */ - font = nk_gdifont_create("Arial", 14); - ctx = nk_gdi_init(font, dc, WINDOW_WIDTH, WINDOW_HEIGHT); - - /* style.c */ - #ifdef INCLUDE_STYLE - /*set_style(ctx, THEME_WHITE);*/ - /*set_style(ctx, THEME_RED);*/ - /*set_style(ctx, THEME_BLUE);*/ - /*set_style(ctx, THEME_DARK);*/ - #endif - - while (running) - { - /* Input */ - MSG msg; - nk_input_begin(ctx); - if (needs_refresh == 0) { - if (GetMessageW(&msg, NULL, 0, 0) <= 0) - running = 0; - else { - TranslateMessage(&msg); - DispatchMessageW(&msg); - } - needs_refresh = 1; - } else needs_refresh = 0; - - while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) { - if (msg.message == WM_QUIT) - running = 0; - TranslateMessage(&msg); - DispatchMessageW(&msg); - needs_refresh = 1; - } - nk_input_end(ctx); - - /* GUI */ - if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200), - NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE| - NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) - { - enum {EASY, HARD}; - static int op = EASY; - static int property = 20; - - nk_layout_row_static(ctx, 30, 80, 1); - if (nk_button_label(ctx, "button")) - fprintf(stdout, "button pressed\n"); - nk_layout_row_dynamic(ctx, 30, 2); - if (nk_option_label(ctx, "easy", op == EASY)) op = EASY; - if (nk_option_label(ctx, "hard", op == HARD)) op = HARD; - nk_layout_row_dynamic(ctx, 22, 1); - nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1); - } - nk_end(ctx); - - /* -------------- EXAMPLES ---------------- */ - #ifdef INCLUDE_CALCULATOR - calculator(ctx); - #endif - #ifdef INCLUDE_OVERVIEW - overview(ctx); - #endif - #ifdef INCLUDE_NODE_EDITOR - node_editor(ctx); - #endif - /* ----------------------------------------- */ - - /* Draw */ - nk_gdi_render(nk_rgb(30,30,30)); - } - - nk_gdifont_del(font); - ReleaseDC(wnd, dc); - UnregisterClassW(wc.lpszClassName, wc.hInstance); - return 0; -} - diff --git a/subprojects/nk_pugl/nuklear/demo/gdi/nuklear_gdi.h b/subprojects/nk_pugl/nuklear/demo/gdi/nuklear_gdi.h deleted file mode 100644 index c875de1..0000000 --- a/subprojects/nk_pugl/nuklear/demo/gdi/nuklear_gdi.h +++ /dev/null @@ -1,842 +0,0 @@ -/* - * Nuklear - 1.32.0 - public domain - * no warrenty implied; use at your own risk. - * authored from 2015-2016 by Micha Mettke - */ -/* - * ============================================================== - * - * API - * - * =============================================================== - */ -#ifndef NK_GDI_H_ -#define NK_GDI_H_ - -#define WIN32_LEAN_AND_MEAN -#include - -typedef struct GdiFont GdiFont; -NK_API struct nk_context* nk_gdi_init(GdiFont *font, HDC window_dc, unsigned int width, unsigned int height); -NK_API int nk_gdi_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); -NK_API void nk_gdi_render(struct nk_color clear); -NK_API void nk_gdi_shutdown(void); - -/* font */ -NK_API GdiFont* nk_gdifont_create(const char *name, int size); -NK_API void nk_gdifont_del(GdiFont *font); -NK_API void nk_gdi_set_font(GdiFont *font); - -#endif - -/* - * ============================================================== - * - * IMPLEMENTATION - * - * =============================================================== - */ -#ifdef NK_GDI_IMPLEMENTATION - -#include -#include - -struct GdiFont { - struct nk_user_font nk; - int height; - HFONT handle; - HDC dc; -}; - -static struct { - HBITMAP bitmap; - HDC window_dc; - HDC memory_dc; - unsigned int width; - unsigned int height; - struct nk_context ctx; -} gdi; - -static void -nk_create_image(struct nk_image * image, const char * frame_buffer, const int width, const int height) -{ - if (image && frame_buffer && (width > 0) && (height > 0)) - { - image->w = width; - image->h = height; - image->region[0] = 0; - image->region[1] = 0; - image->region[2] = width; - image->region[3] = height; - - INT row = ((width * 3 + 3) & ~3); - BITMAPINFO bi = { 0 }; - bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bi.bmiHeader.biWidth = width; - bi.bmiHeader.biHeight = height; - bi.bmiHeader.biPlanes = 1; - bi.bmiHeader.biBitCount = 24; - bi.bmiHeader.biCompression = BI_RGB; - bi.bmiHeader.biSizeImage = row * height; - - LPBYTE lpBuf, pb = NULL; - HBITMAP hbm = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, (void**)&lpBuf, NULL, 0); - - pb = lpBuf + row * height; - unsigned char * src = (unsigned char *)frame_buffer; - for (int v = 0; vhandle.ptr = hbm; - } -} - -static void -nk_delete_image(struct nk_image * image) -{ - if (image && image->handle.id != 0) - { - HBITMAP hbm = image->handle.ptr; - DeleteObject(hbm); - memset(image, 0, sizeof(struct nk_image)); - } -} - -static void -nk_gdi_draw_image(short x, short y, unsigned short w, unsigned short h, - struct nk_image img, struct nk_color col) -{ - HBITMAP hbm = img.handle.ptr; - HDC hDCBits; - BITMAP bitmap; - - if (!gdi.memory_dc || !hbm) - return; - - hDCBits = CreateCompatibleDC(gdi.memory_dc); - GetObject(hbm, sizeof(BITMAP), (LPSTR)&bitmap); - SelectObject(hDCBits, hbm); - StretchBlt(gdi.memory_dc, x, y, w, h, hDCBits, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY); - DeleteDC(hDCBits); -} - -static COLORREF -convert_color(struct nk_color c) -{ - return c.r | (c.g << 8) | (c.b << 16); -} - -static void -nk_gdi_scissor(HDC dc, float x, float y, float w, float h) -{ - SelectClipRgn(dc, NULL); - IntersectClipRect(dc, (int)x, (int)y, (int)(x + w + 1), (int)(y + h + 1)); -} - -static void -nk_gdi_stroke_line(HDC dc, short x0, short y0, short x1, - short y1, unsigned int line_thickness, struct nk_color col) -{ - COLORREF color = convert_color(col); - - HPEN pen = NULL; - if (line_thickness == 1) { - SetDCPenColor(dc, color); - } else { - pen = CreatePen(PS_SOLID, line_thickness, color); - SelectObject(dc, pen); - } - - MoveToEx(dc, x0, y0, NULL); - LineTo(dc, x1, y1); - - if (pen) { - SelectObject(dc, GetStockObject(DC_PEN)); - DeleteObject(pen); - } -} - -static void -nk_gdi_stroke_rect(HDC dc, short x, short y, unsigned short w, - unsigned short h, unsigned short r, unsigned short line_thickness, struct nk_color col) -{ - COLORREF color = convert_color(col); - - HPEN pen = NULL; - if (line_thickness == 1) { - SetDCPenColor(dc, color); - } else { - pen = CreatePen(PS_SOLID, line_thickness, color); - SelectObject(dc, pen); - } - - HGDIOBJ br = SelectObject(dc, GetStockObject(NULL_BRUSH)); - if (r == 0) { - Rectangle(dc, x, y, x + w, y + h); - } else { - RoundRect(dc, x, y, x + w, y + h, r, r); - } - SelectObject(dc, br); - - if (pen) { - SelectObject(dc, GetStockObject(DC_PEN)); - DeleteObject(pen); - } -} - -static void -nk_gdi_fill_rect(HDC dc, short x, short y, unsigned short w, - unsigned short h, unsigned short r, struct nk_color col) -{ - COLORREF color = convert_color(col); - - if (r == 0) { - RECT rect = { x, y, x + w, y + h }; - SetBkColor(dc, color); - ExtTextOutW(dc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL); - } else { - SetDCPenColor(dc, color); - SetDCBrushColor(dc, color); - RoundRect(dc, x, y, x + w, y + h, r, r); - } -} - -static void -nk_gdi_fill_triangle(HDC dc, short x0, short y0, short x1, - short y1, short x2, short y2, struct nk_color col) -{ - COLORREF color = convert_color(col); - POINT points[] = { - { x0, y0 }, - { x1, y1 }, - { x2, y2 }, - }; - - SetDCPenColor(dc, color); - SetDCBrushColor(dc, color); - Polygon(dc, points, 3); -} - -static void -nk_gdi_stroke_triangle(HDC dc, short x0, short y0, short x1, - short y1, short x2, short y2, unsigned short line_thickness, struct nk_color col) -{ - COLORREF color = convert_color(col); - POINT points[] = { - { x0, y0 }, - { x1, y1 }, - { x2, y2 }, - { x0, y0 }, - }; - - HPEN pen = NULL; - if (line_thickness == 1) { - SetDCPenColor(dc, color); - } else { - pen = CreatePen(PS_SOLID, line_thickness, color); - SelectObject(dc, pen); - } - - Polyline(dc, points, 4); - - if (pen) { - SelectObject(dc, GetStockObject(DC_PEN)); - DeleteObject(pen); - } -} - -static void -nk_gdi_fill_polygon(HDC dc, const struct nk_vec2i *pnts, int count, struct nk_color col) -{ - int i = 0; - #define MAX_POINTS 64 - POINT points[MAX_POINTS]; - COLORREF color = convert_color(col); - SetDCBrushColor(dc, color); - SetDCPenColor(dc, color); - for (i = 0; i < count && i < MAX_POINTS; ++i) { - points[i].x = pnts[i].x; - points[i].y = pnts[i].y; - } - Polygon(dc, points, i); - #undef MAX_POINTS -} - -static void -nk_gdi_stroke_polygon(HDC dc, const struct nk_vec2i *pnts, int count, - unsigned short line_thickness, struct nk_color col) -{ - COLORREF color = convert_color(col); - HPEN pen = NULL; - if (line_thickness == 1) { - SetDCPenColor(dc, color); - } else { - pen = CreatePen(PS_SOLID, line_thickness, color); - SelectObject(dc, pen); - } - - if (count > 0) { - int i; - MoveToEx(dc, pnts[0].x, pnts[0].y, NULL); - for (i = 1; i < count; ++i) - LineTo(dc, pnts[i].x, pnts[i].y); - LineTo(dc, pnts[0].x, pnts[0].y); - } - - if (pen) { - SelectObject(dc, GetStockObject(DC_PEN)); - DeleteObject(pen); - } -} - -static void -nk_gdi_stroke_polyline(HDC dc, const struct nk_vec2i *pnts, - int count, unsigned short line_thickness, struct nk_color col) -{ - COLORREF color = convert_color(col); - HPEN pen = NULL; - if (line_thickness == 1) { - SetDCPenColor(dc, color); - } else { - pen = CreatePen(PS_SOLID, line_thickness, color); - SelectObject(dc, pen); - } - - if (count > 0) { - int i; - MoveToEx(dc, pnts[0].x, pnts[0].y, NULL); - for (i = 1; i < count; ++i) - LineTo(dc, pnts[i].x, pnts[i].y); - } - - if (pen) { - SelectObject(dc, GetStockObject(DC_PEN)); - DeleteObject(pen); - } -} - -static void -nk_gdi_fill_circle(HDC dc, short x, short y, unsigned short w, - unsigned short h, struct nk_color col) -{ - COLORREF color = convert_color(col); - SetDCBrushColor(dc, color); - SetDCPenColor(dc, color); - Ellipse(dc, x, y, x + w, y + h); -} - -static void -nk_gdi_stroke_circle(HDC dc, short x, short y, unsigned short w, - unsigned short h, unsigned short line_thickness, struct nk_color col) -{ - COLORREF color = convert_color(col); - HPEN pen = NULL; - if (line_thickness == 1) { - SetDCPenColor(dc, color); - } else { - pen = CreatePen(PS_SOLID, line_thickness, color); - SelectObject(dc, pen); - } - - SetDCBrushColor(dc, OPAQUE); - Ellipse(dc, x, y, x + w, y + h); - - if (pen) { - SelectObject(dc, GetStockObject(DC_PEN)); - DeleteObject(pen); - } -} - -static void -nk_gdi_stroke_curve(HDC dc, struct nk_vec2i p1, - struct nk_vec2i p2, struct nk_vec2i p3, struct nk_vec2i p4, - unsigned short line_thickness, struct nk_color col) -{ - COLORREF color = convert_color(col); - POINT p[] = { - { p1.x, p1.y }, - { p2.x, p2.y }, - { p3.x, p3.y }, - { p4.x, p4.y }, - }; - - HPEN pen = NULL; - if (line_thickness == 1) { - SetDCPenColor(dc, color); - } else { - pen = CreatePen(PS_SOLID, line_thickness, color); - SelectObject(dc, pen); - } - - SetDCBrushColor(dc, OPAQUE); - PolyBezier(dc, p, 4); - - if (pen) { - SelectObject(dc, GetStockObject(DC_PEN)); - DeleteObject(pen); - } -} - -static void -nk_gdi_draw_text(HDC dc, short x, short y, unsigned short w, unsigned short h, - const char *text, int len, GdiFont *font, struct nk_color cbg, struct nk_color cfg) -{ - int wsize; - WCHAR* wstr; - - if(!text || !font || !len) return; - - wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0); - wstr = (WCHAR*)_alloca(wsize * sizeof(wchar_t)); - MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize); - - SetBkColor(dc, convert_color(cbg)); - SetTextColor(dc, convert_color(cfg)); - - SelectObject(dc, font->handle); - ExtTextOutW(dc, x, y, ETO_OPAQUE, NULL, wstr, wsize, NULL); -} - -static void -nk_gdi_clear(HDC dc, struct nk_color col) -{ - COLORREF color = convert_color(col); - RECT rect = { 0, 0, gdi.width, gdi.height }; - SetBkColor(dc, color); - - ExtTextOutW(dc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL); -} - -static void -nk_gdi_blit(HDC dc) -{ - BitBlt(dc, 0, 0, gdi.width, gdi.height, gdi.memory_dc, 0, 0, SRCCOPY); -} - -GdiFont* -nk_gdifont_create(const char *name, int size) -{ - TEXTMETRICW metric; - GdiFont *font = (GdiFont*)calloc(1, sizeof(GdiFont)); - if (!font) - return NULL; - font->dc = CreateCompatibleDC(0); - font->handle = CreateFont(size, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, name); - SelectObject(font->dc, font->handle); - GetTextMetricsW(font->dc, &metric); - font->height = metric.tmHeight; - return font; -} - -static float -nk_gdifont_get_text_width(nk_handle handle, float height, const char *text, int len) -{ - GdiFont *font = (GdiFont*)handle.ptr; - SIZE size; - int wsize; - WCHAR* wstr; - if (!font || !text) - return 0; - - wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0); - wstr = (WCHAR*)_alloca(wsize * sizeof(wchar_t)); - MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize); - if (GetTextExtentPoint32W(font->dc, wstr, wsize, &size)) - return (float)size.cx; - return -1.0f; -} - -void -nk_gdifont_del(GdiFont *font) -{ - if(!font) return; - DeleteObject(font->handle); - DeleteDC(font->dc); - free(font); -} - -static void -nk_gdi_clipbard_paste(nk_handle usr, struct nk_text_edit *edit) -{ - (void)usr; - if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL)) - { - HGLOBAL mem = GetClipboardData(CF_UNICODETEXT); - if (mem) - { - SIZE_T size = GlobalSize(mem) - 1; - if (size) - { - LPCWSTR wstr = (LPCWSTR)GlobalLock(mem); - if (wstr) - { - int utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), NULL, 0, NULL, NULL); - if (utf8size) - { - char* utf8 = (char*)malloc(utf8size); - if (utf8) - { - WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), utf8, utf8size, NULL, NULL); - nk_textedit_paste(edit, utf8, utf8size); - free(utf8); - } - } - GlobalUnlock(mem); - } - } - } - CloseClipboard(); - } -} - -static void -nk_gdi_clipbard_copy(nk_handle usr, const char *text, int len) -{ - if (OpenClipboard(NULL)) - { - int wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0); - if (wsize) - { - HGLOBAL mem = (HGLOBAL)GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t)); - if (mem) - { - wchar_t* wstr = (wchar_t*)GlobalLock(mem); - if (wstr) - { - MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize); - wstr[wsize] = 0; - GlobalUnlock(mem); - - SetClipboardData(CF_UNICODETEXT, mem); - } - } - } - CloseClipboard(); - } -} - -NK_API struct nk_context* -nk_gdi_init(GdiFont *gdifont, HDC window_dc, unsigned int width, unsigned int height) -{ - struct nk_user_font *font = &gdifont->nk; - font->userdata = nk_handle_ptr(gdifont); - font->height = (float)gdifont->height; - font->width = nk_gdifont_get_text_width; - - gdi.bitmap = CreateCompatibleBitmap(window_dc, width, height); - gdi.window_dc = window_dc; - gdi.memory_dc = CreateCompatibleDC(window_dc); - gdi.width = width; - gdi.height = height; - SelectObject(gdi.memory_dc, gdi.bitmap); - - nk_init_default(&gdi.ctx, font); - gdi.ctx.clip.copy = nk_gdi_clipbard_copy; - gdi.ctx.clip.paste = nk_gdi_clipbard_paste; - return &gdi.ctx; -} - -NK_API void -nk_gdi_set_font(GdiFont *gdifont) -{ - struct nk_user_font *font = &gdifont->nk; - font->userdata = nk_handle_ptr(gdifont); - font->height = (float)gdifont->height; - font->width = nk_gdifont_get_text_width; - nk_style_set_font(&gdi.ctx, font); -} - -NK_API int -nk_gdi_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) -{ - switch (msg) - { - case WM_SIZE: - { - unsigned width = LOWORD(lparam); - unsigned height = HIWORD(lparam); - if (width != gdi.width || height != gdi.height) - { - DeleteObject(gdi.bitmap); - gdi.bitmap = CreateCompatibleBitmap(gdi.window_dc, width, height); - gdi.width = width; - gdi.height = height; - SelectObject(gdi.memory_dc, gdi.bitmap); - } - break; - } - - case WM_PAINT: - { - PAINTSTRUCT paint; - HDC dc = BeginPaint(wnd, &paint); - nk_gdi_blit(dc); - EndPaint(wnd, &paint); - return 1; - } - - case WM_KEYDOWN: - case WM_KEYUP: - case WM_SYSKEYDOWN: - case WM_SYSKEYUP: - { - int down = !((lparam >> 31) & 1); - int ctrl = GetKeyState(VK_CONTROL) & (1 << 15); - - switch (wparam) - { - case VK_SHIFT: - case VK_LSHIFT: - case VK_RSHIFT: - nk_input_key(&gdi.ctx, NK_KEY_SHIFT, down); - return 1; - - case VK_DELETE: - nk_input_key(&gdi.ctx, NK_KEY_DEL, down); - return 1; - - case VK_RETURN: - nk_input_key(&gdi.ctx, NK_KEY_ENTER, down); - return 1; - - case VK_TAB: - nk_input_key(&gdi.ctx, NK_KEY_TAB, down); - return 1; - - case VK_LEFT: - if (ctrl) - nk_input_key(&gdi.ctx, NK_KEY_TEXT_WORD_LEFT, down); - else - nk_input_key(&gdi.ctx, NK_KEY_LEFT, down); - return 1; - - case VK_RIGHT: - if (ctrl) - nk_input_key(&gdi.ctx, NK_KEY_TEXT_WORD_RIGHT, down); - else - nk_input_key(&gdi.ctx, NK_KEY_RIGHT, down); - return 1; - - case VK_BACK: - nk_input_key(&gdi.ctx, NK_KEY_BACKSPACE, down); - return 1; - - case VK_HOME: - nk_input_key(&gdi.ctx, NK_KEY_TEXT_START, down); - nk_input_key(&gdi.ctx, NK_KEY_SCROLL_START, down); - return 1; - - case VK_END: - nk_input_key(&gdi.ctx, NK_KEY_TEXT_END, down); - nk_input_key(&gdi.ctx, NK_KEY_SCROLL_END, down); - return 1; - - case VK_NEXT: - nk_input_key(&gdi.ctx, NK_KEY_SCROLL_DOWN, down); - return 1; - - case VK_PRIOR: - nk_input_key(&gdi.ctx, NK_KEY_SCROLL_UP, down); - return 1; - - case 'C': - if (ctrl) { - nk_input_key(&gdi.ctx, NK_KEY_COPY, down); - return 1; - } - break; - - case 'V': - if (ctrl) { - nk_input_key(&gdi.ctx, NK_KEY_PASTE, down); - return 1; - } - break; - - case 'X': - if (ctrl) { - nk_input_key(&gdi.ctx, NK_KEY_CUT, down); - return 1; - } - break; - - case 'Z': - if (ctrl) { - nk_input_key(&gdi.ctx, NK_KEY_TEXT_UNDO, down); - return 1; - } - break; - - case 'R': - if (ctrl) { - nk_input_key(&gdi.ctx, NK_KEY_TEXT_REDO, down); - return 1; - } - break; - } - return 0; - } - - case WM_CHAR: - if (wparam >= 32) - { - nk_input_unicode(&gdi.ctx, (nk_rune)wparam); - return 1; - } - break; - - case WM_LBUTTONDOWN: - nk_input_button(&gdi.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1); - SetCapture(wnd); - return 1; - - case WM_LBUTTONUP: - nk_input_button(&gdi.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0); - nk_input_button(&gdi.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0); - ReleaseCapture(); - return 1; - - case WM_RBUTTONDOWN: - nk_input_button(&gdi.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1); - SetCapture(wnd); - return 1; - - case WM_RBUTTONUP: - nk_input_button(&gdi.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0); - ReleaseCapture(); - return 1; - - case WM_MBUTTONDOWN: - nk_input_button(&gdi.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1); - SetCapture(wnd); - return 1; - - case WM_MBUTTONUP: - nk_input_button(&gdi.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0); - ReleaseCapture(); - return 1; - - case WM_MOUSEWHEEL: - nk_input_scroll(&gdi.ctx, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA)); - return 1; - - case WM_MOUSEMOVE: - nk_input_motion(&gdi.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam)); - return 1; - - case WM_LBUTTONDBLCLK: - nk_input_button(&gdi.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1); - return 1; - } - - return 0; -} - -NK_API void -nk_gdi_shutdown(void) -{ - DeleteObject(gdi.memory_dc); - DeleteObject(gdi.bitmap); - nk_free(&gdi.ctx); -} - -NK_API void -nk_gdi_render(struct nk_color clear) -{ - const struct nk_command *cmd; - - HDC memory_dc = gdi.memory_dc; - SelectObject(memory_dc, GetStockObject(DC_PEN)); - SelectObject(memory_dc, GetStockObject(DC_BRUSH)); - nk_gdi_clear(memory_dc, clear); - - nk_foreach(cmd, &gdi.ctx) - { - switch (cmd->type) { - case NK_COMMAND_NOP: break; - case NK_COMMAND_SCISSOR: { - const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd; - nk_gdi_scissor(memory_dc, s->x, s->y, s->w, s->h); - } break; - case NK_COMMAND_LINE: { - const struct nk_command_line *l = (const struct nk_command_line *)cmd; - nk_gdi_stroke_line(memory_dc, l->begin.x, l->begin.y, l->end.x, - l->end.y, l->line_thickness, l->color); - } break; - case NK_COMMAND_RECT: { - const struct nk_command_rect *r = (const struct nk_command_rect *)cmd; - nk_gdi_stroke_rect(memory_dc, r->x, r->y, r->w, r->h, - (unsigned short)r->rounding, r->line_thickness, r->color); - } break; - case NK_COMMAND_RECT_FILLED: { - const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd; - nk_gdi_fill_rect(memory_dc, r->x, r->y, r->w, r->h, - (unsigned short)r->rounding, r->color); - } break; - case NK_COMMAND_CIRCLE: { - const struct nk_command_circle *c = (const struct nk_command_circle *)cmd; - nk_gdi_stroke_circle(memory_dc, c->x, c->y, c->w, c->h, c->line_thickness, c->color); - } break; - case NK_COMMAND_CIRCLE_FILLED: { - const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd; - nk_gdi_fill_circle(memory_dc, c->x, c->y, c->w, c->h, c->color); - } break; - case NK_COMMAND_TRIANGLE: { - const struct nk_command_triangle*t = (const struct nk_command_triangle*)cmd; - nk_gdi_stroke_triangle(memory_dc, t->a.x, t->a.y, t->b.x, t->b.y, - t->c.x, t->c.y, t->line_thickness, t->color); - } break; - case NK_COMMAND_TRIANGLE_FILLED: { - const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd; - nk_gdi_fill_triangle(memory_dc, t->a.x, t->a.y, t->b.x, t->b.y, - t->c.x, t->c.y, t->color); - } break; - case NK_COMMAND_POLYGON: { - const struct nk_command_polygon *p =(const struct nk_command_polygon*)cmd; - nk_gdi_stroke_polygon(memory_dc, p->points, p->point_count, p->line_thickness,p->color); - } break; - case NK_COMMAND_POLYGON_FILLED: { - const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd; - nk_gdi_fill_polygon(memory_dc, p->points, p->point_count, p->color); - } break; - case NK_COMMAND_POLYLINE: { - const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd; - nk_gdi_stroke_polyline(memory_dc, p->points, p->point_count, p->line_thickness, p->color); - } break; - case NK_COMMAND_TEXT: { - const struct nk_command_text *t = (const struct nk_command_text*)cmd; - nk_gdi_draw_text(memory_dc, t->x, t->y, t->w, t->h, - (const char*)t->string, t->length, - (GdiFont*)t->font->userdata.ptr, - t->background, t->foreground); - } break; - case NK_COMMAND_CURVE: { - const struct nk_command_curve *q = (const struct nk_command_curve *)cmd; - nk_gdi_stroke_curve(memory_dc, q->begin, q->ctrl[0], q->ctrl[1], - q->end, q->line_thickness, q->color); - } break; - case NK_COMMAND_RECT_MULTI_COLOR: - case NK_COMMAND_IMAGE: { - const struct nk_command_image *i = (const struct nk_command_image *)cmd; - nk_gdi_draw_image(i->x, i->y, i->w, i->h, i->img, i->col); - } break; - case NK_COMMAND_ARC: - case NK_COMMAND_ARC_FILLED: - default: break; - } - } - nk_gdi_blit(gdi.window_dc); - nk_clear(&gdi.ctx); -} - -#endif - diff --git a/subprojects/nk_pugl/nuklear/demo/gdip/build.bat b/subprojects/nk_pugl/nuklear/demo/gdip/build.bat deleted file mode 100644 index 0f24655..0000000 --- a/subprojects/nk_pugl/nuklear/demo/gdip/build.bat +++ /dev/null @@ -1,5 +0,0 @@ -@echo off - -call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86 - -cl /nologo /W3 /O2 /fp:fast /Gm- /Fedemo.exe /D_CRT_SECURE_NO_DEPRECATE main.c user32.lib gdiplus.lib shlwapi.lib /link /incremental:no diff --git a/subprojects/nk_pugl/nuklear/demo/gdip/main.c b/subprojects/nk_pugl/nuklear/demo/gdip/main.c deleted file mode 100644 index a90a0cf..0000000 --- a/subprojects/nk_pugl/nuklear/demo/gdip/main.c +++ /dev/null @@ -1,178 +0,0 @@ -/* nuklear - 1.32.0 - public domain */ -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include - -#define WINDOW_WIDTH 800 -#define WINDOW_HEIGHT 600 - -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_STANDARD_VARARGS -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_IMPLEMENTATION -#define NK_GDIP_IMPLEMENTATION -#include "../../nuklear.h" -#include "nuklear_gdip.h" - -/* =============================================================== - * - * EXAMPLE - * - * ===============================================================*/ -/* This are some code examples to provide a small overview of what can be - * done with this library. To try out an example uncomment the defines */ -/*#define INCLUDE_ALL */ -/*#define INCLUDE_STYLE */ -/*#define INCLUDE_CALCULATOR */ -/*#define INCLUDE_OVERVIEW */ -/*#define INCLUDE_NODE_EDITOR */ - -#ifdef INCLUDE_ALL - #define INCLUDE_STYLE - #define INCLUDE_CALCULATOR - #define INCLUDE_OVERVIEW - #define INCLUDE_NODE_EDITOR -#endif - -#ifdef INCLUDE_STYLE - #include "../style.c" -#endif -#ifdef INCLUDE_CALCULATOR - #include "../calculator.c" -#endif -#ifdef INCLUDE_OVERVIEW - #include "../overview.c" -#endif -#ifdef INCLUDE_NODE_EDITOR - #include "../node_editor.c" -#endif - -/* =============================================================== - * - * DEMO - * - * ===============================================================*/ -static LRESULT CALLBACK -WindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) -{ - switch (msg) { - case WM_DESTROY: - PostQuitMessage(0); - return 0; - } - if (nk_gdip_handle_event(wnd, msg, wparam, lparam)) - return 0; - return DefWindowProcW(wnd, msg, wparam, lparam); -} - -int main(void) -{ - GdipFont* font; - struct nk_context *ctx; - - WNDCLASSW wc; - RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT }; - DWORD style = WS_OVERLAPPEDWINDOW; - DWORD exstyle = WS_EX_APPWINDOW; - HWND wnd; - int running = 1; - int needs_refresh = 1; - - /* Win32 */ - memset(&wc, 0, sizeof(wc)); - wc.style = CS_DBLCLKS; - wc.lpfnWndProc = WindowProc; - wc.hInstance = GetModuleHandleW(0); - wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.lpszClassName = L"NuklearWindowClass"; - RegisterClassW(&wc); - - AdjustWindowRectEx(&rect, style, FALSE, exstyle); - - wnd = CreateWindowExW(exstyle, wc.lpszClassName, L"Nuklear Demo", - style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, - rect.right - rect.left, rect.bottom - rect.top, - NULL, NULL, wc.hInstance, NULL); - - /* GUI */ - ctx = nk_gdip_init(wnd, WINDOW_WIDTH, WINDOW_HEIGHT); - font = nk_gdipfont_create("Arial", 12); - nk_gdip_set_font(font); - - /* style.c */ - #ifdef INCLUDE_STYLE - /*set_style(ctx, THEME_WHITE);*/ - /*set_style(ctx, THEME_RED);*/ - /*set_style(ctx, THEME_BLUE);*/ - /*set_style(ctx, THEME_DARK);*/ - #endif - - while (running) - { - /* Input */ - MSG msg; - nk_input_begin(ctx); - if (needs_refresh == 0) { - if (GetMessageW(&msg, NULL, 0, 0) <= 0) - running = 0; - else { - TranslateMessage(&msg); - DispatchMessageW(&msg); - } - needs_refresh = 1; - } else needs_refresh = 0; - while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) { - if (msg.message == WM_QUIT) - running = 0; - TranslateMessage(&msg); - DispatchMessageW(&msg); - needs_refresh = 1; - } - nk_input_end(ctx); - - /* GUI */ - if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200), - NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE| - NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) - { - enum {EASY, HARD}; - static int op = EASY; - static int property = 20; - - nk_layout_row_static(ctx, 30, 80, 1); - if (nk_button_label(ctx, "button")) - fprintf(stdout, "button pressed\n"); - nk_layout_row_dynamic(ctx, 30, 2); - if (nk_option_label(ctx, "easy", op == EASY)) op = EASY; - if (nk_option_label(ctx, "hard", op == HARD)) op = HARD; - nk_layout_row_dynamic(ctx, 22, 1); - nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1); - } - nk_end(ctx); - - /* -------------- EXAMPLES ---------------- */ - #ifdef INCLUDE_CALCULATOR - calculator(ctx); - #endif - #ifdef INCLUDE_OVERVIEW - overview(ctx); - #endif - #ifdef INCLUDE_NODE_EDITOR - node_editor(ctx); - #endif - /* ----------------------------------------- */ - - /* Draw */ - nk_gdip_render(NK_ANTI_ALIASING_ON, nk_rgb(30,30,30)); - } - - nk_gdipfont_del(font); - nk_gdip_shutdown(); - UnregisterClassW(wc.lpszClassName, wc.hInstance); - return 0; -} diff --git a/subprojects/nk_pugl/nuklear/demo/gdip/nuklear_gdip.h b/subprojects/nk_pugl/nuklear/demo/gdip/nuklear_gdip.h deleted file mode 100644 index 8a6c8d4..0000000 --- a/subprojects/nk_pugl/nuklear/demo/gdip/nuklear_gdip.h +++ /dev/null @@ -1,1175 +0,0 @@ -/* - * Nuklear - 1.40.8 - public domain - * no warrenty implied; use at your own risk. - * authored from 2015-2017 by Micha Mettke - */ -/* - * ============================================================== - * - * API - * - * =============================================================== - */ -#ifndef NK_GDIP_H_ -#define NK_GDIP_H_ - -#define WIN32_LEAN_AND_MEAN -#include -#include - -/* font */ -typedef struct GdipFont GdipFont; -NK_API GdipFont* nk_gdipfont_create(const char *name, int size); -NK_API GdipFont* nk_gdipfont_create_from_file(const WCHAR* filename, int size); -NK_API GdipFont* nk_gdipfont_create_from_memory(const void* membuf, int membufSize, int size); -NK_API void nk_gdipfont_del(GdipFont *font); - -NK_API struct nk_context* nk_gdip_init(HWND hwnd, unsigned int width, unsigned int height); -NK_API void nk_gdip_set_font(GdipFont *font); -NK_API int nk_gdip_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); -NK_API void nk_gdip_render(enum nk_anti_aliasing AA, struct nk_color clear); -NK_API void nk_gdip_shutdown(void); - -/* image */ -NK_API struct nk_image nk_gdip_load_image_from_file(const WCHAR* filename); -NK_API struct nk_image nk_gdip_load_image_from_memory(const void* membuf, nk_uint membufSize); -NK_API void nk_gdip_image_free(struct nk_image image); - -#endif -/* - * ============================================================== - * - * IMPLEMENTATION - * - * =============================================================== - */ -#ifdef NK_GDIP_IMPLEMENTATION - -#include -#include - -/* manually declare everything GDI+ needs, because - GDI+ headers are not usable from C */ -#define WINGDIPAPI __stdcall -#define GDIPCONST const - -typedef struct GpGraphics GpGraphics; -typedef struct GpImage GpImage; -typedef struct GpPen GpPen; -typedef struct GpBrush GpBrush; -typedef struct GpStringFormat GpStringFormat; -typedef struct GpFont GpFont; -typedef struct GpFontFamily GpFontFamily; -typedef struct GpFontCollection GpFontCollection; - -typedef GpImage GpBitmap; -typedef GpBrush GpSolidFill; - -typedef int Status; -typedef Status GpStatus; - -typedef float REAL; -typedef DWORD ARGB; -typedef POINT GpPoint; - -typedef enum { - TextRenderingHintSystemDefault = 0, - TextRenderingHintSingleBitPerPixelGridFit = 1, - TextRenderingHintSingleBitPerPixel = 2, - TextRenderingHintAntiAliasGridFit = 3, - TextRenderingHintAntiAlias = 4, - TextRenderingHintClearTypeGridFit = 5 -} TextRenderingHint; - -typedef enum { - StringFormatFlagsDirectionRightToLeft = 0x00000001, - StringFormatFlagsDirectionVertical = 0x00000002, - StringFormatFlagsNoFitBlackBox = 0x00000004, - StringFormatFlagsDisplayFormatControl = 0x00000020, - StringFormatFlagsNoFontFallback = 0x00000400, - StringFormatFlagsMeasureTrailingSpaces = 0x00000800, - StringFormatFlagsNoWrap = 0x00001000, - StringFormatFlagsLineLimit = 0x00002000, - StringFormatFlagsNoClip = 0x00004000 -} StringFormatFlags; - -typedef enum -{ - QualityModeInvalid = -1, - QualityModeDefault = 0, - QualityModeLow = 1, - QualityModeHigh = 2 -} QualityMode; - -typedef enum -{ - SmoothingModeInvalid = QualityModeInvalid, - SmoothingModeDefault = QualityModeDefault, - SmoothingModeHighSpeed = QualityModeLow, - SmoothingModeHighQuality = QualityModeHigh, - SmoothingModeNone, - SmoothingModeAntiAlias, - SmoothingModeAntiAlias8x4 = SmoothingModeAntiAlias, - SmoothingModeAntiAlias8x8 -} SmoothingMode; - -typedef enum -{ - FontStyleRegular = 0, - FontStyleBold = 1, - FontStyleItalic = 2, - FontStyleBoldItalic = 3, - FontStyleUnderline = 4, - FontStyleStrikeout = 8 -} FontStyle; - -typedef enum { - FillModeAlternate, - FillModeWinding -} FillMode; - -typedef enum { - CombineModeReplace, - CombineModeIntersect, - CombineModeUnion, - CombineModeXor, - CombineModeExclude, - CombineModeComplement -} CombineMode; - -typedef enum { - UnitWorld, - UnitDisplay, - UnitPixel, - UnitPoint, - UnitInch, - UnitDocument, - UnitMillimeter -} Unit; - -typedef struct { - FLOAT X; - FLOAT Y; - FLOAT Width; - FLOAT Height; -} RectF; - -typedef enum { - DebugEventLevelFatal, - DebugEventLevelWarning -} DebugEventLevel; - -typedef VOID (WINAPI *DebugEventProc)(DebugEventLevel level, CHAR *message); - -typedef struct { - UINT32 GdiplusVersion; - DebugEventProc DebugEventCallback; - BOOL SuppressBackgroundThread; - BOOL SuppressExternalCodecs; -} GdiplusStartupInput; - -typedef Status (WINAPI *NotificationHookProc)(OUT ULONG_PTR *token); -typedef VOID (WINAPI *NotificationUnhookProc)(ULONG_PTR token); - -typedef struct { - NotificationHookProc NotificationHook; - NotificationUnhookProc NotificationUnhook; -} GdiplusStartupOutput; - -/* startup & shutdown */ - -Status WINAPI GdiplusStartup( - OUT ULONG_PTR *token, - const GdiplusStartupInput *input, - OUT GdiplusStartupOutput *output); - -VOID WINAPI GdiplusShutdown(ULONG_PTR token); - -/* image */ - -GpStatus WINGDIPAPI -GdipCreateBitmapFromGraphics(INT width, - INT height, - GpGraphics* target, - GpBitmap** bitmap); - -GpStatus WINGDIPAPI -GdipDisposeImage(GpImage *image); - -GpStatus WINGDIPAPI -GdipGetImageGraphicsContext(GpImage *image, GpGraphics **graphics); - -GpStatus WINGDIPAPI -GdipGetImageWidth(GpImage *image, UINT *width); - -GpStatus WINGDIPAPI -GdipGetImageHeight(GpImage *image, UINT *height); - -GpStatus WINGDIPAPI -GdipLoadImageFromFile(GDIPCONST WCHAR* filename, GpImage **image); - -GpStatus WINGDIPAPI -GdipLoadImageFromStream(IStream* stream, GpImage **image); - -/* pen */ - -GpStatus WINGDIPAPI -GdipCreatePen1(ARGB color, REAL width, Unit unit, GpPen **pen); - -GpStatus WINGDIPAPI -GdipDeletePen(GpPen *pen); - -GpStatus WINGDIPAPI -GdipSetPenWidth(GpPen *pen, REAL width); - -GpStatus WINGDIPAPI -GdipSetPenColor(GpPen *pen, ARGB argb); - -/* brush */ - -GpStatus WINGDIPAPI -GdipCreateSolidFill(ARGB color, GpSolidFill **brush); - -GpStatus WINGDIPAPI -GdipDeleteBrush(GpBrush *brush); - -GpStatus WINGDIPAPI -GdipSetSolidFillColor(GpSolidFill *brush, ARGB color); - -/* font */ - -GpStatus WINGDIPAPI -GdipCreateFont( - GDIPCONST GpFontFamily *fontFamily, - REAL emSize, - INT style, - Unit unit, - GpFont **font -); - -GpStatus WINGDIPAPI -GdipDeleteFont(GpFont* font); - -GpStatus WINGDIPAPI -GdipGetFontSize(GpFont *font, REAL *size); - -GpStatus WINGDIPAPI -GdipCreateFontFamilyFromName(GDIPCONST WCHAR *name, - GpFontCollection *fontCollection, - GpFontFamily **fontFamily); - -GpStatus WINGDIPAPI -GdipDeleteFontFamily(GpFontFamily *fontFamily); - -GpStatus WINGDIPAPI -GdipStringFormatGetGenericTypographic(GpStringFormat **format); - -GpStatus WINGDIPAPI -GdipSetStringFormatFlags(GpStringFormat *format, INT flags); - -GpStatus WINGDIPAPI -GdipDeleteStringFormat(GpStringFormat *format); - -GpStatus WINGDIPAPI -GdipPrivateAddMemoryFont(GpFontCollection* fontCollection, - GDIPCONST void* memory, INT length); - -GpStatus WINGDIPAPI -GdipPrivateAddFontFile(GpFontCollection* fontCollection, - GDIPCONST WCHAR* filename); - -GpStatus WINGDIPAPI -GdipNewPrivateFontCollection(GpFontCollection** fontCollection); - -GpStatus WINGDIPAPI -GdipDeletePrivateFontCollection(GpFontCollection** fontCollection); - -GpStatus WINGDIPAPI -GdipGetFontCollectionFamilyList(GpFontCollection* fontCollection, - INT numSought, GpFontFamily* gpfamilies[], INT* numFound); - -GpStatus WINGDIPAPI -GdipGetFontCollectionFamilyCount(GpFontCollection* fontCollection, INT* numFound); - - -/* graphics */ - - -GpStatus WINGDIPAPI -GdipCreateFromHWND(HWND hwnd, GpGraphics **graphics); - -GpStatus WINGDIPAPI -GdipCreateFromHDC(HDC hdc, GpGraphics **graphics); - -GpStatus WINGDIPAPI -GdipDeleteGraphics(GpGraphics *graphics); - -GpStatus WINGDIPAPI -GdipSetSmoothingMode(GpGraphics *graphics, SmoothingMode smoothingMode); - -GpStatus WINGDIPAPI -GdipSetClipRectI(GpGraphics *graphics, INT x, INT y, - INT width, INT height, CombineMode combineMode); - -GpStatus WINGDIPAPI -GdipDrawLineI(GpGraphics *graphics, GpPen *pen, INT x1, INT y1, - INT x2, INT y2); - -GpStatus WINGDIPAPI -GdipDrawArcI(GpGraphics *graphics, GpPen *pen, INT x, INT y, - INT width, INT height, REAL startAngle, REAL sweepAngle); - -GpStatus WINGDIPAPI -GdipFillPieI(GpGraphics *graphics, GpBrush *brush, INT x, INT y, - INT width, INT height, REAL startAngle, REAL sweepAngle); - -GpStatus WINGDIPAPI -GdipDrawRectangleI(GpGraphics *graphics, GpPen *pen, INT x, INT y, - INT width, INT height); - -GpStatus WINGDIPAPI -GdipFillRectangleI(GpGraphics *graphics, GpBrush *brush, INT x, INT y, - INT width, INT height); - -GpStatus WINGDIPAPI -GdipFillPolygonI(GpGraphics *graphics, GpBrush *brush, - GDIPCONST GpPoint *points, INT count, FillMode fillMode); - -GpStatus WINGDIPAPI -GdipDrawPolygonI(GpGraphics *graphics, GpPen *pen, GDIPCONST GpPoint *points, - INT count); - -GpStatus WINGDIPAPI -GdipFillEllipseI(GpGraphics *graphics, GpBrush *brush, INT x, INT y, - INT width, INT height); - -GpStatus WINGDIPAPI -GdipDrawEllipseI(GpGraphics *graphics, GpPen *pen, INT x, INT y, - INT width, INT height); - -GpStatus WINGDIPAPI -GdipDrawBezierI(GpGraphics *graphics, GpPen *pen, INT x1, INT y1, - INT x2, INT y2, INT x3, INT y3, INT x4, INT y4); - -GpStatus WINGDIPAPI -GdipDrawString( - GpGraphics *graphics, - GDIPCONST WCHAR *string, - INT length, - GDIPCONST GpFont *font, - GDIPCONST RectF *layoutRect, - GDIPCONST GpStringFormat *stringFormat, - GDIPCONST GpBrush *brush -); - -GpStatus WINGDIPAPI -GdipGraphicsClear(GpGraphics *graphics, ARGB color); - -GpStatus WINGDIPAPI -GdipDrawImageI(GpGraphics *graphics, GpImage *image, INT x, INT y); - -GpStatus WINGDIPAPI -GdipDrawImageRectI(GpGraphics *graphics, GpImage *image, INT x, INT y, - INT width, INT height); - -GpStatus WINGDIPAPI -GdipMeasureString( - GpGraphics *graphics, - GDIPCONST WCHAR *string, - INT length, - GDIPCONST GpFont *font, - GDIPCONST RectF *layoutRect, - GDIPCONST GpStringFormat *stringFormat, - RectF *boundingBox, - INT *codepointsFitted, - INT *linesFilled -); - -GpStatus WINGDIPAPI -GdipSetTextRenderingHint(GpGraphics *graphics, TextRenderingHint mode); - -LWSTDAPI_(IStream *) SHCreateMemStream(const BYTE *pInit, _In_ UINT cbInit); - -struct GdipFont -{ - struct nk_user_font nk; - GpFont* handle; -}; - -static struct { - ULONG_PTR token; - - GpGraphics *window; - GpGraphics *memory; - GpImage *bitmap; - GpPen *pen; - GpSolidFill *brush; - GpStringFormat *format; - GpFontCollection *fontCollection[10]; - INT curFontCollection; - - struct nk_context ctx; -} gdip; - -static ARGB convert_color(struct nk_color c) -{ - return (c.a << 24) | (c.r << 16) | (c.g << 8) | c.b; -} - -static void -nk_gdip_scissor(float x, float y, float w, float h) -{ - GdipSetClipRectI(gdip.memory, (INT)x, (INT)y, (INT)(w + 1), (INT)(h + 1), CombineModeReplace); -} - -static void -nk_gdip_stroke_line(short x0, short y0, short x1, - short y1, unsigned int line_thickness, struct nk_color col) -{ - GdipSetPenWidth(gdip.pen, (REAL)line_thickness); - GdipSetPenColor(gdip.pen, convert_color(col)); - GdipDrawLineI(gdip.memory, gdip.pen, x0, y0, x1, y1); -} - -static void -nk_gdip_stroke_rect(short x, short y, unsigned short w, - unsigned short h, unsigned short r, unsigned short line_thickness, struct nk_color col) -{ - GdipSetPenWidth(gdip.pen, (REAL)line_thickness); - GdipSetPenColor(gdip.pen, convert_color(col)); - if (r == 0) { - GdipDrawRectangleI(gdip.memory, gdip.pen, x, y, w, h); - } else { - INT d = 2 * r; - GdipDrawArcI(gdip.memory, gdip.pen, x, y, d, d, 180, 90); - GdipDrawLineI(gdip.memory, gdip.pen, x + r, y, x + w - r, y); - GdipDrawArcI(gdip.memory, gdip.pen, x + w - d, y, d, d, 270, 90); - GdipDrawLineI(gdip.memory, gdip.pen, x + w, y + r, x + w, y + h - r); - GdipDrawArcI(gdip.memory, gdip.pen, x + w - d, y + h - d, d, d, 0, 90); - GdipDrawLineI(gdip.memory, gdip.pen, x, y + r, x, y + h - r); - GdipDrawArcI(gdip.memory, gdip.pen, x, y + h - d, d, d, 90, 90); - GdipDrawLineI(gdip.memory, gdip.pen, x + r, y + h, x + w - r, y + h); - } -} - -static void -nk_gdip_fill_rect(short x, short y, unsigned short w, - unsigned short h, unsigned short r, struct nk_color col) -{ - GdipSetSolidFillColor(gdip.brush, convert_color(col)); - if (r == 0) { - GdipFillRectangleI(gdip.memory, gdip.brush, x, y, w, h); - } else { - INT d = 2 * r; - GdipFillRectangleI(gdip.memory, gdip.brush, x + r, y, w - d, h); - GdipFillRectangleI(gdip.memory, gdip.brush, x, y + r, r, h - d); - GdipFillRectangleI(gdip.memory, gdip.brush, x + w - r, y + r, r, h - d); - GdipFillPieI(gdip.memory, gdip.brush, x, y, d, d, 180, 90); - GdipFillPieI(gdip.memory, gdip.brush, x + w - d, y, d, d, 270, 90); - GdipFillPieI(gdip.memory, gdip.brush, x + w - d, y + h - d, d, d, 0, 90); - GdipFillPieI(gdip.memory, gdip.brush, x, y + h - d, d, d, 90, 90); - } -} - -static void -nk_gdip_fill_triangle(short x0, short y0, short x1, - short y1, short x2, short y2, struct nk_color col) -{ - POINT points[] = { - { x0, y0 }, - { x1, y1 }, - { x2, y2 }, - }; - - GdipSetSolidFillColor(gdip.brush, convert_color(col)); - GdipFillPolygonI(gdip.memory, gdip.brush, points, 3, FillModeAlternate); -} - -static void -nk_gdip_stroke_triangle(short x0, short y0, short x1, - short y1, short x2, short y2, unsigned short line_thickness, struct nk_color col) -{ - POINT points[] = { - { x0, y0 }, - { x1, y1 }, - { x2, y2 }, - { x0, y0 }, - }; - GdipSetPenWidth(gdip.pen, (REAL)line_thickness); - GdipSetPenColor(gdip.pen, convert_color(col)); - GdipDrawPolygonI(gdip.memory, gdip.pen, points, 4); -} - -static void -nk_gdip_fill_polygon(const struct nk_vec2i *pnts, int count, struct nk_color col) -{ - int i = 0; - #define MAX_POINTS 64 - POINT points[MAX_POINTS]; - GdipSetSolidFillColor(gdip.brush, convert_color(col)); - for (i = 0; i < count && i < MAX_POINTS; ++i) { - points[i].x = pnts[i].x; - points[i].y = pnts[i].y; - } - GdipFillPolygonI(gdip.memory, gdip.brush, points, i, FillModeAlternate); - #undef MAX_POINTS -} - -static void -nk_gdip_stroke_polygon(const struct nk_vec2i *pnts, int count, - unsigned short line_thickness, struct nk_color col) -{ - GdipSetPenWidth(gdip.pen, (REAL)line_thickness); - GdipSetPenColor(gdip.pen, convert_color(col)); - if (count > 0) { - int i; - for (i = 1; i < count; ++i) - GdipDrawLineI(gdip.memory, gdip.pen, pnts[i-1].x, pnts[i-1].y, pnts[i].x, pnts[i].y); - GdipDrawLineI(gdip.memory, gdip.pen, pnts[count-1].x, pnts[count-1].y, pnts[0].x, pnts[0].y); - } -} - -static void -nk_gdip_stroke_polyline(const struct nk_vec2i *pnts, - int count, unsigned short line_thickness, struct nk_color col) -{ - GdipSetPenWidth(gdip.pen, (REAL)line_thickness); - GdipSetPenColor(gdip.pen, convert_color(col)); - if (count > 0) { - int i; - for (i = 1; i < count; ++i) - GdipDrawLineI(gdip.memory, gdip.pen, pnts[i-1].x, pnts[i-1].y, pnts[i].x, pnts[i].y); - } -} - -static void -nk_gdip_fill_circle(short x, short y, unsigned short w, - unsigned short h, struct nk_color col) -{ - GdipSetSolidFillColor(gdip.brush, convert_color(col)); - GdipFillEllipseI(gdip.memory, gdip.brush, x, y, w, h); -} - -static void -nk_gdip_stroke_circle(short x, short y, unsigned short w, - unsigned short h, unsigned short line_thickness, struct nk_color col) -{ - GdipSetPenWidth(gdip.pen, (REAL)line_thickness); - GdipSetPenColor(gdip.pen, convert_color(col)); - GdipDrawEllipseI(gdip.memory, gdip.pen, x, y, w, h); -} - -static void -nk_gdip_stroke_curve(struct nk_vec2i p1, - struct nk_vec2i p2, struct nk_vec2i p3, struct nk_vec2i p4, - unsigned short line_thickness, struct nk_color col) -{ - GdipSetPenWidth(gdip.pen, (REAL)line_thickness); - GdipSetPenColor(gdip.pen, convert_color(col)); - GdipDrawBezierI(gdip.memory, gdip.pen, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y); -} - -static void -nk_gdip_draw_text(short x, short y, unsigned short w, unsigned short h, - const char *text, int len, GdipFont *font, struct nk_color cbg, struct nk_color cfg) -{ - int wsize; - WCHAR* wstr; - RectF layout = { (FLOAT)x, (FLOAT)y, (FLOAT)w, (FLOAT)h }; - - if(!text || !font || !len) return; - - wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0); - wstr = (WCHAR*)_alloca(wsize * sizeof(wchar_t)); - MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize); - - GdipSetSolidFillColor(gdip.brush, convert_color(cfg)); - GdipDrawString(gdip.memory, wstr, wsize, font->handle, &layout, gdip.format, gdip.brush); -} - -static void -nk_gdip_draw_image(short x, short y, unsigned short w, unsigned short h, - struct nk_image img, struct nk_color col) -{ - GpImage *image = img.handle.ptr; - GdipDrawImageRectI(gdip.memory, image, x, y, w, h); -} - -static void -nk_gdip_clear(struct nk_color col) -{ - GdipGraphicsClear(gdip.memory, convert_color(col)); -} - -static void -nk_gdip_blit(GpGraphics *graphics) -{ - GdipDrawImageI(graphics, gdip.bitmap, 0, 0); -} - -static struct nk_image -nk_gdip_image_to_nk(GpImage *image) { - struct nk_image img; - UINT uwidth, uheight; - img = nk_image_ptr( (void*)image ); - GdipGetImageHeight(image, &uheight); - GdipGetImageWidth(image, &uwidth); - img.h = uheight; - img.w = uwidth; - return img; -} - -struct nk_image -nk_gdip_load_image_from_file(const WCHAR *filename) -{ - GpImage *image; - if (GdipLoadImageFromFile(filename, &image)) - return nk_image_id(0); - return nk_gdip_image_to_nk(image); -} - -struct nk_image -nk_gdip_load_image_from_memory(const void *membuf, nk_uint membufSize) -{ - GpImage* image; - GpStatus status; - IStream *stream = SHCreateMemStream((const BYTE*)membuf, membufSize); - if (!stream) - return nk_image_id(0); - - status = GdipLoadImageFromStream(stream, &image); - stream->lpVtbl->Release(stream); - - if (status) - return nk_image_id(0); - - return nk_gdip_image_to_nk(image); -} - -void -nk_gdip_image_free(struct nk_image image) -{ - if (!image.handle.ptr) - return; - GdipDisposeImage(image.handle.ptr); -} - -GdipFont* -nk_gdipfont_create(const char *name, int size) -{ - GdipFont *font = (GdipFont*)calloc(1, sizeof(GdipFont)); - GpFontFamily *family; - - int wsize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0); - WCHAR* wname = (WCHAR*)_alloca((wsize + 1) * sizeof(wchar_t)); - MultiByteToWideChar(CP_UTF8, 0, name, -1, wname, wsize); - wname[wsize] = 0; - - GdipCreateFontFamilyFromName(wname, NULL, &family); - GdipCreateFont(family, (REAL)size, FontStyleRegular, UnitPixel, &font->handle); - GdipDeleteFontFamily(family); - - return font; -} - -GpFontCollection* -nk_gdip_getCurFontCollection(){ - return gdip.fontCollection[gdip.curFontCollection]; -} - -GdipFont* -nk_gdipfont_create_from_collection(int size){ - GpFontFamily **families; - INT count; - GdipFont *font = (GdipFont*)calloc(1, sizeof(GdipFont)); - if( GdipGetFontCollectionFamilyCount(nk_gdip_getCurFontCollection(), &count) ) return NULL; - families = (GpFontFamily**)calloc(1, sizeof(GpFontFamily*)); - if( !families ) return NULL; - if( GdipGetFontCollectionFamilyList(nk_gdip_getCurFontCollection(), count, families, &count) ) return NULL; - if( count < 1 ) return NULL; - if( GdipCreateFont(families[count-1], (REAL)size, FontStyleRegular, UnitPixel, &font->handle) ) return NULL; - free(families); - gdip.curFontCollection++; - return font; -} - -GdipFont* -nk_gdipfont_create_from_memory(const void* membuf, int membufSize, int size) -{ - if( !nk_gdip_getCurFontCollection() ) - if( GdipNewPrivateFontCollection(&gdip.fontCollection[gdip.curFontCollection]) ) return NULL; - if( GdipPrivateAddMemoryFont(nk_gdip_getCurFontCollection(), membuf, membufSize) ) return NULL; - return nk_gdipfont_create_from_collection(size); -} - -GdipFont* -nk_gdipfont_create_from_file(const WCHAR* filename, int size) -{ - if( !nk_gdip_getCurFontCollection() ) - if( GdipNewPrivateFontCollection(&gdip.fontCollection[gdip.curFontCollection]) ) return NULL; - if( GdipPrivateAddFontFile(nk_gdip_getCurFontCollection(), filename) ) return NULL; - return nk_gdipfont_create_from_collection(size); -} - -static float -nk_gdipfont_get_text_width(nk_handle handle, float height, const char *text, int len) -{ - GdipFont *font = (GdipFont *)handle.ptr; - RectF layout = { 0.0f, 0.0f, 65536.0f, 65536.0f }; - RectF bbox; - int wsize; - WCHAR* wstr; - if (!font || !text) - return 0; - - (void)height; - wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0); - wstr = (WCHAR*)_alloca(wsize * sizeof(wchar_t)); - MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize); - - GdipMeasureString(gdip.memory, wstr, wsize, font->handle, &layout, gdip.format, &bbox, NULL, NULL); - return bbox.Width; -} - -void -nk_gdipfont_del(GdipFont *font) -{ - if(!font) return; - GdipDeleteFont(font->handle); - free(font); -} - -static void -nk_gdip_clipbard_paste(nk_handle usr, struct nk_text_edit *edit) -{ - HGLOBAL mem; - SIZE_T size; - LPCWSTR wstr; - int utf8size; - char* utf8; - (void)usr; - - if (!IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL)) - return; - - mem = (HGLOBAL)GetClipboardData(CF_UNICODETEXT); - if (!mem) { - CloseClipboard(); - return; - } - - size = GlobalSize(mem) - 1; - if (!size) { - CloseClipboard(); - return; - } - - wstr = (LPCWSTR)GlobalLock(mem); - if (!wstr) { - CloseClipboard(); - return; - } - - utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), NULL, 0, NULL, NULL); - if (!utf8size) { - GlobalUnlock(mem); - CloseClipboard(); - return; - } - - utf8 = (char*)malloc(utf8size); - if (!utf8) { - GlobalUnlock(mem); - CloseClipboard(); - return; - } - - WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), utf8, utf8size, NULL, NULL); - nk_textedit_paste(edit, utf8, utf8size); - free(utf8); - GlobalUnlock(mem); - CloseClipboard(); -} - -static void -nk_gdip_clipbard_copy(nk_handle usr, const char *text, int len) -{ - HGLOBAL mem; - wchar_t* wstr; - int wsize; - (void)usr; - - if (!OpenClipboard(NULL)) - return; - - wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0); - if (!wsize) { - CloseClipboard(); - return; - } - - mem = (HGLOBAL)GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t)); - if (!mem) { - CloseClipboard(); - return; - } - - wstr = (wchar_t*)GlobalLock(mem); - if (!wstr) { - GlobalFree(mem); - CloseClipboard(); - return; - } - - MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize); - wstr[wsize] = 0; - GlobalUnlock(mem); - if (!SetClipboardData(CF_UNICODETEXT, mem)) - GlobalFree(mem); - CloseClipboard(); -} - -NK_API struct nk_context* -nk_gdip_init(HWND hwnd, unsigned int width, unsigned int height) -{ - int i; - GdiplusStartupInput startup = { 1, NULL, FALSE, TRUE }; - GdiplusStartup(&gdip.token, &startup, NULL); - - GdipCreateFromHWND(hwnd, &gdip.window); - GdipCreateBitmapFromGraphics(width, height, gdip.window, &gdip.bitmap); - GdipGetImageGraphicsContext(gdip.bitmap, &gdip.memory); - GdipCreatePen1(0, 1.0f, UnitPixel, &gdip.pen); - GdipCreateSolidFill(0, &gdip.brush); - GdipStringFormatGetGenericTypographic(&gdip.format); - GdipSetStringFormatFlags(gdip.format, StringFormatFlagsNoFitBlackBox | - StringFormatFlagsMeasureTrailingSpaces | StringFormatFlagsNoWrap | - StringFormatFlagsNoClip); - - for(i=0; i< sizeof(gdip.fontCollection)/sizeof(gdip.fontCollection[0]); i++) - gdip.fontCollection[i] = NULL; - nk_init_default(&gdip.ctx, NULL); - gdip.ctx.clip.copy = nk_gdip_clipbard_copy; - gdip.ctx.clip.paste = nk_gdip_clipbard_paste; - gdip.curFontCollection = 0; - return &gdip.ctx; -} - -NK_API void -nk_gdip_set_font(GdipFont *gdipfont) -{ - struct nk_user_font *font = &gdipfont->nk; - font->userdata = nk_handle_ptr(gdipfont); - GdipGetFontSize(gdipfont->handle, &font->height); - font->width = nk_gdipfont_get_text_width; - nk_style_set_font(&gdip.ctx, font); -} - -NK_API int -nk_gdip_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) -{ - switch (msg) - { - case WM_SIZE: - if (gdip.window) - { - unsigned int width = LOWORD(lparam); - unsigned int height = HIWORD(lparam); - GdipDeleteGraphics(gdip.window); - GdipDeleteGraphics(gdip.memory); - GdipDisposeImage(gdip.bitmap); - GdipCreateFromHWND(wnd, &gdip.window); - GdipCreateBitmapFromGraphics(width, height, gdip.window, &gdip.bitmap); - GdipGetImageGraphicsContext(gdip.bitmap, &gdip.memory); - } - break; - - case WM_PAINT: - { - PAINTSTRUCT paint; - HDC dc = BeginPaint(wnd, &paint); - GpGraphics *graphics; - GdipCreateFromHDC(dc, &graphics); - nk_gdip_blit(graphics); - GdipDeleteGraphics(graphics); - EndPaint(wnd, &paint); - return 1; - } - - case WM_KEYDOWN: - case WM_KEYUP: - case WM_SYSKEYDOWN: - case WM_SYSKEYUP: - { - int down = !((lparam >> 31) & 1); - int ctrl = GetKeyState(VK_CONTROL) & (1 << 15); - - switch (wparam) - { - case VK_SHIFT: - case VK_LSHIFT: - case VK_RSHIFT: - nk_input_key(&gdip.ctx, NK_KEY_SHIFT, down); - return 1; - - case VK_DELETE: - nk_input_key(&gdip.ctx, NK_KEY_DEL, down); - return 1; - - case VK_RETURN: - nk_input_key(&gdip.ctx, NK_KEY_ENTER, down); - return 1; - - case VK_TAB: - nk_input_key(&gdip.ctx, NK_KEY_TAB, down); - return 1; - - case VK_LEFT: - if (ctrl) - nk_input_key(&gdip.ctx, NK_KEY_TEXT_WORD_LEFT, down); - else - nk_input_key(&gdip.ctx, NK_KEY_LEFT, down); - return 1; - - case VK_RIGHT: - if (ctrl) - nk_input_key(&gdip.ctx, NK_KEY_TEXT_WORD_RIGHT, down); - else - nk_input_key(&gdip.ctx, NK_KEY_RIGHT, down); - return 1; - - case VK_BACK: - nk_input_key(&gdip.ctx, NK_KEY_BACKSPACE, down); - return 1; - - case VK_HOME: - nk_input_key(&gdip.ctx, NK_KEY_TEXT_START, down); - nk_input_key(&gdip.ctx, NK_KEY_SCROLL_START, down); - return 1; - - case VK_END: - nk_input_key(&gdip.ctx, NK_KEY_TEXT_END, down); - nk_input_key(&gdip.ctx, NK_KEY_SCROLL_END, down); - return 1; - - case VK_NEXT: - nk_input_key(&gdip.ctx, NK_KEY_SCROLL_DOWN, down); - return 1; - - case VK_PRIOR: - nk_input_key(&gdip.ctx, NK_KEY_SCROLL_UP, down); - return 1; - - case 'C': - if (ctrl) { - nk_input_key(&gdip.ctx, NK_KEY_COPY, down); - return 1; - } - break; - - case 'V': - if (ctrl) { - nk_input_key(&gdip.ctx, NK_KEY_PASTE, down); - return 1; - } - break; - - case 'X': - if (ctrl) { - nk_input_key(&gdip.ctx, NK_KEY_CUT, down); - return 1; - } - break; - - case 'Z': - if (ctrl) { - nk_input_key(&gdip.ctx, NK_KEY_TEXT_UNDO, down); - return 1; - } - break; - - case 'R': - if (ctrl) { - nk_input_key(&gdip.ctx, NK_KEY_TEXT_REDO, down); - return 1; - } - break; - } - return 0; - } - - case WM_CHAR: - if (wparam >= 32) - { - nk_input_unicode(&gdip.ctx, (nk_rune)wparam); - return 1; - } - break; - - case WM_LBUTTONDOWN: - nk_input_button(&gdip.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1); - SetCapture(wnd); - return 1; - - case WM_LBUTTONUP: - nk_input_button(&gdip.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0); - nk_input_button(&gdip.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0); - ReleaseCapture(); - return 1; - - case WM_RBUTTONDOWN: - nk_input_button(&gdip.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1); - SetCapture(wnd); - return 1; - - case WM_RBUTTONUP: - nk_input_button(&gdip.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0); - ReleaseCapture(); - return 1; - - case WM_MBUTTONDOWN: - nk_input_button(&gdip.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1); - SetCapture(wnd); - return 1; - - case WM_MBUTTONUP: - nk_input_button(&gdip.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0); - ReleaseCapture(); - return 1; - - case WM_MOUSEWHEEL: - nk_input_scroll(&gdip.ctx, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA)); - return 1; - - case WM_MOUSEMOVE: - nk_input_motion(&gdip.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam)); - return 1; - - case WM_LBUTTONDBLCLK: - nk_input_button(&gdip.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1); - return 1; - } - - return 0; -} - -NK_API void -nk_gdip_shutdown(void) -{ - int i; - for(i=0; i< gdip.curFontCollection; i++) - GdipDeletePrivateFontCollection( &gdip.fontCollection[i] ); - GdipDeleteGraphics(gdip.window); - GdipDeleteGraphics(gdip.memory); - GdipDisposeImage(gdip.bitmap); - GdipDeletePen(gdip.pen); - GdipDeleteBrush(gdip.brush); - GdipDeleteStringFormat(gdip.format); - GdiplusShutdown(gdip.token); - - nk_free(&gdip.ctx); -} - -NK_API void -nk_gdip_prerender_gui(enum nk_anti_aliasing AA) -{ - const struct nk_command *cmd; - - GdipSetTextRenderingHint(gdip.memory, AA != NK_ANTI_ALIASING_OFF ? - TextRenderingHintClearTypeGridFit : TextRenderingHintSingleBitPerPixelGridFit); - GdipSetSmoothingMode(gdip.memory, AA != NK_ANTI_ALIASING_OFF ? - SmoothingModeHighQuality : SmoothingModeNone); - - nk_foreach(cmd, &gdip.ctx) - { - switch (cmd->type) { - case NK_COMMAND_NOP: break; - case NK_COMMAND_SCISSOR: { - const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd; - nk_gdip_scissor(s->x, s->y, s->w, s->h); - } break; - case NK_COMMAND_LINE: { - const struct nk_command_line *l = (const struct nk_command_line *)cmd; - nk_gdip_stroke_line(l->begin.x, l->begin.y, l->end.x, - l->end.y, l->line_thickness, l->color); - } break; - case NK_COMMAND_RECT: { - const struct nk_command_rect *r = (const struct nk_command_rect *)cmd; - nk_gdip_stroke_rect(r->x, r->y, r->w, r->h, - (unsigned short)r->rounding, r->line_thickness, r->color); - } break; - case NK_COMMAND_RECT_FILLED: { - const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd; - nk_gdip_fill_rect(r->x, r->y, r->w, r->h, - (unsigned short)r->rounding, r->color); - } break; - case NK_COMMAND_CIRCLE: { - const struct nk_command_circle *c = (const struct nk_command_circle *)cmd; - nk_gdip_stroke_circle(c->x, c->y, c->w, c->h, c->line_thickness, c->color); - } break; - case NK_COMMAND_CIRCLE_FILLED: { - const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd; - nk_gdip_fill_circle(c->x, c->y, c->w, c->h, c->color); - } break; - case NK_COMMAND_TRIANGLE: { - const struct nk_command_triangle*t = (const struct nk_command_triangle*)cmd; - nk_gdip_stroke_triangle(t->a.x, t->a.y, t->b.x, t->b.y, - t->c.x, t->c.y, t->line_thickness, t->color); - } break; - case NK_COMMAND_TRIANGLE_FILLED: { - const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd; - nk_gdip_fill_triangle(t->a.x, t->a.y, t->b.x, t->b.y, - t->c.x, t->c.y, t->color); - } break; - case NK_COMMAND_POLYGON: { - const struct nk_command_polygon *p =(const struct nk_command_polygon*)cmd; - nk_gdip_stroke_polygon(p->points, p->point_count, p->line_thickness,p->color); - } break; - case NK_COMMAND_POLYGON_FILLED: { - const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd; - nk_gdip_fill_polygon(p->points, p->point_count, p->color); - } break; - case NK_COMMAND_POLYLINE: { - const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd; - nk_gdip_stroke_polyline(p->points, p->point_count, p->line_thickness, p->color); - } break; - case NK_COMMAND_TEXT: { - const struct nk_command_text *t = (const struct nk_command_text*)cmd; - nk_gdip_draw_text(t->x, t->y, t->w, t->h, - (const char*)t->string, t->length, - (GdipFont*)t->font->userdata.ptr, - t->background, t->foreground); - } break; - case NK_COMMAND_CURVE: { - const struct nk_command_curve *q = (const struct nk_command_curve *)cmd; - nk_gdip_stroke_curve(q->begin, q->ctrl[0], q->ctrl[1], - q->end, q->line_thickness, q->color); - } break; - case NK_COMMAND_IMAGE: { - const struct nk_command_image *i = (const struct nk_command_image *)cmd; - nk_gdip_draw_image(i->x, i->y, i->w, i->h, i->img, i->col); - } break; - case NK_COMMAND_RECT_MULTI_COLOR: - case NK_COMMAND_ARC: - case NK_COMMAND_ARC_FILLED: - default: break; - } - } -} - -NK_API void -nk_gdip_render_gui(enum nk_anti_aliasing AA) -{ - nk_gdip_prerender_gui(AA); - nk_gdip_blit(gdip.window); - nk_clear(&gdip.ctx); -} - -NK_API void -nk_gdip_render(enum nk_anti_aliasing AA, struct nk_color clear) -{ - nk_gdip_clear(clear); - nk_gdip_render_gui(AA); -} - -#endif diff --git a/subprojects/nk_pugl/nuklear/demo/glfw_opengl2/Makefile b/subprojects/nk_pugl/nuklear/demo/glfw_opengl2/Makefile deleted file mode 100644 index c08d65f..0000000 --- a/subprojects/nk_pugl/nuklear/demo/glfw_opengl2/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -# Install -BIN = demo - -# Flags -CFLAGS += -std=c99 -pedantic -O2 - -SRC = main.c -OBJ = $(SRC:.c=.o) - -ifeq ($(OS),Windows_NT) -BIN := $(BIN).exe -LIBS = -lglfw3 -lopengl32 -lm -lGLU32 -else - UNAME_S := $(shell uname -s) - ifeq ($(UNAME_S),Darwin) - LIBS := -lglfw3 -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo -lm -lGLEW -L/usr/local/lib - else - LIBS = -lglfw -lGL -lm -lGLU - endif -endif - -$(BIN): - @mkdir -p bin - rm -f bin/$(BIN) $(OBJS) - $(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS) diff --git a/subprojects/nk_pugl/nuklear/demo/glfw_opengl2/main.c b/subprojects/nk_pugl/nuklear/demo/glfw_opengl2/main.c deleted file mode 100644 index 5d68bb9..0000000 --- a/subprojects/nk_pugl/nuklear/demo/glfw_opengl2/main.c +++ /dev/null @@ -1,182 +0,0 @@ -/* nuklear - v1.32.0 - public domain */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_STANDARD_VARARGS -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT -#define NK_INCLUDE_FONT_BAKING -#define NK_INCLUDE_DEFAULT_FONT -#define NK_IMPLEMENTATION -#define NK_GLFW_GL2_IMPLEMENTATION -#include "../../nuklear.h" -#include "nuklear_glfw_gl2.h" - -#define WINDOW_WIDTH 1200 -#define WINDOW_HEIGHT 800 - -/* =============================================================== - * - * EXAMPLE - * - * ===============================================================*/ -/* This are some code examples to provide a small overview of what can be - * done with this library. To try out an example uncomment the defines */ -/*#define INCLUDE_ALL */ -/*#define INCLUDE_STYLE */ -/*#define INCLUDE_CALCULATOR */ -/*#define INCLUDE_OVERVIEW */ -/*#define INCLUDE_NODE_EDITOR */ - -#ifdef INCLUDE_ALL - #define INCLUDE_STYLE - #define INCLUDE_CALCULATOR - #define INCLUDE_OVERVIEW - #define INCLUDE_NODE_EDITOR -#endif - -#ifdef INCLUDE_STYLE - #include "../style.c" -#endif -#ifdef INCLUDE_CALCULATOR - #include "../calculator.c" -#endif -#ifdef INCLUDE_OVERVIEW - #include "../overview.c" -#endif -#ifdef INCLUDE_NODE_EDITOR - #include "../node_editor.c" -#endif - -/* =============================================================== - * - * DEMO - * - * ===============================================================*/ -static void error_callback(int e, const char *d) -{printf("Error %d: %s\n", e, d);} - -int main(void) -{ - /* Platform */ - static GLFWwindow *win; - int width = 0, height = 0; - struct nk_context *ctx; - struct nk_colorf bg; - - /* GLFW */ - glfwSetErrorCallback(error_callback); - if (!glfwInit()) { - fprintf(stdout, "[GFLW] failed to init!\n"); - exit(1); - } - win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL); - glfwMakeContextCurrent(win); - glfwGetWindowSize(win, &width, &height); - - /* GUI */ - ctx = nk_glfw3_init(win, NK_GLFW3_INSTALL_CALLBACKS); - /* Load Fonts: if none of these are loaded a default font will be used */ - /* Load Cursor: if you uncomment cursor loading please hide the cursor */ - {struct nk_font_atlas *atlas; - nk_glfw3_font_stash_begin(&atlas); - /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/ - /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 14, 0);*/ - /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/ - /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/ - /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/ - /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/ - nk_glfw3_font_stash_end(); - /*nk_style_load_all_cursors(ctx, atlas->cursors);*/ - /*nk_style_set_font(ctx, &droid->handle);*/} - - #ifdef INCLUDE_STYLE - /*set_style(ctx, THEME_WHITE);*/ - /*set_style(ctx, THEME_RED);*/ - /*set_style(ctx, THEME_BLUE);*/ - /*set_style(ctx, THEME_DARK);*/ - #endif - - bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f; - while (!glfwWindowShouldClose(win)) - { - /* Input */ - glfwPollEvents(); - nk_glfw3_new_frame(); - - /* GUI */ - if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250), - NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE| - NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) - { - enum {EASY, HARD}; - static int op = EASY; - static int property = 20; - nk_layout_row_static(ctx, 30, 80, 1); - if (nk_button_label(ctx, "button")) - fprintf(stdout, "button pressed\n"); - - nk_layout_row_dynamic(ctx, 30, 2); - if (nk_option_label(ctx, "easy", op == EASY)) op = EASY; - if (nk_option_label(ctx, "hard", op == HARD)) op = HARD; - - nk_layout_row_dynamic(ctx, 25, 1); - nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1); - - nk_layout_row_dynamic(ctx, 20, 1); - nk_label(ctx, "background:", NK_TEXT_LEFT); - nk_layout_row_dynamic(ctx, 25, 1); - if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) { - nk_layout_row_dynamic(ctx, 120, 1); - bg = nk_color_picker(ctx, bg, NK_RGBA); - nk_layout_row_dynamic(ctx, 25, 1); - bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f); - bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f); - bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f); - bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f); - nk_combo_end(ctx); - } - } - nk_end(ctx); - - /* -------------- EXAMPLES ---------------- */ - #ifdef INCLUDE_CALCULATOR - calculator(ctx); - #endif - #ifdef INCLUDE_OVERVIEW - overview(ctx); - #endif - #ifdef INCLUDE_NODE_EDITOR - node_editor(ctx); - #endif - /* ----------------------------------------- */ - - /* Draw */ - glfwGetWindowSize(win, &width, &height); - glViewport(0, 0, width, height); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(bg.r, bg.g, bg.b, bg.a); - /* IMPORTANT: `nk_glfw_render` modifies some global OpenGL state - * with blending, scissor, face culling and depth test and defaults everything - * back into a default state. Make sure to either save and restore or - * reset your own state after drawing rendering the UI. */ - nk_glfw3_render(NK_ANTI_ALIASING_ON); - glfwSwapBuffers(win); - } - nk_glfw3_shutdown(); - glfwTerminate(); - return 0; -} - diff --git a/subprojects/nk_pugl/nuklear/demo/glfw_opengl2/nuklear_glfw_gl2.h b/subprojects/nk_pugl/nuklear/demo/glfw_opengl2/nuklear_glfw_gl2.h deleted file mode 100644 index 7724b25..0000000 --- a/subprojects/nk_pugl/nuklear/demo/glfw_opengl2/nuklear_glfw_gl2.h +++ /dev/null @@ -1,381 +0,0 @@ -/* - * Nuklear - v1.32.0 - public domain - * no warrenty implied; use at your own risk. - * authored from 2015-2017 by Micha Mettke - */ -/* - * ============================================================== - * - * API - * - * =============================================================== - */ -#ifndef NK_GLFW_GL2_H_ -#define NK_GLFW_GL2_H_ - -#include - -enum nk_glfw_init_state{ - NK_GLFW3_DEFAULT = 0, - NK_GLFW3_INSTALL_CALLBACKS -}; -NK_API struct nk_context* nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state); -NK_API void nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas); -NK_API void nk_glfw3_font_stash_end(void); - -NK_API void nk_glfw3_new_frame(void); -NK_API void nk_glfw3_render(enum nk_anti_aliasing); -NK_API void nk_glfw3_shutdown(void); - -NK_API void nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint); -NK_API void nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff); - -#endif - -/* - * ============================================================== - * - * IMPLEMENTATION - * - * =============================================================== - */ -#ifdef NK_GLFW_GL2_IMPLEMENTATION - -#ifndef NK_GLFW_TEXT_MAX -#define NK_GLFW_TEXT_MAX 256 -#endif -#ifndef NK_GLFW_DOUBLE_CLICK_LO -#define NK_GLFW_DOUBLE_CLICK_LO 0.02 -#endif -#ifndef NK_GLFW_DOUBLE_CLICK_HI -#define NK_GLFW_DOUBLE_CLICK_HI 0.2 -#endif - -struct nk_glfw_device { - struct nk_buffer cmds; - struct nk_draw_null_texture null; - GLuint font_tex; -}; - -struct nk_glfw_vertex { - float position[2]; - float uv[2]; - nk_byte col[4]; -}; - -static struct nk_glfw { - GLFWwindow *win; - int width, height; - int display_width, display_height; - struct nk_glfw_device ogl; - struct nk_context ctx; - struct nk_font_atlas atlas; - struct nk_vec2 fb_scale; - unsigned int text[NK_GLFW_TEXT_MAX]; - int text_len; - struct nk_vec2 scroll; - double last_button_click; - int is_double_click_down; - struct nk_vec2 double_click_pos; -} glfw; - -NK_INTERN void -nk_glfw3_device_upload_atlas(const void *image, int width, int height) -{ - struct nk_glfw_device *dev = &glfw.ogl; - glGenTextures(1, &dev->font_tex); - glBindTexture(GL_TEXTURE_2D, dev->font_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, image); -} - -NK_API void -nk_glfw3_render(enum nk_anti_aliasing AA) -{ - /* setup global state */ - struct nk_glfw_device *dev = &glfw.ogl; - glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT|GL_TRANSFORM_BIT); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glEnable(GL_SCISSOR_TEST); - glEnable(GL_BLEND); - glEnable(GL_TEXTURE_2D); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - /* setup viewport/project */ - glViewport(0,0,(GLsizei)glfw.display_width,(GLsizei)glfw.display_height); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(0.0f, glfw.width, glfw.height, 0.0f, -1.0f, 1.0f); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - { - GLsizei vs = sizeof(struct nk_glfw_vertex); - size_t vp = offsetof(struct nk_glfw_vertex, position); - size_t vt = offsetof(struct nk_glfw_vertex, uv); - size_t vc = offsetof(struct nk_glfw_vertex, col); - - /* convert from command queue into draw list and draw to screen */ - const struct nk_draw_command *cmd; - const nk_draw_index *offset = NULL; - struct nk_buffer vbuf, ebuf; - - /* fill convert configuration */ - struct nk_convert_config config; - static const struct nk_draw_vertex_layout_element vertex_layout[] = { - {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)}, - {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)}, - {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)}, - {NK_VERTEX_LAYOUT_END} - }; - NK_MEMSET(&config, 0, sizeof(config)); - config.vertex_layout = vertex_layout; - config.vertex_size = sizeof(struct nk_glfw_vertex); - config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex); - config.null = dev->null; - config.circle_segment_count = 22; - config.curve_segment_count = 22; - config.arc_segment_count = 22; - config.global_alpha = 1.0f; - config.shape_AA = AA; - config.line_AA = AA; - - /* convert shapes into vertexes */ - nk_buffer_init_default(&vbuf); - nk_buffer_init_default(&ebuf); - nk_convert(&glfw.ctx, &dev->cmds, &vbuf, &ebuf, &config); - - /* setup vertex buffer pointer */ - {const void *vertices = nk_buffer_memory_const(&vbuf); - glVertexPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vp)); - glTexCoordPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vt)); - glColorPointer(4, GL_UNSIGNED_BYTE, vs, (const void*)((const nk_byte*)vertices + vc));} - - /* iterate over and execute each draw command */ - offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf); - nk_draw_foreach(cmd, &glfw.ctx, &dev->cmds) - { - if (!cmd->elem_count) continue; - glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); - glScissor( - (GLint)(cmd->clip_rect.x * glfw.fb_scale.x), - (GLint)((glfw.height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * glfw.fb_scale.y), - (GLint)(cmd->clip_rect.w * glfw.fb_scale.x), - (GLint)(cmd->clip_rect.h * glfw.fb_scale.y)); - glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); - offset += cmd->elem_count; - } - nk_clear(&glfw.ctx); - nk_buffer_free(&vbuf); - nk_buffer_free(&ebuf); - } - - /* default OpenGL state */ - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - - glBindTexture(GL_TEXTURE_2D, 0); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glPopAttrib(); -} - -NK_API void -nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint) -{ - (void)win; - if (glfw.text_len < NK_GLFW_TEXT_MAX) - glfw.text[glfw.text_len++] = codepoint; -} - -NK_API void -nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff) -{ - (void)win; (void)xoff; - glfw.scroll.x += (float)xoff; - glfw.scroll.y += (float)yoff; -} - -NK_API void -nk_glfw3_mouse_button_callback(GLFWwindow* window, int button, int action, int mods) -{ - double x, y; - if (button != GLFW_MOUSE_BUTTON_LEFT) return; - glfwGetCursorPos(window, &x, &y); - if (action == GLFW_PRESS) { - double dt = glfwGetTime() - glfw.last_button_click; - if (dt > NK_GLFW_DOUBLE_CLICK_LO && dt < NK_GLFW_DOUBLE_CLICK_HI) { - glfw.is_double_click_down = nk_true; - glfw.double_click_pos = nk_vec2((float)x, (float)y); - } - glfw.last_button_click = glfwGetTime(); - } else glfw.is_double_click_down = nk_false; -} - -NK_INTERN void -nk_glfw3_clipbard_paste(nk_handle usr, struct nk_text_edit *edit) -{ - const char *text = glfwGetClipboardString(glfw.win); - if (text) nk_textedit_paste(edit, text, nk_strlen(text)); - (void)usr; -} - -NK_INTERN void -nk_glfw3_clipbard_copy(nk_handle usr, const char *text, int len) -{ - char *str = 0; - (void)usr; - if (!len) return; - str = (char*)malloc((size_t)len+1); - if (!str) return; - memcpy(str, text, (size_t)len); - str[len] = '\0'; - glfwSetClipboardString(glfw.win, str); - free(str); -} - -NK_API struct nk_context* -nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state init_state) -{ - glfw.win = win; - if (init_state == NK_GLFW3_INSTALL_CALLBACKS) { - glfwSetScrollCallback(win, nk_gflw3_scroll_callback); - glfwSetCharCallback(win, nk_glfw3_char_callback); - glfwSetMouseButtonCallback(win, nk_glfw3_mouse_button_callback); - } - nk_init_default(&glfw.ctx, 0); - glfw.ctx.clip.copy = nk_glfw3_clipbard_copy; - glfw.ctx.clip.paste = nk_glfw3_clipbard_paste; - glfw.ctx.clip.userdata = nk_handle_ptr(0); - nk_buffer_init_default(&glfw.ogl.cmds); - - glfw.is_double_click_down = nk_false; - glfw.double_click_pos = nk_vec2(0, 0); - - return &glfw.ctx; -} - -NK_API void -nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas) -{ - nk_font_atlas_init_default(&glfw.atlas); - nk_font_atlas_begin(&glfw.atlas); - *atlas = &glfw.atlas; -} - -NK_API void -nk_glfw3_font_stash_end(void) -{ - const void *image; int w, h; - image = nk_font_atlas_bake(&glfw.atlas, &w, &h, NK_FONT_ATLAS_RGBA32); - nk_glfw3_device_upload_atlas(image, w, h); - nk_font_atlas_end(&glfw.atlas, nk_handle_id((int)glfw.ogl.font_tex), &glfw.ogl.null); - if (glfw.atlas.default_font) - nk_style_set_font(&glfw.ctx, &glfw.atlas.default_font->handle); -} - -NK_API void -nk_glfw3_new_frame(void) -{ - int i; - double x, y; - struct nk_context *ctx = &glfw.ctx; - struct GLFWwindow *win = glfw.win; - - glfwGetWindowSize(win, &glfw.width, &glfw.height); - glfwGetFramebufferSize(win, &glfw.display_width, &glfw.display_height); - glfw.fb_scale.x = (float)glfw.display_width/(float)glfw.width; - glfw.fb_scale.y = (float)glfw.display_height/(float)glfw.height; - - nk_input_begin(ctx); - for (i = 0; i < glfw.text_len; ++i) - nk_input_unicode(ctx, glfw.text[i]); - - /* optional grabbing behavior */ - if (ctx->input.mouse.grab) - glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); - else if (ctx->input.mouse.ungrab) - glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - - nk_input_key(ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_SCROLL_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_SCROLL_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_SCROLL_DOWN, glfwGetKey(win, GLFW_KEY_PAGE_DOWN) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_SCROLL_UP, glfwGetKey(win, GLFW_KEY_PAGE_UP) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_SHIFT, glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS|| - glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS); - - if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || - glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) { - nk_input_key(ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_V) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_UNDO, glfwGetKey(win, GLFW_KEY_Z) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_REDO, glfwGetKey(win, GLFW_KEY_R) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_LINE_START, glfwGetKey(win, GLFW_KEY_B) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_LINE_END, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS); - } else { - nk_input_key(ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_COPY, 0); - nk_input_key(ctx, NK_KEY_PASTE, 0); - nk_input_key(ctx, NK_KEY_CUT, 0); - nk_input_key(ctx, NK_KEY_SHIFT, 0); - } - - glfwGetCursorPos(win, &x, &y); - nk_input_motion(ctx, (int)x, (int)y); - if (ctx->input.mouse.grabbed) { - glfwSetCursorPos(glfw.win, (double)ctx->input.mouse.prev.x, (double)ctx->input.mouse.prev.y); - ctx->input.mouse.pos.x = ctx->input.mouse.prev.x; - ctx->input.mouse.pos.y = ctx->input.mouse.prev.y; - } - - nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); - nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS); - nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS); - nk_input_button(ctx, NK_BUTTON_DOUBLE, (int)glfw.double_click_pos.x, (int)glfw.double_click_pos.y, glfw.is_double_click_down); - nk_input_scroll(ctx, glfw.scroll); - nk_input_end(&glfw.ctx); - glfw.text_len = 0; - glfw.scroll = nk_vec2(0,0); -} - -NK_API -void nk_glfw3_shutdown(void) -{ - struct nk_glfw_device *dev = &glfw.ogl; - nk_font_atlas_clear(&glfw.atlas); - nk_free(&glfw.ctx); - glDeleteTextures(1, &dev->font_tex); - nk_buffer_free(&dev->cmds); - memset(&glfw, 0, sizeof(glfw)); -} - -#endif diff --git a/subprojects/nk_pugl/nuklear/demo/glfw_opengl3/Makefile b/subprojects/nk_pugl/nuklear/demo/glfw_opengl3/Makefile deleted file mode 100644 index da95261..0000000 --- a/subprojects/nk_pugl/nuklear/demo/glfw_opengl3/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -# Install -BIN = demo - -# Flags -CFLAGS += -std=c99 -pedantic -O2 - -SRC = main.c -OBJ = $(SRC:.c=.o) - -ifeq ($(OS),Windows_NT) -BIN := $(BIN).exe -LIBS = -lglfw3 -lopengl32 -lm -lGLU32 -lGLEW32 -else - UNAME_S := $(shell uname -s) - GLFW3 := $(shell pkg-config --libs glfw3) - ifeq ($(UNAME_S),Darwin) - LIBS := $(GLFW3) -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo -lm -lGLEW -L/usr/local/lib - else - LIBS = $(GLFW3) -lGL -lm -lGLU -lGLEW - endif -endif - -$(BIN): - @mkdir -p bin - rm -f bin/$(BIN) $(OBJS) - $(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS) diff --git a/subprojects/nk_pugl/nuklear/demo/glfw_opengl3/main.c b/subprojects/nk_pugl/nuklear/demo/glfw_opengl3/main.c deleted file mode 100644 index 529e88c..0000000 --- a/subprojects/nk_pugl/nuklear/demo/glfw_opengl3/main.c +++ /dev/null @@ -1,200 +0,0 @@ -/* nuklear - 1.32.0 - public domain */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_STANDARD_VARARGS -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT -#define NK_INCLUDE_FONT_BAKING -#define NK_INCLUDE_DEFAULT_FONT -#define NK_IMPLEMENTATION -#define NK_GLFW_GL3_IMPLEMENTATION -#include "../../nuklear.h" -#include "nuklear_glfw_gl3.h" - -#define WINDOW_WIDTH 1200 -#define WINDOW_HEIGHT 800 - -#define MAX_VERTEX_BUFFER 512 * 1024 -#define MAX_ELEMENT_BUFFER 128 * 1024 - -/* =============================================================== - * - * EXAMPLE - * - * ===============================================================*/ -/* This are some code examples to provide a small overview of what can be - * done with this library. To try out an example uncomment the defines */ -/*#define INCLUDE_ALL */ -/*#define INCLUDE_STYLE */ -/*#define INCLUDE_CALCULATOR */ -/*#define INCLUDE_OVERVIEW */ -/*#define INCLUDE_NODE_EDITOR */ - -#ifdef INCLUDE_ALL - #define INCLUDE_STYLE - #define INCLUDE_CALCULATOR - #define INCLUDE_OVERVIEW - #define INCLUDE_NODE_EDITOR -#endif - -#ifdef INCLUDE_STYLE - #include "../style.c" -#endif -#ifdef INCLUDE_CALCULATOR - #include "../calculator.c" -#endif -#ifdef INCLUDE_OVERVIEW - #include "../overview.c" -#endif -#ifdef INCLUDE_NODE_EDITOR - #include "../node_editor.c" -#endif - -/* =============================================================== - * - * DEMO - * - * ===============================================================*/ -static void error_callback(int e, const char *d) -{printf("Error %d: %s\n", e, d);} - -int main(void) -{ - /* Platform */ - static GLFWwindow *win; - int width = 0, height = 0; - struct nk_context *ctx; - struct nk_colorf bg; - - /* GLFW */ - glfwSetErrorCallback(error_callback); - if (!glfwInit()) { - fprintf(stdout, "[GFLW] failed to init!\n"); - exit(1); - } - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); -#ifdef __APPLE__ - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); -#endif - win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL); - glfwMakeContextCurrent(win); - glfwGetWindowSize(win, &width, &height); - - /* OpenGL */ - glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); - glewExperimental = 1; - if (glewInit() != GLEW_OK) { - fprintf(stderr, "Failed to setup GLEW\n"); - exit(1); - } - - ctx = nk_glfw3_init(win, NK_GLFW3_INSTALL_CALLBACKS); - /* Load Fonts: if none of these are loaded a default font will be used */ - /* Load Cursor: if you uncomment cursor loading please hide the cursor */ - {struct nk_font_atlas *atlas; - nk_glfw3_font_stash_begin(&atlas); - /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/ - /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 14, 0);*/ - /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/ - /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/ - /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/ - /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/ - nk_glfw3_font_stash_end(); - /*nk_style_load_all_cursors(ctx, atlas->cursors);*/ - /*nk_style_set_font(ctx, &droid->handle);*/} - - #ifdef INCLUDE_STYLE - /*set_style(ctx, THEME_WHITE);*/ - /*set_style(ctx, THEME_RED);*/ - /*set_style(ctx, THEME_BLUE);*/ - /*set_style(ctx, THEME_DARK);*/ - #endif - - bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f; - while (!glfwWindowShouldClose(win)) - { - /* Input */ - glfwPollEvents(); - nk_glfw3_new_frame(); - - /* GUI */ - if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250), - NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE| - NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) - { - enum {EASY, HARD}; - static int op = EASY; - static int property = 20; - nk_layout_row_static(ctx, 30, 80, 1); - if (nk_button_label(ctx, "button")) - fprintf(stdout, "button pressed\n"); - - nk_layout_row_dynamic(ctx, 30, 2); - if (nk_option_label(ctx, "easy", op == EASY)) op = EASY; - if (nk_option_label(ctx, "hard", op == HARD)) op = HARD; - - nk_layout_row_dynamic(ctx, 25, 1); - nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1); - - nk_layout_row_dynamic(ctx, 20, 1); - nk_label(ctx, "background:", NK_TEXT_LEFT); - nk_layout_row_dynamic(ctx, 25, 1); - if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) { - nk_layout_row_dynamic(ctx, 120, 1); - bg = nk_color_picker(ctx, bg, NK_RGBA); - nk_layout_row_dynamic(ctx, 25, 1); - bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f); - bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f); - bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f); - bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f); - nk_combo_end(ctx); - } - } - nk_end(ctx); - - /* -------------- EXAMPLES ---------------- */ - #ifdef INCLUDE_CALCULATOR - calculator(ctx); - #endif - #ifdef INCLUDE_OVERVIEW - overview(ctx); - #endif - #ifdef INCLUDE_NODE_EDITOR - node_editor(ctx); - #endif - /* ----------------------------------------- */ - - /* Draw */ - glfwGetWindowSize(win, &width, &height); - glViewport(0, 0, width, height); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(bg.r, bg.g, bg.b, bg.a); - /* IMPORTANT: `nk_glfw_render` modifies some global OpenGL state - * with blending, scissor, face culling, depth test and viewport and - * defaults everything back into a default state. - * Make sure to either a.) save and restore or b.) reset your own state after - * rendering the UI. */ - nk_glfw3_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER); - glfwSwapBuffers(win); - } - nk_glfw3_shutdown(); - glfwTerminate(); - return 0; -} - diff --git a/subprojects/nk_pugl/nuklear/demo/glfw_opengl3/nuklear_glfw_gl3.h b/subprojects/nk_pugl/nuklear/demo/glfw_opengl3/nuklear_glfw_gl3.h deleted file mode 100644 index 8fe98fc..0000000 --- a/subprojects/nk_pugl/nuklear/demo/glfw_opengl3/nuklear_glfw_gl3.h +++ /dev/null @@ -1,492 +0,0 @@ -/* - * Nuklear - 1.32.0 - public domain - * no warrenty implied; use at your own risk. - * authored from 2015-2016 by Micha Mettke - */ -/* - * ============================================================== - * - * API - * - * =============================================================== - */ -#ifndef NK_GLFW_GL3_H_ -#define NK_GLFW_GL3_H_ - -#include - -enum nk_glfw_init_state{ - NK_GLFW3_DEFAULT=0, - NK_GLFW3_INSTALL_CALLBACKS -}; - -NK_API struct nk_context* nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state); -NK_API void nk_glfw3_shutdown(void); -NK_API void nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas); -NK_API void nk_glfw3_font_stash_end(void); -NK_API void nk_glfw3_new_frame(void); -NK_API void nk_glfw3_render(enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer); - -NK_API void nk_glfw3_device_destroy(void); -NK_API void nk_glfw3_device_create(void); - -NK_API void nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint); -NK_API void nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff); -NK_API void nk_glfw3_mouse_button_callback(GLFWwindow *win, int button, int action, int mods); - -#endif -/* - * ============================================================== - * - * IMPLEMENTATION - * - * =============================================================== - */ -#ifdef NK_GLFW_GL3_IMPLEMENTATION - -#ifndef NK_GLFW_TEXT_MAX -#define NK_GLFW_TEXT_MAX 256 -#endif -#ifndef NK_GLFW_DOUBLE_CLICK_LO -#define NK_GLFW_DOUBLE_CLICK_LO 0.02 -#endif -#ifndef NK_GLFW_DOUBLE_CLICK_HI -#define NK_GLFW_DOUBLE_CLICK_HI 0.2 -#endif - -struct nk_glfw_device { - struct nk_buffer cmds; - struct nk_draw_null_texture null; - GLuint vbo, vao, ebo; - GLuint prog; - GLuint vert_shdr; - GLuint frag_shdr; - GLint attrib_pos; - GLint attrib_uv; - GLint attrib_col; - GLint uniform_tex; - GLint uniform_proj; - GLuint font_tex; -}; - -struct nk_glfw_vertex { - float position[2]; - float uv[2]; - nk_byte col[4]; -}; - -static struct nk_glfw { - GLFWwindow *win; - int width, height; - int display_width, display_height; - struct nk_glfw_device ogl; - struct nk_context ctx; - struct nk_font_atlas atlas; - struct nk_vec2 fb_scale; - unsigned int text[NK_GLFW_TEXT_MAX]; - int text_len; - struct nk_vec2 scroll; - double last_button_click; - int is_double_click_down; - struct nk_vec2 double_click_pos; -} glfw; - -#ifdef __APPLE__ - #define NK_SHADER_VERSION "#version 150\n" -#else - #define NK_SHADER_VERSION "#version 300 es\n" -#endif - -NK_API void -nk_glfw3_device_create(void) -{ - GLint status; - static const GLchar *vertex_shader = - NK_SHADER_VERSION - "uniform mat4 ProjMtx;\n" - "in vec2 Position;\n" - "in vec2 TexCoord;\n" - "in vec4 Color;\n" - "out vec2 Frag_UV;\n" - "out vec4 Frag_Color;\n" - "void main() {\n" - " Frag_UV = TexCoord;\n" - " Frag_Color = Color;\n" - " gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n" - "}\n"; - static const GLchar *fragment_shader = - NK_SHADER_VERSION - "precision mediump float;\n" - "uniform sampler2D Texture;\n" - "in vec2 Frag_UV;\n" - "in vec4 Frag_Color;\n" - "out vec4 Out_Color;\n" - "void main(){\n" - " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" - "}\n"; - - struct nk_glfw_device *dev = &glfw.ogl; - nk_buffer_init_default(&dev->cmds); - dev->prog = glCreateProgram(); - dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER); - dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0); - glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0); - glCompileShader(dev->vert_shdr); - glCompileShader(dev->frag_shdr); - glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status); - assert(status == GL_TRUE); - glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status); - assert(status == GL_TRUE); - glAttachShader(dev->prog, dev->vert_shdr); - glAttachShader(dev->prog, dev->frag_shdr); - glLinkProgram(dev->prog); - glGetProgramiv(dev->prog, GL_LINK_STATUS, &status); - assert(status == GL_TRUE); - - dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture"); - dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx"); - dev->attrib_pos = glGetAttribLocation(dev->prog, "Position"); - dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord"); - dev->attrib_col = glGetAttribLocation(dev->prog, "Color"); - - { - /* buffer setup */ - GLsizei vs = sizeof(struct nk_glfw_vertex); - size_t vp = offsetof(struct nk_glfw_vertex, position); - size_t vt = offsetof(struct nk_glfw_vertex, uv); - size_t vc = offsetof(struct nk_glfw_vertex, col); - - glGenBuffers(1, &dev->vbo); - glGenBuffers(1, &dev->ebo); - glGenVertexArrays(1, &dev->vao); - - glBindVertexArray(dev->vao); - glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); - - glEnableVertexAttribArray((GLuint)dev->attrib_pos); - glEnableVertexAttribArray((GLuint)dev->attrib_uv); - glEnableVertexAttribArray((GLuint)dev->attrib_col); - - glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp); - glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt); - glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc); - } - - glBindTexture(GL_TEXTURE_2D, 0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindVertexArray(0); -} - -NK_INTERN void -nk_glfw3_device_upload_atlas(const void *image, int width, int height) -{ - struct nk_glfw_device *dev = &glfw.ogl; - glGenTextures(1, &dev->font_tex); - glBindTexture(GL_TEXTURE_2D, dev->font_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, image); -} - -NK_API void -nk_glfw3_device_destroy(void) -{ - struct nk_glfw_device *dev = &glfw.ogl; - glDetachShader(dev->prog, dev->vert_shdr); - glDetachShader(dev->prog, dev->frag_shdr); - glDeleteShader(dev->vert_shdr); - glDeleteShader(dev->frag_shdr); - glDeleteProgram(dev->prog); - glDeleteTextures(1, &dev->font_tex); - glDeleteBuffers(1, &dev->vbo); - glDeleteBuffers(1, &dev->ebo); - nk_buffer_free(&dev->cmds); -} - -NK_API void -nk_glfw3_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer) -{ - struct nk_glfw_device *dev = &glfw.ogl; - struct nk_buffer vbuf, ebuf; - GLfloat ortho[4][4] = { - {2.0f, 0.0f, 0.0f, 0.0f}, - {0.0f,-2.0f, 0.0f, 0.0f}, - {0.0f, 0.0f,-1.0f, 0.0f}, - {-1.0f,1.0f, 0.0f, 1.0f}, - }; - ortho[0][0] /= (GLfloat)glfw.width; - ortho[1][1] /= (GLfloat)glfw.height; - - /* setup global state */ - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glEnable(GL_SCISSOR_TEST); - glActiveTexture(GL_TEXTURE0); - - /* setup program */ - glUseProgram(dev->prog); - glUniform1i(dev->uniform_tex, 0); - glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]); - glViewport(0,0,(GLsizei)glfw.display_width,(GLsizei)glfw.display_height); - { - /* convert from command queue into draw list and draw to screen */ - const struct nk_draw_command *cmd; - void *vertices, *elements; - const nk_draw_index *offset = NULL; - - /* allocate vertex and element buffer */ - glBindVertexArray(dev->vao); - glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); - - glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW); - - /* load draw vertices & elements directly into vertex + element buffer */ - vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); - elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY); - { - /* fill convert configuration */ - struct nk_convert_config config; - static const struct nk_draw_vertex_layout_element vertex_layout[] = { - {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)}, - {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)}, - {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)}, - {NK_VERTEX_LAYOUT_END} - }; - NK_MEMSET(&config, 0, sizeof(config)); - config.vertex_layout = vertex_layout; - config.vertex_size = sizeof(struct nk_glfw_vertex); - config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex); - config.null = dev->null; - config.circle_segment_count = 22; - config.curve_segment_count = 22; - config.arc_segment_count = 22; - config.global_alpha = 1.0f; - config.shape_AA = AA; - config.line_AA = AA; - - /* setup buffers to load vertices and elements */ - nk_buffer_init_fixed(&vbuf, vertices, (size_t)max_vertex_buffer); - nk_buffer_init_fixed(&ebuf, elements, (size_t)max_element_buffer); - nk_convert(&glfw.ctx, &dev->cmds, &vbuf, &ebuf, &config); - } - glUnmapBuffer(GL_ARRAY_BUFFER); - glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); - - /* iterate over and execute each draw command */ - nk_draw_foreach(cmd, &glfw.ctx, &dev->cmds) - { - if (!cmd->elem_count) continue; - glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); - glScissor( - (GLint)(cmd->clip_rect.x * glfw.fb_scale.x), - (GLint)((glfw.height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * glfw.fb_scale.y), - (GLint)(cmd->clip_rect.w * glfw.fb_scale.x), - (GLint)(cmd->clip_rect.h * glfw.fb_scale.y)); - glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); - offset += cmd->elem_count; - } - nk_clear(&glfw.ctx); - } - - /* default OpenGL state */ - glUseProgram(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindVertexArray(0); - glDisable(GL_BLEND); - glDisable(GL_SCISSOR_TEST); -} - -NK_API void -nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint) -{ - (void)win; - if (glfw.text_len < NK_GLFW_TEXT_MAX) - glfw.text[glfw.text_len++] = codepoint; -} - -NK_API void -nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff) -{ - (void)win; (void)xoff; - glfw.scroll.x += (float)xoff; - glfw.scroll.y += (float)yoff; -} - -NK_API void -nk_glfw3_mouse_button_callback(GLFWwindow* window, int button, int action, int mods) -{ - double x, y; - if (button != GLFW_MOUSE_BUTTON_LEFT) return; - glfwGetCursorPos(window, &x, &y); - if (action == GLFW_PRESS) { - double dt = glfwGetTime() - glfw.last_button_click; - if (dt > NK_GLFW_DOUBLE_CLICK_LO && dt < NK_GLFW_DOUBLE_CLICK_HI) { - glfw.is_double_click_down = nk_true; - glfw.double_click_pos = nk_vec2((float)x, (float)y); - } - glfw.last_button_click = glfwGetTime(); - } else glfw.is_double_click_down = nk_false; -} - -NK_INTERN void -nk_glfw3_clipbard_paste(nk_handle usr, struct nk_text_edit *edit) -{ - const char *text = glfwGetClipboardString(glfw.win); - if (text) nk_textedit_paste(edit, text, nk_strlen(text)); - (void)usr; -} - -NK_INTERN void -nk_glfw3_clipbard_copy(nk_handle usr, const char *text, int len) -{ - char *str = 0; - (void)usr; - if (!len) return; - str = (char*)malloc((size_t)len+1); - if (!str) return; - memcpy(str, text, (size_t)len); - str[len] = '\0'; - glfwSetClipboardString(glfw.win, str); - free(str); -} - -NK_API struct nk_context* -nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state init_state) -{ - glfw.win = win; - if (init_state == NK_GLFW3_INSTALL_CALLBACKS) { - glfwSetScrollCallback(win, nk_gflw3_scroll_callback); - glfwSetCharCallback(win, nk_glfw3_char_callback); - glfwSetMouseButtonCallback(win, nk_glfw3_mouse_button_callback); - } - nk_init_default(&glfw.ctx, 0); - glfw.ctx.clip.copy = nk_glfw3_clipbard_copy; - glfw.ctx.clip.paste = nk_glfw3_clipbard_paste; - glfw.ctx.clip.userdata = nk_handle_ptr(0); - glfw.last_button_click = 0; - nk_glfw3_device_create(); - - glfw.is_double_click_down = nk_false; - glfw.double_click_pos = nk_vec2(0, 0); - - return &glfw.ctx; -} - -NK_API void -nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas) -{ - nk_font_atlas_init_default(&glfw.atlas); - nk_font_atlas_begin(&glfw.atlas); - *atlas = &glfw.atlas; -} - -NK_API void -nk_glfw3_font_stash_end(void) -{ - const void *image; int w, h; - image = nk_font_atlas_bake(&glfw.atlas, &w, &h, NK_FONT_ATLAS_RGBA32); - nk_glfw3_device_upload_atlas(image, w, h); - nk_font_atlas_end(&glfw.atlas, nk_handle_id((int)glfw.ogl.font_tex), &glfw.ogl.null); - if (glfw.atlas.default_font) - nk_style_set_font(&glfw.ctx, &glfw.atlas.default_font->handle); -} - -NK_API void -nk_glfw3_new_frame(void) -{ - int i; - double x, y; - struct nk_context *ctx = &glfw.ctx; - struct GLFWwindow *win = glfw.win; - - glfwGetWindowSize(win, &glfw.width, &glfw.height); - glfwGetFramebufferSize(win, &glfw.display_width, &glfw.display_height); - glfw.fb_scale.x = (float)glfw.display_width/(float)glfw.width; - glfw.fb_scale.y = (float)glfw.display_height/(float)glfw.height; - - nk_input_begin(ctx); - for (i = 0; i < glfw.text_len; ++i) - nk_input_unicode(ctx, glfw.text[i]); - -#ifdef NK_GLFW_GL3_MOUSE_GRABBING - /* optional grabbing behavior */ - if (ctx->input.mouse.grab) - glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); - else if (ctx->input.mouse.ungrab) - glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_NORMAL); -#endif - - nk_input_key(ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_SCROLL_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_SCROLL_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_SCROLL_DOWN, glfwGetKey(win, GLFW_KEY_PAGE_DOWN) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_SCROLL_UP, glfwGetKey(win, GLFW_KEY_PAGE_UP) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_SHIFT, glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS|| - glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS); - - if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || - glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) { - nk_input_key(ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_V) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_UNDO, glfwGetKey(win, GLFW_KEY_Z) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_REDO, glfwGetKey(win, GLFW_KEY_R) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_LINE_START, glfwGetKey(win, GLFW_KEY_B) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TEXT_LINE_END, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS); - } else { - nk_input_key(ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_COPY, 0); - nk_input_key(ctx, NK_KEY_PASTE, 0); - nk_input_key(ctx, NK_KEY_CUT, 0); - nk_input_key(ctx, NK_KEY_SHIFT, 0); - } - - glfwGetCursorPos(win, &x, &y); - nk_input_motion(ctx, (int)x, (int)y); -#ifdef NK_GLFW_GL3_MOUSE_GRABBING - if (ctx->input.mouse.grabbed) { - glfwSetCursorPos(glfw.win, ctx->input.mouse.prev.x, ctx->input.mouse.prev.y); - ctx->input.mouse.pos.x = ctx->input.mouse.prev.x; - ctx->input.mouse.pos.y = ctx->input.mouse.prev.y; - } -#endif - nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); - nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS); - nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS); - nk_input_button(ctx, NK_BUTTON_DOUBLE, (int)glfw.double_click_pos.x, (int)glfw.double_click_pos.y, glfw.is_double_click_down); - nk_input_scroll(ctx, glfw.scroll); - nk_input_end(&glfw.ctx); - glfw.text_len = 0; - glfw.scroll = nk_vec2(0,0); -} - -NK_API -void nk_glfw3_shutdown(void) -{ - nk_font_atlas_clear(&glfw.atlas); - nk_free(&glfw.ctx); - nk_glfw3_device_destroy(); - memset(&glfw, 0, sizeof(glfw)); -} - -#endif diff --git a/subprojects/nk_pugl/nuklear/demo/node_editor.c b/subprojects/nk_pugl/nuklear/demo/node_editor.c deleted file mode 100644 index d4f34c3..0000000 --- a/subprojects/nk_pugl/nuklear/demo/node_editor.c +++ /dev/null @@ -1,343 +0,0 @@ -/* nuklear - v1.00 - public domain */ -/* This is a simple node editor just to show a simple implementation and that - * it is possible to achieve it with this library. While all nodes inside this - * example use a simple color modifier as content you could change them - * to have your custom content depending on the node time. - * Biggest difference to most usual implementation is that this example does - * not have connectors on the right position of the property that it links. - * This is mainly done out of laziness and could be implemented as well but - * requires calculating the position of all rows and add connectors. - * In addition adding and removing nodes is quite limited at the - * moment since it is based on a simple fixed array. If this is to be converted - * into something more serious it is probably best to extend it.*/ -struct node { - int ID; - char name[32]; - struct nk_rect bounds; - float value; - struct nk_color color; - int input_count; - int output_count; - struct node *next; - struct node *prev; -}; - -struct node_link { - int input_id; - int input_slot; - int output_id; - int output_slot; - struct nk_vec2 in; - struct nk_vec2 out; -}; - -struct node_linking { - int active; - struct node *node; - int input_id; - int input_slot; -}; - -struct node_editor { - int initialized; - struct node node_buf[32]; - struct node_link links[64]; - struct node *begin; - struct node *end; - int node_count; - int link_count; - struct nk_rect bounds; - struct node *selected; - int show_grid; - struct nk_vec2 scrolling; - struct node_linking linking; -}; -static struct node_editor nodeEditor; - -static void -node_editor_push(struct node_editor *editor, struct node *node) -{ - if (!editor->begin) { - node->next = NULL; - node->prev = NULL; - editor->begin = node; - editor->end = node; - } else { - node->prev = editor->end; - if (editor->end) - editor->end->next = node; - node->next = NULL; - editor->end = node; - } -} - -static void -node_editor_pop(struct node_editor *editor, struct node *node) -{ - if (node->next) - node->next->prev = node->prev; - if (node->prev) - node->prev->next = node->next; - if (editor->end == node) - editor->end = node->prev; - if (editor->begin == node) - editor->begin = node->next; - node->next = NULL; - node->prev = NULL; -} - -static struct node* -node_editor_find(struct node_editor *editor, int ID) -{ - struct node *iter = editor->begin; - while (iter) { - if (iter->ID == ID) - return iter; - iter = iter->next; - } - return NULL; -} - -static void -node_editor_add(struct node_editor *editor, const char *name, struct nk_rect bounds, - struct nk_color col, int in_count, int out_count) -{ - static int IDs = 0; - struct node *node; - NK_ASSERT((nk_size)editor->node_count < NK_LEN(editor->node_buf)); - node = &editor->node_buf[editor->node_count++]; - node->ID = IDs++; - node->value = 0; - node->color = nk_rgb(255, 0, 0); - node->input_count = in_count; - node->output_count = out_count; - node->color = col; - node->bounds = bounds; - strcpy(node->name, name); - node_editor_push(editor, node); -} - -static void -node_editor_link(struct node_editor *editor, int in_id, int in_slot, - int out_id, int out_slot) -{ - struct node_link *link; - NK_ASSERT((nk_size)editor->link_count < NK_LEN(editor->links)); - link = &editor->links[editor->link_count++]; - link->input_id = in_id; - link->input_slot = in_slot; - link->output_id = out_id; - link->output_slot = out_slot; -} - -static void -node_editor_init(struct node_editor *editor) -{ - memset(editor, 0, sizeof(*editor)); - editor->begin = NULL; - editor->end = NULL; - node_editor_add(editor, "Source", nk_rect(40, 10, 180, 220), nk_rgb(255, 0, 0), 0, 1); - node_editor_add(editor, "Source", nk_rect(40, 260, 180, 220), nk_rgb(0, 255, 0), 0, 1); - node_editor_add(editor, "Combine", nk_rect(400, 100, 180, 220), nk_rgb(0,0,255), 2, 2); - node_editor_link(editor, 0, 0, 2, 0); - node_editor_link(editor, 1, 0, 2, 1); - editor->show_grid = nk_true; -} - -static int -node_editor(struct nk_context *ctx) -{ - int n = 0; - struct nk_rect total_space; - const struct nk_input *in = &ctx->input; - struct nk_command_buffer *canvas; - struct node *updated = 0; - struct node_editor *nodedit = &nodeEditor; - - if (!nodeEditor.initialized) { - node_editor_init(&nodeEditor); - nodeEditor.initialized = 1; - } - - if (nk_begin(ctx, "NodeEdit", nk_rect(0, 0, 800, 600), - NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE)) - { - /* allocate complete window space */ - canvas = nk_window_get_canvas(ctx); - total_space = nk_window_get_content_region(ctx); - nk_layout_space_begin(ctx, NK_STATIC, total_space.h, nodedit->node_count); - { - struct node *it = nodedit->begin; - struct nk_rect size = nk_layout_space_bounds(ctx); - struct nk_panel *node = 0; - - if (nodedit->show_grid) { - /* display grid */ - float x, y; - const float grid_size = 32.0f; - const struct nk_color grid_color = nk_rgb(50, 50, 50); - for (x = (float)fmod(size.x - nodedit->scrolling.x, grid_size); x < size.w; x += grid_size) - nk_stroke_line(canvas, x+size.x, size.y, x+size.x, size.y+size.h, 1.0f, grid_color); - for (y = (float)fmod(size.y - nodedit->scrolling.y, grid_size); y < size.h; y += grid_size) - nk_stroke_line(canvas, size.x, y+size.y, size.x+size.w, y+size.y, 1.0f, grid_color); - } - - /* execute each node as a movable group */ - while (it) { - /* calculate scrolled node window position and size */ - nk_layout_space_push(ctx, nk_rect(it->bounds.x - nodedit->scrolling.x, - it->bounds.y - nodedit->scrolling.y, it->bounds.w, it->bounds.h)); - - /* execute node window */ - if (nk_group_begin(ctx, it->name, NK_WINDOW_MOVABLE|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER|NK_WINDOW_TITLE)) - { - /* always have last selected node on top */ - - node = nk_window_get_panel(ctx); - if (nk_input_mouse_clicked(in, NK_BUTTON_LEFT, node->bounds) && - (!(it->prev && nk_input_mouse_clicked(in, NK_BUTTON_LEFT, - nk_layout_space_rect_to_screen(ctx, node->bounds)))) && - nodedit->end != it) - { - updated = it; - } - - /* ================= NODE CONTENT =====================*/ - nk_layout_row_dynamic(ctx, 25, 1); - nk_button_color(ctx, it->color); - it->color.r = (nk_byte)nk_propertyi(ctx, "#R:", 0, it->color.r, 255, 1,1); - it->color.g = (nk_byte)nk_propertyi(ctx, "#G:", 0, it->color.g, 255, 1,1); - it->color.b = (nk_byte)nk_propertyi(ctx, "#B:", 0, it->color.b, 255, 1,1); - it->color.a = (nk_byte)nk_propertyi(ctx, "#A:", 0, it->color.a, 255, 1,1); - /* ====================================================*/ - nk_group_end(ctx); - } - { - /* node connector and linking */ - float space; - struct nk_rect bounds; - bounds = nk_layout_space_rect_to_local(ctx, node->bounds); - bounds.x += nodedit->scrolling.x; - bounds.y += nodedit->scrolling.y; - it->bounds = bounds; - - /* output connector */ - space = node->bounds.h / (float)((it->output_count) + 1); - for (n = 0; n < it->output_count; ++n) { - struct nk_rect circle; - circle.x = node->bounds.x + node->bounds.w-4; - circle.y = node->bounds.y + space * (float)(n+1); - circle.w = 8; circle.h = 8; - nk_fill_circle(canvas, circle, nk_rgb(100, 100, 100)); - - /* start linking process */ - if (nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, circle, nk_true)) { - nodedit->linking.active = nk_true; - nodedit->linking.node = it; - nodedit->linking.input_id = it->ID; - nodedit->linking.input_slot = n; - } - - /* draw curve from linked node slot to mouse position */ - if (nodedit->linking.active && nodedit->linking.node == it && - nodedit->linking.input_slot == n) { - struct nk_vec2 l0 = nk_vec2(circle.x + 3, circle.y + 3); - struct nk_vec2 l1 = in->mouse.pos; - nk_stroke_curve(canvas, l0.x, l0.y, l0.x + 50.0f, l0.y, - l1.x - 50.0f, l1.y, l1.x, l1.y, 1.0f, nk_rgb(100, 100, 100)); - } - } - - /* input connector */ - space = node->bounds.h / (float)((it->input_count) + 1); - for (n = 0; n < it->input_count; ++n) { - struct nk_rect circle; - circle.x = node->bounds.x-4; - circle.y = node->bounds.y + space * (float)(n+1); - circle.w = 8; circle.h = 8; - nk_fill_circle(canvas, circle, nk_rgb(100, 100, 100)); - if (nk_input_is_mouse_released(in, NK_BUTTON_LEFT) && - nk_input_is_mouse_hovering_rect(in, circle) && - nodedit->linking.active && nodedit->linking.node != it) { - nodedit->linking.active = nk_false; - node_editor_link(nodedit, nodedit->linking.input_id, - nodedit->linking.input_slot, it->ID, n); - } - } - } - it = it->next; - } - - /* reset linking connection */ - if (nodedit->linking.active && nk_input_is_mouse_released(in, NK_BUTTON_LEFT)) { - nodedit->linking.active = nk_false; - nodedit->linking.node = NULL; - fprintf(stdout, "linking failed\n"); - } - - /* draw each link */ - for (n = 0; n < nodedit->link_count; ++n) { - struct node_link *link = &nodedit->links[n]; - struct node *ni = node_editor_find(nodedit, link->input_id); - struct node *no = node_editor_find(nodedit, link->output_id); - float spacei = node->bounds.h / (float)((ni->output_count) + 1); - float spaceo = node->bounds.h / (float)((no->input_count) + 1); - struct nk_vec2 l0 = nk_layout_space_to_screen(ctx, - nk_vec2(ni->bounds.x + ni->bounds.w, 3.0f + ni->bounds.y + spacei * (float)(link->input_slot+1))); - struct nk_vec2 l1 = nk_layout_space_to_screen(ctx, - nk_vec2(no->bounds.x, 3.0f + no->bounds.y + spaceo * (float)(link->output_slot+1))); - - l0.x -= nodedit->scrolling.x; - l0.y -= nodedit->scrolling.y; - l1.x -= nodedit->scrolling.x; - l1.y -= nodedit->scrolling.y; - nk_stroke_curve(canvas, l0.x, l0.y, l0.x + 50.0f, l0.y, - l1.x - 50.0f, l1.y, l1.x, l1.y, 1.0f, nk_rgb(100, 100, 100)); - } - - if (updated) { - /* reshuffle nodes to have least recently selected node on top */ - node_editor_pop(nodedit, updated); - node_editor_push(nodedit, updated); - } - - /* node selection */ - if (nk_input_mouse_clicked(in, NK_BUTTON_LEFT, nk_layout_space_bounds(ctx))) { - it = nodedit->begin; - nodedit->selected = NULL; - nodedit->bounds = nk_rect(in->mouse.pos.x, in->mouse.pos.y, 100, 200); - while (it) { - struct nk_rect b = nk_layout_space_rect_to_screen(ctx, it->bounds); - b.x -= nodedit->scrolling.x; - b.y -= nodedit->scrolling.y; - if (nk_input_is_mouse_hovering_rect(in, b)) - nodedit->selected = it; - it = it->next; - } - } - - /* contextual menu */ - if (nk_contextual_begin(ctx, 0, nk_vec2(100, 220), nk_window_get_bounds(ctx))) { - const char *grid_option[] = {"Show Grid", "Hide Grid"}; - nk_layout_row_dynamic(ctx, 25, 1); - if (nk_contextual_item_label(ctx, "New", NK_TEXT_CENTERED)) - node_editor_add(nodedit, "New", nk_rect(400, 260, 180, 220), - nk_rgb(255, 255, 255), 1, 2); - if (nk_contextual_item_label(ctx, grid_option[nodedit->show_grid],NK_TEXT_CENTERED)) - nodedit->show_grid = !nodedit->show_grid; - nk_contextual_end(ctx); - } - } - nk_layout_space_end(ctx); - - /* window content scrolling */ - if (nk_input_is_mouse_hovering_rect(in, nk_window_get_bounds(ctx)) && - nk_input_is_mouse_down(in, NK_BUTTON_MIDDLE)) { - nodedit->scrolling.x += in->mouse.delta.x; - nodedit->scrolling.y += in->mouse.delta.y; - } - } - nk_end(ctx); - return !nk_window_is_closed(ctx, "NodeEdit"); -} - diff --git a/subprojects/nk_pugl/nuklear/demo/overview.c b/subprojects/nk_pugl/nuklear/demo/overview.c deleted file mode 100644 index 3c3f381..0000000 --- a/subprojects/nk_pugl/nuklear/demo/overview.c +++ /dev/null @@ -1,1249 +0,0 @@ - -static int -overview(struct nk_context *ctx) -{ - /* window flags */ - static int show_menu = nk_true; - static int titlebar = nk_true; - static int border = nk_true; - static int resize = nk_true; - static int movable = nk_true; - static int no_scrollbar = nk_false; - static int scale_left = nk_false; - static nk_flags window_flags = 0; - static int minimizable = nk_true; - - /* popups */ - static enum nk_style_header_align header_align = NK_HEADER_RIGHT; - static int show_app_about = nk_false; - - /* window flags */ - window_flags = 0; - ctx->style.window.header.align = header_align; - if (border) window_flags |= NK_WINDOW_BORDER; - if (resize) window_flags |= NK_WINDOW_SCALABLE; - if (movable) window_flags |= NK_WINDOW_MOVABLE; - if (no_scrollbar) window_flags |= NK_WINDOW_NO_SCROLLBAR; - if (scale_left) window_flags |= NK_WINDOW_SCALE_LEFT; - if (minimizable) window_flags |= NK_WINDOW_MINIMIZABLE; - - if (nk_begin(ctx, "Overview", nk_rect(10, 10, 400, 600), window_flags)) - { - if (show_menu) - { - /* menubar */ - enum menu_states {MENU_DEFAULT, MENU_WINDOWS}; - static nk_size mprog = 60; - static int mslider = 10; - static int mcheck = nk_true; - nk_menubar_begin(ctx); - - /* menu #1 */ - nk_layout_row_begin(ctx, NK_STATIC, 25, 5); - nk_layout_row_push(ctx, 45); - if (nk_menu_begin_label(ctx, "MENU", NK_TEXT_LEFT, nk_vec2(120, 200))) - { - static size_t prog = 40; - static int slider = 10; - static int check = nk_true; - nk_layout_row_dynamic(ctx, 25, 1); - if (nk_menu_item_label(ctx, "Hide", NK_TEXT_LEFT)) - show_menu = nk_false; - if (nk_menu_item_label(ctx, "About", NK_TEXT_LEFT)) - show_app_about = nk_true; - nk_progress(ctx, &prog, 100, NK_MODIFIABLE); - nk_slider_int(ctx, 0, &slider, 16, 1); - nk_checkbox_label(ctx, "check", &check); - nk_menu_end(ctx); - } - /* menu #2 */ - nk_layout_row_push(ctx, 60); - if (nk_menu_begin_label(ctx, "ADVANCED", NK_TEXT_LEFT, nk_vec2(200, 600))) - { - enum menu_state {MENU_NONE,MENU_FILE, MENU_EDIT,MENU_VIEW,MENU_CHART}; - static enum menu_state menu_state = MENU_NONE; - enum nk_collapse_states state; - - state = (menu_state == MENU_FILE) ? NK_MAXIMIZED: NK_MINIMIZED; - if (nk_tree_state_push(ctx, NK_TREE_TAB, "FILE", &state)) { - menu_state = MENU_FILE; - nk_menu_item_label(ctx, "New", NK_TEXT_LEFT); - nk_menu_item_label(ctx, "Open", NK_TEXT_LEFT); - nk_menu_item_label(ctx, "Save", NK_TEXT_LEFT); - nk_menu_item_label(ctx, "Close", NK_TEXT_LEFT); - nk_menu_item_label(ctx, "Exit", NK_TEXT_LEFT); - nk_tree_pop(ctx); - } else menu_state = (menu_state == MENU_FILE) ? MENU_NONE: menu_state; - - state = (menu_state == MENU_EDIT) ? NK_MAXIMIZED: NK_MINIMIZED; - if (nk_tree_state_push(ctx, NK_TREE_TAB, "EDIT", &state)) { - menu_state = MENU_EDIT; - nk_menu_item_label(ctx, "Copy", NK_TEXT_LEFT); - nk_menu_item_label(ctx, "Delete", NK_TEXT_LEFT); - nk_menu_item_label(ctx, "Cut", NK_TEXT_LEFT); - nk_menu_item_label(ctx, "Paste", NK_TEXT_LEFT); - nk_tree_pop(ctx); - } else menu_state = (menu_state == MENU_EDIT) ? MENU_NONE: menu_state; - - state = (menu_state == MENU_VIEW) ? NK_MAXIMIZED: NK_MINIMIZED; - if (nk_tree_state_push(ctx, NK_TREE_TAB, "VIEW", &state)) { - menu_state = MENU_VIEW; - nk_menu_item_label(ctx, "About", NK_TEXT_LEFT); - nk_menu_item_label(ctx, "Options", NK_TEXT_LEFT); - nk_menu_item_label(ctx, "Customize", NK_TEXT_LEFT); - nk_tree_pop(ctx); - } else menu_state = (menu_state == MENU_VIEW) ? MENU_NONE: menu_state; - - state = (menu_state == MENU_CHART) ? NK_MAXIMIZED: NK_MINIMIZED; - if (nk_tree_state_push(ctx, NK_TREE_TAB, "CHART", &state)) { - size_t i = 0; - const float values[]={26.0f,13.0f,30.0f,15.0f,25.0f,10.0f,20.0f,40.0f,12.0f,8.0f,22.0f,28.0f}; - menu_state = MENU_CHART; - nk_layout_row_dynamic(ctx, 150, 1); - nk_chart_begin(ctx, NK_CHART_COLUMN, NK_LEN(values), 0, 50); - for (i = 0; i < NK_LEN(values); ++i) - nk_chart_push(ctx, values[i]); - nk_chart_end(ctx); - nk_tree_pop(ctx); - } else menu_state = (menu_state == MENU_CHART) ? MENU_NONE: menu_state; - nk_menu_end(ctx); - } - /* menu widgets */ - nk_layout_row_push(ctx, 70); - nk_progress(ctx, &mprog, 100, NK_MODIFIABLE); - nk_slider_int(ctx, 0, &mslider, 16, 1); - nk_checkbox_label(ctx, "check", &mcheck); - nk_menubar_end(ctx); - } - - if (show_app_about) - { - /* about popup */ - static struct nk_rect s = {20, 100, 300, 190}; - if (nk_popup_begin(ctx, NK_POPUP_STATIC, "About", NK_WINDOW_CLOSABLE, s)) - { - nk_layout_row_dynamic(ctx, 20, 1); - nk_label(ctx, "Nuklear", NK_TEXT_LEFT); - nk_label(ctx, "By Micha Mettke", NK_TEXT_LEFT); - nk_label(ctx, "nuklear is licensed under the public domain License.", NK_TEXT_LEFT); - nk_popup_end(ctx); - } else show_app_about = nk_false; - } - - /* window flags */ - if (nk_tree_push(ctx, NK_TREE_TAB, "Window", NK_MINIMIZED)) { - nk_layout_row_dynamic(ctx, 30, 2); - nk_checkbox_label(ctx, "Titlebar", &titlebar); - nk_checkbox_label(ctx, "Menu", &show_menu); - nk_checkbox_label(ctx, "Border", &border); - nk_checkbox_label(ctx, "Resizable", &resize); - nk_checkbox_label(ctx, "Movable", &movable); - nk_checkbox_label(ctx, "No Scrollbar", &no_scrollbar); - nk_checkbox_label(ctx, "Minimizable", &minimizable); - nk_checkbox_label(ctx, "Scale Left", &scale_left); - nk_tree_pop(ctx); - } - - if (nk_tree_push(ctx, NK_TREE_TAB, "Widgets", NK_MINIMIZED)) - { - enum options {A,B,C}; - static int checkbox; - static int option; - if (nk_tree_push(ctx, NK_TREE_NODE, "Text", NK_MINIMIZED)) - { - /* Text Widgets */ - nk_layout_row_dynamic(ctx, 20, 1); - nk_label(ctx, "Label aligned left", NK_TEXT_LEFT); - nk_label(ctx, "Label aligned centered", NK_TEXT_CENTERED); - nk_label(ctx, "Label aligned right", NK_TEXT_RIGHT); - nk_label_colored(ctx, "Blue text", NK_TEXT_LEFT, nk_rgb(0,0,255)); - nk_label_colored(ctx, "Yellow text", NK_TEXT_LEFT, nk_rgb(255,255,0)); - nk_text(ctx, "Text without /0", 15, NK_TEXT_RIGHT); - - nk_layout_row_static(ctx, 100, 200, 1); - nk_label_wrap(ctx, "This is a very long line to hopefully get this text to be wrapped into multiple lines to show line wrapping"); - nk_layout_row_dynamic(ctx, 100, 1); - nk_label_wrap(ctx, "This is another long text to show dynamic window changes on multiline text"); - nk_tree_pop(ctx); - } - - if (nk_tree_push(ctx, NK_TREE_NODE, "Button", NK_MINIMIZED)) - { - /* Buttons Widgets */ - nk_layout_row_static(ctx, 30, 100, 3); - if (nk_button_label(ctx, "Button")) - fprintf(stdout, "Button pressed!\n"); - nk_button_set_behavior(ctx, NK_BUTTON_REPEATER); - if (nk_button_label(ctx, "Repeater")) - fprintf(stdout, "Repeater is being pressed!\n"); - nk_button_set_behavior(ctx, NK_BUTTON_DEFAULT); - nk_button_color(ctx, nk_rgb(0,0,255)); - - nk_layout_row_static(ctx, 25, 25, 8); - nk_button_symbol(ctx, NK_SYMBOL_CIRCLE_SOLID); - nk_button_symbol(ctx, NK_SYMBOL_CIRCLE_OUTLINE); - nk_button_symbol(ctx, NK_SYMBOL_RECT_SOLID); - nk_button_symbol(ctx, NK_SYMBOL_RECT_OUTLINE); - nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_UP); - nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_DOWN); - nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_LEFT); - nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_RIGHT); - - nk_layout_row_static(ctx, 30, 100, 2); - nk_button_symbol_label(ctx, NK_SYMBOL_TRIANGLE_LEFT, "prev", NK_TEXT_RIGHT); - nk_button_symbol_label(ctx, NK_SYMBOL_TRIANGLE_RIGHT, "next", NK_TEXT_LEFT); - nk_tree_pop(ctx); - } - - if (nk_tree_push(ctx, NK_TREE_NODE, "Basic", NK_MINIMIZED)) - { - /* Basic widgets */ - static int int_slider = 5; - static float float_slider = 2.5f; - static size_t prog_value = 40; - static float property_float = 2; - static int property_int = 10; - static int property_neg = 10; - - static float range_float_min = 0; - static float range_float_max = 100; - static float range_float_value = 50; - static int range_int_min = 0; - static int range_int_value = 2048; - static int range_int_max = 4096; - static const float ratio[] = {120, 150}; - - nk_layout_row_static(ctx, 30, 100, 1); - nk_checkbox_label(ctx, "Checkbox", &checkbox); - - nk_layout_row_static(ctx, 30, 80, 3); - option = nk_option_label(ctx, "optionA", option == A) ? A : option; - option = nk_option_label(ctx, "optionB", option == B) ? B : option; - option = nk_option_label(ctx, "optionC", option == C) ? C : option; - - - nk_layout_row(ctx, NK_STATIC, 30, 2, ratio); - nk_labelf(ctx, NK_TEXT_LEFT, "Slider int"); - nk_slider_int(ctx, 0, &int_slider, 10, 1); - - nk_label(ctx, "Slider float", NK_TEXT_LEFT); - nk_slider_float(ctx, 0, &float_slider, 5.0, 0.5f); - nk_labelf(ctx, NK_TEXT_LEFT, "Progressbar: %zu" , prog_value); - nk_progress(ctx, &prog_value, 100, NK_MODIFIABLE); - - nk_layout_row(ctx, NK_STATIC, 25, 2, ratio); - nk_label(ctx, "Property float:", NK_TEXT_LEFT); - nk_property_float(ctx, "Float:", 0, &property_float, 64.0f, 0.1f, 0.2f); - nk_label(ctx, "Property int:", NK_TEXT_LEFT); - nk_property_int(ctx, "Int:", 0, &property_int, 100.0f, 1, 1); - nk_label(ctx, "Property neg:", NK_TEXT_LEFT); - nk_property_int(ctx, "Neg:", -10, &property_neg, 10, 1, 1); - - nk_layout_row_dynamic(ctx, 25, 1); - nk_label(ctx, "Range:", NK_TEXT_LEFT); - nk_layout_row_dynamic(ctx, 25, 3); - nk_property_float(ctx, "#min:", 0, &range_float_min, range_float_max, 1.0f, 0.2f); - nk_property_float(ctx, "#float:", range_float_min, &range_float_value, range_float_max, 1.0f, 0.2f); - nk_property_float(ctx, "#max:", range_float_min, &range_float_max, 100, 1.0f, 0.2f); - - nk_property_int(ctx, "#min:", INT_MIN, &range_int_min, range_int_max, 1, 10); - nk_property_int(ctx, "#neg:", range_int_min, &range_int_value, range_int_max, 1, 10); - nk_property_int(ctx, "#max:", range_int_min, &range_int_max, INT_MAX, 1, 10); - - nk_tree_pop(ctx); - } - - if (nk_tree_push(ctx, NK_TREE_NODE, "Selectable", NK_MINIMIZED)) - { - if (nk_tree_push(ctx, NK_TREE_NODE, "List", NK_MINIMIZED)) - { - static int selected[4] = {nk_false, nk_false, nk_true, nk_false}; - nk_layout_row_static(ctx, 18, 100, 1); - nk_selectable_label(ctx, "Selectable", NK_TEXT_LEFT, &selected[0]); - nk_selectable_label(ctx, "Selectable", NK_TEXT_LEFT, &selected[1]); - nk_label(ctx, "Not Selectable", NK_TEXT_LEFT); - nk_selectable_label(ctx, "Selectable", NK_TEXT_LEFT, &selected[2]); - nk_selectable_label(ctx, "Selectable", NK_TEXT_LEFT, &selected[3]); - nk_tree_pop(ctx); - } - if (nk_tree_push(ctx, NK_TREE_NODE, "Grid", NK_MINIMIZED)) - { - int i; - static int selected[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; - nk_layout_row_static(ctx, 50, 50, 4); - for (i = 0; i < 16; ++i) { - if (nk_selectable_label(ctx, "Z", NK_TEXT_CENTERED, &selected[i])) { - int x = (i % 4), y = i / 4; - if (x > 0) selected[i - 1] ^= 1; - if (x < 3) selected[i + 1] ^= 1; - if (y > 0) selected[i - 4] ^= 1; - if (y < 3) selected[i + 4] ^= 1; - } - } - nk_tree_pop(ctx); - } - nk_tree_pop(ctx); - } - - if (nk_tree_push(ctx, NK_TREE_NODE, "Combo", NK_MINIMIZED)) - { - /* Combobox Widgets - * In this library comboboxes are not limited to being a popup - * list of selectable text. Instead it is a abstract concept of - * having something that is *selected* or displayed, a popup window - * which opens if something needs to be modified and the content - * of the popup which causes the *selected* or displayed value to - * change or if wanted close the combobox. - * - * While strange at first handling comboboxes in a abstract way - * solves the problem of overloaded window content. For example - * changing a color value requires 4 value modifier (slider, property,...) - * for RGBA then you need a label and ways to display the current color. - * If you want to go fancy you even add rgb and hsv ratio boxes. - * While fine for one color if you have a lot of them it because - * tedious to look at and quite wasteful in space. You could add - * a popup which modifies the color but this does not solve the - * fact that it still requires a lot of cluttered space to do. - * - * In these kind of instance abstract comboboxes are quite handy. All - * value modifiers are hidden inside the combobox popup and only - * the color is shown if not open. This combines the clarity of the - * popup with the ease of use of just using the space for modifiers. - * - * Other instances are for example time and especially date picker, - * which only show the currently activated time/data and hide the - * selection logic inside the combobox popup. - */ - static float chart_selection = 8.0f; - static int current_weapon = 0; - static int check_values[5]; - static float position[3]; - static struct nk_color combo_color = {130, 50, 50, 255}; - static struct nk_colorf combo_color2 = {0.509f, 0.705f, 0.2f, 1.0f}; - static size_t prog_a = 20, prog_b = 40, prog_c = 10, prog_d = 90; - static const char *weapons[] = {"Fist","Pistol","Shotgun","Plasma","BFG"}; - - char buffer[64]; - size_t sum = 0; - - /* default combobox */ - nk_layout_row_static(ctx, 25, 200, 1); - current_weapon = nk_combo(ctx, weapons, NK_LEN(weapons), current_weapon, 25, nk_vec2(200,200)); - - /* slider color combobox */ - if (nk_combo_begin_color(ctx, combo_color, nk_vec2(200,200))) { - float ratios[] = {0.15f, 0.85f}; - nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratios); - nk_label(ctx, "R:", NK_TEXT_LEFT); - combo_color.r = (nk_byte)nk_slide_int(ctx, 0, combo_color.r, 255, 5); - nk_label(ctx, "G:", NK_TEXT_LEFT); - combo_color.g = (nk_byte)nk_slide_int(ctx, 0, combo_color.g, 255, 5); - nk_label(ctx, "B:", NK_TEXT_LEFT); - combo_color.b = (nk_byte)nk_slide_int(ctx, 0, combo_color.b, 255, 5); - nk_label(ctx, "A:", NK_TEXT_LEFT); - combo_color.a = (nk_byte)nk_slide_int(ctx, 0, combo_color.a , 255, 5); - nk_combo_end(ctx); - } - /* complex color combobox */ - if (nk_combo_begin_color(ctx, nk_rgb_cf(combo_color2), nk_vec2(200,400))) { - enum color_mode {COL_RGB, COL_HSV}; - static int col_mode = COL_RGB; - #ifndef DEMO_DO_NOT_USE_COLOR_PICKER - nk_layout_row_dynamic(ctx, 120, 1); - combo_color2 = nk_color_picker(ctx, combo_color2, NK_RGBA); - #endif - - nk_layout_row_dynamic(ctx, 25, 2); - col_mode = nk_option_label(ctx, "RGB", col_mode == COL_RGB) ? COL_RGB : col_mode; - col_mode = nk_option_label(ctx, "HSV", col_mode == COL_HSV) ? COL_HSV : col_mode; - - nk_layout_row_dynamic(ctx, 25, 1); - if (col_mode == COL_RGB) { - combo_color2.r = nk_propertyf(ctx, "#R:", 0, combo_color2.r, 1.0f, 0.01f,0.005f); - combo_color2.g = nk_propertyf(ctx, "#G:", 0, combo_color2.g, 1.0f, 0.01f,0.005f); - combo_color2.b = nk_propertyf(ctx, "#B:", 0, combo_color2.b, 1.0f, 0.01f,0.005f); - combo_color2.a = nk_propertyf(ctx, "#A:", 0, combo_color2.a, 1.0f, 0.01f,0.005f); - } else { - float hsva[4]; - nk_colorf_hsva_fv(hsva, combo_color2); - hsva[0] = nk_propertyf(ctx, "#H:", 0, hsva[0], 1.0f, 0.01f,0.05f); - hsva[1] = nk_propertyf(ctx, "#S:", 0, hsva[1], 1.0f, 0.01f,0.05f); - hsva[2] = nk_propertyf(ctx, "#V:", 0, hsva[2], 1.0f, 0.01f,0.05f); - hsva[3] = nk_propertyf(ctx, "#A:", 0, hsva[3], 1.0f, 0.01f,0.05f); - combo_color2 = nk_hsva_colorfv(hsva); - } - nk_combo_end(ctx); - } - /* progressbar combobox */ - sum = prog_a + prog_b + prog_c + prog_d; - sprintf(buffer, "%lu", sum); - if (nk_combo_begin_label(ctx, buffer, nk_vec2(200,200))) { - nk_layout_row_dynamic(ctx, 30, 1); - nk_progress(ctx, &prog_a, 100, NK_MODIFIABLE); - nk_progress(ctx, &prog_b, 100, NK_MODIFIABLE); - nk_progress(ctx, &prog_c, 100, NK_MODIFIABLE); - nk_progress(ctx, &prog_d, 100, NK_MODIFIABLE); - nk_combo_end(ctx); - } - - /* checkbox combobox */ - sum = (size_t)(check_values[0] + check_values[1] + check_values[2] + check_values[3] + check_values[4]); - sprintf(buffer, "%lu", sum); - if (nk_combo_begin_label(ctx, buffer, nk_vec2(200,200))) { - nk_layout_row_dynamic(ctx, 30, 1); - nk_checkbox_label(ctx, weapons[0], &check_values[0]); - nk_checkbox_label(ctx, weapons[1], &check_values[1]); - nk_checkbox_label(ctx, weapons[2], &check_values[2]); - nk_checkbox_label(ctx, weapons[3], &check_values[3]); - nk_combo_end(ctx); - } - - /* complex text combobox */ - sprintf(buffer, "%.2f, %.2f, %.2f", position[0], position[1],position[2]); - if (nk_combo_begin_label(ctx, buffer, nk_vec2(200,200))) { - nk_layout_row_dynamic(ctx, 25, 1); - nk_property_float(ctx, "#X:", -1024.0f, &position[0], 1024.0f, 1,0.5f); - nk_property_float(ctx, "#Y:", -1024.0f, &position[1], 1024.0f, 1,0.5f); - nk_property_float(ctx, "#Z:", -1024.0f, &position[2], 1024.0f, 1,0.5f); - nk_combo_end(ctx); - } - - /* chart combobox */ - sprintf(buffer, "%.1f", chart_selection); - if (nk_combo_begin_label(ctx, buffer, nk_vec2(200,250))) { - size_t i = 0; - static const float values[]={26.0f,13.0f,30.0f,15.0f,25.0f,10.0f,20.0f,40.0f, 12.0f, 8.0f, 22.0f, 28.0f, 5.0f}; - nk_layout_row_dynamic(ctx, 150, 1); - nk_chart_begin(ctx, NK_CHART_COLUMN, NK_LEN(values), 0, 50); - for (i = 0; i < NK_LEN(values); ++i) { - nk_flags res = nk_chart_push(ctx, values[i]); - if (res & NK_CHART_CLICKED) { - chart_selection = values[i]; - nk_combo_close(ctx); - } - } - nk_chart_end(ctx); - nk_combo_end(ctx); - } - - { - static int time_selected = 0; - static int date_selected = 0; - static struct tm sel_time; - static struct tm sel_date; - if (!time_selected || !date_selected) { - /* keep time and date updated if nothing is selected */ - time_t cur_time = time(0); - struct tm *n = localtime(&cur_time); - if (!time_selected) - memcpy(&sel_time, n, sizeof(struct tm)); - if (!date_selected) - memcpy(&sel_date, n, sizeof(struct tm)); - } - - /* time combobox */ - sprintf(buffer, "%02d:%02d:%02d", sel_time.tm_hour, sel_time.tm_min, sel_time.tm_sec); - if (nk_combo_begin_label(ctx, buffer, nk_vec2(200,250))) { - time_selected = 1; - nk_layout_row_dynamic(ctx, 25, 1); - sel_time.tm_sec = nk_propertyi(ctx, "#S:", 0, sel_time.tm_sec, 60, 1, 1); - sel_time.tm_min = nk_propertyi(ctx, "#M:", 0, sel_time.tm_min, 60, 1, 1); - sel_time.tm_hour = nk_propertyi(ctx, "#H:", 0, sel_time.tm_hour, 23, 1, 1); - nk_combo_end(ctx); - } - - /* date combobox */ - sprintf(buffer, "%02d-%02d-%02d", sel_date.tm_mday, sel_date.tm_mon+1, sel_date.tm_year+1900); - if (nk_combo_begin_label(ctx, buffer, nk_vec2(350,400))) - { - int i = 0; - const char *month[] = {"January", "February", "March", - "April", "May", "June", "July", "August", "September", - "October", "November", "December"}; - const char *week_days[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"}; - const int month_days[] = {31,28,31,30,31,30,31,31,30,31,30,31}; - int year = sel_date.tm_year+1900; - int leap_year = (!(year % 4) && ((year % 100))) || !(year % 400); - int days = (sel_date.tm_mon == 1) ? - month_days[sel_date.tm_mon] + leap_year: - month_days[sel_date.tm_mon]; - - /* header with month and year */ - date_selected = 1; - nk_layout_row_begin(ctx, NK_DYNAMIC, 20, 3); - nk_layout_row_push(ctx, 0.05f); - if (nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_LEFT)) { - if (sel_date.tm_mon == 0) { - sel_date.tm_mon = 11; - sel_date.tm_year = NK_MAX(0, sel_date.tm_year-1); - } else sel_date.tm_mon--; - } - nk_layout_row_push(ctx, 0.9f); - sprintf(buffer, "%s %d", month[sel_date.tm_mon], year); - nk_label(ctx, buffer, NK_TEXT_CENTERED); - nk_layout_row_push(ctx, 0.05f); - if (nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_RIGHT)) { - if (sel_date.tm_mon == 11) { - sel_date.tm_mon = 0; - sel_date.tm_year++; - } else sel_date.tm_mon++; - } - nk_layout_row_end(ctx); - - /* good old week day formula (double because precision) */ - {int year_n = (sel_date.tm_mon < 2) ? year-1: year; - int y = year_n % 100; - int c = year_n / 100; - int y4 = (int)((float)y / 4); - int c4 = (int)((float)c / 4); - int m = (int)(2.6 * (double)(((sel_date.tm_mon + 10) % 12) + 1) - 0.2); - int week_day = (((1 + m + y + y4 + c4 - 2 * c) % 7) + 7) % 7; - - /* weekdays */ - nk_layout_row_dynamic(ctx, 35, 7); - for (i = 0; i < (int)NK_LEN(week_days); ++i) - nk_label(ctx, week_days[i], NK_TEXT_CENTERED); - - /* days */ - if (week_day > 0) nk_spacing(ctx, week_day); - for (i = 1; i <= days; ++i) { - sprintf(buffer, "%d", i); - if (nk_button_label(ctx, buffer)) { - sel_date.tm_mday = i; - nk_combo_close(ctx); - } - }} - nk_combo_end(ctx); - } - } - - nk_tree_pop(ctx); - } - - if (nk_tree_push(ctx, NK_TREE_NODE, "Input", NK_MINIMIZED)) - { - static const float ratio[] = {120, 150}; - static char field_buffer[64]; - static char text[9][64]; - static int text_len[9]; - static char box_buffer[512]; - static int field_len; - static int box_len; - nk_flags active; - - nk_layout_row(ctx, NK_STATIC, 25, 2, ratio); - nk_label(ctx, "Default:", NK_TEXT_LEFT); - - nk_edit_string(ctx, NK_EDIT_SIMPLE, text[0], &text_len[0], 64, nk_filter_default); - nk_label(ctx, "Int:", NK_TEXT_LEFT); - nk_edit_string(ctx, NK_EDIT_SIMPLE, text[1], &text_len[1], 64, nk_filter_decimal); - nk_label(ctx, "Float:", NK_TEXT_LEFT); - nk_edit_string(ctx, NK_EDIT_SIMPLE, text[2], &text_len[2], 64, nk_filter_float); - nk_label(ctx, "Hex:", NK_TEXT_LEFT); - nk_edit_string(ctx, NK_EDIT_SIMPLE, text[4], &text_len[4], 64, nk_filter_hex); - nk_label(ctx, "Octal:", NK_TEXT_LEFT); - nk_edit_string(ctx, NK_EDIT_SIMPLE, text[5], &text_len[5], 64, nk_filter_oct); - nk_label(ctx, "Binary:", NK_TEXT_LEFT); - nk_edit_string(ctx, NK_EDIT_SIMPLE, text[6], &text_len[6], 64, nk_filter_binary); - - nk_label(ctx, "Password:", NK_TEXT_LEFT); - { - int i = 0; - int old_len = text_len[8]; - char buffer[64]; - for (i = 0; i < text_len[8]; ++i) buffer[i] = '*'; - nk_edit_string(ctx, NK_EDIT_FIELD, buffer, &text_len[8], 64, nk_filter_default); - if (old_len < text_len[8]) - memcpy(&text[8][old_len], &buffer[old_len], (nk_size)(text_len[8] - old_len)); - } - - nk_label(ctx, "Field:", NK_TEXT_LEFT); - nk_edit_string(ctx, NK_EDIT_FIELD, field_buffer, &field_len, 64, nk_filter_default); - - nk_label(ctx, "Box:", NK_TEXT_LEFT); - nk_layout_row_static(ctx, 180, 278, 1); - nk_edit_string(ctx, NK_EDIT_BOX, box_buffer, &box_len, 512, nk_filter_default); - - nk_layout_row(ctx, NK_STATIC, 25, 2, ratio); - active = nk_edit_string(ctx, NK_EDIT_FIELD|NK_EDIT_SIG_ENTER, text[7], &text_len[7], 64, nk_filter_ascii); - if (nk_button_label(ctx, "Submit") || - (active & NK_EDIT_COMMITED)) - { - text[7][text_len[7]] = '\n'; - text_len[7]++; - memcpy(&box_buffer[box_len], &text[7], (nk_size)text_len[7]); - box_len += text_len[7]; - text_len[7] = 0; - } - nk_tree_pop(ctx); - } - nk_tree_pop(ctx); - } - - if (nk_tree_push(ctx, NK_TREE_TAB, "Chart", NK_MINIMIZED)) - { - /* Chart Widgets - * This library has two different rather simple charts. The line and the - * column chart. Both provide a simple way of visualizing values and - * have a retained mode and immediate mode API version. For the retain - * mode version `nk_plot` and `nk_plot_function` you either provide - * an array or a callback to call to handle drawing the graph. - * For the immediate mode version you start by calling `nk_chart_begin` - * and need to provide min and max values for scaling on the Y-axis. - * and then call `nk_chart_push` to push values into the chart. - * Finally `nk_chart_end` needs to be called to end the process. */ - float id = 0; - static int col_index = -1; - static int line_index = -1; - float step = (2*3.141592654f) / 32; - - int i; - int index = -1; - struct nk_rect bounds; - - /* line chart */ - id = 0; - index = -1; - nk_layout_row_dynamic(ctx, 100, 1); - bounds = nk_widget_bounds(ctx); - if (nk_chart_begin(ctx, NK_CHART_LINES, 32, -1.0f, 1.0f)) { - for (i = 0; i < 32; ++i) { - nk_flags res = nk_chart_push(ctx, (float)cos(id)); - if (res & NK_CHART_HOVERING) - index = (int)i; - if (res & NK_CHART_CLICKED) - line_index = (int)i; - id += step; - } - nk_chart_end(ctx); - } - - if (index != -1) - nk_tooltipf(ctx, "Value: %.2f", (float)cos((float)index*step)); - if (line_index != -1) { - nk_layout_row_dynamic(ctx, 20, 1); - nk_labelf(ctx, NK_TEXT_LEFT, "Selected value: %.2f", (float)cos((float)index*step)); - } - - /* column chart */ - nk_layout_row_dynamic(ctx, 100, 1); - bounds = nk_widget_bounds(ctx); - if (nk_chart_begin(ctx, NK_CHART_COLUMN, 32, 0.0f, 1.0f)) { - for (i = 0; i < 32; ++i) { - nk_flags res = nk_chart_push(ctx, (float)fabs(sin(id))); - if (res & NK_CHART_HOVERING) - index = (int)i; - if (res & NK_CHART_CLICKED) - col_index = (int)i; - id += step; - } - nk_chart_end(ctx); - } - if (index != -1) - nk_tooltipf(ctx, "Value: %.2f", (float)fabs(sin(step * (float)index))); - if (col_index != -1) { - nk_layout_row_dynamic(ctx, 20, 1); - nk_labelf(ctx, NK_TEXT_LEFT, "Selected value: %.2f", (float)fabs(sin(step * (float)col_index))); - } - - /* mixed chart */ - nk_layout_row_dynamic(ctx, 100, 1); - bounds = nk_widget_bounds(ctx); - if (nk_chart_begin(ctx, NK_CHART_COLUMN, 32, 0.0f, 1.0f)) { - nk_chart_add_slot(ctx, NK_CHART_LINES, 32, -1.0f, 1.0f); - nk_chart_add_slot(ctx, NK_CHART_LINES, 32, -1.0f, 1.0f); - for (id = 0, i = 0; i < 32; ++i) { - nk_chart_push_slot(ctx, (float)fabs(sin(id)), 0); - nk_chart_push_slot(ctx, (float)cos(id), 1); - nk_chart_push_slot(ctx, (float)sin(id), 2); - id += step; - } - } - nk_chart_end(ctx); - - /* mixed colored chart */ - nk_layout_row_dynamic(ctx, 100, 1); - bounds = nk_widget_bounds(ctx); - if (nk_chart_begin_colored(ctx, NK_CHART_LINES, nk_rgb(255,0,0), nk_rgb(150,0,0), 32, 0.0f, 1.0f)) { - nk_chart_add_slot_colored(ctx, NK_CHART_LINES, nk_rgb(0,0,255), nk_rgb(0,0,150),32, -1.0f, 1.0f); - nk_chart_add_slot_colored(ctx, NK_CHART_LINES, nk_rgb(0,255,0), nk_rgb(0,150,0), 32, -1.0f, 1.0f); - for (id = 0, i = 0; i < 32; ++i) { - nk_chart_push_slot(ctx, (float)fabs(sin(id)), 0); - nk_chart_push_slot(ctx, (float)cos(id), 1); - nk_chart_push_slot(ctx, (float)sin(id), 2); - id += step; - } - } - nk_chart_end(ctx); - nk_tree_pop(ctx); - } - - if (nk_tree_push(ctx, NK_TREE_TAB, "Popup", NK_MINIMIZED)) - { - static struct nk_color color = {255,0,0, 255}; - static int select[4]; - static int popup_active; - const struct nk_input *in = &ctx->input; - struct nk_rect bounds; - - /* menu contextual */ - nk_layout_row_static(ctx, 30, 160, 1); - bounds = nk_widget_bounds(ctx); - nk_label(ctx, "Right click me for menu", NK_TEXT_LEFT); - - if (nk_contextual_begin(ctx, 0, nk_vec2(100, 300), bounds)) { - static size_t prog = 40; - static int slider = 10; - - nk_layout_row_dynamic(ctx, 25, 1); - nk_checkbox_label(ctx, "Menu", &show_menu); - nk_progress(ctx, &prog, 100, NK_MODIFIABLE); - nk_slider_int(ctx, 0, &slider, 16, 1); - if (nk_contextual_item_label(ctx, "About", NK_TEXT_CENTERED)) - show_app_about = nk_true; - nk_selectable_label(ctx, select[0]?"Unselect":"Select", NK_TEXT_LEFT, &select[0]); - nk_selectable_label(ctx, select[1]?"Unselect":"Select", NK_TEXT_LEFT, &select[1]); - nk_selectable_label(ctx, select[2]?"Unselect":"Select", NK_TEXT_LEFT, &select[2]); - nk_selectable_label(ctx, select[3]?"Unselect":"Select", NK_TEXT_LEFT, &select[3]); - nk_contextual_end(ctx); - } - - /* color contextual */ - nk_layout_row_begin(ctx, NK_STATIC, 30, 2); - nk_layout_row_push(ctx, 100); - nk_label(ctx, "Right Click here:", NK_TEXT_LEFT); - nk_layout_row_push(ctx, 50); - bounds = nk_widget_bounds(ctx); - nk_button_color(ctx, color); - nk_layout_row_end(ctx); - - if (nk_contextual_begin(ctx, 0, nk_vec2(350, 60), bounds)) { - nk_layout_row_dynamic(ctx, 30, 4); - color.r = (nk_byte)nk_propertyi(ctx, "#r", 0, color.r, 255, 1, 1); - color.g = (nk_byte)nk_propertyi(ctx, "#g", 0, color.g, 255, 1, 1); - color.b = (nk_byte)nk_propertyi(ctx, "#b", 0, color.b, 255, 1, 1); - color.a = (nk_byte)nk_propertyi(ctx, "#a", 0, color.a, 255, 1, 1); - nk_contextual_end(ctx); - } - - /* popup */ - nk_layout_row_begin(ctx, NK_STATIC, 30, 2); - nk_layout_row_push(ctx, 100); - nk_label(ctx, "Popup:", NK_TEXT_LEFT); - nk_layout_row_push(ctx, 50); - if (nk_button_label(ctx, "Popup")) - popup_active = 1; - nk_layout_row_end(ctx); - - if (popup_active) - { - static struct nk_rect s = {20, 100, 220, 90}; - if (nk_popup_begin(ctx, NK_POPUP_STATIC, "Error", 0, s)) - { - nk_layout_row_dynamic(ctx, 25, 1); - nk_label(ctx, "A terrible error as occured", NK_TEXT_LEFT); - nk_layout_row_dynamic(ctx, 25, 2); - if (nk_button_label(ctx, "OK")) { - popup_active = 0; - nk_popup_close(ctx); - } - if (nk_button_label(ctx, "Cancel")) { - popup_active = 0; - nk_popup_close(ctx); - } - nk_popup_end(ctx); - } else popup_active = nk_false; - } - - /* tooltip */ - nk_layout_row_static(ctx, 30, 150, 1); - bounds = nk_widget_bounds(ctx); - nk_label(ctx, "Hover me for tooltip", NK_TEXT_LEFT); - if (nk_input_is_mouse_hovering_rect(in, bounds)) - nk_tooltip(ctx, "This is a tooltip"); - - nk_tree_pop(ctx); - } - - if (nk_tree_push(ctx, NK_TREE_TAB, "Layout", NK_MINIMIZED)) - { - if (nk_tree_push(ctx, NK_TREE_NODE, "Widget", NK_MINIMIZED)) - { - float ratio_two[] = {0.2f, 0.6f, 0.2f}; - float width_two[] = {100, 200, 50}; - - nk_layout_row_dynamic(ctx, 30, 1); - nk_label(ctx, "Dynamic fixed column layout with generated position and size:", NK_TEXT_LEFT); - nk_layout_row_dynamic(ctx, 30, 3); - nk_button_label(ctx, "button"); - nk_button_label(ctx, "button"); - nk_button_label(ctx, "button"); - - nk_layout_row_dynamic(ctx, 30, 1); - nk_label(ctx, "static fixed column layout with generated position and size:", NK_TEXT_LEFT); - nk_layout_row_static(ctx, 30, 100, 3); - nk_button_label(ctx, "button"); - nk_button_label(ctx, "button"); - nk_button_label(ctx, "button"); - - nk_layout_row_dynamic(ctx, 30, 1); - nk_label(ctx, "Dynamic array-based custom column layout with generated position and custom size:",NK_TEXT_LEFT); - nk_layout_row(ctx, NK_DYNAMIC, 30, 3, ratio_two); - nk_button_label(ctx, "button"); - nk_button_label(ctx, "button"); - nk_button_label(ctx, "button"); - - nk_layout_row_dynamic(ctx, 30, 1); - nk_label(ctx, "Static array-based custom column layout with generated position and custom size:",NK_TEXT_LEFT ); - nk_layout_row(ctx, NK_STATIC, 30, 3, width_two); - nk_button_label(ctx, "button"); - nk_button_label(ctx, "button"); - nk_button_label(ctx, "button"); - - nk_layout_row_dynamic(ctx, 30, 1); - nk_label(ctx, "Dynamic immediate mode custom column layout with generated position and custom size:",NK_TEXT_LEFT); - nk_layout_row_begin(ctx, NK_DYNAMIC, 30, 3); - nk_layout_row_push(ctx, 0.2f); - nk_button_label(ctx, "button"); - nk_layout_row_push(ctx, 0.6f); - nk_button_label(ctx, "button"); - nk_layout_row_push(ctx, 0.2f); - nk_button_label(ctx, "button"); - nk_layout_row_end(ctx); - - nk_layout_row_dynamic(ctx, 30, 1); - nk_label(ctx, "Static immediate mode custom column layout with generated position and custom size:", NK_TEXT_LEFT); - nk_layout_row_begin(ctx, NK_STATIC, 30, 3); - nk_layout_row_push(ctx, 100); - nk_button_label(ctx, "button"); - nk_layout_row_push(ctx, 200); - nk_button_label(ctx, "button"); - nk_layout_row_push(ctx, 50); - nk_button_label(ctx, "button"); - nk_layout_row_end(ctx); - - nk_layout_row_dynamic(ctx, 30, 1); - nk_label(ctx, "Static free space with custom position and custom size:", NK_TEXT_LEFT); - nk_layout_space_begin(ctx, NK_STATIC, 60, 4); - nk_layout_space_push(ctx, nk_rect(100, 0, 100, 30)); - nk_button_label(ctx, "button"); - nk_layout_space_push(ctx, nk_rect(0, 15, 100, 30)); - nk_button_label(ctx, "button"); - nk_layout_space_push(ctx, nk_rect(200, 15, 100, 30)); - nk_button_label(ctx, "button"); - nk_layout_space_push(ctx, nk_rect(100, 30, 100, 30)); - nk_button_label(ctx, "button"); - nk_layout_space_end(ctx); - - nk_layout_row_dynamic(ctx, 30, 1); - nk_label(ctx, "Row template:", NK_TEXT_LEFT); - nk_layout_row_template_begin(ctx, 30); - nk_layout_row_template_push_dynamic(ctx); - nk_layout_row_template_push_variable(ctx, 80); - nk_layout_row_template_push_static(ctx, 80); - nk_layout_row_template_end(ctx); - nk_button_label(ctx, "button"); - nk_button_label(ctx, "button"); - nk_button_label(ctx, "button"); - - nk_tree_pop(ctx); - } - - if (nk_tree_push(ctx, NK_TREE_NODE, "Group", NK_MINIMIZED)) - { - static int group_titlebar = nk_false; - static int group_border = nk_true; - static int group_no_scrollbar = nk_false; - static int group_width = 320; - static int group_height = 200; - - nk_flags group_flags = 0; - if (group_border) group_flags |= NK_WINDOW_BORDER; - if (group_no_scrollbar) group_flags |= NK_WINDOW_NO_SCROLLBAR; - if (group_titlebar) group_flags |= NK_WINDOW_TITLE; - - nk_layout_row_dynamic(ctx, 30, 3); - nk_checkbox_label(ctx, "Titlebar", &group_titlebar); - nk_checkbox_label(ctx, "Border", &group_border); - nk_checkbox_label(ctx, "No Scrollbar", &group_no_scrollbar); - - nk_layout_row_begin(ctx, NK_STATIC, 22, 3); - nk_layout_row_push(ctx, 50); - nk_label(ctx, "size:", NK_TEXT_LEFT); - nk_layout_row_push(ctx, 130); - nk_property_int(ctx, "#Width:", 100, &group_width, 500, 10, 1); - nk_layout_row_push(ctx, 130); - nk_property_int(ctx, "#Height:", 100, &group_height, 500, 10, 1); - nk_layout_row_end(ctx); - - nk_layout_row_static(ctx, (float)group_height, group_width, 2); - if (nk_group_begin(ctx, "Group", group_flags)) { - int i = 0; - static int selected[16]; - nk_layout_row_static(ctx, 18, 100, 1); - for (i = 0; i < 16; ++i) - nk_selectable_label(ctx, (selected[i]) ? "Selected": "Unselected", NK_TEXT_CENTERED, &selected[i]); - nk_group_end(ctx); - } - nk_tree_pop(ctx); - } - - if (nk_tree_push(ctx, NK_TREE_NODE, "Notebook", NK_MINIMIZED)) - { - static int current_tab = 0; - struct nk_rect bounds; - float step = (2*3.141592654f) / 32; - enum chart_type {CHART_LINE, CHART_HISTO, CHART_MIXED}; - const char *names[] = {"Lines", "Columns", "Mixed"}; - float id = 0; - int i; - - /* Header */ - nk_style_push_vec2(ctx, &ctx->style.window.spacing, nk_vec2(0,0)); - nk_style_push_float(ctx, &ctx->style.button.rounding, 0); - nk_layout_row_begin(ctx, NK_STATIC, 20, 3); - for (i = 0; i < 3; ++i) { - /* make sure button perfectly fits text */ - const struct nk_user_font *f = ctx->style.font; - float text_width = f->width(f->userdata, f->height, names[i], nk_strlen(names[i])); - float widget_width = text_width + 3 * ctx->style.button.padding.x; - nk_layout_row_push(ctx, widget_width); - if (current_tab == i) { - /* active tab gets highlighted */ - struct nk_style_item button_color = ctx->style.button.normal; - ctx->style.button.normal = ctx->style.button.active; - current_tab = nk_button_label(ctx, names[i]) ? i: current_tab; - ctx->style.button.normal = button_color; - } else current_tab = nk_button_label(ctx, names[i]) ? i: current_tab; - } - nk_style_pop_float(ctx); - - /* Body */ - nk_layout_row_dynamic(ctx, 140, 1); - if (nk_group_begin(ctx, "Notebook", NK_WINDOW_BORDER)) - { - nk_style_pop_vec2(ctx); - switch (current_tab) { - default: break; - case CHART_LINE: - nk_layout_row_dynamic(ctx, 100, 1); - bounds = nk_widget_bounds(ctx); - if (nk_chart_begin_colored(ctx, NK_CHART_LINES, nk_rgb(255,0,0), nk_rgb(150,0,0), 32, 0.0f, 1.0f)) { - nk_chart_add_slot_colored(ctx, NK_CHART_LINES, nk_rgb(0,0,255), nk_rgb(0,0,150),32, -1.0f, 1.0f); - for (i = 0, id = 0; i < 32; ++i) { - nk_chart_push_slot(ctx, (float)fabs(sin(id)), 0); - nk_chart_push_slot(ctx, (float)cos(id), 1); - id += step; - } - } - nk_chart_end(ctx); - break; - case CHART_HISTO: - nk_layout_row_dynamic(ctx, 100, 1); - bounds = nk_widget_bounds(ctx); - if (nk_chart_begin_colored(ctx, NK_CHART_COLUMN, nk_rgb(255,0,0), nk_rgb(150,0,0), 32, 0.0f, 1.0f)) { - for (i = 0, id = 0; i < 32; ++i) { - nk_chart_push_slot(ctx, (float)fabs(sin(id)), 0); - id += step; - } - } - nk_chart_end(ctx); - break; - case CHART_MIXED: - nk_layout_row_dynamic(ctx, 100, 1); - bounds = nk_widget_bounds(ctx); - if (nk_chart_begin_colored(ctx, NK_CHART_LINES, nk_rgb(255,0,0), nk_rgb(150,0,0), 32, 0.0f, 1.0f)) { - nk_chart_add_slot_colored(ctx, NK_CHART_LINES, nk_rgb(0,0,255), nk_rgb(0,0,150),32, -1.0f, 1.0f); - nk_chart_add_slot_colored(ctx, NK_CHART_COLUMN, nk_rgb(0,255,0), nk_rgb(0,150,0), 32, 0.0f, 1.0f); - for (i = 0, id = 0; i < 32; ++i) { - nk_chart_push_slot(ctx, (float)fabs(sin(id)), 0); - nk_chart_push_slot(ctx, (float)fabs(cos(id)), 1); - nk_chart_push_slot(ctx, (float)fabs(sin(id)), 2); - id += step; - } - } - nk_chart_end(ctx); - break; - } - nk_group_end(ctx); - } else nk_style_pop_vec2(ctx); - nk_tree_pop(ctx); - } - - if (nk_tree_push(ctx, NK_TREE_NODE, "Simple", NK_MINIMIZED)) - { - nk_layout_row_dynamic(ctx, 300, 2); - if (nk_group_begin(ctx, "Group_Without_Border", 0)) { - int i = 0; - char buffer[64]; - nk_layout_row_static(ctx, 18, 150, 1); - for (i = 0; i < 64; ++i) { - sprintf(buffer, "0x%02x", i); - nk_labelf(ctx, NK_TEXT_LEFT, "%s: scrollable region", buffer); - } - nk_group_end(ctx); - } - if (nk_group_begin(ctx, "Group_With_Border", NK_WINDOW_BORDER)) { - int i = 0; - char buffer[64]; - nk_layout_row_dynamic(ctx, 25, 2); - for (i = 0; i < 64; ++i) { - sprintf(buffer, "%08d", ((((i%7)*10)^32))+(64+(i%2)*2)); - nk_button_label(ctx, buffer); - } - nk_group_end(ctx); - } - nk_tree_pop(ctx); - } - - if (nk_tree_push(ctx, NK_TREE_NODE, "Complex", NK_MINIMIZED)) - { - int i; - nk_layout_space_begin(ctx, NK_STATIC, 500, 64); - nk_layout_space_push(ctx, nk_rect(0,0,150,500)); - if (nk_group_begin(ctx, "Group_left", NK_WINDOW_BORDER)) { - static int selected[32]; - nk_layout_row_static(ctx, 18, 100, 1); - for (i = 0; i < 32; ++i) - nk_selectable_label(ctx, (selected[i]) ? "Selected": "Unselected", NK_TEXT_CENTERED, &selected[i]); - nk_group_end(ctx); - } - - nk_layout_space_push(ctx, nk_rect(160,0,150,240)); - if (nk_group_begin(ctx, "Group_top", NK_WINDOW_BORDER)) { - nk_layout_row_dynamic(ctx, 25, 1); - nk_button_label(ctx, "#FFAA"); - nk_button_label(ctx, "#FFBB"); - nk_button_label(ctx, "#FFCC"); - nk_button_label(ctx, "#FFDD"); - nk_button_label(ctx, "#FFEE"); - nk_button_label(ctx, "#FFFF"); - nk_group_end(ctx); - } - - nk_layout_space_push(ctx, nk_rect(160,250,150,250)); - if (nk_group_begin(ctx, "Group_buttom", NK_WINDOW_BORDER)) { - nk_layout_row_dynamic(ctx, 25, 1); - nk_button_label(ctx, "#FFAA"); - nk_button_label(ctx, "#FFBB"); - nk_button_label(ctx, "#FFCC"); - nk_button_label(ctx, "#FFDD"); - nk_button_label(ctx, "#FFEE"); - nk_button_label(ctx, "#FFFF"); - nk_group_end(ctx); - } - - nk_layout_space_push(ctx, nk_rect(320,0,150,150)); - if (nk_group_begin(ctx, "Group_right_top", NK_WINDOW_BORDER)) { - static int selected[4]; - nk_layout_row_static(ctx, 18, 100, 1); - for (i = 0; i < 4; ++i) - nk_selectable_label(ctx, (selected[i]) ? "Selected": "Unselected", NK_TEXT_CENTERED, &selected[i]); - nk_group_end(ctx); - } - - nk_layout_space_push(ctx, nk_rect(320,160,150,150)); - if (nk_group_begin(ctx, "Group_right_center", NK_WINDOW_BORDER)) { - static int selected[4]; - nk_layout_row_static(ctx, 18, 100, 1); - for (i = 0; i < 4; ++i) - nk_selectable_label(ctx, (selected[i]) ? "Selected": "Unselected", NK_TEXT_CENTERED, &selected[i]); - nk_group_end(ctx); - } - - nk_layout_space_push(ctx, nk_rect(320,320,150,150)); - if (nk_group_begin(ctx, "Group_right_bottom", NK_WINDOW_BORDER)) { - static int selected[4]; - nk_layout_row_static(ctx, 18, 100, 1); - for (i = 0; i < 4; ++i) - nk_selectable_label(ctx, (selected[i]) ? "Selected": "Unselected", NK_TEXT_CENTERED, &selected[i]); - nk_group_end(ctx); - } - nk_layout_space_end(ctx); - nk_tree_pop(ctx); - } - - if (nk_tree_push(ctx, NK_TREE_NODE, "Splitter", NK_MINIMIZED)) - { - const struct nk_input *in = &ctx->input; - nk_layout_row_static(ctx, 20, 320, 1); - nk_label(ctx, "Use slider and spinner to change tile size", NK_TEXT_LEFT); - nk_label(ctx, "Drag the space between tiles to change tile ratio", NK_TEXT_LEFT); - - if (nk_tree_push(ctx, NK_TREE_NODE, "Vertical", NK_MINIMIZED)) - { - static float a = 100, b = 100, c = 100; - struct nk_rect bounds; - - float row_layout[5]; - row_layout[0] = a; - row_layout[1] = 8; - row_layout[2] = b; - row_layout[3] = 8; - row_layout[4] = c; - - /* header */ - nk_layout_row_static(ctx, 30, 100, 2); - nk_label(ctx, "left:", NK_TEXT_LEFT); - nk_slider_float(ctx, 10.0f, &a, 200.0f, 10.0f); - - nk_label(ctx, "middle:", NK_TEXT_LEFT); - nk_slider_float(ctx, 10.0f, &b, 200.0f, 10.0f); - - nk_label(ctx, "right:", NK_TEXT_LEFT); - nk_slider_float(ctx, 10.0f, &c, 200.0f, 10.0f); - - /* tiles */ - nk_layout_row(ctx, NK_STATIC, 200, 5, row_layout); - - /* left space */ - if (nk_group_begin(ctx, "left", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR)) { - nk_layout_row_dynamic(ctx, 25, 1); - nk_button_label(ctx, "#FFAA"); - nk_button_label(ctx, "#FFBB"); - nk_button_label(ctx, "#FFCC"); - nk_button_label(ctx, "#FFDD"); - nk_button_label(ctx, "#FFEE"); - nk_button_label(ctx, "#FFFF"); - nk_group_end(ctx); - } - - /* scaler */ - bounds = nk_widget_bounds(ctx); - nk_spacing(ctx, 1); - if ((nk_input_is_mouse_hovering_rect(in, bounds) || - nk_input_is_mouse_prev_hovering_rect(in, bounds)) && - nk_input_is_mouse_down(in, NK_BUTTON_LEFT)) - { - a = row_layout[0] + in->mouse.delta.x; - b = row_layout[2] - in->mouse.delta.x; - } - - /* middle space */ - if (nk_group_begin(ctx, "center", NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR)) { - nk_layout_row_dynamic(ctx, 25, 1); - nk_button_label(ctx, "#FFAA"); - nk_button_label(ctx, "#FFBB"); - nk_button_label(ctx, "#FFCC"); - nk_button_label(ctx, "#FFDD"); - nk_button_label(ctx, "#FFEE"); - nk_button_label(ctx, "#FFFF"); - nk_group_end(ctx); - } - - /* scaler */ - bounds = nk_widget_bounds(ctx); - nk_spacing(ctx, 1); - if ((nk_input_is_mouse_hovering_rect(in, bounds) || - nk_input_is_mouse_prev_hovering_rect(in, bounds)) && - nk_input_is_mouse_down(in, NK_BUTTON_LEFT)) - { - b = (row_layout[2] + in->mouse.delta.x); - c = (row_layout[4] - in->mouse.delta.x); - } - - /* right space */ - if (nk_group_begin(ctx, "right", NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR)) { - nk_layout_row_dynamic(ctx, 25, 1); - nk_button_label(ctx, "#FFAA"); - nk_button_label(ctx, "#FFBB"); - nk_button_label(ctx, "#FFCC"); - nk_button_label(ctx, "#FFDD"); - nk_button_label(ctx, "#FFEE"); - nk_button_label(ctx, "#FFFF"); - nk_group_end(ctx); - } - - nk_tree_pop(ctx); - } - - if (nk_tree_push(ctx, NK_TREE_NODE, "Horizontal", NK_MINIMIZED)) - { - static float a = 100, b = 100, c = 100; - struct nk_rect bounds; - - /* header */ - nk_layout_row_static(ctx, 30, 100, 2); - nk_label(ctx, "top:", NK_TEXT_LEFT); - nk_slider_float(ctx, 10.0f, &a, 200.0f, 10.0f); - - nk_label(ctx, "middle:", NK_TEXT_LEFT); - nk_slider_float(ctx, 10.0f, &b, 200.0f, 10.0f); - - nk_label(ctx, "bottom:", NK_TEXT_LEFT); - nk_slider_float(ctx, 10.0f, &c, 200.0f, 10.0f); - - /* top space */ - nk_layout_row_dynamic(ctx, a, 1); - if (nk_group_begin(ctx, "top", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER)) { - nk_layout_row_dynamic(ctx, 25, 3); - nk_button_label(ctx, "#FFAA"); - nk_button_label(ctx, "#FFBB"); - nk_button_label(ctx, "#FFCC"); - nk_button_label(ctx, "#FFDD"); - nk_button_label(ctx, "#FFEE"); - nk_button_label(ctx, "#FFFF"); - nk_group_end(ctx); - } - - /* scaler */ - nk_layout_row_dynamic(ctx, 8, 1); - bounds = nk_widget_bounds(ctx); - nk_spacing(ctx, 1); - if ((nk_input_is_mouse_hovering_rect(in, bounds) || - nk_input_is_mouse_prev_hovering_rect(in, bounds)) && - nk_input_is_mouse_down(in, NK_BUTTON_LEFT)) - { - a = a + in->mouse.delta.y; - b = b - in->mouse.delta.y; - } - - /* middle space */ - nk_layout_row_dynamic(ctx, b, 1); - if (nk_group_begin(ctx, "middle", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER)) { - nk_layout_row_dynamic(ctx, 25, 3); - nk_button_label(ctx, "#FFAA"); - nk_button_label(ctx, "#FFBB"); - nk_button_label(ctx, "#FFCC"); - nk_button_label(ctx, "#FFDD"); - nk_button_label(ctx, "#FFEE"); - nk_button_label(ctx, "#FFFF"); - nk_group_end(ctx); - } - - { - /* scaler */ - nk_layout_row_dynamic(ctx, 8, 1); - bounds = nk_widget_bounds(ctx); - if ((nk_input_is_mouse_hovering_rect(in, bounds) || - nk_input_is_mouse_prev_hovering_rect(in, bounds)) && - nk_input_is_mouse_down(in, NK_BUTTON_LEFT)) - { - b = b + in->mouse.delta.y; - c = c - in->mouse.delta.y; - } - } - - /* bottom space */ - nk_layout_row_dynamic(ctx, c, 1); - if (nk_group_begin(ctx, "bottom", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER)) { - nk_layout_row_dynamic(ctx, 25, 3); - nk_button_label(ctx, "#FFAA"); - nk_button_label(ctx, "#FFBB"); - nk_button_label(ctx, "#FFCC"); - nk_button_label(ctx, "#FFDD"); - nk_button_label(ctx, "#FFEE"); - nk_button_label(ctx, "#FFFF"); - nk_group_end(ctx); - } - nk_tree_pop(ctx); - } - nk_tree_pop(ctx); - } - nk_tree_pop(ctx); - } - } - nk_end(ctx); - return !nk_window_is_closed(ctx, "Overview"); -} - diff --git a/subprojects/nk_pugl/nuklear/demo/sdl_opengl2/Makefile b/subprojects/nk_pugl/nuklear/demo/sdl_opengl2/Makefile deleted file mode 100644 index b73174a..0000000 --- a/subprojects/nk_pugl/nuklear/demo/sdl_opengl2/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -# Install -BIN = demo - -# Flags -CFLAGS += -std=c99 -pedantic -O2 - -SRC = main.c -OBJ = $(SRC:.c=.o) - -ifeq ($(OS),Windows_NT) -BIN := $(BIN).exe -LIBS = -lmingw32 -lSDL2main -lSDL2 -lopengl32 -lm -lGLU32 -else - UNAME_S := $(shell uname -s) - ifeq ($(UNAME_S),Darwin) - LIBS = -lSDL2 -framework OpenGL -lm - else - LIBS = -lSDL2 -lGL -lm -lGLU - endif -endif - -$(BIN): - @mkdir -p bin - rm -f bin/$(BIN) $(OBJS) - $(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS) diff --git a/subprojects/nk_pugl/nuklear/demo/sdl_opengl2/main.c b/subprojects/nk_pugl/nuklear/demo/sdl_opengl2/main.c deleted file mode 100644 index 0fbf3ff..0000000 --- a/subprojects/nk_pugl/nuklear/demo/sdl_opengl2/main.c +++ /dev/null @@ -1,198 +0,0 @@ -/* nuklear - 1.32.0 - public domain */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_STANDARD_VARARGS -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT -#define NK_INCLUDE_FONT_BAKING -#define NK_INCLUDE_DEFAULT_FONT -#define NK_IMPLEMENTATION -#define NK_SDL_GL2_IMPLEMENTATION -#include "../../nuklear.h" -#include "nuklear_sdl_gl2.h" - -#define WINDOW_WIDTH 1200 -#define WINDOW_HEIGHT 800 - -/* =============================================================== - * - * EXAMPLE - * - * ===============================================================*/ -/* This are some code examples to provide a small overview of what can be - * done with this library. To try out an example uncomment the defines */ -/*#define INCLUDE_ALL */ -/*#define INCLUDE_STYLE */ -/*#define INCLUDE_CALCULATOR */ -/*#define INCLUDE_OVERVIEW */ -/*#define INCLUDE_NODE_EDITOR */ - -#ifdef INCLUDE_ALL - #define INCLUDE_STYLE - #define INCLUDE_CALCULATOR - #define INCLUDE_OVERVIEW - #define INCLUDE_NODE_EDITOR -#endif - -#ifdef INCLUDE_STYLE - #include "../style.c" -#endif -#ifdef INCLUDE_CALCULATOR - #include "../calculator.c" -#endif -#ifdef INCLUDE_OVERVIEW - #include "../overview.c" -#endif -#ifdef INCLUDE_NODE_EDITOR - #include "../node_editor.c" -#endif - -/* =============================================================== - * - * DEMO - * - * ===============================================================*/ -int -main(void) -{ - /* Platform */ - SDL_Window *win; - SDL_GLContext glContext; - int win_width, win_height; - int running = 1; - - /* GUI */ - struct nk_context *ctx; - struct nk_colorf bg; - - /* SDL setup */ - SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "0"); - SDL_Init(SDL_INIT_VIDEO); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); - win = SDL_CreateWindow("Demo", - SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN|SDL_WINDOW_ALLOW_HIGHDPI); - glContext = SDL_GL_CreateContext(win); - SDL_GetWindowSize(win, &win_width, &win_height); - - /* GUI */ - ctx = nk_sdl_init(win); - /* Load Fonts: if none of these are loaded a default font will be used */ - /* Load Cursor: if you uncomment cursor loading please hide the cursor */ - {struct nk_font_atlas *atlas; - nk_sdl_font_stash_begin(&atlas); - /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/ - /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 16, 0);*/ - /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/ - /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/ - /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/ - /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/ - nk_sdl_font_stash_end(); - /*nk_style_load_all_cursors(ctx, atlas->cursors);*/ - /*nk_style_set_font(ctx, &roboto->handle)*/;} - - #ifdef INCLUDE_STYLE - /*set_style(ctx, THEME_WHITE);*/ - /*set_style(ctx, THEME_RED);*/ - /*set_style(ctx, THEME_BLUE);*/ - /*set_style(ctx, THEME_DARK);*/ - #endif - - bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f; - while (running) - { - /* Input */ - SDL_Event evt; - nk_input_begin(ctx); - while (SDL_PollEvent(&evt)) { - if (evt.type == SDL_QUIT) goto cleanup; - nk_sdl_handle_event(&evt); - } - nk_input_end(ctx); - - /* GUI */ - if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250), - NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE| - NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) - { - enum {EASY, HARD}; - static int op = EASY; - static int property = 20; - - nk_layout_row_static(ctx, 30, 80, 1); - if (nk_button_label(ctx, "button")) - fprintf(stdout, "button pressed\n"); - nk_layout_row_dynamic(ctx, 30, 2); - if (nk_option_label(ctx, "easy", op == EASY)) op = EASY; - if (nk_option_label(ctx, "hard", op == HARD)) op = HARD; - nk_layout_row_dynamic(ctx, 25, 1); - nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1); - - nk_layout_row_dynamic(ctx, 20, 1); - nk_label(ctx, "background:", NK_TEXT_LEFT); - nk_layout_row_dynamic(ctx, 25, 1); - if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) { - nk_layout_row_dynamic(ctx, 120, 1); - bg = nk_color_picker(ctx, bg, NK_RGBA); - nk_layout_row_dynamic(ctx, 25, 1); - bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f); - bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f); - bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f); - bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f); - nk_combo_end(ctx); - } - } - nk_end(ctx); - - /* -------------- EXAMPLES ---------------- */ - #ifdef INCLUDE_CALCULATOR - calculator(ctx); - #endif - #ifdef INCLUDE_OVERVIEW - overview(ctx); - #endif - #ifdef INCLUDE_NODE_EDITOR - node_editor(ctx); - #endif - /* ----------------------------------------- */ - - /* Draw */ - SDL_GetWindowSize(win, &win_width, &win_height); - glViewport(0, 0, win_width, win_height); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(bg.r, bg.g, bg.b, bg.a); - /* IMPORTANT: `nk_sdl_render` modifies some global OpenGL state - * with blending, scissor, face culling, depth test and viewport and - * defaults everything back into a default state. - * Make sure to either a.) save and restore or b.) reset your own state after - * rendering the UI. */ - nk_sdl_render(NK_ANTI_ALIASING_ON); - SDL_GL_SwapWindow(win); - } - -cleanup: - nk_sdl_shutdown(); - SDL_GL_DeleteContext(glContext); - SDL_DestroyWindow(win); - SDL_Quit(); - return 0; -} - diff --git a/subprojects/nk_pugl/nuklear/demo/sdl_opengl2/nuklear_sdl_gl2.h b/subprojects/nk_pugl/nuklear/demo/sdl_opengl2/nuklear_sdl_gl2.h deleted file mode 100644 index 62dc64e..0000000 --- a/subprojects/nk_pugl/nuklear/demo/sdl_opengl2/nuklear_sdl_gl2.h +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Nuklear - 1.32.0 - public domain - * no warrenty implied; use at your own risk. - * authored from 2015-2017 by Micha Mettke - */ -/* - * ============================================================== - * - * API - * - * =============================================================== - */ -#ifndef NK_SDL_GL2_H_ -#define NK_SDL_GL2_H_ - -#include -NK_API struct nk_context* nk_sdl_init(SDL_Window *win); -NK_API void nk_sdl_font_stash_begin(struct nk_font_atlas **atlas); -NK_API void nk_sdl_font_stash_end(void); -NK_API int nk_sdl_handle_event(SDL_Event *evt); -NK_API void nk_sdl_render(enum nk_anti_aliasing); -NK_API void nk_sdl_shutdown(void); - -#endif -/* - * ============================================================== - * - * IMPLEMENTATION - * - * =============================================================== - */ -#ifdef NK_SDL_GL2_IMPLEMENTATION - -struct nk_sdl_device { - struct nk_buffer cmds; - struct nk_draw_null_texture null; - GLuint font_tex; -}; - -struct nk_sdl_vertex { - float position[2]; - float uv[2]; - nk_byte col[4]; -}; - -static struct nk_sdl { - SDL_Window *win; - struct nk_sdl_device ogl; - struct nk_context ctx; - struct nk_font_atlas atlas; -} sdl; - -NK_INTERN void -nk_sdl_device_upload_atlas(const void *image, int width, int height) -{ - struct nk_sdl_device *dev = &sdl.ogl; - glGenTextures(1, &dev->font_tex); - glBindTexture(GL_TEXTURE_2D, dev->font_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, image); -} - -NK_API void -nk_sdl_render(enum nk_anti_aliasing AA) -{ - /* setup global state */ - struct nk_sdl_device *dev = &sdl.ogl; - int width, height; - int display_width, display_height; - struct nk_vec2 scale; - - SDL_GetWindowSize(sdl.win, &width, &height); - SDL_GL_GetDrawableSize(sdl.win, &display_width, &display_height); - scale.x = (float)display_width/(float)width; - scale.y = (float)display_height/(float)height; - - glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT|GL_TRANSFORM_BIT); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glEnable(GL_SCISSOR_TEST); - glEnable(GL_BLEND); - glEnable(GL_TEXTURE_2D); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - /* setup viewport/project */ - glViewport(0,0,(GLsizei)display_width,(GLsizei)display_height); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(0.0f, width, height, 0.0f, -1.0f, 1.0f); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - { - GLsizei vs = sizeof(struct nk_sdl_vertex); - size_t vp = offsetof(struct nk_sdl_vertex, position); - size_t vt = offsetof(struct nk_sdl_vertex, uv); - size_t vc = offsetof(struct nk_sdl_vertex, col); - - /* convert from command queue into draw list and draw to screen */ - const struct nk_draw_command *cmd; - const nk_draw_index *offset = NULL; - struct nk_buffer vbuf, ebuf; - - /* fill converting configuration */ - struct nk_convert_config config; - static const struct nk_draw_vertex_layout_element vertex_layout[] = { - {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, position)}, - {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, uv)}, - {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sdl_vertex, col)}, - {NK_VERTEX_LAYOUT_END} - }; - NK_MEMSET(&config, 0, sizeof(config)); - config.vertex_layout = vertex_layout; - config.vertex_size = sizeof(struct nk_sdl_vertex); - config.vertex_alignment = NK_ALIGNOF(struct nk_sdl_vertex); - config.null = dev->null; - config.circle_segment_count = 22; - config.curve_segment_count = 22; - config.arc_segment_count = 22; - config.global_alpha = 1.0f; - config.shape_AA = AA; - config.line_AA = AA; - - /* convert shapes into vertexes */ - nk_buffer_init_default(&vbuf); - nk_buffer_init_default(&ebuf); - nk_convert(&sdl.ctx, &dev->cmds, &vbuf, &ebuf, &config); - - /* setup vertex buffer pointer */ - {const void *vertices = nk_buffer_memory_const(&vbuf); - glVertexPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vp)); - glTexCoordPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vt)); - glColorPointer(4, GL_UNSIGNED_BYTE, vs, (const void*)((const nk_byte*)vertices + vc));} - - /* iterate over and execute each draw command */ - offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf); - nk_draw_foreach(cmd, &sdl.ctx, &dev->cmds) - { - if (!cmd->elem_count) continue; - glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); - glScissor( - (GLint)(cmd->clip_rect.x * scale.x), - (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y), - (GLint)(cmd->clip_rect.w * scale.x), - (GLint)(cmd->clip_rect.h * scale.y)); - glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); - offset += cmd->elem_count; - } - nk_clear(&sdl.ctx); - nk_buffer_free(&vbuf); - nk_buffer_free(&ebuf); - } - - /* default OpenGL state */ - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - - glBindTexture(GL_TEXTURE_2D, 0); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glPopAttrib(); -} - -static void -nk_sdl_clipbard_paste(nk_handle usr, struct nk_text_edit *edit) -{ - const char *text = SDL_GetClipboardText(); - if (text) nk_textedit_paste(edit, text, nk_strlen(text)); - (void)usr; -} - -static void -nk_sdl_clipbard_copy(nk_handle usr, const char *text, int len) -{ - char *str = 0; - (void)usr; - if (!len) return; - str = (char*)malloc((size_t)len+1); - if (!str) return; - memcpy(str, text, (size_t)len); - str[len] = '\0'; - SDL_SetClipboardText(str); - free(str); -} - -NK_API struct nk_context* -nk_sdl_init(SDL_Window *win) -{ - sdl.win = win; - nk_init_default(&sdl.ctx, 0); - sdl.ctx.clip.copy = nk_sdl_clipbard_copy; - sdl.ctx.clip.paste = nk_sdl_clipbard_paste; - sdl.ctx.clip.userdata = nk_handle_ptr(0); - nk_buffer_init_default(&sdl.ogl.cmds); - return &sdl.ctx; -} - -NK_API void -nk_sdl_font_stash_begin(struct nk_font_atlas **atlas) -{ - nk_font_atlas_init_default(&sdl.atlas); - nk_font_atlas_begin(&sdl.atlas); - *atlas = &sdl.atlas; -} - -NK_API void -nk_sdl_font_stash_end(void) -{ - const void *image; int w, h; - image = nk_font_atlas_bake(&sdl.atlas, &w, &h, NK_FONT_ATLAS_RGBA32); - nk_sdl_device_upload_atlas(image, w, h); - nk_font_atlas_end(&sdl.atlas, nk_handle_id((int)sdl.ogl.font_tex), &sdl.ogl.null); - if (sdl.atlas.default_font) - nk_style_set_font(&sdl.ctx, &sdl.atlas.default_font->handle); -} - -NK_API int -nk_sdl_handle_event(SDL_Event *evt) -{ - struct nk_context *ctx = &sdl.ctx; - - /* optional grabbing behavior */ - if (ctx->input.mouse.grab) { - SDL_SetRelativeMouseMode(SDL_TRUE); - ctx->input.mouse.grab = 0; - } else if (ctx->input.mouse.ungrab) { - int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y; - SDL_SetRelativeMouseMode(SDL_FALSE); - SDL_WarpMouseInWindow(sdl.win, x, y); - ctx->input.mouse.ungrab = 0; - } - if (evt->type == SDL_KEYUP || evt->type == SDL_KEYDOWN) { - /* key events */ - int down = evt->type == SDL_KEYDOWN; - const Uint8* state = SDL_GetKeyboardState(0); - SDL_Keycode sym = evt->key.keysym.sym; - if (sym == SDLK_RSHIFT || sym == SDLK_LSHIFT) - nk_input_key(ctx, NK_KEY_SHIFT, down); - else if (sym == SDLK_DELETE) - nk_input_key(ctx, NK_KEY_DEL, down); - else if (sym == SDLK_RETURN) - nk_input_key(ctx, NK_KEY_ENTER, down); - else if (sym == SDLK_TAB) - nk_input_key(ctx, NK_KEY_TAB, down); - else if (sym == SDLK_BACKSPACE) - nk_input_key(ctx, NK_KEY_BACKSPACE, down); - else if (sym == SDLK_HOME) { - nk_input_key(ctx, NK_KEY_TEXT_START, down); - nk_input_key(ctx, NK_KEY_SCROLL_START, down); - } else if (sym == SDLK_END) { - nk_input_key(ctx, NK_KEY_TEXT_END, down); - nk_input_key(ctx, NK_KEY_SCROLL_END, down); - } else if (sym == SDLK_PAGEDOWN) { - nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down); - } else if (sym == SDLK_PAGEUP) { - nk_input_key(ctx, NK_KEY_SCROLL_UP, down); - } else if (sym == SDLK_z) - nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && state[SDL_SCANCODE_LCTRL]); - else if (sym == SDLK_r) - nk_input_key(ctx, NK_KEY_TEXT_REDO, down && state[SDL_SCANCODE_LCTRL]); - else if (sym == SDLK_c) - nk_input_key(ctx, NK_KEY_COPY, down && state[SDL_SCANCODE_LCTRL]); - else if (sym == SDLK_v) - nk_input_key(ctx, NK_KEY_PASTE, down && state[SDL_SCANCODE_LCTRL]); - else if (sym == SDLK_x) - nk_input_key(ctx, NK_KEY_CUT, down && state[SDL_SCANCODE_LCTRL]); - else if (sym == SDLK_b) - nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && state[SDL_SCANCODE_LCTRL]); - else if (sym == SDLK_e) - nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && state[SDL_SCANCODE_LCTRL]); - else if (sym == SDLK_UP) - nk_input_key(ctx, NK_KEY_UP, down); - else if (sym == SDLK_DOWN) - nk_input_key(ctx, NK_KEY_DOWN, down); - else if (sym == SDLK_LEFT) { - if (state[SDL_SCANCODE_LCTRL]) - nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down); - else nk_input_key(ctx, NK_KEY_LEFT, down); - } else if (sym == SDLK_RIGHT) { - if (state[SDL_SCANCODE_LCTRL]) - nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down); - else nk_input_key(ctx, NK_KEY_RIGHT, down); - } else return 0; - return 1; - } else if (evt->type == SDL_MOUSEBUTTONDOWN || evt->type == SDL_MOUSEBUTTONUP) { - /* mouse button */ - int down = evt->type == SDL_MOUSEBUTTONDOWN; - const int x = evt->button.x, y = evt->button.y; - if (evt->button.button == SDL_BUTTON_LEFT) { - if (evt->button.clicks > 1) - nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, down); - nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down); - } else if (evt->button.button == SDL_BUTTON_MIDDLE) - nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down); - else if (evt->button.button == SDL_BUTTON_RIGHT) - nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down); - return 1; - } else if (evt->type == SDL_MOUSEMOTION) { - /* mouse motion */ - if (ctx->input.mouse.grabbed) { - int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y; - nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel); - } else nk_input_motion(ctx, evt->motion.x, evt->motion.y); - return 1; - } else if (evt->type == SDL_TEXTINPUT) { - /* text input */ - nk_glyph glyph; - memcpy(glyph, evt->text.text, NK_UTF_SIZE); - nk_input_glyph(ctx, glyph); - return 1; - } else if (evt->type == SDL_MOUSEWHEEL) { - /* mouse wheel */ - nk_input_scroll(ctx,nk_vec2((float)evt->wheel.x,(float)evt->wheel.y)); - return 1; - } - return 0; -} - -NK_API -void nk_sdl_shutdown(void) -{ - struct nk_sdl_device *dev = &sdl.ogl; - nk_font_atlas_clear(&sdl.atlas); - nk_free(&sdl.ctx); - glDeleteTextures(1, &dev->font_tex); - nk_buffer_free(&dev->cmds); - memset(&sdl, 0, sizeof(sdl)); -} - -#endif diff --git a/subprojects/nk_pugl/nuklear/demo/sdl_opengl3/Makefile b/subprojects/nk_pugl/nuklear/demo/sdl_opengl3/Makefile deleted file mode 100644 index c6fcb45..0000000 --- a/subprojects/nk_pugl/nuklear/demo/sdl_opengl3/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -# Install -BIN = demo - -# Flags -CFLAGS += -std=c99 -pedantic -O2 - -SRC = main.c -OBJ = $(SRC:.c=.o) - -ifeq ($(OS),Windows_NT) -BIN := $(BIN).exe -LIBS = -lmingw32 -lSDL2main -lSDL2 -lopengl32 -lm -lGLU32 -lGLEW32 -else - UNAME_S := $(shell uname -s) - ifeq ($(UNAME_S),Darwin) - LIBS = -lSDL2 -framework OpenGL -lm -lGLEW - else - LIBS = -lSDL2 -lGL -lm -lGLU -lGLEW - endif -endif - -$(BIN): - @mkdir -p bin - rm -f bin/$(BIN) $(OBJS) - $(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS) diff --git a/subprojects/nk_pugl/nuklear/demo/sdl_opengl3/main.c b/subprojects/nk_pugl/nuklear/demo/sdl_opengl3/main.c deleted file mode 100644 index 9959d8a..0000000 --- a/subprojects/nk_pugl/nuklear/demo/sdl_opengl3/main.c +++ /dev/null @@ -1,208 +0,0 @@ -/* nuklear - 1.32.0 - public domain */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_STANDARD_VARARGS -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT -#define NK_INCLUDE_FONT_BAKING -#define NK_INCLUDE_DEFAULT_FONT -#define NK_IMPLEMENTATION -#define NK_SDL_GL3_IMPLEMENTATION -#include "../../nuklear.h" -#include "nuklear_sdl_gl3.h" - -#define WINDOW_WIDTH 1200 -#define WINDOW_HEIGHT 800 - -#define MAX_VERTEX_MEMORY 512 * 1024 -#define MAX_ELEMENT_MEMORY 128 * 1024 - -/* =============================================================== - * - * EXAMPLE - * - * ===============================================================*/ -/* This are some code examples to provide a small overview of what can be - * done with this library. To try out an example uncomment the defines */ -/*#define INCLUDE_ALL */ -/*#define INCLUDE_STYLE */ -/*#define INCLUDE_CALCULATOR */ -/*#define INCLUDE_OVERVIEW */ -/*#define INCLUDE_NODE_EDITOR */ - -#ifdef INCLUDE_ALL - #define INCLUDE_STYLE - #define INCLUDE_CALCULATOR - #define INCLUDE_OVERVIEW - #define INCLUDE_NODE_EDITOR -#endif - -#ifdef INCLUDE_STYLE - #include "../style.c" -#endif -#ifdef INCLUDE_CALCULATOR - #include "../calculator.c" -#endif -#ifdef INCLUDE_OVERVIEW - #include "../overview.c" -#endif -#ifdef INCLUDE_NODE_EDITOR - #include "../node_editor.c" -#endif - -/* =============================================================== - * - * DEMO - * - * ===============================================================*/ -int main(void) -{ - /* Platform */ - SDL_Window *win; - SDL_GLContext glContext; - int win_width, win_height; - int running = 1; - - /* GUI */ - struct nk_context *ctx; - struct nk_colorf bg; - - /* SDL setup */ - SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "0"); - SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTS); - SDL_GL_SetAttribute (SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); - SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - win = SDL_CreateWindow("Demo", - SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN|SDL_WINDOW_ALLOW_HIGHDPI); - glContext = SDL_GL_CreateContext(win); - SDL_GetWindowSize(win, &win_width, &win_height); - - /* OpenGL setup */ - glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); - glewExperimental = 1; - if (glewInit() != GLEW_OK) { - fprintf(stderr, "Failed to setup GLEW\n"); - exit(1); - } - - ctx = nk_sdl_init(win); - /* Load Fonts: if none of these are loaded a default font will be used */ - /* Load Cursor: if you uncomment cursor loading please hide the cursor */ - {struct nk_font_atlas *atlas; - nk_sdl_font_stash_begin(&atlas); - /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/ - /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 16, 0);*/ - /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/ - /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/ - /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/ - /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/ - nk_sdl_font_stash_end(); - /*nk_style_load_all_cursors(ctx, atlas->cursors);*/ - /*nk_style_set_font(ctx, &roboto->handle);*/} - - /* style.c */ - #ifdef INCLUDE_STYLE - /*set_style(ctx, THEME_WHITE);*/ - /*set_style(ctx, THEME_RED);*/ - /*set_style(ctx, THEME_BLUE);*/ - /*set_style(ctx, THEME_DARK);*/ - #endif - - bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f; - while (running) - { - /* Input */ - SDL_Event evt; - nk_input_begin(ctx); - while (SDL_PollEvent(&evt)) { - if (evt.type == SDL_QUIT) goto cleanup; - nk_sdl_handle_event(&evt); - } nk_input_end(ctx); - - /* GUI */ - if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250), - NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE| - NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) - { - enum {EASY, HARD}; - static int op = EASY; - static int property = 20; - - nk_layout_row_static(ctx, 30, 80, 1); - if (nk_button_label(ctx, "button")) - printf("button pressed!\n"); - nk_layout_row_dynamic(ctx, 30, 2); - if (nk_option_label(ctx, "easy", op == EASY)) op = EASY; - if (nk_option_label(ctx, "hard", op == HARD)) op = HARD; - nk_layout_row_dynamic(ctx, 22, 1); - nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1); - - nk_layout_row_dynamic(ctx, 20, 1); - nk_label(ctx, "background:", NK_TEXT_LEFT); - nk_layout_row_dynamic(ctx, 25, 1); - if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) { - nk_layout_row_dynamic(ctx, 120, 1); - bg = nk_color_picker(ctx, bg, NK_RGBA); - nk_layout_row_dynamic(ctx, 25, 1); - bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f); - bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f); - bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f); - bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f); - nk_combo_end(ctx); - } - } - nk_end(ctx); - - /* -------------- EXAMPLES ---------------- */ - #ifdef INCLUDE_CALCULATOR - calculator(ctx); - #endif - #ifdef INCLUDE_OVERVIEW - overview(ctx); - #endif - #ifdef INCLUDE_NODE_EDITOR - node_editor(ctx); - #endif - /* ----------------------------------------- */ - - /* Draw */ - SDL_GetWindowSize(win, &win_width, &win_height); - glViewport(0, 0, win_width, win_height); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(bg.r, bg.g, bg.b, bg.a); - /* IMPORTANT: `nk_sdl_render` modifies some global OpenGL state - * with blending, scissor, face culling, depth test and viewport and - * defaults everything back into a default state. - * Make sure to either a.) save and restore or b.) reset your own state after - * rendering the UI. */ - nk_sdl_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_MEMORY, MAX_ELEMENT_MEMORY); - SDL_GL_SwapWindow(win); - } - -cleanup: - nk_sdl_shutdown(); - SDL_GL_DeleteContext(glContext); - SDL_DestroyWindow(win); - SDL_Quit(); - return 0; -} - diff --git a/subprojects/nk_pugl/nuklear/demo/sdl_opengl3/nuklear_sdl_gl3.h b/subprojects/nk_pugl/nuklear/demo/sdl_opengl3/nuklear_sdl_gl3.h deleted file mode 100644 index eb53ebb..0000000 --- a/subprojects/nk_pugl/nuklear/demo/sdl_opengl3/nuklear_sdl_gl3.h +++ /dev/null @@ -1,442 +0,0 @@ -/* - * Nuklear - 1.32.0 - public domain - * no warrenty implied; use at your own risk. - * authored from 2015-2016 by Micha Mettke - */ -/* - * ============================================================== - * - * API - * - * =============================================================== - */ -#ifndef NK_SDL_GL3_H_ -#define NK_SDL_GL3_H_ - -#include -#include - -NK_API struct nk_context* nk_sdl_init(SDL_Window *win); -NK_API void nk_sdl_font_stash_begin(struct nk_font_atlas **atlas); -NK_API void nk_sdl_font_stash_end(void); -NK_API int nk_sdl_handle_event(SDL_Event *evt); -NK_API void nk_sdl_render(enum nk_anti_aliasing , int max_vertex_buffer, int max_element_buffer); -NK_API void nk_sdl_shutdown(void); -NK_API void nk_sdl_device_destroy(void); -NK_API void nk_sdl_device_create(void); - -#endif - -/* - * ============================================================== - * - * IMPLEMENTATION - * - * =============================================================== - */ -#ifdef NK_SDL_GL3_IMPLEMENTATION - -#include - -struct nk_sdl_device { - struct nk_buffer cmds; - struct nk_draw_null_texture null; - GLuint vbo, vao, ebo; - GLuint prog; - GLuint vert_shdr; - GLuint frag_shdr; - GLint attrib_pos; - GLint attrib_uv; - GLint attrib_col; - GLint uniform_tex; - GLint uniform_proj; - GLuint font_tex; -}; - -struct nk_sdl_vertex { - float position[2]; - float uv[2]; - nk_byte col[4]; -}; - -static struct nk_sdl { - SDL_Window *win; - struct nk_sdl_device ogl; - struct nk_context ctx; - struct nk_font_atlas atlas; -} sdl; - -#ifdef __APPLE__ - #define NK_SHADER_VERSION "#version 150\n" -#else - #define NK_SHADER_VERSION "#version 300 es\n" -#endif -NK_API void -nk_sdl_device_create(void) -{ - GLint status; - static const GLchar *vertex_shader = - NK_SHADER_VERSION - "uniform mat4 ProjMtx;\n" - "in vec2 Position;\n" - "in vec2 TexCoord;\n" - "in vec4 Color;\n" - "out vec2 Frag_UV;\n" - "out vec4 Frag_Color;\n" - "void main() {\n" - " Frag_UV = TexCoord;\n" - " Frag_Color = Color;\n" - " gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n" - "}\n"; - static const GLchar *fragment_shader = - NK_SHADER_VERSION - "precision mediump float;\n" - "uniform sampler2D Texture;\n" - "in vec2 Frag_UV;\n" - "in vec4 Frag_Color;\n" - "out vec4 Out_Color;\n" - "void main(){\n" - " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" - "}\n"; - - struct nk_sdl_device *dev = &sdl.ogl; - nk_buffer_init_default(&dev->cmds); - dev->prog = glCreateProgram(); - dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER); - dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0); - glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0); - glCompileShader(dev->vert_shdr); - glCompileShader(dev->frag_shdr); - glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status); - assert(status == GL_TRUE); - glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status); - assert(status == GL_TRUE); - glAttachShader(dev->prog, dev->vert_shdr); - glAttachShader(dev->prog, dev->frag_shdr); - glLinkProgram(dev->prog); - glGetProgramiv(dev->prog, GL_LINK_STATUS, &status); - assert(status == GL_TRUE); - - dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture"); - dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx"); - dev->attrib_pos = glGetAttribLocation(dev->prog, "Position"); - dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord"); - dev->attrib_col = glGetAttribLocation(dev->prog, "Color"); - - { - /* buffer setup */ - GLsizei vs = sizeof(struct nk_sdl_vertex); - size_t vp = offsetof(struct nk_sdl_vertex, position); - size_t vt = offsetof(struct nk_sdl_vertex, uv); - size_t vc = offsetof(struct nk_sdl_vertex, col); - - glGenBuffers(1, &dev->vbo); - glGenBuffers(1, &dev->ebo); - glGenVertexArrays(1, &dev->vao); - - glBindVertexArray(dev->vao); - glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); - - glEnableVertexAttribArray((GLuint)dev->attrib_pos); - glEnableVertexAttribArray((GLuint)dev->attrib_uv); - glEnableVertexAttribArray((GLuint)dev->attrib_col); - - glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp); - glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt); - glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc); - } - - glBindTexture(GL_TEXTURE_2D, 0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindVertexArray(0); -} - -NK_INTERN void -nk_sdl_device_upload_atlas(const void *image, int width, int height) -{ - struct nk_sdl_device *dev = &sdl.ogl; - glGenTextures(1, &dev->font_tex); - glBindTexture(GL_TEXTURE_2D, dev->font_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, image); -} - -NK_API void -nk_sdl_device_destroy(void) -{ - struct nk_sdl_device *dev = &sdl.ogl; - glDetachShader(dev->prog, dev->vert_shdr); - glDetachShader(dev->prog, dev->frag_shdr); - glDeleteShader(dev->vert_shdr); - glDeleteShader(dev->frag_shdr); - glDeleteProgram(dev->prog); - glDeleteTextures(1, &dev->font_tex); - glDeleteBuffers(1, &dev->vbo); - glDeleteBuffers(1, &dev->ebo); - nk_buffer_free(&dev->cmds); -} - -NK_API void -nk_sdl_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer) -{ - struct nk_sdl_device *dev = &sdl.ogl; - int width, height; - int display_width, display_height; - struct nk_vec2 scale; - GLfloat ortho[4][4] = { - {2.0f, 0.0f, 0.0f, 0.0f}, - {0.0f,-2.0f, 0.0f, 0.0f}, - {0.0f, 0.0f,-1.0f, 0.0f}, - {-1.0f,1.0f, 0.0f, 1.0f}, - }; - SDL_GetWindowSize(sdl.win, &width, &height); - SDL_GL_GetDrawableSize(sdl.win, &display_width, &display_height); - ortho[0][0] /= (GLfloat)width; - ortho[1][1] /= (GLfloat)height; - - scale.x = (float)display_width/(float)width; - scale.y = (float)display_height/(float)height; - - /* setup global state */ - glViewport(0,0,display_width,display_height); - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glEnable(GL_SCISSOR_TEST); - glActiveTexture(GL_TEXTURE0); - - /* setup program */ - glUseProgram(dev->prog); - glUniform1i(dev->uniform_tex, 0); - glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]); - { - /* convert from command queue into draw list and draw to screen */ - const struct nk_draw_command *cmd; - void *vertices, *elements; - const nk_draw_index *offset = NULL; - struct nk_buffer vbuf, ebuf; - - /* allocate vertex and element buffer */ - glBindVertexArray(dev->vao); - glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); - - glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW); - - /* load vertices/elements directly into vertex/element buffer */ - vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); - elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY); - { - /* fill convert configuration */ - struct nk_convert_config config; - static const struct nk_draw_vertex_layout_element vertex_layout[] = { - {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, position)}, - {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, uv)}, - {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sdl_vertex, col)}, - {NK_VERTEX_LAYOUT_END} - }; - NK_MEMSET(&config, 0, sizeof(config)); - config.vertex_layout = vertex_layout; - config.vertex_size = sizeof(struct nk_sdl_vertex); - config.vertex_alignment = NK_ALIGNOF(struct nk_sdl_vertex); - config.null = dev->null; - config.circle_segment_count = 22; - config.curve_segment_count = 22; - config.arc_segment_count = 22; - config.global_alpha = 1.0f; - config.shape_AA = AA; - config.line_AA = AA; - - /* setup buffers to load vertices and elements */ - nk_buffer_init_fixed(&vbuf, vertices, (nk_size)max_vertex_buffer); - nk_buffer_init_fixed(&ebuf, elements, (nk_size)max_element_buffer); - nk_convert(&sdl.ctx, &dev->cmds, &vbuf, &ebuf, &config); - } - glUnmapBuffer(GL_ARRAY_BUFFER); - glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); - - /* iterate over and execute each draw command */ - nk_draw_foreach(cmd, &sdl.ctx, &dev->cmds) { - if (!cmd->elem_count) continue; - glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); - glScissor((GLint)(cmd->clip_rect.x * scale.x), - (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y), - (GLint)(cmd->clip_rect.w * scale.x), - (GLint)(cmd->clip_rect.h * scale.y)); - glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); - offset += cmd->elem_count; - } - nk_clear(&sdl.ctx); - } - - glUseProgram(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindVertexArray(0); - glDisable(GL_BLEND); - glDisable(GL_SCISSOR_TEST); -} - -static void -nk_sdl_clipbard_paste(nk_handle usr, struct nk_text_edit *edit) -{ - const char *text = SDL_GetClipboardText(); - if (text) nk_textedit_paste(edit, text, nk_strlen(text)); - (void)usr; -} - -static void -nk_sdl_clipbard_copy(nk_handle usr, const char *text, int len) -{ - char *str = 0; - (void)usr; - if (!len) return; - str = (char*)malloc((size_t)len+1); - if (!str) return; - memcpy(str, text, (size_t)len); - str[len] = '\0'; - SDL_SetClipboardText(str); - free(str); -} - -NK_API struct nk_context* -nk_sdl_init(SDL_Window *win) -{ - sdl.win = win; - nk_init_default(&sdl.ctx, 0); - sdl.ctx.clip.copy = nk_sdl_clipbard_copy; - sdl.ctx.clip.paste = nk_sdl_clipbard_paste; - sdl.ctx.clip.userdata = nk_handle_ptr(0); - nk_sdl_device_create(); - return &sdl.ctx; -} - -NK_API void -nk_sdl_font_stash_begin(struct nk_font_atlas **atlas) -{ - nk_font_atlas_init_default(&sdl.atlas); - nk_font_atlas_begin(&sdl.atlas); - *atlas = &sdl.atlas; -} - -NK_API void -nk_sdl_font_stash_end(void) -{ - const void *image; int w, h; - image = nk_font_atlas_bake(&sdl.atlas, &w, &h, NK_FONT_ATLAS_RGBA32); - nk_sdl_device_upload_atlas(image, w, h); - nk_font_atlas_end(&sdl.atlas, nk_handle_id((int)sdl.ogl.font_tex), &sdl.ogl.null); - if (sdl.atlas.default_font) - nk_style_set_font(&sdl.ctx, &sdl.atlas.default_font->handle); - -} - -NK_API int -nk_sdl_handle_event(SDL_Event *evt) -{ - struct nk_context *ctx = &sdl.ctx; - if (evt->type == SDL_KEYUP || evt->type == SDL_KEYDOWN) { - /* key events */ - int down = evt->type == SDL_KEYDOWN; - const Uint8* state = SDL_GetKeyboardState(0); - SDL_Keycode sym = evt->key.keysym.sym; - if (sym == SDLK_RSHIFT || sym == SDLK_LSHIFT) - nk_input_key(ctx, NK_KEY_SHIFT, down); - else if (sym == SDLK_DELETE) - nk_input_key(ctx, NK_KEY_DEL, down); - else if (sym == SDLK_RETURN) - nk_input_key(ctx, NK_KEY_ENTER, down); - else if (sym == SDLK_TAB) - nk_input_key(ctx, NK_KEY_TAB, down); - else if (sym == SDLK_BACKSPACE) - nk_input_key(ctx, NK_KEY_BACKSPACE, down); - else if (sym == SDLK_HOME) { - nk_input_key(ctx, NK_KEY_TEXT_START, down); - nk_input_key(ctx, NK_KEY_SCROLL_START, down); - } else if (sym == SDLK_END) { - nk_input_key(ctx, NK_KEY_TEXT_END, down); - nk_input_key(ctx, NK_KEY_SCROLL_END, down); - } else if (sym == SDLK_PAGEDOWN) { - nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down); - } else if (sym == SDLK_PAGEUP) { - nk_input_key(ctx, NK_KEY_SCROLL_UP, down); - } else if (sym == SDLK_z) - nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && state[SDL_SCANCODE_LCTRL]); - else if (sym == SDLK_r) - nk_input_key(ctx, NK_KEY_TEXT_REDO, down && state[SDL_SCANCODE_LCTRL]); - else if (sym == SDLK_c) - nk_input_key(ctx, NK_KEY_COPY, down && state[SDL_SCANCODE_LCTRL]); - else if (sym == SDLK_v) - nk_input_key(ctx, NK_KEY_PASTE, down && state[SDL_SCANCODE_LCTRL]); - else if (sym == SDLK_x) - nk_input_key(ctx, NK_KEY_CUT, down && state[SDL_SCANCODE_LCTRL]); - else if (sym == SDLK_b) - nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && state[SDL_SCANCODE_LCTRL]); - else if (sym == SDLK_e) - nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && state[SDL_SCANCODE_LCTRL]); - else if (sym == SDLK_UP) - nk_input_key(ctx, NK_KEY_UP, down); - else if (sym == SDLK_DOWN) - nk_input_key(ctx, NK_KEY_DOWN, down); - else if (sym == SDLK_LEFT) { - if (state[SDL_SCANCODE_LCTRL]) - nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down); - else nk_input_key(ctx, NK_KEY_LEFT, down); - } else if (sym == SDLK_RIGHT) { - if (state[SDL_SCANCODE_LCTRL]) - nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down); - else nk_input_key(ctx, NK_KEY_RIGHT, down); - } else return 0; - return 1; - } else if (evt->type == SDL_MOUSEBUTTONDOWN || evt->type == SDL_MOUSEBUTTONUP) { - /* mouse button */ - int down = evt->type == SDL_MOUSEBUTTONDOWN; - const int x = evt->button.x, y = evt->button.y; - if (evt->button.button == SDL_BUTTON_LEFT) { - if (evt->button.clicks > 1) - nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, down); - nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down); - } else if (evt->button.button == SDL_BUTTON_MIDDLE) - nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down); - else if (evt->button.button == SDL_BUTTON_RIGHT) - nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down); - return 1; - } else if (evt->type == SDL_MOUSEMOTION) { - /* mouse motion */ - if (ctx->input.mouse.grabbed) { - int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y; - nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel); - } else nk_input_motion(ctx, evt->motion.x, evt->motion.y); - return 1; - } else if (evt->type == SDL_TEXTINPUT) { - /* text input */ - nk_glyph glyph; - memcpy(glyph, evt->text.text, NK_UTF_SIZE); - nk_input_glyph(ctx, glyph); - return 1; - } else if (evt->type == SDL_MOUSEWHEEL) { - /* mouse wheel */ - nk_input_scroll(ctx,nk_vec2((float)evt->wheel.x,(float)evt->wheel.y)); - return 1; - } - return 0; -} - -NK_API -void nk_sdl_shutdown(void) -{ - nk_font_atlas_clear(&sdl.atlas); - nk_free(&sdl.ctx); - nk_sdl_device_destroy(); - memset(&sdl, 0, sizeof(sdl)); -} - -#endif diff --git a/subprojects/nk_pugl/nuklear/demo/sdl_opengles2/Makefile b/subprojects/nk_pugl/nuklear/demo/sdl_opengles2/Makefile deleted file mode 100644 index 7385305..0000000 --- a/subprojects/nk_pugl/nuklear/demo/sdl_opengles2/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -# Install -BIN = demo - -# Flags -CFLAGS += -std=c99 -pedantic -O2 - -SRC = main.c -OBJ = $(SRC:.c=.o) - -UNAME_S := $(shell uname -s) -ifeq ($(UNAME_S),Darwin) - LIBS = -lSDL2 -framework OpenGLES -lm -else - LIBS = -lSDL2 -lGLESv2 -lm -endif - -$(BIN): prepare - $(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS) - -web: prepare - emcc $(SRC) -Os -s USE_SDL=2 -o bin/index.html - -prepare: - @mkdir -p bin - rm -f bin/$(BIN) $(OBJS) diff --git a/subprojects/nk_pugl/nuklear/demo/sdl_opengles2/main.c b/subprojects/nk_pugl/nuklear/demo/sdl_opengles2/main.c deleted file mode 100644 index 16a271a..0000000 --- a/subprojects/nk_pugl/nuklear/demo/sdl_opengles2/main.c +++ /dev/null @@ -1,191 +0,0 @@ -/* nuklear - 1.40.8 - public domain */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_STANDARD_VARARGS -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT -#define NK_INCLUDE_FONT_BAKING -#define NK_INCLUDE_DEFAULT_FONT -#define NK_IMPLEMENTATION -#define NK_SDL_GLES2_IMPLEMENTATION -#include "../../nuklear.h" -#include "nuklear_sdl_gles2.h" - -#define WINDOW_WIDTH 800 -#define WINDOW_HEIGHT 600 - -#define MAX_VERTEX_MEMORY 512 * 1024 -#define MAX_ELEMENT_MEMORY 128 * 1024 - -#define UNUSED(a) (void)a -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#define MAX(a,b) ((a) < (b) ? (b) : (a)) -#define LEN(a) (sizeof(a)/sizeof(a)[0]) - -/* =============================================================== - * - * EXAMPLE - * - * ===============================================================*/ -/* This are some code examples to provide a small overview of what can be - * done with this library. To try out an example uncomment the include - * and the corresponding function. */ -/*#include "../style.c"*/ -/*#include "../calculator.c"*/ -/*#include "../overview.c"*/ -/*#include "../node_editor.c"*/ - -/* =============================================================== - * - * DEMO - * - * ===============================================================*/ - - -/* Platform */ -SDL_Window *win; -int running = nk_true; - -static void -MainLoop(void* loopArg){ - struct nk_context *ctx = (struct nk_context *)loopArg; - - /* Input */ - SDL_Event evt; - nk_input_begin(ctx); - while (SDL_PollEvent(&evt)) { - if (evt.type == SDL_QUIT) running = nk_false; - nk_sdl_handle_event(&evt); - } - nk_input_end(ctx); - - - /* GUI */ - if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200), - NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE| - NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) - { - nk_menubar_begin(ctx); - nk_layout_row_begin(ctx, NK_STATIC, 25, 2); - nk_layout_row_push(ctx, 45); - if (nk_menu_begin_label(ctx, "FILE", NK_TEXT_LEFT, nk_vec2(120, 200))) { - nk_layout_row_dynamic(ctx, 30, 1); - nk_menu_item_label(ctx, "OPEN", NK_TEXT_LEFT); - nk_menu_item_label(ctx, "CLOSE", NK_TEXT_LEFT); - nk_menu_end(ctx); - } - nk_layout_row_push(ctx, 45); - if (nk_menu_begin_label(ctx, "EDIT", NK_TEXT_LEFT, nk_vec2(120, 200))) { - nk_layout_row_dynamic(ctx, 30, 1); - nk_menu_item_label(ctx, "COPY", NK_TEXT_LEFT); - nk_menu_item_label(ctx, "CUT", NK_TEXT_LEFT); - nk_menu_item_label(ctx, "PASTE", NK_TEXT_LEFT); - nk_menu_end(ctx); - } - nk_layout_row_end(ctx); - nk_menubar_end(ctx); - - enum {EASY, HARD}; - static int op = EASY; - static int property = 20; - nk_layout_row_static(ctx, 30, 80, 1); - if (nk_button_label(ctx, "button")) - fprintf(stdout, "button pressed\n"); - nk_layout_row_dynamic(ctx, 30, 2); - if (nk_option_label(ctx, "easy", op == EASY)) op = EASY; - if (nk_option_label(ctx, "hard", op == HARD)) op = HARD; - nk_layout_row_dynamic(ctx, 25, 1); - nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1); - } - nk_end(ctx); - - /* -------------- EXAMPLES ---------------- */ - /*calculator(ctx);*/ - /*overview(ctx);*/ - /*node_editor(ctx);*/ - /* ----------------------------------------- */ - - /* Draw */ - {float bg[4]; - int win_width, win_height; - nk_color_fv(bg, nk_rgb(28,48,62)); - SDL_GetWindowSize(win, &win_width, &win_height); - glViewport(0, 0, win_width, win_height); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(bg[0], bg[1], bg[2], bg[3]); - /* IMPORTANT: `nk_sdl_render` modifies some global OpenGL state - * with blending, scissor, face culling, depth test and viewport and - * defaults everything back into a default state. - * Make sure to either a.) save and restore or b.) reset your own state after - * rendering the UI. */ - nk_sdl_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_MEMORY, MAX_ELEMENT_MEMORY); - SDL_GL_SwapWindow(win);} -} - -int main(int argc, char* argv[]) -{ - /* GUI */ - struct nk_context *ctx; - SDL_GLContext glContext; - /* SDL setup */ - SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "0"); - /*SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTS); // - do NOT init SDL on GL ES 2 */ - SDL_GL_SetAttribute (SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); - SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - win = SDL_CreateWindow("Demo", - SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN|SDL_WINDOW_ALLOW_HIGHDPI); - glContext = SDL_GL_CreateContext(win); - - /* OpenGL setup */ - glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); - - ctx = nk_sdl_init(win); - /* Load Fonts: if none of these are loaded a default font will be used */ - /* Load Cursor: if you uncomment cursor loading please hide the cursor */ - {struct nk_font_atlas *atlas; - nk_sdl_font_stash_begin(&atlas); - /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/ - /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 16, 0);*/ - /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/ - /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/ - /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/ - /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/ - nk_sdl_font_stash_end(); - /*nk_style_load_all_cursors(ctx, atlas->cursors);*/ - /*nk_style_set_font(ctx, &roboto->handle)*/;} - - /* style.c */ - /*set_style(ctx, THEME_WHITE);*/ - /*set_style(ctx, THEME_RED);*/ - /*set_style(ctx, THEME_BLUE);*/ - /*set_style(ctx, THEME_DARK);*/ - -#if defined(__EMSCRIPTEN__) - #include - emscripten_set_main_loop_arg(MainLoop, (void*)ctx, 0, nk_true); -#else - while (running) MainLoop((void*)ctx); -#endif - - nk_sdl_shutdown(); - SDL_GL_DeleteContext(glContext); - SDL_DestroyWindow(win); - SDL_Quit(); - return 0; -} - diff --git a/subprojects/nk_pugl/nuklear/demo/sdl_opengles2/nuklear_sdl_gles2.h b/subprojects/nk_pugl/nuklear/demo/sdl_opengles2/nuklear_sdl_gles2.h deleted file mode 100644 index f96e610..0000000 --- a/subprojects/nk_pugl/nuklear/demo/sdl_opengles2/nuklear_sdl_gles2.h +++ /dev/null @@ -1,443 +0,0 @@ -/* - * Nuklear - 1.40.8 - public domain - * no warrenty implied; use at your own risk. - * authored from 2015-2017 by Micha Mettke - * emscripten from 2016 by Chris Willcocks - * OpenGL ES 2.0 from 2017 by Dmitry Hrabrov a.k.a. DeXPeriX - */ -/* - * ============================================================== - * - * API - * - * =============================================================== - */ -#ifndef NK_SDL_GLES2_H_ -#define NK_SDL_GLES2_H_ - -#include -#include - - -NK_API struct nk_context* nk_sdl_init(SDL_Window *win); -NK_API void nk_sdl_font_stash_begin(struct nk_font_atlas **atlas); -NK_API void nk_sdl_font_stash_end(void); -NK_API int nk_sdl_handle_event(SDL_Event *evt); -NK_API void nk_sdl_render(enum nk_anti_aliasing , int max_vertex_buffer, int max_element_buffer); -NK_API void nk_sdl_shutdown(void); -NK_API void nk_sdl_device_destroy(void); -NK_API void nk_sdl_device_create(void); - -#endif - -/* - * ============================================================== - * - * IMPLEMENTATION - * - * =============================================================== - */ -#ifdef NK_SDL_GLES2_IMPLEMENTATION - -#include - -struct nk_sdl_device { - struct nk_buffer cmds; - struct nk_draw_null_texture null; - GLuint vbo, ebo; - GLuint prog; - GLuint vert_shdr; - GLuint frag_shdr; - GLint attrib_pos; - GLint attrib_uv; - GLint attrib_col; - GLint uniform_tex; - GLint uniform_proj; - GLuint font_tex; - GLsizei vs; - size_t vp, vt, vc; -}; - -struct nk_sdl_vertex { - GLfloat position[2]; - GLfloat uv[2]; - nk_byte col[4]; -}; - -static struct nk_sdl { - SDL_Window *win; - struct nk_sdl_device ogl; - struct nk_context ctx; - struct nk_font_atlas atlas; -} sdl; - - -#define NK_SHADER_VERSION "#version 100\n" - - -NK_API void -nk_sdl_device_create(void) -{ - GLint status; - static const GLchar *vertex_shader = - NK_SHADER_VERSION - "uniform mat4 ProjMtx;\n" - "attribute vec2 Position;\n" - "attribute vec2 TexCoord;\n" - "attribute vec4 Color;\n" - "varying vec2 Frag_UV;\n" - "varying vec4 Frag_Color;\n" - "void main() {\n" - " Frag_UV = TexCoord;\n" - " Frag_Color = Color;\n" - " gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n" - "}\n"; - static const GLchar *fragment_shader = - NK_SHADER_VERSION - "precision mediump float;\n" - "uniform sampler2D Texture;\n" - "varying vec2 Frag_UV;\n" - "varying vec4 Frag_Color;\n" - "void main(){\n" - " gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV);\n" - "}\n"; - - struct nk_sdl_device *dev = &sdl.ogl; - - nk_buffer_init_default(&dev->cmds); - dev->prog = glCreateProgram(); - dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER); - dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0); - glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0); - glCompileShader(dev->vert_shdr); - glCompileShader(dev->frag_shdr); - glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status); - assert(status == GL_TRUE); - glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status); - assert(status == GL_TRUE); - glAttachShader(dev->prog, dev->vert_shdr); - glAttachShader(dev->prog, dev->frag_shdr); - glLinkProgram(dev->prog); - glGetProgramiv(dev->prog, GL_LINK_STATUS, &status); - assert(status == GL_TRUE); - - - dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture"); - dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx"); - dev->attrib_pos = glGetAttribLocation(dev->prog, "Position"); - dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord"); - dev->attrib_col = glGetAttribLocation(dev->prog, "Color"); - { - dev->vs = sizeof(struct nk_sdl_vertex); - dev->vp = offsetof(struct nk_sdl_vertex, position); - dev->vt = offsetof(struct nk_sdl_vertex, uv); - dev->vc = offsetof(struct nk_sdl_vertex, col); - - /* Allocate buffers */ - glGenBuffers(1, &dev->vbo); - glGenBuffers(1, &dev->ebo); - } - glBindTexture(GL_TEXTURE_2D, 0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -} - -NK_INTERN void -nk_sdl_device_upload_atlas(const void *image, int width, int height) -{ - struct nk_sdl_device *dev = &sdl.ogl; - glGenTextures(1, &dev->font_tex); - glBindTexture(GL_TEXTURE_2D, dev->font_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, image); -} - -NK_API void -nk_sdl_device_destroy(void) -{ - struct nk_sdl_device *dev = &sdl.ogl; - glDetachShader(dev->prog, dev->vert_shdr); - glDetachShader(dev->prog, dev->frag_shdr); - glDeleteShader(dev->vert_shdr); - glDeleteShader(dev->frag_shdr); - glDeleteProgram(dev->prog); - glDeleteTextures(1, &dev->font_tex); - glDeleteBuffers(1, &dev->vbo); - glDeleteBuffers(1, &dev->ebo); - nk_buffer_free(&dev->cmds); -} - -NK_API void -nk_sdl_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer) -{ - struct nk_sdl_device *dev = &sdl.ogl; - int width, height; - int display_width, display_height; - struct nk_vec2 scale; - GLfloat ortho[4][4] = { - {2.0f, 0.0f, 0.0f, 0.0f}, - {0.0f,-2.0f, 0.0f, 0.0f}, - {0.0f, 0.0f,-1.0f, 0.0f}, - {-1.0f,1.0f, 0.0f, 1.0f}, - }; - SDL_GetWindowSize(sdl.win, &width, &height); - SDL_GL_GetDrawableSize(sdl.win, &display_width, &display_height); - ortho[0][0] /= (GLfloat)width; - ortho[1][1] /= (GLfloat)height; - - scale.x = (float)display_width/(float)width; - scale.y = (float)display_height/(float)height; - - /* setup global state */ - glViewport(0,0,display_width,display_height); - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glEnable(GL_SCISSOR_TEST); - glActiveTexture(GL_TEXTURE0); - - /* setup program */ - glUseProgram(dev->prog); - glUniform1i(dev->uniform_tex, 0); - glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]); - { - /* convert from command queue into draw list and draw to screen */ - const struct nk_draw_command *cmd; - void *vertices, *elements; - const nk_draw_index *offset = NULL; - - /* Bind buffers */ - glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); - - { - /* buffer setup */ - glEnableVertexAttribArray((GLuint)dev->attrib_pos); - glEnableVertexAttribArray((GLuint)dev->attrib_uv); - glEnableVertexAttribArray((GLuint)dev->attrib_col); - - glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, dev->vs, (void*)dev->vp); - glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, dev->vs, (void*)dev->vt); - glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, dev->vs, (void*)dev->vc); - } - - glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW); - - /* load vertices/elements directly into vertex/element buffer */ - vertices = malloc((size_t)max_vertex_buffer); - elements = malloc((size_t)max_element_buffer); - { - /* fill convert configuration */ - struct nk_convert_config config; - static const struct nk_draw_vertex_layout_element vertex_layout[] = { - {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, position)}, - {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, uv)}, - {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sdl_vertex, col)}, - {NK_VERTEX_LAYOUT_END} - }; - NK_MEMSET(&config, 0, sizeof(config)); - config.vertex_layout = vertex_layout; - config.vertex_size = sizeof(struct nk_sdl_vertex); - config.vertex_alignment = NK_ALIGNOF(struct nk_sdl_vertex); - config.null = dev->null; - config.circle_segment_count = 22; - config.curve_segment_count = 22; - config.arc_segment_count = 22; - config.global_alpha = 1.0f; - config.shape_AA = AA; - config.line_AA = AA; - - /* setup buffers to load vertices and elements */ - {struct nk_buffer vbuf, ebuf; - nk_buffer_init_fixed(&vbuf, vertices, (nk_size)max_vertex_buffer); - nk_buffer_init_fixed(&ebuf, elements, (nk_size)max_element_buffer); - nk_convert(&sdl.ctx, &dev->cmds, &vbuf, &ebuf, &config);} - } - glBufferSubData(GL_ARRAY_BUFFER, 0, (size_t)max_vertex_buffer, vertices); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, (size_t)max_element_buffer, elements); - free(vertices); - free(elements); - - /* iterate over and execute each draw command */ - nk_draw_foreach(cmd, &sdl.ctx, &dev->cmds) { - if (!cmd->elem_count) continue; - glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); - glScissor((GLint)(cmd->clip_rect.x * scale.x), - (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y), - (GLint)(cmd->clip_rect.w * scale.x), - (GLint)(cmd->clip_rect.h * scale.y)); - glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); - offset += cmd->elem_count; - } - nk_clear(&sdl.ctx); - } - - glUseProgram(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - glDisable(GL_BLEND); - glDisable(GL_SCISSOR_TEST); -} - -static void -nk_sdl_clipbard_paste(nk_handle usr, struct nk_text_edit *edit) -{ - const char *text = SDL_GetClipboardText(); - if (text) nk_textedit_paste(edit, text, nk_strlen(text)); - (void)usr; -} - -static void -nk_sdl_clipbard_copy(nk_handle usr, const char *text, int len) -{ - char *str = 0; - (void)usr; - if (!len) return; - str = (char*)malloc((size_t)len+1); - if (!str) return; - memcpy(str, text, (size_t)len); - str[len] = '\0'; - SDL_SetClipboardText(str); - free(str); -} - -NK_API struct nk_context* -nk_sdl_init(SDL_Window *win) -{ - sdl.win = win; - nk_init_default(&sdl.ctx, 0); - sdl.ctx.clip.copy = nk_sdl_clipbard_copy; - sdl.ctx.clip.paste = nk_sdl_clipbard_paste; - sdl.ctx.clip.userdata = nk_handle_ptr(0); - nk_sdl_device_create(); - return &sdl.ctx; -} - -NK_API void -nk_sdl_font_stash_begin(struct nk_font_atlas **atlas) -{ - nk_font_atlas_init_default(&sdl.atlas); - nk_font_atlas_begin(&sdl.atlas); - *atlas = &sdl.atlas; -} - -NK_API void -nk_sdl_font_stash_end(void) -{ - const void *image; int w, h; - image = nk_font_atlas_bake(&sdl.atlas, &w, &h, NK_FONT_ATLAS_RGBA32); - nk_sdl_device_upload_atlas(image, w, h); - nk_font_atlas_end(&sdl.atlas, nk_handle_id((int)sdl.ogl.font_tex), &sdl.ogl.null); - if (sdl.atlas.default_font) - nk_style_set_font(&sdl.ctx, &sdl.atlas.default_font->handle); - -} - -NK_API int -nk_sdl_handle_event(SDL_Event *evt) -{ - struct nk_context *ctx = &sdl.ctx; - if (evt->type == SDL_KEYUP || evt->type == SDL_KEYDOWN) { - /* key events */ - int down = evt->type == SDL_KEYDOWN; - const Uint8* state = SDL_GetKeyboardState(0); - SDL_Keycode sym = evt->key.keysym.sym; - if (sym == SDLK_RSHIFT || sym == SDLK_LSHIFT) - nk_input_key(ctx, NK_KEY_SHIFT, down); - else if (sym == SDLK_DELETE) - nk_input_key(ctx, NK_KEY_DEL, down); - else if (sym == SDLK_RETURN) - nk_input_key(ctx, NK_KEY_ENTER, down); - else if (sym == SDLK_TAB) - nk_input_key(ctx, NK_KEY_TAB, down); - else if (sym == SDLK_BACKSPACE) - nk_input_key(ctx, NK_KEY_BACKSPACE, down); - else if (sym == SDLK_HOME) { - nk_input_key(ctx, NK_KEY_TEXT_START, down); - nk_input_key(ctx, NK_KEY_SCROLL_START, down); - } else if (sym == SDLK_END) { - nk_input_key(ctx, NK_KEY_TEXT_END, down); - nk_input_key(ctx, NK_KEY_SCROLL_END, down); - } else if (sym == SDLK_PAGEDOWN) { - nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down); - } else if (sym == SDLK_PAGEUP) { - nk_input_key(ctx, NK_KEY_SCROLL_UP, down); - } else if (sym == SDLK_z) - nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && state[SDL_SCANCODE_LCTRL]); - else if (sym == SDLK_r) - nk_input_key(ctx, NK_KEY_TEXT_REDO, down && state[SDL_SCANCODE_LCTRL]); - else if (sym == SDLK_c) - nk_input_key(ctx, NK_KEY_COPY, down && state[SDL_SCANCODE_LCTRL]); - else if (sym == SDLK_v) - nk_input_key(ctx, NK_KEY_PASTE, down && state[SDL_SCANCODE_LCTRL]); - else if (sym == SDLK_x) - nk_input_key(ctx, NK_KEY_CUT, down && state[SDL_SCANCODE_LCTRL]); - else if (sym == SDLK_b) - nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && state[SDL_SCANCODE_LCTRL]); - else if (sym == SDLK_e) - nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && state[SDL_SCANCODE_LCTRL]); - else if (sym == SDLK_UP) - nk_input_key(ctx, NK_KEY_UP, down); - else if (sym == SDLK_DOWN) - nk_input_key(ctx, NK_KEY_DOWN, down); - else if (sym == SDLK_LEFT) { - if (state[SDL_SCANCODE_LCTRL]) - nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down); - else nk_input_key(ctx, NK_KEY_LEFT, down); - } else if (sym == SDLK_RIGHT) { - if (state[SDL_SCANCODE_LCTRL]) - nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down); - else nk_input_key(ctx, NK_KEY_RIGHT, down); - } else return 0; - return 1; - } else if (evt->type == SDL_MOUSEBUTTONDOWN || evt->type == SDL_MOUSEBUTTONUP) { - /* mouse button */ - int down = evt->type == SDL_MOUSEBUTTONDOWN; - const int x = evt->button.x, y = evt->button.y; - if (evt->button.button == SDL_BUTTON_LEFT) { - if (evt->button.clicks > 1) - nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, down); - nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down); - } else if (evt->button.button == SDL_BUTTON_MIDDLE) - nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down); - else if (evt->button.button == SDL_BUTTON_RIGHT) - nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down); - return 1; - } else if (evt->type == SDL_MOUSEMOTION) { - /* mouse motion */ - if (ctx->input.mouse.grabbed) { - int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y; - nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel); - } else nk_input_motion(ctx, evt->motion.x, evt->motion.y); - return 1; - } else if (evt->type == SDL_TEXTINPUT) { - /* text input */ - nk_glyph glyph; - memcpy(glyph, evt->text.text, NK_UTF_SIZE); - nk_input_glyph(ctx, glyph); - return 1; - } else if (evt->type == SDL_MOUSEWHEEL) { - /* mouse wheel */ - nk_input_scroll(ctx,nk_vec2((float)evt->wheel.x,(float)evt->wheel.y)); - return 1; - } - return 0; -} - -NK_API -void nk_sdl_shutdown(void) -{ - nk_font_atlas_clear(&sdl.atlas); - nk_free(&sdl.ctx); - nk_sdl_device_destroy(); - memset(&sdl, 0, sizeof(sdl)); -} - -#endif diff --git a/subprojects/nk_pugl/nuklear/demo/sfml_opengl2/Makefile b/subprojects/nk_pugl/nuklear/demo/sfml_opengl2/Makefile deleted file mode 100644 index 28848a4..0000000 --- a/subprojects/nk_pugl/nuklear/demo/sfml_opengl2/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -# Install -CC = g++ -BIN = demo - -# Flags -CFLAGS += -s -O2 - -SRC = main.cpp -OBJ = $(SRC:.cpp=.o) - -ifeq ($(OS),Windows_NT) - # Edit the line below to point to your SFML folder on Windows - SFML_DIR = C:/Users/Ricky/MinGW-Libs/SFML - - BIN := $(BIN).exe - LIBS = -lmingw32 -DSFML_STATIC -lsfml-window-s -lsfml-system-s -lopengl32 -lwinmm -lgdi32 -else - # Edit the line below to point to your SFML folder on Linux/MacOS - SFML_DIR = /home/ricky/Libraries/SFML - - UNAME_S := $(shell uname -s) - ifeq ($(UNAME_S),Darwin) - LIBS = -lsfml-window -lsfml-system -pthread -framework OpenGL - else - LIBS = -DSFML_STATIC -lsfml-window-s -lsfml-system-s -pthread -ludev -lGL -lX11 -lXrandr - endif -endif - -SFML_INC = -I $(SFML_DIR)/include -SFML_LIB = -L $(SFML_DIR)/lib - -$(BIN): - $(CC) $(SRC) $(CFLAGS) -o $(BIN) $(SFML_INC) $(SFML_LIB) $(LIBS) diff --git a/subprojects/nk_pugl/nuklear/demo/sfml_opengl2/Readme.md b/subprojects/nk_pugl/nuklear/demo/sfml_opengl2/Readme.md deleted file mode 100644 index e3879c0..0000000 --- a/subprojects/nk_pugl/nuklear/demo/sfml_opengl2/Readme.md +++ /dev/null @@ -1,9 +0,0 @@ -# SFML 2.4 nuklear backend - -This backend provides support for [SFML 2.4](http://www.sfml-dev.org). It will work on all platforms supported by SFML. - -## Compiling - -You have to edit the Makefile provided so that you can build the demo. Edit the SFML_DIR variable to point to your SFML root folder. This will be the folder to which SFML was installed and contains the lib and include folders. - -On Linux there is an extra step. You need to install the the udev development files. diff --git a/subprojects/nk_pugl/nuklear/demo/sfml_opengl2/main.cpp b/subprojects/nk_pugl/nuklear/demo/sfml_opengl2/main.cpp deleted file mode 100644 index 805c1f8..0000000 --- a/subprojects/nk_pugl/nuklear/demo/sfml_opengl2/main.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* nuklear - v1.32.0 - public domain */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_STANDARD_VARARGS -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT -#define NK_INCLUDE_FONT_BAKING -#define NK_INCLUDE_DEFAULT_FONT -#define NK_IMPLEMENTATION -#define NK_SFML_GL2_IMPLEMENTATION -#include "../../nuklear.h" -#include "nuklear_sfml_gl2.h" - -#define WINDOW_WIDTH 1200 -#define WINDOW_HEIGHT 800 - -/* =============================================================== - * - * EXAMPLE - * - * ===============================================================*/ -/* This are some code examples to provide a small overview of what can be - * done with this library. To try out an example uncomment the defines */ -/*#define INCLUDE_ALL */ -/*#define INCLUDE_STYLE */ -/*#define INCLUDE_CALCULATOR */ -/*#define INCLUDE_OVERVIEW */ -/*#define INCLUDE_NODE_EDITOR */ - -#ifdef INCLUDE_ALL - #define INCLUDE_STYLE - #define INCLUDE_CALCULATOR - #define INCLUDE_OVERVIEW - #define INCLUDE_NODE_EDITOR -#endif - -#ifdef INCLUDE_STYLE - #include "../style.c" -#endif -#ifdef INCLUDE_CALCULATOR - #include "../calculator.c" -#endif -#ifdef INCLUDE_OVERVIEW - #include "../overview.c" -#endif -#ifdef INCLUDE_NODE_EDITOR - #include "../node_editor.c" -#endif - -/* =============================================================== - * - * DEMO - * - * ===============================================================*/ -int main(void) -{ - /* Platform */ - sf::ContextSettings settings(24, 8, 4, 2, 2); - sf::Window win(sf::VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT), "Demo", sf::Style::Default, settings); - win.setVerticalSyncEnabled(true); - win.setActive(true); - glViewport(0, 0, win.getSize().x, win.getSize().y); - - /* GUI */ - struct nk_context *ctx; - ctx = nk_sfml_init(&win); - /* Load Fonts: if none of these are loaded a default font will be used */ - /* Load Cursor: if you uncomment cursor loading please hide the cursor */ - struct nk_font_atlas *atlas; - nk_sfml_font_stash_begin(&atlas); - /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/ - /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 14, 0);*/ - /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/ - /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/ - /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/ - /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/ - nk_sfml_font_stash_end(); - /*nk_style_load_all_cursors(ctx, atlas->cursors);*/ - /*nk_style_set_font(ctx, &droid->handle);*/ - - /* style.c */ - #ifdef INCLUDE_STYLE - /*set_style(ctx, THEME_WHITE);*/ - /*set_style(ctx, THEME_RED);*/ - /*set_style(ctx, THEME_BLUE);*/ - /*set_style(ctx, THEME_DARK);*/ - #endif - - struct nk_colorf bg; - bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f; - while (win.isOpen()) - { - /* Input */ - sf::Event evt; - nk_input_begin(ctx); - while(win.pollEvent(evt)) { - if(evt.type == sf::Event::Closed) - win.close(); - else if(evt.type == sf::Event::Resized) - glViewport(0, 0, evt.size.width, evt.size.height); - nk_sfml_handle_event(&evt); - } - nk_input_end(ctx); - - /* GUI */ - if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250), - NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE| - NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) - { - enum {EASY, HARD}; - static int op = EASY; - static int property = 20; - nk_layout_row_static(ctx, 30, 80, 1); - if (nk_button_label(ctx, "button")) - fprintf(stdout, "button pressed\n"); - - nk_layout_row_dynamic(ctx, 30, 2); - if (nk_option_label(ctx, "easy", op == EASY)) op = EASY; - if (nk_option_label(ctx, "hard", op == HARD)) op = HARD; - - nk_layout_row_dynamic(ctx, 25, 1); - nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1); - - nk_layout_row_dynamic(ctx, 20, 1); - nk_label(ctx, "background:", NK_TEXT_LEFT); - nk_layout_row_dynamic(ctx, 25, 1); - if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) { - nk_layout_row_dynamic(ctx, 120, 1); - bg = nk_color_picker(ctx, bg, NK_RGBA); - nk_layout_row_dynamic(ctx, 25, 1); - bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f); - bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f); - bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f); - bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f); - nk_combo_end(ctx); - } - } - nk_end(ctx); - - /* -------------- EXAMPLES ---------------- */ - #ifdef INCLUDE_CALCULATOR - calculator(ctx); - #endif - #ifdef INCLUDE_OVERVIEW - overview(ctx); - #endif - #ifdef INCLUDE_NODE_EDITOR - node_editor(ctx); - #endif - /* ----------------------------------------- */ - - /* Draw */ - win.setActive(true); - nk_color_fv(bg, background); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(bg.r, bg.g, bg.b, bg.a); - /* IMPORTANT: `nk_sfml_render` modifies some global OpenGL state - * with blending, scissor, face culling and depth test and defaults everything - * back into a default state. Make sure to either save and restore or - * reset your own state after drawing rendering the UI. */ - nk_sfml_render(NK_ANTI_ALIASING_ON); - win.display(); - } - nk_sfml_shutdown(); - return 0; -} - diff --git a/subprojects/nk_pugl/nuklear/demo/sfml_opengl2/nuklear_sfml_gl2.h b/subprojects/nk_pugl/nuklear/demo/sfml_opengl2/nuklear_sfml_gl2.h deleted file mode 100644 index 9649ec0..0000000 --- a/subprojects/nk_pugl/nuklear/demo/sfml_opengl2/nuklear_sfml_gl2.h +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Nuklear - 1.32.0 - public domain - * no warrenty implied; use at your own risk. - * authored from 2015-2016 by Micha Mettke - */ -/* - * ============================================================== - * - * API - * - * =============================================================== - */ -#ifndef NK_SFML_GL2_H_ -#define NK_SFML_GL2_H_ - -#include - -NK_API struct nk_context* nk_sfml_init(sf::Window* window); -NK_API void nk_sfml_font_stash_begin(struct nk_font_atlas** atlas); -NK_API void nk_sfml_font_stash_end(void); -NK_API int nk_sfml_handle_event(sf::Event* event); -NK_API void nk_sfml_render(enum nk_anti_aliasing); -NK_API void nk_sfml_shutdown(void); - -#endif -/* - * ============================================================== - * - * IMPLEMENTATION - * - * =============================================================== - */ - #ifdef NK_SFML_GL2_IMPLEMENTATION - -struct nk_sfml_device { - struct nk_buffer cmds; - struct nk_draw_null_texture null; - GLuint font_tex; -}; - -struct nk_sfml_vertex { - float position[2]; - float uv[2]; - nk_byte col[4]; -}; - -static struct nk_sfml { - sf::Window* window; - struct nk_sfml_device ogl; - struct nk_context ctx; - struct nk_font_atlas atlas; -} sfml; - -NK_INTERN void -nk_sfml_device_upload_atlas(const void* image, int width, int height) -{ - struct nk_sfml_device* dev = &sfml.ogl; - glGenTextures(1, &dev->font_tex); - glBindTexture(GL_TEXTURE_2D, dev->font_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, image); -} - -NK_API void -nk_sfml_render(enum nk_anti_aliasing AA) -{ - /* setup global state */ - struct nk_sfml_device* dev = &sfml.ogl; - - int window_width = sfml.window->getSize().x; - int window_height = sfml.window->getSize().y; - - glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glEnable(GL_SCISSOR_TEST); - glEnable(GL_BLEND); - glEnable(GL_TEXTURE_2D); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glViewport(0, 0, (GLsizei)window_width, (GLsizei)window_height); - glMatrixMode(GL_TEXTURE); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(0.0f, window_width, window_height, 0.0f, -1.0f, 1.0f); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - { - GLsizei vs = sizeof(struct nk_sfml_vertex); - size_t vp = offsetof(struct nk_sfml_vertex, position); - size_t vt = offsetof(struct nk_sfml_vertex, uv); - size_t vc = offsetof(struct nk_sfml_vertex, col); - - /* convert from command queue into draw list and draw to screen */ - const struct nk_draw_command* cmd; - const nk_draw_index* offset = NULL; - struct nk_buffer vbuf, ebuf; - - /* fill converting configuration */ - struct nk_convert_config config; - static const struct nk_draw_vertex_layout_element vertex_layout[] = { - {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sfml_vertex, position)}, - {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sfml_vertex, uv)}, - {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sfml_vertex, col)}, - {NK_VERTEX_LAYOUT_END} - }; - NK_MEMSET(&config, 0, sizeof(config)); - config.vertex_layout = vertex_layout; - config.vertex_size = sizeof(struct nk_sfml_vertex); - config.vertex_alignment = NK_ALIGNOF(struct nk_sfml_vertex); - config.null = dev->null; - config.circle_segment_count = 22; - config.curve_segment_count = 22; - config.arc_segment_count = 22; - config.global_alpha = 1.0f; - config.shape_AA = AA; - config.line_AA = AA; - - /* convert shapes into vertices */ - nk_buffer_init_default(&vbuf); - nk_buffer_init_default(&ebuf); - nk_convert(&sfml.ctx, &dev->cmds, &vbuf, &ebuf, &config); - - /* setup vertex buffer pointer */ - const void* vertices = nk_buffer_memory_const(&vbuf); - glVertexPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vp)); - glTexCoordPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vt)); - glColorPointer(4, GL_UNSIGNED_BYTE, vs, (const void*)((const nk_byte*)vertices + vc)); - - /* iterate over and execute each draw command */ - offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf); - nk_draw_foreach(cmd, &sfml.ctx, &dev->cmds) - { - if(!cmd->elem_count) continue; - glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); - glScissor( - (GLint)(cmd->clip_rect.x), - (GLint)((window_height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h))), - (GLint)(cmd->clip_rect.w), - (GLint)(cmd->clip_rect.h)); - glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); - offset += cmd->elem_count; - } - nk_clear(&sfml.ctx); - nk_buffer_free(&vbuf); - nk_buffer_free(&ebuf); - } - - /* default OpenGL state */ - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - - glBindTexture(GL_TEXTURE_2D, 0); - glMatrixMode(GL_TEXTURE); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glPopAttrib(); -} - -static void -nk_sfml_clipboard_paste(nk_handle usr, struct nk_text_edit* edit) -{ -#if 0 - /* Not Implemented in SFML */ - sf::Clipboard clipboard(sfml.window); - const char* text = clipboard.getText(); - - if(text) - nk_textedit_paste(edit, text, nk_strlen(text)); - (void)usr; -#endif -} - -static void -nk_sfml_clipboard_copy(nk_handle usr, const char* text, int len) -{ -#if 0 - char* str = 0; - (void)usr; - if(!len) return; - str = (char*)malloc((size_t)len+1); - if(!str) return; - memcpy(str, text, (size_t)len); - str[len] = '\0'; - - /* Not Implemented in SFML */ - sf::Clipboard clipboard(sfml.window); - clipboard.setText(str); - free(str); -#endif -} - -NK_API struct nk_context* -nk_sfml_init(sf::Window* window) -{ - sfml.window = window; - nk_init_default(&sfml.ctx, 0); - sfml.ctx.clip.copy = nk_sfml_clipboard_copy; - sfml.ctx.clip.paste = nk_sfml_clipboard_paste; - sfml.ctx.clip.userdata = nk_handle_ptr(0); - nk_buffer_init_default(&sfml.ogl.cmds); - return &sfml.ctx; -} - -NK_API void -nk_sfml_font_stash_begin(struct nk_font_atlas** atlas) -{ - nk_font_atlas_init_default(&sfml.atlas); - nk_font_atlas_begin(&sfml.atlas); - *atlas = &sfml.atlas; -} - -NK_API void -nk_sfml_font_stash_end() -{ - int w, h; - const void* img; - img = nk_font_atlas_bake(&sfml.atlas, &w, &h, NK_FONT_ATLAS_RGBA32); - nk_sfml_device_upload_atlas(img, w, h); - nk_font_atlas_end(&sfml.atlas, nk_handle_id((int)sfml.ogl.font_tex), &sfml.ogl.null); - if(sfml.atlas.default_font) - nk_style_set_font(&sfml.ctx, &sfml.atlas.default_font->handle); -} - -NK_API int -nk_sfml_handle_event(sf::Event* evt) -{ - struct nk_context* ctx = &sfml.ctx; - /* optional grabbing behavior */ - if(ctx->input.mouse.grab) - ctx->input.mouse.grab = 0; - else if(ctx->input.mouse.ungrab) { - int x = (int)ctx->input.mouse.prev.x; - int y = (int)ctx->input.mouse.prev.y; - sf::Mouse::setPosition(sf::Vector2i(x, y), *sfml.window); - ctx->input.mouse.ungrab = 0; - } - if(evt->type == sf::Event::KeyReleased || evt->type == sf::Event::KeyPressed) - { - int down = evt->type == sf::Event::KeyPressed; - sf::Keyboard::Key key = evt->key.code; - if(key == sf::Keyboard::RShift || key == sf::Keyboard::LShift) - nk_input_key(ctx, NK_KEY_SHIFT, down); - else if(key == sf::Keyboard::Delete) - nk_input_key(ctx, NK_KEY_DEL, down); - else if(key == sf::Keyboard::Return) - nk_input_key(ctx, NK_KEY_ENTER, down); - else if(key == sf::Keyboard::Tab) - nk_input_key(ctx, NK_KEY_TAB, down); - else if(key == sf::Keyboard::BackSpace) - nk_input_key(ctx, NK_KEY_BACKSPACE, down); - else if(key == sf::Keyboard::Home) { - nk_input_key(ctx, NK_KEY_TEXT_START, down); - nk_input_key(ctx, NK_KEY_SCROLL_START, down); - } else if(key == sf::Keyboard::End) { - nk_input_key(ctx, NK_KEY_TEXT_END, down); - nk_input_key(ctx, NK_KEY_SCROLL_END, down); - } else if(key == sf::Keyboard::PageDown) - nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down); - else if(key == sf::Keyboard::PageUp) - nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down); - else if(key == sf::Keyboard::Z) - nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)); - else if(key == sf::Keyboard::R) - nk_input_key(ctx, NK_KEY_TEXT_REDO, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)); - else if(key == sf::Keyboard::C) - nk_input_key(ctx, NK_KEY_COPY, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)); - else if(key == sf::Keyboard::V) - nk_input_key(ctx, NK_KEY_PASTE, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)); - else if(key == sf::Keyboard::X) - nk_input_key(ctx, NK_KEY_CUT, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)); - else if(key == sf::Keyboard::B) - nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)); - else if(key == sf::Keyboard::E) - nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)); - else if(key == sf::Keyboard::Up) - nk_input_key(ctx, NK_KEY_UP, down); - else if(key == sf::Keyboard::Down) - nk_input_key(ctx, NK_KEY_DOWN, down); - else if(key == sf::Keyboard::Left) { - if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)) - nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down); - else nk_input_key(ctx, NK_KEY_LEFT, down); - } else if(key == sf::Keyboard::Right) { - if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)) - nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down); - else nk_input_key(ctx, NK_KEY_RIGHT, down); - } else return 0; - return 1; - } else if(evt->type == sf::Event::MouseButtonPressed || evt->type == sf::Event::MouseButtonReleased) { - int down = evt->type == sf::Event::MouseButtonPressed; - const int x = evt->mouseButton.x, y = evt->mouseButton.y; - if(evt->mouseButton.button == sf::Mouse::Left) - nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down); - if(evt->mouseButton.button == sf::Mouse::Middle) - nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down); - if(evt->mouseButton.button == sf::Mouse::Right) - nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down); - else return 0; - return 1; - } else if(evt->type == sf::Event::MouseMoved) { - nk_input_motion(ctx, evt->mouseMove.x, evt->mouseMove.y); - return 1; - } else if(evt->type == sf::Event::TouchBegan || evt->type == sf::Event::TouchEnded) { - int down = evt->type == sf::Event::TouchBegan; - const int x = evt->touch.x, y = evt->touch.y; - ctx->input.mouse.pos.x = x; - ctx->input.mouse.pos.y = y; - nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down); - return 1; - } else if(evt->type == sf::Event::TouchMoved) { - if(ctx->input.mouse.grabbed) { - int x = (int)ctx->input.mouse.prev.x; - int y = (int)ctx->input.mouse.prev.y; - nk_input_motion(ctx, x + evt->touch.x, y + evt->touch.y); - } else nk_input_motion(ctx, evt->touch.x, evt->touch.y); - return 1; - } else if(evt->type == sf::Event::TextEntered) { - nk_input_unicode(ctx, evt->text.unicode); - return 1; - } else if(evt->type == sf::Event::MouseWheelScrolled) { - nk_input_scroll(ctx, nk_vec2(0,evt->mouseWheelScroll.delta)); - return 1; - } - return 0; -} - -NK_API -void nk_sfml_shutdown(void) -{ - struct nk_sfml_device* dev = &sfml.ogl; - nk_font_atlas_clear(&sfml.atlas); - nk_free(&sfml.ctx); - glDeleteTextures(1, &dev->font_tex); - nk_buffer_free(&dev->cmds); - memset(&sfml, 0, sizeof(sfml)); -} - -#endif diff --git a/subprojects/nk_pugl/nuklear/demo/sfml_opengl3/Makefile b/subprojects/nk_pugl/nuklear/demo/sfml_opengl3/Makefile deleted file mode 100644 index b30bf28..0000000 --- a/subprojects/nk_pugl/nuklear/demo/sfml_opengl3/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -# Install -CC = g++ -BIN = demo - -# Flags -CFLAGS += -s -O2 - -SRC = main.cpp -OBJ = $(SRC:.cpp=.o) - -ifeq ($(OS),Windows_NT) - # Edit the line below to point to your SFML/GLAD folder on Windows - SFML_DIR = C:/Users/Ricky/MinGW-Libs/SFML - GLAD_DIR = C:/Users/Ricky/MinGW-Libs/GLAD - - BIN := $(BIN).exe - LIBS = -lmingw32 -DSFML_STATIC -lsfml-window-s -lsfml-system-s -lopengl32 -lwinmm -lgdi32 -else - # Edit the line below to point to your SFML/GLAD folder on Linux/MacOS - SFML_DIR = /home/ricky/Libraries/SFML - GLAD_DIR = /home/ricky/Libraries/GLAD - - UNAME_S := $(shell uname -s) - ifeq ($(UNAME_S),Darwin) - LIBS = -lsfml-window -lsfml-system -pthread -framework OpenGL - else - LIBS = -DSFML_STATIC -lsfml-window-s -lsfml-system-s -pthread -ludev -lGL -lX11 -lXrandr - endif -endif - -SFML_INC = -I $(SFML_DIR)/include -SFML_LIB = -L $(SFML_DIR)/lib -GLAD_INC = -I $(GLAD_DIR)/include -GLAD_SRC = $(GLAD_DIR)/src/glad.c - -$(BIN): - $(CC) $(GLAD_SRC) $(SRC) $(CFLAGS) $(GLAD_INC) $(SFML_INC) $(SFML_LIB) $(SFML_EXT) -o $(BIN) $(LIBS) diff --git a/subprojects/nk_pugl/nuklear/demo/sfml_opengl3/Readme.md b/subprojects/nk_pugl/nuklear/demo/sfml_opengl3/Readme.md deleted file mode 100644 index ac03e75..0000000 --- a/subprojects/nk_pugl/nuklear/demo/sfml_opengl3/Readme.md +++ /dev/null @@ -1,11 +0,0 @@ -# SFML 2.4 nuklear backend - -This backend provides support for [SFML 2.4](http://www.sfml-dev.org). It will work on all platforms supported by SFML. - -## Compiling - -This backend uses Glad to handle OpenGL extensions. You can download the Glad files used to test this backend from [this link](http://glad.dav1d.de/#profile=compatibility&api=gl%3D3.2&api=gles1%3Dnone&api=gles2%3D3.2&api=glsc2%3Dnone&extensions=GL_3DFX_multisample&extensions=GL_3DFX_tbuffer&extensions=GL_3DFX_texture_compression_FXT1&extensions=GL_AMD_blend_minmax_factor&extensions=GL_AMD_compressed_3DC_texture&extensions=GL_AMD_compressed_ATC_texture&extensions=GL_AMD_conservative_depth&extensions=GL_AMD_debug_output&extensions=GL_AMD_depth_clamp_separate&extensions=GL_AMD_draw_buffers_blend&extensions=GL_AMD_gcn_shader&extensions=GL_AMD_gpu_shader_half_float&extensions=GL_AMD_gpu_shader_int64&extensions=GL_AMD_interleaved_elements&extensions=GL_AMD_multi_draw_indirect&extensions=GL_AMD_name_gen_delete&extensions=GL_AMD_occlusion_query_event&extensions=GL_AMD_performance_monitor&extensions=GL_AMD_pinned_memory&extensions=GL_AMD_program_binary_Z400&extensions=GL_AMD_query_buffer_object&extensions=GL_AMD_sample_positions&extensions=GL_AMD_seamless_cubemap_per_texture&extensions=GL_AMD_shader_atomic_counter_ops&extensions=GL_AMD_shader_ballot&extensions=GL_AMD_shader_explicit_vertex_parameter&extensions=GL_AMD_shader_stencil_export&extensions=GL_AMD_shader_trinary_minmax&extensions=GL_AMD_sparse_texture&extensions=GL_AMD_stencil_operation_extended&extensions=GL_AMD_texture_texture4&extensions=GL_AMD_transform_feedback3_lines_triangles&extensions=GL_AMD_transform_feedback4&extensions=GL_AMD_vertex_shader_layer&extensions=GL_AMD_vertex_shader_tessellator&extensions=GL_AMD_vertex_shader_viewport_index&extensions=GL_ANDROID_extension_pack_es31a&extensions=GL_ANGLE_depth_texture&extensions=GL_ANGLE_framebuffer_blit&extensions=GL_ANGLE_framebuffer_multisample&extensions=GL_ANGLE_instanced_arrays&extensions=GL_ANGLE_pack_reverse_row_order&extensions=GL_ANGLE_program_binary&extensions=GL_ANGLE_texture_compression_dxt3&extensions=GL_ANGLE_texture_compression_dxt5&extensions=GL_ANGLE_texture_usage&extensions=GL_ANGLE_translated_shader_source&extensions=GL_APPLE_aux_depth_stencil&extensions=GL_APPLE_client_storage&extensions=GL_APPLE_clip_distance&extensions=GL_APPLE_color_buffer_packed_float&extensions=GL_APPLE_copy_texture_levels&extensions=GL_APPLE_element_array&extensions=GL_APPLE_fence&extensions=GL_APPLE_float_pixels&extensions=GL_APPLE_flush_buffer_range&extensions=GL_APPLE_framebuffer_multisample&extensions=GL_APPLE_object_purgeable&extensions=GL_APPLE_rgb_422&extensions=GL_APPLE_row_bytes&extensions=GL_APPLE_specular_vector&extensions=GL_APPLE_sync&extensions=GL_APPLE_texture_format_BGRA8888&extensions=GL_APPLE_texture_max_level&extensions=GL_APPLE_texture_packed_float&extensions=GL_APPLE_texture_range&extensions=GL_APPLE_transform_hint&extensions=GL_APPLE_vertex_array_object&extensions=GL_APPLE_vertex_array_range&extensions=GL_APPLE_vertex_program_evaluators&extensions=GL_APPLE_ycbcr_422&extensions=GL_ARB_ES2_compatibility&extensions=GL_ARB_ES3_1_compatibility&extensions=GL_ARB_ES3_2_compatibility&extensions=GL_ARB_ES3_compatibility&extensions=GL_ARB_arrays_of_arrays&extensions=GL_ARB_base_instance&extensions=GL_ARB_bindless_texture&extensions=GL_ARB_blend_func_extended&extensions=GL_ARB_buffer_storage&extensions=GL_ARB_cl_event&extensions=GL_ARB_clear_buffer_object&extensions=GL_ARB_clear_texture&extensions=GL_ARB_clip_control&extensions=GL_ARB_color_buffer_float&extensions=GL_ARB_compatibility&extensions=GL_ARB_compressed_texture_pixel_storage&extensions=GL_ARB_compute_shader&extensions=GL_ARB_compute_variable_group_size&extensions=GL_ARB_conditional_render_inverted&extensions=GL_ARB_conservative_depth&extensions=GL_ARB_copy_buffer&extensions=GL_ARB_copy_image&extensions=GL_ARB_cull_distance&extensions=GL_ARB_debug_output&extensions=GL_ARB_depth_buffer_float&extensions=GL_ARB_depth_clamp&extensions=GL_ARB_depth_texture&extensions=GL_ARB_derivative_control&extensions=GL_ARB_direct_state_access&extensions=GL_ARB_draw_buffers&extensions=GL_ARB_draw_buffers_blend&extensions=GL_ARB_draw_elements_base_vertex&extensions=GL_ARB_draw_indirect&extensions=GL_ARB_draw_instanced&extensions=GL_ARB_enhanced_layouts&extensions=GL_ARB_explicit_attrib_location&extensions=GL_ARB_explicit_uniform_location&extensions=GL_ARB_fragment_coord_conventions&extensions=GL_ARB_fragment_layer_viewport&extensions=GL_ARB_fragment_program&extensions=GL_ARB_fragment_program_shadow&extensions=GL_ARB_fragment_shader&extensions=GL_ARB_fragment_shader_interlock&extensions=GL_ARB_framebuffer_no_attachments&extensions=GL_ARB_framebuffer_object&extensions=GL_ARB_framebuffer_sRGB&extensions=GL_ARB_geometry_shader4&extensions=GL_ARB_get_program_binary&extensions=GL_ARB_get_texture_sub_image&extensions=GL_ARB_gpu_shader5&extensions=GL_ARB_gpu_shader_fp64&extensions=GL_ARB_gpu_shader_int64&extensions=GL_ARB_half_float_pixel&extensions=GL_ARB_half_float_vertex&extensions=GL_ARB_imaging&extensions=GL_ARB_indirect_parameters&extensions=GL_ARB_instanced_arrays&extensions=GL_ARB_internalformat_query&extensions=GL_ARB_internalformat_query2&extensions=GL_ARB_invalidate_subdata&extensions=GL_ARB_map_buffer_alignment&extensions=GL_ARB_map_buffer_range&extensions=GL_ARB_matrix_palette&extensions=GL_ARB_multi_bind&extensions=GL_ARB_multi_draw_indirect&extensions=GL_ARB_multisample&extensions=GL_ARB_multitexture&extensions=GL_ARB_occlusion_query&extensions=GL_ARB_occlusion_query2&extensions=GL_ARB_parallel_shader_compile&extensions=GL_ARB_pipeline_statistics_query&extensions=GL_ARB_pixel_buffer_object&extensions=GL_ARB_point_parameters&extensions=GL_ARB_point_sprite&extensions=GL_ARB_post_depth_coverage&extensions=GL_ARB_program_interface_query&extensions=GL_ARB_provoking_vertex&extensions=GL_ARB_query_buffer_object&extensions=GL_ARB_robust_buffer_access_behavior&extensions=GL_ARB_robustness&extensions=GL_ARB_robustness_isolation&extensions=GL_ARB_sample_locations&extensions=GL_ARB_sample_shading&extensions=GL_ARB_sampler_objects&extensions=GL_ARB_seamless_cube_map&extensions=GL_ARB_seamless_cubemap_per_texture&extensions=GL_ARB_separate_shader_objects&extensions=GL_ARB_shader_atomic_counter_ops&extensions=GL_ARB_shader_atomic_counters&extensions=GL_ARB_shader_ballot&extensions=GL_ARB_shader_bit_encoding&extensions=GL_ARB_shader_clock&extensions=GL_ARB_shader_draw_parameters&extensions=GL_ARB_shader_group_vote&extensions=GL_ARB_shader_image_load_store&extensions=GL_ARB_shader_image_size&extensions=GL_ARB_shader_objects&extensions=GL_ARB_shader_precision&extensions=GL_ARB_shader_stencil_export&extensions=GL_ARB_shader_storage_buffer_object&extensions=GL_ARB_shader_subroutine&extensions=GL_ARB_shader_texture_image_samples&extensions=GL_ARB_shader_texture_lod&extensions=GL_ARB_shader_viewport_layer_array&extensions=GL_ARB_shading_language_100&extensions=GL_ARB_shading_language_420pack&extensions=GL_ARB_shading_language_include&extensions=GL_ARB_shading_language_packing&extensions=GL_ARB_shadow&extensions=GL_ARB_shadow_ambient&extensions=GL_ARB_sparse_buffer&extensions=GL_ARB_sparse_texture&extensions=GL_ARB_sparse_texture2&extensions=GL_ARB_sparse_texture_clamp&extensions=GL_ARB_stencil_texturing&extensions=GL_ARB_sync&extensions=GL_ARB_tessellation_shader&extensions=GL_ARB_texture_barrier&extensions=GL_ARB_texture_border_clamp&extensions=GL_ARB_texture_buffer_object&extensions=GL_ARB_texture_buffer_object_rgb32&extensions=GL_ARB_texture_buffer_range&extensions=GL_ARB_texture_compression&extensions=GL_ARB_texture_compression_bptc&extensions=GL_ARB_texture_compression_rgtc&extensions=GL_ARB_texture_cube_map&extensions=GL_ARB_texture_cube_map_array&extensions=GL_ARB_texture_env_add&extensions=GL_ARB_texture_env_combine&extensions=GL_ARB_texture_env_crossbar&extensions=GL_ARB_texture_env_dot3&extensions=GL_ARB_texture_filter_minmax&extensions=GL_ARB_texture_float&extensions=GL_ARB_texture_gather&extensions=GL_ARB_texture_mirror_clamp_to_edge&extensions=GL_ARB_texture_mirrored_repeat&extensions=GL_ARB_texture_multisample&extensions=GL_ARB_texture_non_power_of_two&extensions=GL_ARB_texture_query_levels&extensions=GL_ARB_texture_query_lod&extensions=GL_ARB_texture_rectangle&extensions=GL_ARB_texture_rg&extensions=GL_ARB_texture_rgb10_a2ui&extensions=GL_ARB_texture_stencil8&extensions=GL_ARB_texture_storage&extensions=GL_ARB_texture_storage_multisample&extensions=GL_ARB_texture_swizzle&extensions=GL_ARB_texture_view&extensions=GL_ARB_timer_query&extensions=GL_ARB_transform_feedback2&extensions=GL_ARB_transform_feedback3&extensions=GL_ARB_transform_feedback_instanced&extensions=GL_ARB_transform_feedback_overflow_query&extensions=GL_ARB_transpose_matrix&extensions=GL_ARB_uniform_buffer_object&extensions=GL_ARB_vertex_array_bgra&extensions=GL_ARB_vertex_array_object&extensions=GL_ARB_vertex_attrib_64bit&extensions=GL_ARB_vertex_attrib_binding&extensions=GL_ARB_vertex_blend&extensions=GL_ARB_vertex_buffer_object&extensions=GL_ARB_vertex_program&extensions=GL_ARB_vertex_shader&extensions=GL_ARB_vertex_type_10f_11f_11f_rev&extensions=GL_ARB_vertex_type_2_10_10_10_rev&extensions=GL_ARB_viewport_array&extensions=GL_ARB_window_pos&extensions=GL_ARM_mali_program_binary&extensions=GL_ARM_mali_shader_binary&extensions=GL_ARM_rgba8&extensions=GL_ARM_shader_framebuffer_fetch&extensions=GL_ARM_shader_framebuffer_fetch_depth_stencil&extensions=GL_ATI_draw_buffers&extensions=GL_ATI_element_array&extensions=GL_ATI_envmap_bumpmap&extensions=GL_ATI_fragment_shader&extensions=GL_ATI_map_object_buffer&extensions=GL_ATI_meminfo&extensions=GL_ATI_pixel_format_float&extensions=GL_ATI_pn_triangles&extensions=GL_ATI_separate_stencil&extensions=GL_ATI_text_fragment_shader&extensions=GL_ATI_texture_env_combine3&extensions=GL_ATI_texture_float&extensions=GL_ATI_texture_mirror_once&extensions=GL_ATI_vertex_array_object&extensions=GL_ATI_vertex_attrib_array_object&extensions=GL_ATI_vertex_streams&extensions=GL_DMP_program_binary&extensions=GL_DMP_shader_binary&extensions=GL_EXT_422_pixels&extensions=GL_EXT_YUV_target&extensions=GL_EXT_abgr&extensions=GL_EXT_base_instance&extensions=GL_EXT_bgra&extensions=GL_EXT_bindable_uniform&extensions=GL_EXT_blend_color&extensions=GL_EXT_blend_equation_separate&extensions=GL_EXT_blend_func_extended&extensions=GL_EXT_blend_func_separate&extensions=GL_EXT_blend_logic_op&extensions=GL_EXT_blend_minmax&extensions=GL_EXT_blend_subtract&extensions=GL_EXT_buffer_storage&extensions=GL_EXT_clear_texture&extensions=GL_EXT_clip_cull_distance&extensions=GL_EXT_clip_volume_hint&extensions=GL_EXT_cmyka&extensions=GL_EXT_color_buffer_float&extensions=GL_EXT_color_buffer_half_float&extensions=GL_EXT_color_subtable&extensions=GL_EXT_compiled_vertex_array&extensions=GL_EXT_conservative_depth&extensions=GL_EXT_convolution&extensions=GL_EXT_coordinate_frame&extensions=GL_EXT_copy_image&extensions=GL_EXT_copy_texture&extensions=GL_EXT_cull_vertex&extensions=GL_EXT_debug_label&extensions=GL_EXT_debug_marker&extensions=GL_EXT_depth_bounds_test&extensions=GL_EXT_direct_state_access&extensions=GL_EXT_discard_framebuffer&extensions=GL_EXT_disjoint_timer_query&extensions=GL_EXT_draw_buffers&extensions=GL_EXT_draw_buffers2&extensions=GL_EXT_draw_buffers_indexed&extensions=GL_EXT_draw_elements_base_vertex&extensions=GL_EXT_draw_instanced&extensions=GL_EXT_draw_range_elements&extensions=GL_EXT_draw_transform_feedback&extensions=GL_EXT_float_blend&extensions=GL_EXT_fog_coord&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_multisample_blit_scaled&extensions=GL_EXT_framebuffer_object&extensions=GL_EXT_framebuffer_sRGB&extensions=GL_EXT_geometry_point_size&extensions=GL_EXT_geometry_shader&extensions=GL_EXT_geometry_shader4&extensions=GL_EXT_gpu_program_parameters&extensions=GL_EXT_gpu_shader4&extensions=GL_EXT_gpu_shader5&extensions=GL_EXT_histogram&extensions=GL_EXT_index_array_formats&extensions=GL_EXT_index_func&extensions=GL_EXT_index_material&extensions=GL_EXT_index_texture&extensions=GL_EXT_instanced_arrays&extensions=GL_EXT_light_texture&extensions=GL_EXT_map_buffer_range&extensions=GL_EXT_misc_attribute&extensions=GL_EXT_multi_draw_arrays&extensions=GL_EXT_multi_draw_indirect&extensions=GL_EXT_multisample&extensions=GL_EXT_multisampled_compatibility&extensions=GL_EXT_multisampled_render_to_texture&extensions=GL_EXT_multiview_draw_buffers&extensions=GL_EXT_occlusion_query_boolean&extensions=GL_EXT_packed_depth_stencil&extensions=GL_EXT_packed_float&extensions=GL_EXT_packed_pixels&extensions=GL_EXT_paletted_texture&extensions=GL_EXT_pixel_buffer_object&extensions=GL_EXT_pixel_transform&extensions=GL_EXT_pixel_transform_color_table&extensions=GL_EXT_point_parameters&extensions=GL_EXT_polygon_offset&extensions=GL_EXT_polygon_offset_clamp&extensions=GL_EXT_post_depth_coverage&extensions=GL_EXT_primitive_bounding_box&extensions=GL_EXT_protected_textures&extensions=GL_EXT_provoking_vertex&extensions=GL_EXT_pvrtc_sRGB&extensions=GL_EXT_raster_multisample&extensions=GL_EXT_read_format_bgra&extensions=GL_EXT_render_snorm&extensions=GL_EXT_rescale_normal&extensions=GL_EXT_robustness&extensions=GL_EXT_sRGB&extensions=GL_EXT_sRGB_write_control&extensions=GL_EXT_secondary_color&extensions=GL_EXT_separate_shader_objects&extensions=GL_EXT_separate_specular_color&extensions=GL_EXT_shader_framebuffer_fetch&extensions=GL_EXT_shader_group_vote&extensions=GL_EXT_shader_image_load_formatted&extensions=GL_EXT_shader_image_load_store&extensions=GL_EXT_shader_implicit_conversions&extensions=GL_EXT_shader_integer_mix&extensions=GL_EXT_shader_io_blocks&extensions=GL_EXT_shader_non_constant_global_initializers&extensions=GL_EXT_shader_pixel_local_storage&extensions=GL_EXT_shader_pixel_local_storage2&extensions=GL_EXT_shader_texture_lod&extensions=GL_EXT_shadow_funcs&extensions=GL_EXT_shadow_samplers&extensions=GL_EXT_shared_texture_palette&extensions=GL_EXT_sparse_texture&extensions=GL_EXT_sparse_texture2&extensions=GL_EXT_stencil_clear_tag&extensions=GL_EXT_stencil_two_side&extensions=GL_EXT_stencil_wrap&extensions=GL_EXT_subtexture&extensions=GL_EXT_tessellation_point_size&extensions=GL_EXT_tessellation_shader&extensions=GL_EXT_texture&extensions=GL_EXT_texture3D&extensions=GL_EXT_texture_array&extensions=GL_EXT_texture_border_clamp&extensions=GL_EXT_texture_buffer&extensions=GL_EXT_texture_buffer_object&extensions=GL_EXT_texture_compression_dxt1&extensions=GL_EXT_texture_compression_latc&extensions=GL_EXT_texture_compression_rgtc&extensions=GL_EXT_texture_compression_s3tc&extensions=GL_EXT_texture_cube_map&extensions=GL_EXT_texture_cube_map_array&extensions=GL_EXT_texture_env_add&extensions=GL_EXT_texture_env_combine&extensions=GL_EXT_texture_env_dot3&extensions=GL_EXT_texture_filter_anisotropic&extensions=GL_EXT_texture_filter_minmax&extensions=GL_EXT_texture_format_BGRA8888&extensions=GL_EXT_texture_integer&extensions=GL_EXT_texture_lod_bias&extensions=GL_EXT_texture_mirror_clamp&extensions=GL_EXT_texture_norm16&extensions=GL_EXT_texture_object&extensions=GL_EXT_texture_perturb_normal&extensions=GL_EXT_texture_rg&extensions=GL_EXT_texture_sRGB&extensions=GL_EXT_texture_sRGB_R8&extensions=GL_EXT_texture_sRGB_RG8&extensions=GL_EXT_texture_sRGB_decode&extensions=GL_EXT_texture_shared_exponent&extensions=GL_EXT_texture_snorm&extensions=GL_EXT_texture_storage&extensions=GL_EXT_texture_swizzle&extensions=GL_EXT_texture_type_2_10_10_10_REV&extensions=GL_EXT_texture_view&extensions=GL_EXT_timer_query&extensions=GL_EXT_transform_feedback&extensions=GL_EXT_unpack_subimage&extensions=GL_EXT_vertex_array&extensions=GL_EXT_vertex_array_bgra&extensions=GL_EXT_vertex_attrib_64bit&extensions=GL_EXT_vertex_shader&extensions=GL_EXT_vertex_weighting&extensions=GL_EXT_window_rectangles&extensions=GL_EXT_x11_sync_object&extensions=GL_FJ_shader_binary_GCCSO&extensions=GL_GREMEDY_frame_terminator&extensions=GL_GREMEDY_string_marker&extensions=GL_HP_convolution_border_modes&extensions=GL_HP_image_transform&extensions=GL_HP_occlusion_test&extensions=GL_HP_texture_lighting&extensions=GL_IBM_cull_vertex&extensions=GL_IBM_multimode_draw_arrays&extensions=GL_IBM_rasterpos_clip&extensions=GL_IBM_static_data&extensions=GL_IBM_texture_mirrored_repeat&extensions=GL_IBM_vertex_array_lists&extensions=GL_IMG_bindless_texture&extensions=GL_IMG_framebuffer_downsample&extensions=GL_IMG_multisampled_render_to_texture&extensions=GL_IMG_program_binary&extensions=GL_IMG_read_format&extensions=GL_IMG_shader_binary&extensions=GL_IMG_texture_compression_pvrtc&extensions=GL_IMG_texture_compression_pvrtc2&extensions=GL_IMG_texture_filter_cubic&extensions=GL_INGR_blend_func_separate&extensions=GL_INGR_color_clamp&extensions=GL_INGR_interlace_read&extensions=GL_INTEL_conservative_rasterization&extensions=GL_INTEL_fragment_shader_ordering&extensions=GL_INTEL_framebuffer_CMAA&extensions=GL_INTEL_map_texture&extensions=GL_INTEL_parallel_arrays&extensions=GL_INTEL_performance_query&extensions=GL_KHR_blend_equation_advanced&extensions=GL_KHR_blend_equation_advanced_coherent&extensions=GL_KHR_context_flush_control&extensions=GL_KHR_debug&extensions=GL_KHR_no_error&extensions=GL_KHR_robust_buffer_access_behavior&extensions=GL_KHR_robustness&extensions=GL_KHR_texture_compression_astc_hdr&extensions=GL_KHR_texture_compression_astc_ldr&extensions=GL_KHR_texture_compression_astc_sliced_3d&extensions=GL_MESAX_texture_stack&extensions=GL_MESA_pack_invert&extensions=GL_MESA_resize_buffers&extensions=GL_MESA_window_pos&extensions=GL_MESA_ycbcr_texture&extensions=GL_NVX_conditional_render&extensions=GL_NVX_gpu_memory_info&extensions=GL_NV_bindless_multi_draw_indirect&extensions=GL_NV_bindless_multi_draw_indirect_count&extensions=GL_NV_bindless_texture&extensions=GL_NV_blend_equation_advanced&extensions=GL_NV_blend_equation_advanced_coherent&extensions=GL_NV_blend_square&extensions=GL_NV_clip_space_w_scaling&extensions=GL_NV_command_list&extensions=GL_NV_compute_program5&extensions=GL_NV_conditional_render&extensions=GL_NV_conservative_raster&extensions=GL_NV_conservative_raster_dilate&extensions=GL_NV_conservative_raster_pre_snap_triangles&extensions=GL_NV_copy_buffer&extensions=GL_NV_copy_depth_to_color&extensions=GL_NV_copy_image&extensions=GL_NV_coverage_sample&extensions=GL_NV_deep_texture3D&extensions=GL_NV_depth_buffer_float&extensions=GL_NV_depth_clamp&extensions=GL_NV_depth_nonlinear&extensions=GL_NV_draw_buffers&extensions=GL_NV_draw_instanced&extensions=GL_NV_draw_texture&extensions=GL_NV_evaluators&extensions=GL_NV_explicit_attrib_location&extensions=GL_NV_explicit_multisample&extensions=GL_NV_fbo_color_attachments&extensions=GL_NV_fence&extensions=GL_NV_fill_rectangle&extensions=GL_NV_float_buffer&extensions=GL_NV_fog_distance&extensions=GL_NV_fragment_coverage_to_color&extensions=GL_NV_fragment_program&extensions=GL_NV_fragment_program2&extensions=GL_NV_fragment_program4&extensions=GL_NV_fragment_program_option&extensions=GL_NV_fragment_shader_interlock&extensions=GL_NV_framebuffer_blit&extensions=GL_NV_framebuffer_mixed_samples&extensions=GL_NV_framebuffer_multisample&extensions=GL_NV_framebuffer_multisample_coverage&extensions=GL_NV_generate_mipmap_sRGB&extensions=GL_NV_geometry_program4&extensions=GL_NV_geometry_shader4&extensions=GL_NV_geometry_shader_passthrough&extensions=GL_NV_gpu_program4&extensions=GL_NV_gpu_program5&extensions=GL_NV_gpu_program5_mem_extended&extensions=GL_NV_gpu_shader5&extensions=GL_NV_half_float&extensions=GL_NV_image_formats&extensions=GL_NV_instanced_arrays&extensions=GL_NV_internalformat_sample_query&extensions=GL_NV_light_max_exponent&extensions=GL_NV_multisample_coverage&extensions=GL_NV_multisample_filter_hint&extensions=GL_NV_non_square_matrices&extensions=GL_NV_occlusion_query&extensions=GL_NV_packed_depth_stencil&extensions=GL_NV_parameter_buffer_object&extensions=GL_NV_parameter_buffer_object2&extensions=GL_NV_path_rendering&extensions=GL_NV_path_rendering_shared_edge&extensions=GL_NV_pixel_data_range&extensions=GL_NV_point_sprite&extensions=GL_NV_polygon_mode&extensions=GL_NV_present_video&extensions=GL_NV_primitive_restart&extensions=GL_NV_read_buffer&extensions=GL_NV_read_buffer_front&extensions=GL_NV_read_depth&extensions=GL_NV_read_depth_stencil&extensions=GL_NV_read_stencil&extensions=GL_NV_register_combiners&extensions=GL_NV_register_combiners2&extensions=GL_NV_robustness_video_memory_purge&extensions=GL_NV_sRGB_formats&extensions=GL_NV_sample_locations&extensions=GL_NV_sample_mask_override_coverage&extensions=GL_NV_shader_atomic_counters&extensions=GL_NV_shader_atomic_float&extensions=GL_NV_shader_atomic_float64&extensions=GL_NV_shader_atomic_fp16_vector&extensions=GL_NV_shader_atomic_int64&extensions=GL_NV_shader_buffer_load&extensions=GL_NV_shader_buffer_store&extensions=GL_NV_shader_noperspective_interpolation&extensions=GL_NV_shader_storage_buffer_object&extensions=GL_NV_shader_thread_group&extensions=GL_NV_shader_thread_shuffle&extensions=GL_NV_shadow_samplers_array&extensions=GL_NV_shadow_samplers_cube&extensions=GL_NV_stereo_view_rendering&extensions=GL_NV_tessellation_program5&extensions=GL_NV_texgen_emboss&extensions=GL_NV_texgen_reflection&extensions=GL_NV_texture_barrier&extensions=GL_NV_texture_border_clamp&extensions=GL_NV_texture_compression_s3tc_update&extensions=GL_NV_texture_compression_vtc&extensions=GL_NV_texture_env_combine4&extensions=GL_NV_texture_expand_normal&extensions=GL_NV_texture_multisample&extensions=GL_NV_texture_npot_2D_mipmap&extensions=GL_NV_texture_rectangle&extensions=GL_NV_texture_shader&extensions=GL_NV_texture_shader2&extensions=GL_NV_texture_shader3&extensions=GL_NV_transform_feedback&extensions=GL_NV_transform_feedback2&extensions=GL_NV_uniform_buffer_unified_memory&extensions=GL_NV_vdpau_interop&extensions=GL_NV_vertex_array_range&extensions=GL_NV_vertex_array_range2&extensions=GL_NV_vertex_attrib_integer_64bit&extensions=GL_NV_vertex_buffer_unified_memory&extensions=GL_NV_vertex_program&extensions=GL_NV_vertex_program1_1&extensions=GL_NV_vertex_program2&extensions=GL_NV_vertex_program2_option&extensions=GL_NV_vertex_program3&extensions=GL_NV_vertex_program4&extensions=GL_NV_video_capture&extensions=GL_NV_viewport_array&extensions=GL_NV_viewport_array2&extensions=GL_NV_viewport_swizzle&extensions=GL_OES_EGL_image&extensions=GL_OES_EGL_image_external&extensions=GL_OES_EGL_image_external_essl3&extensions=GL_OES_byte_coordinates&extensions=GL_OES_compressed_ETC1_RGB8_sub_texture&extensions=GL_OES_compressed_ETC1_RGB8_texture&extensions=GL_OES_compressed_paletted_texture&extensions=GL_OES_copy_image&extensions=GL_OES_depth24&extensions=GL_OES_depth32&extensions=GL_OES_depth_texture&extensions=GL_OES_draw_buffers_indexed&extensions=GL_OES_draw_elements_base_vertex&extensions=GL_OES_element_index_uint&extensions=GL_OES_fbo_render_mipmap&extensions=GL_OES_fixed_point&extensions=GL_OES_fragment_precision_high&extensions=GL_OES_geometry_point_size&extensions=GL_OES_geometry_shader&extensions=GL_OES_get_program_binary&extensions=GL_OES_gpu_shader5&extensions=GL_OES_mapbuffer&extensions=GL_OES_packed_depth_stencil&extensions=GL_OES_primitive_bounding_box&extensions=GL_OES_query_matrix&extensions=GL_OES_read_format&extensions=GL_OES_required_internalformat&extensions=GL_OES_rgb8_rgba8&extensions=GL_OES_sample_shading&extensions=GL_OES_sample_variables&extensions=GL_OES_shader_image_atomic&extensions=GL_OES_shader_io_blocks&extensions=GL_OES_shader_multisample_interpolation&extensions=GL_OES_single_precision&extensions=GL_OES_standard_derivatives&extensions=GL_OES_stencil1&extensions=GL_OES_stencil4&extensions=GL_OES_surfaceless_context&extensions=GL_OES_tessellation_point_size&extensions=GL_OES_tessellation_shader&extensions=GL_OES_texture_3D&extensions=GL_OES_texture_border_clamp&extensions=GL_OES_texture_buffer&extensions=GL_OES_texture_compression_astc&extensions=GL_OES_texture_cube_map_array&extensions=GL_OES_texture_float&extensions=GL_OES_texture_float_linear&extensions=GL_OES_texture_half_float&extensions=GL_OES_texture_half_float_linear&extensions=GL_OES_texture_npot&extensions=GL_OES_texture_stencil8&extensions=GL_OES_texture_storage_multisample_2d_array&extensions=GL_OES_texture_view&extensions=GL_OES_vertex_array_object&extensions=GL_OES_vertex_half_float&extensions=GL_OES_vertex_type_10_10_10_2&extensions=GL_OES_viewport_array&extensions=GL_OML_interlace&extensions=GL_OML_resample&extensions=GL_OML_subsample&extensions=GL_OVR_multiview&extensions=GL_OVR_multiview2&extensions=GL_OVR_multiview_multisampled_render_to_texture&extensions=GL_PGI_misc_hints&extensions=GL_PGI_vertex_hints&extensions=GL_QCOM_alpha_test&extensions=GL_QCOM_binning_control&extensions=GL_QCOM_driver_control&extensions=GL_QCOM_extended_get&extensions=GL_QCOM_extended_get2&extensions=GL_QCOM_perfmon_global_mode&extensions=GL_QCOM_tiled_rendering&extensions=GL_QCOM_writeonly_rendering&extensions=GL_REND_screen_coordinates&extensions=GL_S3_s3tc&extensions=GL_SGIS_detail_texture&extensions=GL_SGIS_fog_function&extensions=GL_SGIS_generate_mipmap&extensions=GL_SGIS_multisample&extensions=GL_SGIS_pixel_texture&extensions=GL_SGIS_point_line_texgen&extensions=GL_SGIS_point_parameters&extensions=GL_SGIS_sharpen_texture&extensions=GL_SGIS_texture4D&extensions=GL_SGIS_texture_border_clamp&extensions=GL_SGIS_texture_color_mask&extensions=GL_SGIS_texture_edge_clamp&extensions=GL_SGIS_texture_filter4&extensions=GL_SGIS_texture_lod&extensions=GL_SGIS_texture_select&extensions=GL_SGIX_async&extensions=GL_SGIX_async_histogram&extensions=GL_SGIX_async_pixel&extensions=GL_SGIX_blend_alpha_minmax&extensions=GL_SGIX_calligraphic_fragment&extensions=GL_SGIX_clipmap&extensions=GL_SGIX_convolution_accuracy&extensions=GL_SGIX_depth_pass_instrument&extensions=GL_SGIX_depth_texture&extensions=GL_SGIX_flush_raster&extensions=GL_SGIX_fog_offset&extensions=GL_SGIX_fragment_lighting&extensions=GL_SGIX_framezoom&extensions=GL_SGIX_igloo_interface&extensions=GL_SGIX_instruments&extensions=GL_SGIX_interlace&extensions=GL_SGIX_ir_instrument1&extensions=GL_SGIX_list_priority&extensions=GL_SGIX_pixel_texture&extensions=GL_SGIX_pixel_tiles&extensions=GL_SGIX_polynomial_ffd&extensions=GL_SGIX_reference_plane&extensions=GL_SGIX_resample&extensions=GL_SGIX_scalebias_hint&extensions=GL_SGIX_shadow&extensions=GL_SGIX_shadow_ambient&extensions=GL_SGIX_sprite&extensions=GL_SGIX_subsample&extensions=GL_SGIX_tag_sample_buffer&extensions=GL_SGIX_texture_add_env&extensions=GL_SGIX_texture_coordinate_clamp&extensions=GL_SGIX_texture_lod_bias&extensions=GL_SGIX_texture_multi_buffer&extensions=GL_SGIX_texture_scale_bias&extensions=GL_SGIX_vertex_preclip&extensions=GL_SGIX_ycrcb&extensions=GL_SGIX_ycrcb_subsample&extensions=GL_SGIX_ycrcba&extensions=GL_SGI_color_matrix&extensions=GL_SGI_color_table&extensions=GL_SGI_texture_color_table&extensions=GL_SUNX_constant_data&extensions=GL_SUN_convolution_border_modes&extensions=GL_SUN_global_alpha&extensions=GL_SUN_mesh_array&extensions=GL_SUN_slice_accum&extensions=GL_SUN_triangle_list&extensions=GL_SUN_vertex&extensions=GL_VIV_shader_binary&extensions=GL_WIN_phong_shading&extensions=GL_WIN_specular_fog&language=c&specification=gl&loader=on) or you can create your own loader by visiting the [Glad site](http://glad.dav1d.de/). - -Once SFML and Glad have been installed on your system you have to edit the Makefile provided so that you can build the demo. There are two variables that need to be edited: SFML_DIR and GLAD_DIR. Make these point to your SFML root folder and Glad root folder respectively. - -On Linux there is an extra step. You need to install the the udev development files. diff --git a/subprojects/nk_pugl/nuklear/demo/sfml_opengl3/main.cpp b/subprojects/nk_pugl/nuklear/demo/sfml_opengl3/main.cpp deleted file mode 100644 index 5dc2a6e..0000000 --- a/subprojects/nk_pugl/nuklear/demo/sfml_opengl3/main.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/* nuklear - v1.32.0 - public domain */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_STANDARD_VARARGS -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT -#define NK_INCLUDE_FONT_BAKING -#define NK_INCLUDE_DEFAULT_FONT -#define NK_IMPLEMENTATION -#define NK_SFML_GL3_IMPLEMENTATION -#include "../../nuklear.h" -#include "nuklear_sfml_gl3.h" - -#define WINDOW_WIDTH 1200 -#define WINDOW_HEIGHT 800 - -#define MAX_VERTEX_BUFFER 512 * 1024 -#define MAX_ELEMENT_BUFFER 128 * 1024 - -/* =============================================================== - * - * EXAMPLE - * - * ===============================================================*/ -/* This are some code examples to provide a small overview of what can be - * done with this library. To try out an example uncomment the defines */ -/*#define INCLUDE_ALL */ -/*#define INCLUDE_STYLE */ -/*#define INCLUDE_CALCULATOR */ -/*#define INCLUDE_OVERVIEW */ -/*#define INCLUDE_NODE_EDITOR */ - -#ifdef INCLUDE_ALL - #define INCLUDE_STYLE - #define INCLUDE_CALCULATOR - #define INCLUDE_OVERVIEW - #define INCLUDE_NODE_EDITOR -#endif - -#ifdef INCLUDE_STYLE - #include "../style.c" -#endif -#ifdef INCLUDE_CALCULATOR - #include "../calculator.c" -#endif -#ifdef INCLUDE_OVERVIEW - #include "../overview.c" -#endif -#ifdef INCLUDE_NODE_EDITOR - #include "../node_editor.c" -#endif - -/* =============================================================== - * - * DEMO - * - * ===============================================================*/ -int main(void) -{ - /* Platform */ - sf::ContextSettings settings(24, 8, 4, 3, 3); - sf::Window win(sf::VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT), "Demo", sf::Style::Default, settings); - win.setVerticalSyncEnabled(true); - win.setActive(true); - if(!gladLoadGL()) { /* Load OpenGL extensions */ - printf("Failed to load OpenGL extensions!\n"); - return -1; - } - glViewport(0, 0, win.getSize().x, win.getSize().y); - - /* GUI */ - struct nk_context *ctx; - ctx = nk_sfml_init(&win); - /* Load Fonts: if none of these are loaded a default font will be used */ - /* Load Cursor: if you uncomment cursor loading please hide the cursor */ - struct nk_font_atlas *atlas; - nk_sfml_font_stash_begin(&atlas); - /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/ - /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 14, 0);*/ - /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/ - /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/ - /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/ - /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/ - nk_sfml_font_stash_end(); - /*nk_style_load_all_cursors(ctx, atlas->cursors);*/ - /*nk_style_set_font(ctx, &droid->handle);*/ - - /* style.c */ - #ifdef INCLUDE_STYLE - /*set_style(ctx, THEME_WHITE);*/ - /*set_style(ctx, THEME_RED);*/ - /*set_style(ctx, THEME_BLUE);*/ - /*set_style(ctx, THEME_DARK);*/ - #endif - - struct nk_colorf bg; - bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f; - while (win.isOpen()) - { - /* Input */ - sf::Event evt; - nk_input_begin(ctx); - while(win.pollEvent(evt)) { - if(evt.type == sf::Event::Closed) - win.close(); - else if(evt.type == sf::Event::Resized) - glViewport(0, 0, evt.size.width, evt.size.height); - - nk_sfml_handle_event(&evt); - } - nk_input_end(ctx); - - /* GUI */ - if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250), - NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE| - NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) - { - enum {EASY, HARD}; - static int op = EASY; - static int property = 20; - nk_layout_row_static(ctx, 30, 80, 1); - if (nk_button_label(ctx, "button")) - fprintf(stdout, "button pressed\n"); - - nk_layout_row_dynamic(ctx, 30, 2); - if (nk_option_label(ctx, "easy", op == EASY)) op = EASY; - if (nk_option_label(ctx, "hard", op == HARD)) op = HARD; - - nk_layout_row_dynamic(ctx, 25, 1); - nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1); - - nk_layout_row_dynamic(ctx, 20, 1); - nk_label(ctx, "background:", NK_TEXT_LEFT); - nk_layout_row_dynamic(ctx, 25, 1); - if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) { - nk_layout_row_dynamic(ctx, 120, 1); - bg = nk_color_picker(ctx, bg, NK_RGBA); - nk_layout_row_dynamic(ctx, 25, 1); - bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f); - bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f); - bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f); - bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f); - nk_combo_end(ctx); - } - } - nk_end(ctx); - - /* -------------- EXAMPLES ---------------- */ - #ifdef INCLUDE_CALCULATOR - calculator(ctx); - #endif - #ifdef INCLUDE_OVERVIEW - overview(ctx); - #endif - #ifdef INCLUDE_NODE_EDITOR - node_editor(ctx); - #endif - /* ----------------------------------------- */ - - /* Draw */ - float bg[4]; - win.setActive(true); - nk_color_fv(bg, background); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(bg.r, bg.g, bg.b, bg.a); - /* IMPORTANT: `nk_sfml_render` modifies some global OpenGL state - * with blending, scissor, face culling and depth test and defaults everything - * back into a default state. Make sure to either save and restore or - * reset your own state after drawing rendering the UI. */ - nk_sfml_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER); - win.display(); - } - nk_sfml_shutdown(); - return 0; -} - diff --git a/subprojects/nk_pugl/nuklear/demo/sfml_opengl3/nuklear_sfml_gl3.h b/subprojects/nk_pugl/nuklear/demo/sfml_opengl3/nuklear_sfml_gl3.h deleted file mode 100644 index 40b390e..0000000 --- a/subprojects/nk_pugl/nuklear/demo/sfml_opengl3/nuklear_sfml_gl3.h +++ /dev/null @@ -1,463 +0,0 @@ -/* - * Nuklear - 1.32.0 - public domain - * no warrenty implied; use at your own risk. - * authored from 2015-2016 by Micha Mettke - */ -/* - * ============================================================== - * - * API - * - * =============================================================== - */ -#ifndef NK_SFML_GL3_H_ -#define NK_SFML_GL3_H_ - -/* Feel free to edit here and include your own extension wrangler */ -#include -/* I use GLAD but you can use GLEW or what you like */ - -#include - -NK_API struct nk_context* nk_sfml_init(sf::Window* window); -NK_API void nk_sfml_font_stash_begin(struct nk_font_atlas** atlas); -NK_API void nk_sfml_font_stash_end(void); -NK_API int nk_sfml_handle_event(sf::Event* event); -NK_API void nk_sfml_render(enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer); -NK_API void nk_sfml_shutdown(void); - -NK_API void nk_sfml_device_create(void); -NK_API void nk_sfml_device_destroy(void); - -#endif -/* - * ============================================================== - * - * IMPLEMENTATION - * - * =============================================================== - */ - #ifdef NK_SFML_GL3_IMPLEMENTATION - -#include - -struct nk_sfml_device { - struct nk_buffer cmds; - struct nk_draw_null_texture null; - GLuint vbo, vao, ebo; - GLuint prog; - GLuint vert_shdr; - GLuint frag_shdr; - GLint attrib_pos; - GLint attrib_uv; - GLint attrib_col; - GLint uniform_tex; - GLint uniform_proj; - GLuint font_tex; -}; -struct nk_sfml_vertex { - float position[2]; - float uv[2]; - nk_byte col[4]; -}; -static struct nk_sfml { - sf::Window* window; - struct nk_sfml_device ogl; - struct nk_context ctx; - struct nk_font_atlas atlas; -} sfml; - -#ifdef __APPLE__ - #define NK_SHADER_VERSION "#version 150\n" -#else - #define NK_SHADER_VERSION "#version 300 es\n" -#endif - -NK_API void -nk_sfml_device_create(void) -{ - GLint status; - static const GLchar* vertex_shader = - NK_SHADER_VERSION - "uniform mat4 ProjMtx;\n" - "in vec2 Position;\n" - "in vec2 TexCoord;\n" - "in vec4 Color;\n" - "out vec2 Frag_UV;\n" - "out vec4 Frag_Color;\n" - "void main() {\n" - " Frag_UV = TexCoord;\n" - " Frag_Color = Color;\n" - " gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n" - "}\n"; - static const GLchar *fragment_shader = - NK_SHADER_VERSION - "precision mediump float;\n" - "uniform sampler2D Texture;\n" - "in vec2 Frag_UV;\n" - "in vec4 Frag_Color;\n" - "out vec4 Out_Color;\n" - "void main(){\n" - " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" - "}\n"; - - struct nk_sfml_device* dev = &sfml.ogl; - nk_buffer_init_default(&dev->cmds); - - dev->prog = glCreateProgram(); - dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER); - dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER); - - glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0); - glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0); - glCompileShader(dev->vert_shdr); - glCompileShader(dev->frag_shdr); - - glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status); - assert(status == GL_TRUE); - - glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status); - assert(status == GL_TRUE); - - glAttachShader(dev->prog, dev->vert_shdr); - glAttachShader(dev->prog, dev->frag_shdr); - glLinkProgram(dev->prog); - - glGetProgramiv(dev->prog, GL_LINK_STATUS, &status); - assert(status == GL_TRUE); - - dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture"); - dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx"); - dev->attrib_pos = glGetAttribLocation(dev->prog, "Position"); - dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord"); - dev->attrib_col = glGetAttribLocation(dev->prog, "Color"); - { - /* buffer setup */ - GLsizei vs = sizeof(struct nk_sfml_vertex); - size_t vp = offsetof(struct nk_sfml_vertex, position); - size_t vt = offsetof(struct nk_sfml_vertex, uv); - size_t vc = offsetof(struct nk_sfml_vertex, col); - - glGenBuffers(1, &dev->vbo); - glGenBuffers(1, &dev->ebo); - glGenVertexArrays(1, &dev->vao); - - glBindVertexArray(dev->vao); - glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); - - glEnableVertexAttribArray((GLuint)dev->attrib_pos); - glEnableVertexAttribArray((GLuint)dev->attrib_uv); - glEnableVertexAttribArray((GLuint)dev->attrib_col); - - glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp); - glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt); - glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc); - } - glBindTexture(GL_TEXTURE_2D, 0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindVertexArray(0); -} - -NK_API void -nk_sfml_device_destroy(void) -{ - struct nk_sfml_device* dev = &sfml.ogl; - - glDetachShader(dev->prog, dev->vert_shdr); - glDetachShader(dev->prog, dev->frag_shdr); - glDeleteShader(dev->vert_shdr); - glDeleteShader(dev->vert_shdr); - glDeleteProgram(dev->prog); - glDeleteTextures(1, &dev->font_tex); - glDeleteBuffers(1, &dev->vbo); - glDeleteBuffers(1, &dev->ebo); - nk_buffer_free(&dev->cmds); -} - -NK_INTERN void -nk_sfml_device_upload_atlas(const void* image, int width, int height) -{ - struct nk_sfml_device* dev = &sfml.ogl; - glGenTextures(1, &dev->font_tex); - glBindTexture(GL_TEXTURE_2D, dev->font_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, image); -} - -NK_API void -nk_sfml_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer) -{ - /* setup global state */ - struct nk_sfml_device* dev = &sfml.ogl; - int window_width = sfml.window->getSize().x; - int window_height = sfml.window->getSize().y; - GLfloat ortho[4][4] = { - {2.0f, 0.0f, 0.0f, 0.0f}, - {0.0f,-2.0f, 0.0f, 0.0f}, - {0.0f, 0.0f,-1.0f, 0.0f}, - {-1.0f,1.0f, 0.0f, 1.0f}, - }; - ortho[0][0] /= (GLfloat)window_width; - ortho[1][1] /= (GLfloat)window_height; - - glViewport(0, 0, window_width, window_height); - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glEnable(GL_SCISSOR_TEST); - glActiveTexture(GL_TEXTURE0); - - /* setup program */ - glUseProgram(dev->prog); - glUniform1i(dev->uniform_tex, 0); - glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]); - { - /* convert from command queue into draw list and draw to screen */ - const struct nk_draw_command *cmd; - void *vertices, *elements; - const nk_draw_index *offset = NULL; - - /* allocate vertex and element buffer */ - glBindVertexArray(dev->vao); - glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); - - glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW); - - /* load vertices/elements directly into vertex/element buffer */ - vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); - elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY); - { - /* fill convert configuration */ - struct nk_convert_config config; - static const struct nk_draw_vertex_layout_element vertex_layout[] = { - {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sfml_vertex, position)}, - {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sfml_vertex, uv)}, - {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sfml_vertex, col)}, - {NK_VERTEX_LAYOUT_END} - }; - - NK_MEMSET(&config, 0, sizeof(config)); - config.vertex_layout = vertex_layout; - config.vertex_size = sizeof(struct nk_sfml_vertex); - config.vertex_alignment = NK_ALIGNOF(struct nk_sfml_vertex); - config.null = dev->null; - config.circle_segment_count = 22; - config.curve_segment_count = 22; - config.arc_segment_count = 22; - config.global_alpha = 1.0f; - config.shape_AA = AA; - config.line_AA = AA; - - /* setup buffers to load vertices and elements */ - struct nk_buffer vbuf, ebuf; - nk_buffer_init_fixed(&vbuf, vertices, (nk_size)max_vertex_buffer); - nk_buffer_init_fixed(&ebuf, elements, (nk_size)max_element_buffer); - nk_convert(&sfml.ctx, &dev->cmds, &vbuf, &ebuf, &config); - } - glUnmapBuffer(GL_ARRAY_BUFFER); - glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); - - /* iterate over and execute each draw command */ - nk_draw_foreach(cmd, &sfml.ctx, &dev->cmds) - { - if (!cmd->elem_count) continue; - glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); - glScissor( - (GLint)(cmd->clip_rect.x), - (GLint)((window_height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h))), - (GLint)(cmd->clip_rect.w), - (GLint)(cmd->clip_rect.h)); - glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); - offset += cmd->elem_count; - } - nk_clear(&sfml.ctx); - } - glUseProgram(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindVertexArray(0); - glDisable(GL_BLEND); - glDisable(GL_SCISSOR_TEST); -} - -static void -nk_sfml_clipboard_paste(nk_handle usr, struct nk_text_edit* edit) -{ -#if 0 - /* Not Implemented in SFML */ - (void)usr; - sf::Clipboard clipboard(sfml.window); - const char* text = clipboard.getText(); - if(text) nk_textedit_paste(edit, text, nk_strlen(text)); -#endif -} -static void -nk_sfml_clipboard_copy(nk_handle usr, const char* text, int len) -{ -#if 0 - char* str = 0; - (void)usr; - if(!len) return; - str = (char*)malloc((size_t)len+1); - if(!str) return; - memcpy(str, text, (size_t)len); - str[len] = '\0'; - - /* Not Implemented in SFML */ - sf::Clipboard clipboard(sfml.window); - clipboard.setText(str); - free(str); -#endif -} - -NK_API struct nk_context* -nk_sfml_init(sf::Window* window) -{ - sfml.window = window; - nk_init_default(&sfml.ctx, 0); - sfml.ctx.clip.copy = nk_sfml_clipboard_copy; - sfml.ctx.clip.paste = nk_sfml_clipboard_paste; - sfml.ctx.clip.userdata = nk_handle_ptr(0); - nk_sfml_device_create(); - return &sfml.ctx; -} - -NK_API void -nk_sfml_font_stash_begin(struct nk_font_atlas** atlas) -{ - nk_font_atlas_init_default(&sfml.atlas); - nk_font_atlas_begin(&sfml.atlas); - *atlas = &sfml.atlas; -} - -NK_API void -nk_sfml_font_stash_end() -{ - const void* image; - int w, h; - image = nk_font_atlas_bake(&sfml.atlas, &w, &h, NK_FONT_ATLAS_RGBA32); - nk_sfml_device_upload_atlas(image, w, h); - nk_font_atlas_end(&sfml.atlas, nk_handle_id((int)sfml.ogl.font_tex), &sfml.ogl.null); - if(sfml.atlas.default_font) - nk_style_set_font(&sfml.ctx, &sfml.atlas.default_font->handle); -} - -NK_API int -nk_sfml_handle_event(sf::Event* evt) -{ - struct nk_context* ctx = &sfml.ctx; - /* optional grabbing behavior */ - if(ctx->input.mouse.grab) - ctx->input.mouse.grab = 0; - else if(ctx->input.mouse.ungrab) { - int x = (int)ctx->input.mouse.prev.x; - int y = (int)ctx->input.mouse.prev.y; - sf::Mouse::setPosition(sf::Vector2i(x, y), *sfml.window); - ctx->input.mouse.ungrab = 0; - } - if(evt->type == sf::Event::KeyReleased || evt->type == sf::Event::KeyPressed) - { - int down = evt->type == sf::Event::KeyPressed; - sf::Keyboard::Key key = evt->key.code; - if(key == sf::Keyboard::RShift || key == sf::Keyboard::LShift) - nk_input_key(ctx, NK_KEY_SHIFT, down); - else if(key == sf::Keyboard::Delete) - nk_input_key(ctx, NK_KEY_DEL, down); - else if(key == sf::Keyboard::Return) - nk_input_key(ctx, NK_KEY_ENTER, down); - else if(key == sf::Keyboard::Tab) - nk_input_key(ctx, NK_KEY_TAB, down); - else if(key == sf::Keyboard::BackSpace) - nk_input_key(ctx, NK_KEY_BACKSPACE, down); - else if(key == sf::Keyboard::Home) { - nk_input_key(ctx, NK_KEY_TEXT_START, down); - nk_input_key(ctx, NK_KEY_SCROLL_START, down); - } else if(key == sf::Keyboard::End) { - nk_input_key(ctx, NK_KEY_TEXT_END, down); - nk_input_key(ctx, NK_KEY_SCROLL_END, down); - } else if(key == sf::Keyboard::PageDown) - nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down); - else if(key == sf::Keyboard::PageUp) - nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down); - else if(key == sf::Keyboard::Z) - nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)); - else if(key == sf::Keyboard::R) - nk_input_key(ctx, NK_KEY_TEXT_REDO, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)); - else if(key == sf::Keyboard::C) - nk_input_key(ctx, NK_KEY_COPY, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)); - else if(key == sf::Keyboard::V) - nk_input_key(ctx, NK_KEY_PASTE, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)); - else if(key == sf::Keyboard::X) - nk_input_key(ctx, NK_KEY_CUT, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)); - else if(key == sf::Keyboard::B) - nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)); - else if(key == sf::Keyboard::E) - nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)); - else if(key == sf::Keyboard::Up) - nk_input_key(ctx, NK_KEY_UP, down); - else if(key == sf::Keyboard::Down) - nk_input_key(ctx, NK_KEY_DOWN, down); - else if(key == sf::Keyboard::Left) { - if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)) - nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down); - else nk_input_key(ctx, NK_KEY_LEFT, down); - } else if(key == sf::Keyboard::Right) { - if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)) - nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down); - else nk_input_key(ctx, NK_KEY_RIGHT, down); - } else return 0; - return 1; - } else if(evt->type == sf::Event::MouseButtonPressed || evt->type == sf::Event::MouseButtonReleased) { - int down = evt->type == sf::Event::MouseButtonPressed; - const int x = evt->mouseButton.x, y = evt->mouseButton.y; - if(evt->mouseButton.button == sf::Mouse::Left) - nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down); - if(evt->mouseButton.button == sf::Mouse::Middle) - nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down); - if(evt->mouseButton.button == sf::Mouse::Right) - nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down); - else return 0; - return 1; - } else if(evt->type == sf::Event::MouseMoved) { - nk_input_motion(ctx, evt->mouseMove.x, evt->mouseMove.y); - return 1; - } else if(evt->type == sf::Event::TouchBegan || evt->type == sf::Event::TouchEnded) { - int down = evt->type == sf::Event::TouchBegan; - const int x = evt->touch.x, y = evt->touch.y; - nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down); - return 1; - } else if(evt->type == sf::Event::TouchMoved) { - if(ctx->input.mouse.grabbed) { - int x = (int)ctx->input.mouse.prev.x; - int y = (int)ctx->input.mouse.prev.y; - nk_input_motion(ctx, x + evt->touch.x, y + evt->touch.y); - } else nk_input_motion(ctx, evt->touch.x, evt->touch.y); - return 1; - } else if(evt->type == sf::Event::TextEntered) { - nk_input_unicode(ctx, evt->text.unicode); - return 1; - } else if(evt->type == sf::Event::MouseWheelScrolled) { - nk_input_scroll(ctx, nk_vec2(0,evt->mouseWheelScroll.delta)); - return 1; - } - return 0; -} - -NK_API -void nk_sfml_shutdown() -{ - nk_font_atlas_clear(&sfml.atlas); - nk_free(&sfml.ctx); - nk_sfml_device_destroy(); - memset(&sfml, 0, sizeof(sfml)); -} - -#endif diff --git a/subprojects/nk_pugl/nuklear/demo/style.c b/subprojects/nk_pugl/nuklear/demo/style.c deleted file mode 100644 index 17c48fe..0000000 --- a/subprojects/nk_pugl/nuklear/demo/style.c +++ /dev/null @@ -1,132 +0,0 @@ -enum theme {THEME_BLACK, THEME_WHITE, THEME_RED, THEME_BLUE, THEME_DARK}; - -static void -set_style(struct nk_context *ctx, enum theme theme) -{ - struct nk_color table[NK_COLOR_COUNT]; - if (theme == THEME_WHITE) { - table[NK_COLOR_TEXT] = nk_rgba(70, 70, 70, 255); - table[NK_COLOR_WINDOW] = nk_rgba(175, 175, 175, 255); - table[NK_COLOR_HEADER] = nk_rgba(175, 175, 175, 255); - table[NK_COLOR_BORDER] = nk_rgba(0, 0, 0, 255); - table[NK_COLOR_BUTTON] = nk_rgba(185, 185, 185, 255); - table[NK_COLOR_BUTTON_HOVER] = nk_rgba(170, 170, 170, 255); - table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(160, 160, 160, 255); - table[NK_COLOR_TOGGLE] = nk_rgba(150, 150, 150, 255); - table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(120, 120, 120, 255); - table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(175, 175, 175, 255); - table[NK_COLOR_SELECT] = nk_rgba(190, 190, 190, 255); - table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(175, 175, 175, 255); - table[NK_COLOR_SLIDER] = nk_rgba(190, 190, 190, 255); - table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(80, 80, 80, 255); - table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(70, 70, 70, 255); - table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(60, 60, 60, 255); - table[NK_COLOR_PROPERTY] = nk_rgba(175, 175, 175, 255); - table[NK_COLOR_EDIT] = nk_rgba(150, 150, 150, 255); - table[NK_COLOR_EDIT_CURSOR] = nk_rgba(0, 0, 0, 255); - table[NK_COLOR_COMBO] = nk_rgba(175, 175, 175, 255); - table[NK_COLOR_CHART] = nk_rgba(160, 160, 160, 255); - table[NK_COLOR_CHART_COLOR] = nk_rgba(45, 45, 45, 255); - table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba( 255, 0, 0, 255); - table[NK_COLOR_SCROLLBAR] = nk_rgba(180, 180, 180, 255); - table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(140, 140, 140, 255); - table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(150, 150, 150, 255); - table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(160, 160, 160, 255); - table[NK_COLOR_TAB_HEADER] = nk_rgba(180, 180, 180, 255); - nk_style_from_table(ctx, table); - } else if (theme == THEME_RED) { - table[NK_COLOR_TEXT] = nk_rgba(190, 190, 190, 255); - table[NK_COLOR_WINDOW] = nk_rgba(30, 33, 40, 215); - table[NK_COLOR_HEADER] = nk_rgba(181, 45, 69, 220); - table[NK_COLOR_BORDER] = nk_rgba(51, 55, 67, 255); - table[NK_COLOR_BUTTON] = nk_rgba(181, 45, 69, 255); - table[NK_COLOR_BUTTON_HOVER] = nk_rgba(190, 50, 70, 255); - table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(195, 55, 75, 255); - table[NK_COLOR_TOGGLE] = nk_rgba(51, 55, 67, 255); - table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(45, 60, 60, 255); - table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(181, 45, 69, 255); - table[NK_COLOR_SELECT] = nk_rgba(51, 55, 67, 255); - table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(181, 45, 69, 255); - table[NK_COLOR_SLIDER] = nk_rgba(51, 55, 67, 255); - table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(181, 45, 69, 255); - table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(186, 50, 74, 255); - table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(191, 55, 79, 255); - table[NK_COLOR_PROPERTY] = nk_rgba(51, 55, 67, 255); - table[NK_COLOR_EDIT] = nk_rgba(51, 55, 67, 225); - table[NK_COLOR_EDIT_CURSOR] = nk_rgba(190, 190, 190, 255); - table[NK_COLOR_COMBO] = nk_rgba(51, 55, 67, 255); - table[NK_COLOR_CHART] = nk_rgba(51, 55, 67, 255); - table[NK_COLOR_CHART_COLOR] = nk_rgba(170, 40, 60, 255); - table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba( 255, 0, 0, 255); - table[NK_COLOR_SCROLLBAR] = nk_rgba(30, 33, 40, 255); - table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(64, 84, 95, 255); - table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(70, 90, 100, 255); - table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(75, 95, 105, 255); - table[NK_COLOR_TAB_HEADER] = nk_rgba(181, 45, 69, 220); - nk_style_from_table(ctx, table); - } else if (theme == THEME_BLUE) { - table[NK_COLOR_TEXT] = nk_rgba(20, 20, 20, 255); - table[NK_COLOR_WINDOW] = nk_rgba(202, 212, 214, 215); - table[NK_COLOR_HEADER] = nk_rgba(137, 182, 224, 220); - table[NK_COLOR_BORDER] = nk_rgba(140, 159, 173, 255); - table[NK_COLOR_BUTTON] = nk_rgba(137, 182, 224, 255); - table[NK_COLOR_BUTTON_HOVER] = nk_rgba(142, 187, 229, 255); - table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(147, 192, 234, 255); - table[NK_COLOR_TOGGLE] = nk_rgba(177, 210, 210, 255); - table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(182, 215, 215, 255); - table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(137, 182, 224, 255); - table[NK_COLOR_SELECT] = nk_rgba(177, 210, 210, 255); - table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(137, 182, 224, 255); - table[NK_COLOR_SLIDER] = nk_rgba(177, 210, 210, 255); - table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(137, 182, 224, 245); - table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(142, 188, 229, 255); - table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(147, 193, 234, 255); - table[NK_COLOR_PROPERTY] = nk_rgba(210, 210, 210, 255); - table[NK_COLOR_EDIT] = nk_rgba(210, 210, 210, 225); - table[NK_COLOR_EDIT_CURSOR] = nk_rgba(20, 20, 20, 255); - table[NK_COLOR_COMBO] = nk_rgba(210, 210, 210, 255); - table[NK_COLOR_CHART] = nk_rgba(210, 210, 210, 255); - table[NK_COLOR_CHART_COLOR] = nk_rgba(137, 182, 224, 255); - table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba( 255, 0, 0, 255); - table[NK_COLOR_SCROLLBAR] = nk_rgba(190, 200, 200, 255); - table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(64, 84, 95, 255); - table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(70, 90, 100, 255); - table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(75, 95, 105, 255); - table[NK_COLOR_TAB_HEADER] = nk_rgba(156, 193, 220, 255); - nk_style_from_table(ctx, table); - } else if (theme == THEME_DARK) { - table[NK_COLOR_TEXT] = nk_rgba(210, 210, 210, 255); - table[NK_COLOR_WINDOW] = nk_rgba(57, 67, 71, 215); - table[NK_COLOR_HEADER] = nk_rgba(51, 51, 56, 220); - table[NK_COLOR_BORDER] = nk_rgba(46, 46, 46, 255); - table[NK_COLOR_BUTTON] = nk_rgba(48, 83, 111, 255); - table[NK_COLOR_BUTTON_HOVER] = nk_rgba(58, 93, 121, 255); - table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(63, 98, 126, 255); - table[NK_COLOR_TOGGLE] = nk_rgba(50, 58, 61, 255); - table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(45, 53, 56, 255); - table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(48, 83, 111, 255); - table[NK_COLOR_SELECT] = nk_rgba(57, 67, 61, 255); - table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(48, 83, 111, 255); - table[NK_COLOR_SLIDER] = nk_rgba(50, 58, 61, 255); - table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(48, 83, 111, 245); - table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(53, 88, 116, 255); - table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(58, 93, 121, 255); - table[NK_COLOR_PROPERTY] = nk_rgba(50, 58, 61, 255); - table[NK_COLOR_EDIT] = nk_rgba(50, 58, 61, 225); - table[NK_COLOR_EDIT_CURSOR] = nk_rgba(210, 210, 210, 255); - table[NK_COLOR_COMBO] = nk_rgba(50, 58, 61, 255); - table[NK_COLOR_CHART] = nk_rgba(50, 58, 61, 255); - table[NK_COLOR_CHART_COLOR] = nk_rgba(48, 83, 111, 255); - table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba(255, 0, 0, 255); - table[NK_COLOR_SCROLLBAR] = nk_rgba(50, 58, 61, 255); - table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(48, 83, 111, 255); - table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(53, 88, 116, 255); - table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(58, 93, 121, 255); - table[NK_COLOR_TAB_HEADER] = nk_rgba(48, 83, 111, 255); - nk_style_from_table(ctx, table); - } else { - nk_style_default(ctx); - } -} - - diff --git a/subprojects/nk_pugl/nuklear/demo/x11/Makefile b/subprojects/nk_pugl/nuklear/demo/x11/Makefile deleted file mode 100644 index 9057c7b..0000000 --- a/subprojects/nk_pugl/nuklear/demo/x11/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# Install -BIN = zahnrad - -# Flags -CFLAGS += -std=c89 -pedantic -O2 - -SRC = main.c -OBJ = $(SRC:.c=.o) - -$(BIN): - @mkdir -p bin - rm -f bin/$(BIN) $(OBJS) - $(CC) $(SRC) $(CFLAGS) -D_POSIX_C_SOURCE=200809L -o bin/$(BIN) -lX11 -lm diff --git a/subprojects/nk_pugl/nuklear/demo/x11/main.c b/subprojects/nk_pugl/nuklear/demo/x11/main.c deleted file mode 100644 index 791653d..0000000 --- a/subprojects/nk_pugl/nuklear/demo/x11/main.c +++ /dev/null @@ -1,224 +0,0 @@ -/* nuklear - v1.32.0 - public domain */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_STANDARD_VARARGS -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_IMPLEMENTATION -#define NK_XLIB_IMPLEMENTATION -#include "../../nuklear.h" -#include "nuklear_xlib.h" - -#define DTIME 20 -#define WINDOW_WIDTH 800 -#define WINDOW_HEIGHT 600 - -typedef struct XWindow XWindow; -struct XWindow { - Display *dpy; - Window root; - Visual *vis; - Colormap cmap; - XWindowAttributes attr; - XSetWindowAttributes swa; - Window win; - int screen; - XFont *font; - unsigned int width; - unsigned int height; - Atom wm_delete_window; -}; - -static void -die(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fputs("\n", stderr); - exit(EXIT_FAILURE); -} - -static long -timestamp(void) -{ - struct timeval tv; - if (gettimeofday(&tv, NULL) < 0) return 0; - return (long)((long)tv.tv_sec * 1000 + (long)tv.tv_usec/1000); -} - -static void -sleep_for(long t) -{ - struct timespec req; - const time_t sec = (int)(t/1000); - const long ms = t - (sec * 1000); - req.tv_sec = sec; - req.tv_nsec = ms * 1000000L; - while(-1 == nanosleep(&req, &req)); -} - -/* =============================================================== - * - * EXAMPLE - * - * ===============================================================*/ -/* This are some code examples to provide a small overview of what can be - * done with this library. To try out an example uncomment the defines */ -/*#define INCLUDE_ALL */ -/*#define INCLUDE_STYLE */ -/*#define INCLUDE_CALCULATOR */ -/*#define INCLUDE_OVERVIEW */ -/*#define INCLUDE_NODE_EDITOR */ - -#ifdef INCLUDE_ALL - #define INCLUDE_STYLE - #define INCLUDE_CALCULATOR - #define INCLUDE_OVERVIEW - #define INCLUDE_NODE_EDITOR -#endif - -#ifdef INCLUDE_STYLE - #include "../style.c" -#endif -#ifdef INCLUDE_CALCULATOR - #include "../calculator.c" -#endif -#ifdef INCLUDE_OVERVIEW - #include "../overview.c" -#endif -#ifdef INCLUDE_NODE_EDITOR - #include "../node_editor.c" -#endif - -/* =============================================================== - * - * DEMO - * - * ===============================================================*/ -int -main(void) -{ - long dt; - long started; - int running = 1; - XWindow xw; - struct nk_context *ctx; - - /* X11 */ - memset(&xw, 0, sizeof xw); - xw.dpy = XOpenDisplay(NULL); - if (!xw.dpy) die("Could not open a display; perhaps $DISPLAY is not set?"); - xw.root = DefaultRootWindow(xw.dpy); - xw.screen = XDefaultScreen(xw.dpy); - xw.vis = XDefaultVisual(xw.dpy, xw.screen); - xw.cmap = XCreateColormap(xw.dpy,xw.root,xw.vis,AllocNone); - - xw.swa.colormap = xw.cmap; - xw.swa.event_mask = - ExposureMask | KeyPressMask | KeyReleaseMask | - ButtonPress | ButtonReleaseMask| ButtonMotionMask | - Button1MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask| - PointerMotionMask | KeymapStateMask; - xw.win = XCreateWindow(xw.dpy, xw.root, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, - XDefaultDepth(xw.dpy, xw.screen), InputOutput, - xw.vis, CWEventMask | CWColormap, &xw.swa); - - XStoreName(xw.dpy, xw.win, "X11"); - XMapWindow(xw.dpy, xw.win); - xw.wm_delete_window = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False); - XSetWMProtocols(xw.dpy, xw.win, &xw.wm_delete_window, 1); - XGetWindowAttributes(xw.dpy, xw.win, &xw.attr); - xw.width = (unsigned int)xw.attr.width; - xw.height = (unsigned int)xw.attr.height; - - /* GUI */ - xw.font = nk_xfont_create(xw.dpy, "fixed"); - ctx = nk_xlib_init(xw.font, xw.dpy, xw.screen, xw.win, xw.width, xw.height); - - #ifdef INCLUDE_STYLE - /*set_style(ctx, THEME_WHITE);*/ - /*set_style(ctx, THEME_RED);*/ - /*set_style(ctx, THEME_BLUE);*/ - /*set_style(ctx, THEME_DARK);*/ - #endif - - while (running) - { - /* Input */ - XEvent evt; - started = timestamp(); - nk_input_begin(ctx); - while (XPending(xw.dpy)) { - XNextEvent(xw.dpy, &evt); - if (evt.type == ClientMessage) goto cleanup; - if (XFilterEvent(&evt, xw.win)) continue; - nk_xlib_handle_event(xw.dpy, xw.screen, xw.win, &evt); - } - nk_input_end(ctx); - - /* GUI */ - if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200), - NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE| - NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) - { - enum {EASY, HARD}; - static int op = EASY; - static int property = 20; - - nk_layout_row_static(ctx, 30, 80, 1); - if (nk_button_label(ctx, "button")) - fprintf(stdout, "button pressed\n"); - nk_layout_row_dynamic(ctx, 30, 2); - if (nk_option_label(ctx, "easy", op == EASY)) op = EASY; - if (nk_option_label(ctx, "hard", op == HARD)) op = HARD; - nk_layout_row_dynamic(ctx, 25, 1); - nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1); - } - nk_end(ctx); - if (nk_window_is_hidden(ctx, "Demo")) break; - - /* -------------- EXAMPLES ---------------- */ - #ifdef INCLUDE_CALCULATOR - calculator(ctx); - #endif - #ifdef INCLUDE_OVERVIEW - overview(ctx); - #endif - #ifdef INCLUDE_NODE_EDITOR - node_editor(ctx); - #endif - /* ----------------------------------------- */ - - /* Draw */ - XClearWindow(xw.dpy, xw.win); - nk_xlib_render(xw.win, nk_rgb(30,30,30)); - XFlush(xw.dpy); - - /* Timing */ - dt = timestamp() - started; - if (dt < DTIME) - sleep_for(DTIME - dt); - } - -cleanup: - nk_xfont_del(xw.dpy, xw.font); - nk_xlib_shutdown(); - XUnmapWindow(xw.dpy, xw.win); - XFreeColormap(xw.dpy, xw.cmap); - XDestroyWindow(xw.dpy, xw.win); - XCloseDisplay(xw.dpy); - return 0; -} - diff --git a/subprojects/nk_pugl/nuklear/demo/x11/nuklear_xlib.h b/subprojects/nk_pugl/nuklear/demo/x11/nuklear_xlib.h deleted file mode 100644 index 8b6b4ff..0000000 --- a/subprojects/nk_pugl/nuklear/demo/x11/nuklear_xlib.h +++ /dev/null @@ -1,957 +0,0 @@ -/* - * Nuklear - v1.40.8 - public domain - * no warrenty implied; use at your own risk. - * authored from 2015-2017 by Micha Mettke - */ -/* - * ============================================================== - * - * API - * - * =============================================================== - */ -#ifndef NK_XLIB_H_ -#define NK_XLIB_H_ - -#include - -typedef struct XFont XFont; -NK_API struct nk_context* nk_xlib_init(XFont*, Display*, int scrn, Window root, unsigned w, unsigned h); -NK_API int nk_xlib_handle_event(Display*, int scrn, Window, XEvent*); -NK_API void nk_xlib_render(Drawable screen, struct nk_color clear); -NK_API void nk_xlib_shutdown(void); -NK_API void nk_xlib_set_font(XFont*); -NK_API void nk_xlib_push_font(XFont*); -NK_API void nk_xlib_paste(nk_handle, struct nk_text_edit*); -NK_API void nk_xlib_copy(nk_handle, const char*, int len); - -/* Image */ -#ifdef NK_XLIB_INCLUDE_STB_IMAGE -NK_API struct nk_image nk_xsurf_load_image_from_file(char const *filename); -NK_API struct nk_image nk_xsurf_load_image_from_memory(const void *membuf, nk_uint membufSize); -#endif - -/* Font */ -NK_API XFont* nk_xfont_create(Display *dpy, const char *name); -NK_API void nk_xfont_del(Display *dpy, XFont *font); - -#endif -/* - * ============================================================== - * - * IMPLEMENTATION - * - * =============================================================== - */ -#ifdef NK_XLIB_IMPLEMENTATION -#include -#include -#include -#include -#include - -#include -#include -#include - - -#ifdef NK_XLIB_IMPLEMENT_STB_IMAGE -#define STB_IMAGE_IMPLEMENTATION -#endif - -#ifdef NK_XLIB_INCLUDE_STB_IMAGE -#include "../../example/stb_image.h" -#endif - - -#ifndef NK_X11_DOUBLE_CLICK_LO -#define NK_X11_DOUBLE_CLICK_LO 20 -#endif -#ifndef NK_X11_DOUBLE_CLICK_HI -#define NK_X11_DOUBLE_CLICK_HI 200 -#endif - -typedef struct XSurface XSurface; -typedef struct XImageWithAlpha XImageWithAlpha; -struct XFont { - int ascent; - int descent; - int height; - XFontSet set; - XFontStruct *xfont; - struct nk_user_font handle; -}; -struct XSurface { - GC gc; - Display *dpy; - int screen; - Window root; - Drawable drawable; - unsigned int w, h; -}; -struct XImageWithAlpha { - XImage* ximage; - GC clipMaskGC; - Pixmap clipMask; -}; -static struct { - char *clipboard_data; - int clipboard_len; - struct nk_text_edit* clipboard_target; - - Atom xa_clipboard; - Atom xa_targets; - Atom xa_text; - Atom xa_utf8_string; - - struct nk_context ctx; - struct XSurface *surf; - Cursor cursor; - Display *dpy; - Window root; - long last_button_click; -} xlib; - -NK_INTERN long -nk_timestamp(void) -{ - struct timeval tv; - if (gettimeofday(&tv, NULL) < 0) return 0; - return (long)((long)tv.tv_sec * 1000 + (long)tv.tv_usec/1000); -} - -NK_INTERN unsigned long -nk_color_from_byte(const nk_byte *c) -{ - unsigned long res = 0; - res |= (unsigned long)c[0] << 16; - res |= (unsigned long)c[1] << 8; - res |= (unsigned long)c[2] << 0; - return (res); -} - -NK_INTERN XSurface* -nk_xsurf_create(int screen, unsigned int w, unsigned int h) -{ - XSurface *surface = (XSurface*)calloc(1, sizeof(XSurface)); - surface->w = w; - surface->h = h; - surface->dpy = xlib.dpy; - surface->screen = screen; - surface->root = xlib.root; - surface->gc = XCreateGC(xlib.dpy, xlib.root, 0, NULL); - XSetLineAttributes(xlib.dpy, surface->gc, 1, LineSolid, CapButt, JoinMiter); - surface->drawable = XCreatePixmap(xlib.dpy, xlib.root, w, h, - (unsigned int)DefaultDepth(xlib.dpy, screen)); - return surface; -} - -NK_INTERN void -nk_xsurf_resize(XSurface *surf, unsigned int w, unsigned int h) -{ - if(!surf) return; - if (surf->w == w && surf->h == h) return; - surf->w = w; surf->h = h; - if(surf->drawable) XFreePixmap(surf->dpy, surf->drawable); - surf->drawable = XCreatePixmap(surf->dpy, surf->root, w, h, - (unsigned int)DefaultDepth(surf->dpy, surf->screen)); -} - -NK_INTERN void -nk_xsurf_scissor(XSurface *surf, float x, float y, float w, float h) -{ - XRectangle clip_rect; - clip_rect.x = (short)(x-1); - clip_rect.y = (short)(y-1); - clip_rect.width = (unsigned short)(w+2); - clip_rect.height = (unsigned short)(h+2); - XSetClipRectangles(surf->dpy, surf->gc, 0, 0, &clip_rect, 1, Unsorted); -} - -NK_INTERN void -nk_xsurf_stroke_line(XSurface *surf, short x0, short y0, short x1, - short y1, unsigned int line_thickness, struct nk_color col) -{ - unsigned long c = nk_color_from_byte(&col.r); - XSetForeground(surf->dpy, surf->gc, c); - XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter); - XDrawLine(surf->dpy, surf->drawable, surf->gc, (int)x0, (int)y0, (int)x1, (int)y1); - XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter); -} - -NK_INTERN void -nk_xsurf_stroke_rect(XSurface* surf, short x, short y, unsigned short w, - unsigned short h, unsigned short r, unsigned short line_thickness, struct nk_color col) -{ - unsigned long c = nk_color_from_byte(&col.r); - XSetForeground(surf->dpy, surf->gc, c); - XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter); - if (r == 0) {XDrawRectangle(surf->dpy, surf->drawable, surf->gc, x, y, w, h);return;} - - {short xc = x + r; - short yc = y + r; - short wc = (short)(w - 2 * r); - short hc = (short)(h - 2 * r); - - XDrawLine(surf->dpy, surf->drawable, surf->gc, xc, y, xc+wc, y); - XDrawLine(surf->dpy, surf->drawable, surf->gc, x+w, yc, x+w, yc+hc); - XDrawLine(surf->dpy, surf->drawable, surf->gc, xc, y+h, xc+wc, y+h); - XDrawLine(surf->dpy, surf->drawable, surf->gc, x, yc, x, yc+hc); - - XDrawArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, y, - (unsigned)r*2, (unsigned)r*2, 0 * 64, 90 * 64); - XDrawArc(surf->dpy, surf->drawable, surf->gc, x, y, - (unsigned)r*2, (unsigned)r*2, 90 * 64, 90 * 64); - XDrawArc(surf->dpy, surf->drawable, surf->gc, x, yc + hc - r, - (unsigned)r*2, (unsigned)2*r, 180 * 64, 90 * 64); - XDrawArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, yc + hc - r, - (unsigned)r*2, (unsigned)2*r, -90 * 64, 90 * 64);} - XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter); -} - -NK_INTERN void -nk_xsurf_fill_rect(XSurface* surf, short x, short y, unsigned short w, - unsigned short h, unsigned short r, struct nk_color col) -{ - unsigned long c = nk_color_from_byte(&col.r); - XSetForeground(surf->dpy, surf->gc, c); - if (r == 0) {XFillRectangle(surf->dpy, surf->drawable, surf->gc, x, y, w, h); return;} - - {short xc = x + r; - short yc = y + r; - short wc = (short)(w - 2 * r); - short hc = (short)(h - 2 * r); - - XPoint pnts[12]; - pnts[0].x = x; - pnts[0].y = yc; - pnts[1].x = xc; - pnts[1].y = yc; - pnts[2].x = xc; - pnts[2].y = y; - - pnts[3].x = xc + wc; - pnts[3].y = y; - pnts[4].x = xc + wc; - pnts[4].y = yc; - pnts[5].x = x + w; - pnts[5].y = yc; - - pnts[6].x = x + w; - pnts[6].y = yc + hc; - pnts[7].x = xc + wc; - pnts[7].y = yc + hc; - pnts[8].x = xc + wc; - pnts[8].y = y + h; - - pnts[9].x = xc; - pnts[9].y = y + h; - pnts[10].x = xc; - pnts[10].y = yc + hc; - pnts[11].x = x; - pnts[11].y = yc + hc; - - XFillPolygon(surf->dpy, surf->drawable, surf->gc, pnts, 12, Convex, CoordModeOrigin); - XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, y, - (unsigned)r*2, (unsigned)r*2, 0 * 64, 90 * 64); - XFillArc(surf->dpy, surf->drawable, surf->gc, x, y, - (unsigned)r*2, (unsigned)r*2, 90 * 64, 90 * 64); - XFillArc(surf->dpy, surf->drawable, surf->gc, x, yc + hc - r, - (unsigned)r*2, (unsigned)2*r, 180 * 64, 90 * 64); - XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, yc + hc - r, - (unsigned)r*2, (unsigned)2*r, -90 * 64, 90 * 64);} -} - -NK_INTERN void -nk_xsurf_fill_triangle(XSurface *surf, short x0, short y0, short x1, - short y1, short x2, short y2, struct nk_color col) -{ - XPoint pnts[3]; - unsigned long c = nk_color_from_byte(&col.r); - pnts[0].x = (short)x0; - pnts[0].y = (short)y0; - pnts[1].x = (short)x1; - pnts[1].y = (short)y1; - pnts[2].x = (short)x2; - pnts[2].y = (short)y2; - XSetForeground(surf->dpy, surf->gc, c); - XFillPolygon(surf->dpy, surf->drawable, surf->gc, pnts, 3, Convex, CoordModeOrigin); -} - -NK_INTERN void -nk_xsurf_stroke_triangle(XSurface *surf, short x0, short y0, short x1, - short y1, short x2, short y2, unsigned short line_thickness, struct nk_color col) -{ - unsigned long c = nk_color_from_byte(&col.r); - XSetForeground(surf->dpy, surf->gc, c); - XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter); - XDrawLine(surf->dpy, surf->drawable, surf->gc, x0, y0, x1, y1); - XDrawLine(surf->dpy, surf->drawable, surf->gc, x1, y1, x2, y2); - XDrawLine(surf->dpy, surf->drawable, surf->gc, x2, y2, x0, y0); - XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter); -} - -NK_INTERN void -nk_xsurf_fill_polygon(XSurface *surf, const struct nk_vec2i *pnts, int count, - struct nk_color col) -{ - int i = 0; - #define MAX_POINTS 128 - XPoint xpnts[MAX_POINTS]; - unsigned long c = nk_color_from_byte(&col.r); - XSetForeground(surf->dpy, surf->gc, c); - for (i = 0; i < count && i < MAX_POINTS; ++i) { - xpnts[i].x = pnts[i].x; - xpnts[i].y = pnts[i].y; - } - XFillPolygon(surf->dpy, surf->drawable, surf->gc, xpnts, count, Convex, CoordModeOrigin); - #undef MAX_POINTS -} - -NK_INTERN void -nk_xsurf_stroke_polygon(XSurface *surf, const struct nk_vec2i *pnts, int count, - unsigned short line_thickness, struct nk_color col) -{ - int i = 0; - unsigned long c = nk_color_from_byte(&col.r); - XSetForeground(surf->dpy, surf->gc, c); - XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter); - for (i = 1; i < count; ++i) - XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[i-1].x, pnts[i-1].y, pnts[i].x, pnts[i].y); - XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[count-1].x, pnts[count-1].y, pnts[0].x, pnts[0].y); - XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter); -} - -NK_INTERN void -nk_xsurf_stroke_polyline(XSurface *surf, const struct nk_vec2i *pnts, - int count, unsigned short line_thickness, struct nk_color col) -{ - int i = 0; - unsigned long c = nk_color_from_byte(&col.r); - XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter); - XSetForeground(surf->dpy, surf->gc, c); - for (i = 0; i < count-1; ++i) - XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[i].x, pnts[i].y, pnts[i+1].x, pnts[i+1].y); - XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter); -} - -NK_INTERN void -nk_xsurf_fill_circle(XSurface *surf, short x, short y, unsigned short w, - unsigned short h, struct nk_color col) -{ - unsigned long c = nk_color_from_byte(&col.r); - XSetForeground(surf->dpy, surf->gc, c); - XFillArc(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y, - (unsigned)w, (unsigned)h, 0, 360 * 64); -} - -NK_INTERN void -nk_xsurf_stroke_circle(XSurface *surf, short x, short y, unsigned short w, - unsigned short h, unsigned short line_thickness, struct nk_color col) -{ - unsigned long c = nk_color_from_byte(&col.r); - XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter); - XSetForeground(surf->dpy, surf->gc, c); - XDrawArc(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y, - (unsigned)w, (unsigned)h, 0, 360 * 64); - XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter); -} - -NK_INTERN void -nk_xsurf_stroke_curve(XSurface *surf, struct nk_vec2i p1, - struct nk_vec2i p2, struct nk_vec2i p3, struct nk_vec2i p4, - unsigned int num_segments, unsigned short line_thickness, struct nk_color col) -{ - unsigned int i_step; - float t_step; - struct nk_vec2i last = p1; - - XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter); - num_segments = NK_MAX(num_segments, 1); - t_step = 1.0f/(float)num_segments; - for (i_step = 1; i_step <= num_segments; ++i_step) { - float t = t_step * (float)i_step; - float u = 1.0f - t; - float w1 = u*u*u; - float w2 = 3*u*u*t; - float w3 = 3*u*t*t; - float w4 = t * t *t; - float x = w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x; - float y = w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y; - nk_xsurf_stroke_line(surf, last.x, last.y, (short)x, (short)y, line_thickness,col); - last.x = (short)x; last.y = (short)y; - } - XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter); -} - -NK_INTERN void -nk_xsurf_draw_text(XSurface *surf, short x, short y, unsigned short w, unsigned short h, - const char *text, int len, XFont *font, struct nk_color cbg, struct nk_color cfg) -{ - int tx, ty; - unsigned long bg = nk_color_from_byte(&cbg.r); - unsigned long fg = nk_color_from_byte(&cfg.r); - - XSetForeground(surf->dpy, surf->gc, bg); - XFillRectangle(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y, (unsigned)w, (unsigned)h); - if(!text || !font || !len) return; - - tx = (int)x; - ty = (int)y + font->ascent; - XSetForeground(surf->dpy, surf->gc, fg); - if(font->set) - XmbDrawString(surf->dpy,surf->drawable,font->set,surf->gc,tx,ty,(const char*)text,(int)len); - else XDrawString(surf->dpy, surf->drawable, surf->gc, tx, ty, (const char*)text, (int)len); -} - - -#ifdef NK_XLIB_INCLUDE_STB_IMAGE -NK_INTERN struct nk_image -nk_stbi_image_to_xsurf(unsigned char *data, int width, int height, int channels) { - XSurface *surf = xlib.surf; - struct nk_image img; - int bpl = channels; - long i, isize = width*height*channels; - XImageWithAlpha *aimage = (XImageWithAlpha*)calloc( 1, sizeof(XImageWithAlpha) ); - int depth = DefaultDepth(surf->dpy, surf->screen); - if (data == NULL) return nk_image_id(0); - if (aimage == NULL) return nk_image_id(0); - - switch (depth){ - case 24: - bpl = 4; - break; - case 16: - case 15: - bpl = 2; - break; - default: - bpl = 1; - break; - } - - /* rgba to bgra */ - if (channels >= 3){ - for (i=0; i < isize; i += channels) { - unsigned char red = data[i+2]; - unsigned char blue = data[i]; - data[i] = red; - data[i+2] = blue; - } - } - - if (channels == 4){ - const unsigned alpha_treshold = 127; - aimage->clipMask = XCreatePixmap(surf->dpy, surf->drawable, width, height, 1); - - if( aimage->clipMask ){ - aimage->clipMaskGC = XCreateGC(surf->dpy, aimage->clipMask, 0, 0); - XSetForeground(surf->dpy, aimage->clipMaskGC, BlackPixel(surf->dpy, surf->screen)); - XFillRectangle(surf->dpy, aimage->clipMask, aimage->clipMaskGC, 0, 0, width, height); - - XSetForeground(surf->dpy, aimage->clipMaskGC, WhitePixel(surf->dpy, surf->screen)); - for (i=0; i < isize; i += channels){ - unsigned char alpha = data[i+3]; - int div = i / channels; - int x = div % width; - int y = div / width; - if( alpha > alpha_treshold ) - XDrawPoint(surf->dpy, aimage->clipMask, aimage->clipMaskGC, x, y); - } - } - } - - aimage->ximage = XCreateImage(surf->dpy, - CopyFromParent, depth, - ZPixmap, 0, - (char*)data, - width, height, - bpl*8, bpl * width); - img = nk_image_ptr( (void*)aimage); - img.h = height; - img.w = width; - return img; -} - -NK_API struct nk_image -nk_xsurf_load_image_from_memory(const void *membuf, nk_uint membufSize) -{ - int x,y,n; - unsigned char *data; - data = stbi_load_from_memory(membuf, membufSize, &x, &y, &n, 0); - return nk_stbi_image_to_xsurf(data, x, y, n); -} - -NK_API struct nk_image -nk_xsurf_load_image_from_file(char const *filename) -{ - int x,y,n; - unsigned char *data; - data = stbi_load(filename, &x, &y, &n, 0); - return nk_stbi_image_to_xsurf(data, x, y, n); -} -#endif /* NK_XLIB_INCLUDE_STB_IMAGE */ - -NK_INTERN void -nk_xsurf_draw_image(XSurface *surf, short x, short y, unsigned short w, unsigned short h, - struct nk_image img, struct nk_color col) -{ - XImageWithAlpha *aimage = img.handle.ptr; - if (aimage){ - if (aimage->clipMask){ - XSetClipMask(surf->dpy, surf->gc, aimage->clipMask); - XSetClipOrigin(surf->dpy, surf->gc, x, y); - } - XPutImage(surf->dpy, surf->drawable, surf->gc, aimage->ximage, 0, 0, x, y, w, h); - XSetClipMask(surf->dpy, surf->gc, None); - } -} - -void -nk_xsurf_image_free(struct nk_image* image) -{ - XSurface *surf = xlib.surf; - XImageWithAlpha *aimage = image->handle.ptr; - if (!aimage) return; - XDestroyImage(aimage->ximage); - XFreePixmap(surf->dpy, aimage->clipMask); - XFreeGC(surf->dpy, aimage->clipMaskGC); - free(aimage); -} - - -NK_INTERN void -nk_xsurf_clear(XSurface *surf, unsigned long color) -{ - XSetForeground(surf->dpy, surf->gc, color); - XFillRectangle(surf->dpy, surf->drawable, surf->gc, 0, 0, surf->w, surf->h); -} - -NK_INTERN void -nk_xsurf_blit(Drawable target, XSurface *surf, unsigned int w, unsigned int h) -{ - XCopyArea(surf->dpy, surf->drawable, target, surf->gc, 0, 0, w, h, 0, 0); -} - -NK_INTERN void -nk_xsurf_del(XSurface *surf) -{ - XFreePixmap(surf->dpy, surf->drawable); - XFreeGC(surf->dpy, surf->gc); - free(surf); -} - -NK_API XFont* -nk_xfont_create(Display *dpy, const char *name) -{ - int n; - char *def, **missing; - XFont *font = (XFont*)calloc(1, sizeof(XFont)); - font->set = XCreateFontSet(dpy, name, &missing, &n, &def); - if(missing) { - while(n--) - fprintf(stderr, "missing fontset: %s\n", missing[n]); - XFreeStringList(missing); - } - if(font->set) { - XFontStruct **xfonts; - char **font_names; - XExtentsOfFontSet(font->set); - n = XFontsOfFontSet(font->set, &xfonts, &font_names); - while(n--) { - font->ascent = NK_MAX(font->ascent, (*xfonts)->ascent); - font->descent = NK_MAX(font->descent,(*xfonts)->descent); - xfonts++; - } - } else { - if(!(font->xfont = XLoadQueryFont(dpy, name)) - && !(font->xfont = XLoadQueryFont(dpy, "fixed"))) { - free(font); - return 0; - } - font->ascent = font->xfont->ascent; - font->descent = font->xfont->descent; - } - font->height = font->ascent + font->descent; - return font; -} - -NK_INTERN float -nk_xfont_get_text_width(nk_handle handle, float height, const char *text, int len) -{ - XFont *font = (XFont*)handle.ptr; - XRectangle r; - if(!font || !text) - return 0; - - if(font->set) { - XmbTextExtents(font->set, (const char*)text, len, NULL, &r); - return (float)r.width; - } else{ - int w = XTextWidth(font->xfont, (const char*)text, len); - return (float)w; - } -} - -NK_API void -nk_xfont_del(Display *dpy, XFont *font) -{ - if(!font) return; - if(font->set) - XFreeFontSet(dpy, font->set); - else - XFreeFont(dpy, font->xfont); - free(font); -} - -NK_API struct nk_context* -nk_xlib_init(XFont *xfont, Display *dpy, int screen, Window root, - unsigned int w, unsigned int h) -{ - struct nk_user_font *font = &xfont->handle; - font->userdata = nk_handle_ptr(xfont); - font->height = (float)xfont->height; - font->width = nk_xfont_get_text_width; - xlib.dpy = dpy; - xlib.root = root; - - if (!setlocale(LC_ALL,"")) return 0; - if (!XSupportsLocale()) return 0; - if (!XSetLocaleModifiers("@im=none")) return 0; - - xlib.xa_clipboard = XInternAtom(dpy, "CLIPBOARD", False); - xlib.xa_targets = XInternAtom(dpy, "TARGETS", False); - xlib.xa_text = XInternAtom(dpy, "TEXT", False); - xlib.xa_utf8_string = XInternAtom(dpy, "UTF8_STRING", False); - - /* create invisible cursor */ - {static XColor dummy; char data[1] = {0}; - Pixmap blank = XCreateBitmapFromData(dpy, root, data, 1, 1); - if (blank == None) return 0; - xlib.cursor = XCreatePixmapCursor(dpy, blank, blank, &dummy, &dummy, 0, 0); - XFreePixmap(dpy, blank);} - - xlib.surf = nk_xsurf_create(screen, w, h); - nk_init_default(&xlib.ctx, font); - return &xlib.ctx; -} - -NK_API void -nk_xlib_set_font(XFont *xfont) -{ - struct nk_user_font *font = &xfont->handle; - font->userdata = nk_handle_ptr(xfont); - font->height = (float)xfont->height; - font->width = nk_xfont_get_text_width; - nk_style_set_font(&xlib.ctx, font); -} - -NK_API void -nk_xlib_push_font(XFont *xfont) -{ - struct nk_user_font *font = &xfont->handle; - font->userdata = nk_handle_ptr(xfont); - font->height = (float)xfont->height; - font->width = nk_xfont_get_text_width; - nk_style_push_font(&xlib.ctx, font); -} - -NK_API void -nk_xlib_paste(nk_handle handle, struct nk_text_edit* edit) -{ - NK_UNUSED(handle); - /* Paste in X is asynchronous, so can not use a temporary text edit */ - NK_ASSERT(edit != &xlib.ctx.text_edit && "Paste not supported for temporary editors"); - xlib.clipboard_target = edit; - /* Request the contents of the primary buffer */ - XConvertSelection(xlib.dpy, XA_PRIMARY, XA_STRING, XA_PRIMARY, xlib.root, CurrentTime); -} - -NK_API void -nk_xlib_copy(nk_handle handle, const char* str, int len) -{ - NK_UNUSED(handle); - free(xlib.clipboard_data); - xlib.clipboard_len = 0; - xlib.clipboard_data = malloc((size_t)len); - if (xlib.clipboard_data) { - memcpy(xlib.clipboard_data, str, (size_t)len); - xlib.clipboard_len = len; - XSetSelectionOwner(xlib.dpy, XA_PRIMARY, xlib.root, CurrentTime); - XSetSelectionOwner(xlib.dpy, xlib.xa_clipboard, xlib.root, CurrentTime); - } -} - -NK_API int -nk_xlib_handle_event(Display *dpy, int screen, Window win, XEvent *evt) -{ - struct nk_context *ctx = &xlib.ctx; - - /* optional grabbing behavior */ - if (ctx->input.mouse.grab) { - XDefineCursor(xlib.dpy, xlib.root, xlib.cursor); - ctx->input.mouse.grab = 0; - } else if (ctx->input.mouse.ungrab) { - XWarpPointer(xlib.dpy, None, xlib.root, 0, 0, 0, 0, - (int)ctx->input.mouse.prev.x, (int)ctx->input.mouse.prev.y); - XUndefineCursor(xlib.dpy, xlib.root); - ctx->input.mouse.ungrab = 0; - } - - if (evt->type == KeyPress || evt->type == KeyRelease) - { - /* Key handler */ - int ret, down = (evt->type == KeyPress); - KeySym *code = XGetKeyboardMapping(xlib.surf->dpy, (KeyCode)evt->xkey.keycode, 1, &ret); - if (*code == XK_Shift_L || *code == XK_Shift_R) nk_input_key(ctx, NK_KEY_SHIFT, down); - else if (*code == XK_Delete) nk_input_key(ctx, NK_KEY_DEL, down); - else if (*code == XK_Return) nk_input_key(ctx, NK_KEY_ENTER, down); - else if (*code == XK_Tab) nk_input_key(ctx, NK_KEY_TAB, down); - else if (*code == XK_Left) nk_input_key(ctx, NK_KEY_LEFT, down); - else if (*code == XK_Right) nk_input_key(ctx, NK_KEY_RIGHT, down); - else if (*code == XK_Up) nk_input_key(ctx, NK_KEY_UP, down); - else if (*code == XK_Down) nk_input_key(ctx, NK_KEY_DOWN, down); - else if (*code == XK_BackSpace) nk_input_key(ctx, NK_KEY_BACKSPACE, down); - else if (*code == XK_Escape) nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, down); - else if (*code == XK_Page_Up) nk_input_key(ctx, NK_KEY_SCROLL_UP, down); - else if (*code == XK_Page_Down) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down); - else if (*code == XK_Home) { - nk_input_key(ctx, NK_KEY_TEXT_START, down); - nk_input_key(ctx, NK_KEY_SCROLL_START, down); - } else if (*code == XK_End) { - nk_input_key(ctx, NK_KEY_TEXT_END, down); - nk_input_key(ctx, NK_KEY_SCROLL_END, down); - } else { - if (*code == 'c' && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_COPY, down); - else if (*code == 'v' && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_PASTE, down); - else if (*code == 'x' && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_CUT, down); - else if (*code == 'z' && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_TEXT_UNDO, down); - else if (*code == 'r' && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_TEXT_REDO, down); - else if (*code == XK_Left && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down); - else if (*code == XK_Right && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down); - else if (*code == 'b' && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down); - else if (*code == 'e' && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down); - else { - if (*code == 'i') - nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, down); - else if (*code == 'r') - nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, down); - if (down) { - char buf[32]; - KeySym keysym = 0; - if (XLookupString((XKeyEvent*)evt, buf, 32, &keysym, NULL) != NoSymbol) - nk_input_glyph(ctx, buf); - } - } - } - XFree(code); - return 1; - } else if (evt->type == ButtonPress || evt->type == ButtonRelease) { - /* Button handler */ - int down = (evt->type == ButtonPress); - const int x = evt->xbutton.x, y = evt->xbutton.y; - if (evt->xbutton.button == Button1) { - if (down) { /* Double-Click Button handler */ - long dt = nk_timestamp() - xlib.last_button_click; - if (dt > NK_X11_DOUBLE_CLICK_LO && dt < NK_X11_DOUBLE_CLICK_HI) - nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_true); - xlib.last_button_click = nk_timestamp(); - } else nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_false); - nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down); - } else if (evt->xbutton.button == Button2) - nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down); - else if (evt->xbutton.button == Button3) - nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down); - else if (evt->xbutton.button == Button4) - nk_input_scroll(ctx, nk_vec2(0, 1.0f)); - else if (evt->xbutton.button == Button5) - nk_input_scroll(ctx, nk_vec2(0, -1.0f)); - else return 0; - return 1; - } else if (evt->type == MotionNotify) { - /* Mouse motion handler */ - const int x = evt->xmotion.x, y = evt->xmotion.y; - nk_input_motion(ctx, x, y); - if (ctx->input.mouse.grabbed) { - ctx->input.mouse.pos.x = ctx->input.mouse.prev.x; - ctx->input.mouse.pos.y = ctx->input.mouse.prev.y; - XWarpPointer(xlib.dpy, None, xlib.surf->root, 0, 0, 0, 0, (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y); - } - return 1; - } else if (evt->type == Expose || evt->type == ConfigureNotify) { - /* Window resize handler */ - unsigned int width, height; - XWindowAttributes attr; - XGetWindowAttributes(dpy, win, &attr); - width = (unsigned int)attr.width; - height = (unsigned int)attr.height; - nk_xsurf_resize(xlib.surf, width, height); - return 1; - } else if (evt->type == KeymapNotify) { - XRefreshKeyboardMapping(&evt->xmapping); - return 1; - } else if (evt->type == SelectionClear) { - free(xlib.clipboard_data); - xlib.clipboard_data = NULL; - xlib.clipboard_len = 0; - return 1; - } else if (evt->type == SelectionRequest) { - XEvent reply; - reply.xselection.type = SelectionNotify; - reply.xselection.requestor = evt->xselectionrequest.requestor; - reply.xselection.selection = evt->xselectionrequest.selection; - reply.xselection.target = evt->xselectionrequest.target; - reply.xselection.property = None; /* Default refuse */ - reply.xselection.time = evt->xselectionrequest.time; - - if (reply.xselection.target == xlib.xa_targets) { - Atom target_list[4]; - target_list[0] = xlib.xa_targets; - target_list[1] = xlib.xa_text; - target_list[2] = xlib.xa_utf8_string; - target_list[3] = XA_STRING; - - reply.xselection.property = evt->xselectionrequest.property; - XChangeProperty(evt->xselection.display,evt->xselectionrequest.requestor, - reply.xselection.property, XA_ATOM, 32, PropModeReplace, - (unsigned char*)&target_list, 4); - } else if (xlib.clipboard_data && (reply.xselection.target == xlib.xa_text || - reply.xselection.target == xlib.xa_utf8_string || reply.xselection.target == XA_STRING)) { - reply.xselection.property = evt->xselectionrequest.property; - XChangeProperty(evt->xselection.display,evt->xselectionrequest.requestor, - reply.xselection.property, reply.xselection.target, 8, PropModeReplace, - (unsigned char*)xlib.clipboard_data, xlib.clipboard_len); - } - XSendEvent(evt->xselection.display, evt->xselectionrequest.requestor, True, 0, &reply); - XFlush(evt->xselection.display); - return 1; - } else if (evt->type == SelectionNotify && xlib.clipboard_target) { - if ((evt->xselection.target != XA_STRING) && - (evt->xselection.target != xlib.xa_utf8_string) && - (evt->xselection.target != xlib.xa_text)) - return 1; - - {Atom actual_type; - int actual_format; - unsigned long pos = 0, len, remain; - unsigned char* data = 0; - do { - XGetWindowProperty(dpy, win, XA_PRIMARY, (int)pos, 1024, False, - AnyPropertyType, &actual_type, &actual_format, &len, &remain, &data); - if (len && data) - nk_textedit_text(xlib.clipboard_target, (char*)data, (int)len); - if (data != 0) XFree(data); - pos += (len * (unsigned long)actual_format) / 32; - } while (remain != 0);} - return 1; - } - return 0; -} - -NK_API void -nk_xlib_shutdown(void) -{ - nk_xsurf_del(xlib.surf); - nk_free(&xlib.ctx); - XFreeCursor(xlib.dpy, xlib.cursor); - nk_memset(&xlib, 0, sizeof(xlib)); -} - -NK_API void -nk_xlib_render(Drawable screen, struct nk_color clear) -{ - const struct nk_command *cmd; - struct nk_context *ctx = &xlib.ctx; - XSurface *surf = xlib.surf; - - nk_xsurf_clear(xlib.surf, nk_color_from_byte(&clear.r)); - nk_foreach(cmd, &xlib.ctx) - { - switch (cmd->type) { - case NK_COMMAND_NOP: break; - case NK_COMMAND_SCISSOR: { - const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd; - nk_xsurf_scissor(surf, s->x, s->y, s->w, s->h); - } break; - case NK_COMMAND_LINE: { - const struct nk_command_line *l = (const struct nk_command_line *)cmd; - nk_xsurf_stroke_line(surf, l->begin.x, l->begin.y, l->end.x, - l->end.y, l->line_thickness, l->color); - } break; - case NK_COMMAND_RECT: { - const struct nk_command_rect *r = (const struct nk_command_rect *)cmd; - nk_xsurf_stroke_rect(surf, r->x, r->y, NK_MAX(r->w -r->line_thickness, 0), - NK_MAX(r->h - r->line_thickness, 0), (unsigned short)r->rounding, - r->line_thickness, r->color); - } break; - case NK_COMMAND_RECT_FILLED: { - const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd; - nk_xsurf_fill_rect(surf, r->x, r->y, r->w, r->h, - (unsigned short)r->rounding, r->color); - } break; - case NK_COMMAND_CIRCLE: { - const struct nk_command_circle *c = (const struct nk_command_circle *)cmd; - nk_xsurf_stroke_circle(surf, c->x, c->y, c->w, c->h, c->line_thickness, c->color); - } break; - case NK_COMMAND_CIRCLE_FILLED: { - const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd; - nk_xsurf_fill_circle(surf, c->x, c->y, c->w, c->h, c->color); - } break; - case NK_COMMAND_TRIANGLE: { - const struct nk_command_triangle*t = (const struct nk_command_triangle*)cmd; - nk_xsurf_stroke_triangle(surf, t->a.x, t->a.y, t->b.x, t->b.y, - t->c.x, t->c.y, t->line_thickness, t->color); - } break; - case NK_COMMAND_TRIANGLE_FILLED: { - const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd; - nk_xsurf_fill_triangle(surf, t->a.x, t->a.y, t->b.x, t->b.y, - t->c.x, t->c.y, t->color); - } break; - case NK_COMMAND_POLYGON: { - const struct nk_command_polygon *p =(const struct nk_command_polygon*)cmd; - nk_xsurf_stroke_polygon(surf, p->points, p->point_count, p->line_thickness,p->color); - } break; - case NK_COMMAND_POLYGON_FILLED: { - const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd; - nk_xsurf_fill_polygon(surf, p->points, p->point_count, p->color); - } break; - case NK_COMMAND_POLYLINE: { - const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd; - nk_xsurf_stroke_polyline(surf, p->points, p->point_count, p->line_thickness, p->color); - } break; - case NK_COMMAND_TEXT: { - const struct nk_command_text *t = (const struct nk_command_text*)cmd; - nk_xsurf_draw_text(surf, t->x, t->y, t->w, t->h, - (const char*)t->string, t->length, - (XFont*)t->font->userdata.ptr, - t->background, t->foreground); - } break; - case NK_COMMAND_CURVE: { - const struct nk_command_curve *q = (const struct nk_command_curve *)cmd; - nk_xsurf_stroke_curve(surf, q->begin, q->ctrl[0], q->ctrl[1], - q->end, 22, q->line_thickness, q->color); - } break; - case NK_COMMAND_IMAGE: { - const struct nk_command_image *i = (const struct nk_command_image *)cmd; - nk_xsurf_draw_image(surf, i->x, i->y, i->w, i->h, i->img, i->col); - } break; - case NK_COMMAND_RECT_MULTI_COLOR: - case NK_COMMAND_ARC: - case NK_COMMAND_ARC_FILLED: - case NK_COMMAND_CUSTOM: - default: break; - } - } - nk_clear(ctx); - nk_xsurf_blit(screen, surf, surf->w, surf->h); -} -#endif diff --git a/subprojects/nk_pugl/nuklear/demo/x11_opengl2/Makefile b/subprojects/nk_pugl/nuklear/demo/x11_opengl2/Makefile deleted file mode 100644 index a3d6d32..0000000 --- a/subprojects/nk_pugl/nuklear/demo/x11_opengl2/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -# Install -BIN = demo - -# Compiler -CC = clang -DCC = gcc - -# Flags -CFLAGS += -std=c99 -pedantic -O2 - -SRC = main.c -OBJ = $(SRC:.c=.o) - -# Modes -.PHONY: gcc -gcc: CC = gcc -gcc: $(BIN) - -.PHONY: clang -clang: CC = clang -clang: $(BIN) - -$(BIN): - @mkdir -p bin - rm -f bin/$(BIN) $(OBJS) - $(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) -lX11 -lm -lGL -lm -lGLU diff --git a/subprojects/nk_pugl/nuklear/demo/x11_opengl2/main.c b/subprojects/nk_pugl/nuklear/demo/x11_opengl2/main.c deleted file mode 100644 index 12cbed1..0000000 --- a/subprojects/nk_pugl/nuklear/demo/x11_opengl2/main.c +++ /dev/null @@ -1,345 +0,0 @@ -/* nuklear - v1.32.0 - public domain */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_STANDARD_VARARGS -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT -#define NK_INCLUDE_FONT_BAKING -#define NK_INCLUDE_DEFAULT_FONT -#define NK_IMPLEMENTATION -#define NK_XLIB_GL2_IMPLEMENTATION -#include "../../nuklear.h" -#include "nuklear_xlib_gl2.h" - -#define WINDOW_WIDTH 1200 -#define WINDOW_HEIGHT 800 - -#define MAX_VERTEX_BUFFER 512 * 1024 -#define MAX_ELEMENT_BUFFER 128 * 1024 - -/* =============================================================== - * - * EXAMPLE - * - * ===============================================================*/ -/* This are some code examples to provide a small overview of what can be - * done with this library. To try out an example uncomment the defines */ -/*#define INCLUDE_ALL */ -/*#define INCLUDE_STYLE */ -/*#define INCLUDE_CALCULATOR */ -/*#define INCLUDE_OVERVIEW */ -/*#define INCLUDE_NODE_EDITOR */ - -#ifdef INCLUDE_ALL - #define INCLUDE_STYLE - #define INCLUDE_CALCULATOR - #define INCLUDE_OVERVIEW - #define INCLUDE_NODE_EDITOR -#endif - -#ifdef INCLUDE_STYLE - #include "../style.c" -#endif -#ifdef INCLUDE_CALCULATOR - #include "../calculator.c" -#endif -#ifdef INCLUDE_OVERVIEW - #include "../overview.c" -#endif -#ifdef INCLUDE_NODE_EDITOR - #include "../node_editor.c" -#endif - -/* =============================================================== - * - * DEMO - * - * ===============================================================*/ -struct XWindow { - Display *dpy; - Window win; - XVisualInfo *vis; - Colormap cmap; - XSetWindowAttributes swa; - XWindowAttributes attr; - GLXFBConfig fbc; - Atom wm_delete_window; - int width, height; -}; -static int gl_err = nk_false; -static int gl_error_handler(Display *dpy, XErrorEvent *ev) -{NK_UNUSED(dpy); NK_UNUSED(ev); gl_err = nk_true; return 0;} - -static void -die(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fputs("\n", stderr); - exit(EXIT_FAILURE); -} - -static int -has_extension(const char *string, const char *ext) -{ - const char *start, *where, *term; - where = strchr(ext, ' '); - if (where || *ext == '\0') - return nk_false; - - for (start = string;;) { - where = strstr((const char*)start, ext); - if (!where) break; - term = where + strlen(ext); - if (where == start || *(where - 1) == ' ') { - if (*term == ' ' || *term == '\0') - return nk_true; - } - start = term; - } - return nk_false; -} - -int main(void) -{ - /* Platform */ - int running = 1; - struct XWindow win; - GLXContext glContext; - struct nk_context *ctx; - struct nk_colorf bg; - - memset(&win, 0, sizeof(win)); - win.dpy = XOpenDisplay(NULL); - if (!win.dpy) die("Failed to open X display\n"); - { - /* check glx version */ - int glx_major, glx_minor; - if (!glXQueryVersion(win.dpy, &glx_major, &glx_minor)) - die("[X11]: Error: Failed to query OpenGL version\n"); - if ((glx_major == 1 && glx_minor < 3) || (glx_major < 1)) - die("[X11]: Error: Invalid GLX version!\n"); - } - { - /* find and pick matching framebuffer visual */ - int fb_count; - static GLint attr[] = { - GLX_X_RENDERABLE, True, - GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, - GLX_RENDER_TYPE, GLX_RGBA_BIT, - GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, - GLX_RED_SIZE, 8, - GLX_GREEN_SIZE, 8, - GLX_BLUE_SIZE, 8, - GLX_ALPHA_SIZE, 8, - GLX_DEPTH_SIZE, 24, - GLX_STENCIL_SIZE, 8, - GLX_DOUBLEBUFFER, True, - None - }; - GLXFBConfig *fbc; - fbc = glXChooseFBConfig(win.dpy, DefaultScreen(win.dpy), attr, &fb_count); - if (!fbc) die("[X11]: Error: failed to retrieve framebuffer configuration\n"); - { - /* pick framebuffer with most samples per pixel */ - int i; - int fb_best = -1, best_num_samples = -1; - for (i = 0; i < fb_count; ++i) { - XVisualInfo *vi = glXGetVisualFromFBConfig(win.dpy, fbc[i]); - if (vi) { - int sample_buffer, samples; - glXGetFBConfigAttrib(win.dpy, fbc[i], GLX_SAMPLE_BUFFERS, &sample_buffer); - glXGetFBConfigAttrib(win.dpy, fbc[i], GLX_SAMPLES, &samples); - if ((fb_best < 0) || (sample_buffer && samples > best_num_samples)) - fb_best = i, best_num_samples = samples; - } - } - win.fbc = fbc[fb_best]; - XFree(fbc); - win.vis = glXGetVisualFromFBConfig(win.dpy, win.fbc); - } - } - { - /* create window */ - win.cmap = XCreateColormap(win.dpy, RootWindow(win.dpy, win.vis->screen), win.vis->visual, AllocNone); - win.swa.colormap = win.cmap; - win.swa.background_pixmap = None; - win.swa.border_pixel = 0; - win.swa.event_mask = - ExposureMask | KeyPressMask | KeyReleaseMask | - ButtonPress | ButtonReleaseMask| ButtonMotionMask | - Button1MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask| - PointerMotionMask| StructureNotifyMask; - win.win = XCreateWindow(win.dpy, RootWindow(win.dpy, win.vis->screen), 0, 0, - WINDOW_WIDTH, WINDOW_HEIGHT, 0, win.vis->depth, InputOutput, - win.vis->visual, CWBorderPixel|CWColormap|CWEventMask, &win.swa); - if (!win.win) die("[X11]: Failed to create window\n"); - XFree(win.vis); - XStoreName(win.dpy, win.win, "Demo"); - XMapWindow(win.dpy, win.win); - win.wm_delete_window = XInternAtom(win.dpy, "WM_DELETE_WINDOW", False); - XSetWMProtocols(win.dpy, win.win, &win.wm_delete_window, 1); - } - { - /* create opengl context */ - typedef GLXContext(*glxCreateContext)(Display*, GLXFBConfig, GLXContext, Bool, const int*); - int(*old_handler)(Display*, XErrorEvent*) = XSetErrorHandler(gl_error_handler); - const char *extensions_str = glXQueryExtensionsString(win.dpy, DefaultScreen(win.dpy)); - glxCreateContext create_context = (glxCreateContext) - glXGetProcAddressARB((const GLubyte*)"glXCreateContextAttribsARB"); - - gl_err = nk_false; - if (!has_extension(extensions_str, "GLX_ARB_create_context") || !create_context) { - fprintf(stdout, "[X11]: glXCreateContextAttribARB() not found...\n"); - fprintf(stdout, "[X11]: ... using old-style GLX context\n"); - glContext = glXCreateNewContext(win.dpy, win.fbc, GLX_RGBA_TYPE, 0, True); - } else { - GLint attr[] = { - GLX_CONTEXT_MAJOR_VERSION_ARB, 2, - GLX_CONTEXT_MINOR_VERSION_ARB, 2, - None - }; - glContext = create_context(win.dpy, win.fbc, 0, True, attr); - XSync(win.dpy, False); - if (gl_err || !glContext) { - /* Could not create GL 3.0 context. Fallback to old 2.x context. - * If a version below 3.0 is requested, implementations will - * return the newest context version compatible with OpenGL - * version less than version 3.0.*/ - attr[1] = 1; attr[3] = 0; - gl_err = nk_false; - fprintf(stdout, "[X11] Failed to create OpenGL 3.0 context\n"); - fprintf(stdout, "[X11] ... using old-style GLX context!\n"); - glContext = create_context(win.dpy, win.fbc, 0, True, attr); - } - } - XSync(win.dpy, False); - XSetErrorHandler(old_handler); - if (gl_err || !glContext) - die("[X11]: Failed to create an OpenGL context\n"); - glXMakeCurrent(win.dpy, win.win, glContext); - } - - ctx = nk_x11_init(win.dpy, win.win); - /* Load Fonts: if none of these are loaded a default font will be used */ - /* Load Cursor: if you uncomment cursor loading please hide the cursor */ - {struct nk_font_atlas *atlas; - nk_x11_font_stash_begin(&atlas); - /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/ - /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 14, 0);*/ - /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/ - /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/ - /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/ - /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/ - nk_x11_font_stash_end(); - /*nk_style_load_all_cursors(ctx, atlas->cursors);*/ - /*nk_style_set_font(ctx, &droid->handle);*/} - - #ifdef INCLUDE_STYLE - /*set_style(ctx, THEME_WHITE);*/ - /*set_style(ctx, THEME_RED);*/ - /*set_style(ctx, THEME_BLUE);*/ - /*set_style(ctx, THEME_DARK);*/ - #endif - - bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f; - while (running) - { - /* Input */ - XEvent evt; - nk_input_begin(ctx); - while (XPending(win.dpy)) { - XNextEvent(win.dpy, &evt); - if (evt.type == ClientMessage) goto cleanup; - if (XFilterEvent(&evt, win.win)) continue; - nk_x11_handle_event(&evt); - } - nk_input_end(ctx); - - /* GUI */ - if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200), - NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE| - NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) - { - enum {EASY, HARD}; - static int op = EASY; - static int property = 20; - - nk_layout_row_static(ctx, 30, 80, 1); - if (nk_button_label(ctx, "button")) - fprintf(stdout, "button pressed\n"); - nk_layout_row_dynamic(ctx, 30, 2); - if (nk_option_label(ctx, "easy", op == EASY)) op = EASY; - if (nk_option_label(ctx, "hard", op == HARD)) op = HARD; - nk_layout_row_dynamic(ctx, 25, 1); - nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1); - - nk_layout_row_dynamic(ctx, 20, 1); - nk_label(ctx, "background:", NK_TEXT_LEFT); - nk_layout_row_dynamic(ctx, 25, 1); - if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) { - nk_layout_row_dynamic(ctx, 120, 1); - bg = nk_color_picker(ctx, bg, NK_RGBA); - nk_layout_row_dynamic(ctx, 25, 1); - bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f); - bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f); - bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f); - bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f); - nk_combo_end(ctx); - } - } - nk_end(ctx); - - /* -------------- EXAMPLES ---------------- */ - #ifdef INCLUDE_CALCULATOR - calculator(ctx); - #endif - #ifdef INCLUDE_OVERVIEW - overview(ctx); - #endif - #ifdef INCLUDE_NODE_EDITOR - node_editor(ctx); - #endif - /* ----------------------------------------- */ - - /* Draw */ - XGetWindowAttributes(win.dpy, win.win, &win.attr); - glViewport(0, 0, win.width, win.height); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(bg.r, bg.g, bg.b, bg.a); - /* IMPORTANT: `nk_x11_render` modifies some global OpenGL state - * with blending, scissor, face culling, depth test and viewport and - * defaults everything back into a default state. - * Make sure to either a.) save and restore or b.) reset your own state after - * rendering the UI. */ - nk_x11_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER); - glXSwapBuffers(win.dpy, win.win); - } - -cleanup: - nk_x11_shutdown(); - glXMakeCurrent(win.dpy, 0, 0); - glXDestroyContext(win.dpy, glContext); - XUnmapWindow(win.dpy, win.win); - XFreeColormap(win.dpy, win.cmap); - XDestroyWindow(win.dpy, win.win); - XCloseDisplay(win.dpy); - return 0; - -} diff --git a/subprojects/nk_pugl/nuklear/demo/x11_opengl2/nuklear_xlib_gl2.h b/subprojects/nk_pugl/nuklear/demo/x11_opengl2/nuklear_xlib_gl2.h deleted file mode 100644 index ab36eb6..0000000 --- a/subprojects/nk_pugl/nuklear/demo/x11_opengl2/nuklear_xlib_gl2.h +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Nuklear - 1.32.0 - public domain - * no warrenty implied; use at your own risk. - * authored from 2015-2016 by Micha Mettke - */ -/* - * ============================================================== - * - * API - * - * =============================================================== - */ -#ifndef NK_XLIB_GL2_H_ -#define NK_XLIB_GL2_H_ - -#include -NK_API struct nk_context* nk_x11_init(Display *dpy, Window win); -NK_API void nk_x11_font_stash_begin(struct nk_font_atlas **atlas); -NK_API void nk_x11_font_stash_end(void); -NK_API int nk_x11_handle_event(XEvent *evt); -NK_API void nk_x11_render(enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer); -NK_API void nk_x11_shutdown(void); - -#endif -/* - * ============================================================== - * - * IMPLEMENTATION - * - * =============================================================== - */ -#ifdef NK_XLIB_GL2_IMPLEMENTATION -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include - -#ifndef NK_X11_DOUBLE_CLICK_LO -#define NK_X11_DOUBLE_CLICK_LO 20 -#endif -#ifndef NK_X11_DOUBLE_CLICK_HI -#define NK_X11_DOUBLE_CLICK_HI 200 -#endif - -struct nk_x11_vertex { - float position[2]; - float uv[2]; - nk_byte col[4]; -}; - -struct nk_x11_device { - struct nk_buffer cmds; - struct nk_draw_null_texture null; - GLuint font_tex; -}; - -static struct nk_x11 { - struct nk_x11_device ogl; - struct nk_context ctx; - struct nk_font_atlas atlas; - Cursor cursor; - Display *dpy; - Window win; - long last_button_click; -} x11; - -NK_INTERN long -nk_timestamp(void) -{ - struct timeval tv; - if (gettimeofday(&tv, NULL) < 0) return 0; - return (long)((long)tv.tv_sec * 1000 + (long)tv.tv_usec/1000); -} - -NK_INTERN void -nk_x11_device_upload_atlas(const void *image, int width, int height) -{ - struct nk_x11_device *dev = &x11.ogl; - glGenTextures(1, &dev->font_tex); - glBindTexture(GL_TEXTURE_2D, dev->font_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, image); -} - -NK_API void -nk_x11_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer) -{ - /* setup global state */ - struct nk_x11_device *dev = &x11.ogl; - int width, height; - - XWindowAttributes attr; - XGetWindowAttributes(x11.dpy, x11.win, &attr); - width = attr.width; - height = attr.height; - - glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT|GL_TRANSFORM_BIT); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glEnable(GL_SCISSOR_TEST); - glEnable(GL_BLEND); - glEnable(GL_TEXTURE_2D); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - /* setup viewport/project */ - glViewport(0,0,(GLsizei)width,(GLsizei)height); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(0.0f, width, height, 0.0f, -1.0f, 1.0f); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - { - GLsizei vs = sizeof(struct nk_x11_vertex); - size_t vp = offsetof(struct nk_x11_vertex, position); - size_t vt = offsetof(struct nk_x11_vertex, uv); - size_t vc = offsetof(struct nk_x11_vertex, col); - - /* convert from command queue into draw list and draw to screen */ - const struct nk_draw_command *cmd; - const nk_draw_index *offset = NULL; - struct nk_buffer vbuf, ebuf; - - /* fill convert configuration */ - struct nk_convert_config config; - static const struct nk_draw_vertex_layout_element vertex_layout[] = { - {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_x11_vertex, position)}, - {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_x11_vertex, uv)}, - {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_x11_vertex, col)}, - {NK_VERTEX_LAYOUT_END} - }; - NK_MEMSET(&config, 0, sizeof(config)); - config.vertex_layout = vertex_layout; - config.vertex_size = sizeof(struct nk_x11_vertex); - config.vertex_alignment = NK_ALIGNOF(struct nk_x11_vertex); - config.null = dev->null; - config.circle_segment_count = 22; - config.curve_segment_count = 22; - config.arc_segment_count = 22; - config.global_alpha = 1.0f; - config.shape_AA = AA; - config.line_AA = AA; - - /* convert shapes into vertexes */ - nk_buffer_init_default(&vbuf); - nk_buffer_init_default(&ebuf); - nk_convert(&x11.ctx, &dev->cmds, &vbuf, &ebuf, &config); - - /* setup vertex buffer pointer */ - {const void *vertices = nk_buffer_memory_const(&vbuf); - glVertexPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vp)); - glTexCoordPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vt)); - glColorPointer(4, GL_UNSIGNED_BYTE, vs, (const void*)((const nk_byte*)vertices + vc));} - - /* iterate over and execute each draw command */ - offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf); - nk_draw_foreach(cmd, &x11.ctx, &dev->cmds) - { - if (!cmd->elem_count) continue; - glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); - glScissor( - (GLint)(cmd->clip_rect.x), - (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h))), - (GLint)(cmd->clip_rect.w), - (GLint)(cmd->clip_rect.h)); - glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); - offset += cmd->elem_count; - } - nk_clear(&x11.ctx); - nk_buffer_free(&vbuf); - nk_buffer_free(&ebuf); - } - - /* default OpenGL state */ - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - - glBindTexture(GL_TEXTURE_2D, 0); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glPopAttrib(); - -} - -NK_API void -nk_x11_font_stash_begin(struct nk_font_atlas **atlas) -{ - nk_font_atlas_init_default(&x11.atlas); - nk_font_atlas_begin(&x11.atlas); - *atlas = &x11.atlas; -} - -NK_API void -nk_x11_font_stash_end(void) -{ - const void *image; int w, h; - image = nk_font_atlas_bake(&x11.atlas, &w, &h, NK_FONT_ATLAS_RGBA32); - nk_x11_device_upload_atlas(image, w, h); - nk_font_atlas_end(&x11.atlas, nk_handle_id((int)x11.ogl.font_tex), &x11.ogl.null); - if (x11.atlas.default_font) - nk_style_set_font(&x11.ctx, &x11.atlas.default_font->handle); -} - -NK_API int -nk_x11_handle_event(XEvent *evt) -{ - struct nk_context *ctx = &x11.ctx; - - /* optional grabbing behavior */ - if (ctx->input.mouse.grab) { - XDefineCursor(x11.dpy, x11.win, x11.cursor); - ctx->input.mouse.grab = 0; - } else if (ctx->input.mouse.ungrab) { - XWarpPointer(x11.dpy, None, x11.win, 0, 0, 0, 0, - (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y); - XUndefineCursor(x11.dpy, x11.win); - ctx->input.mouse.ungrab = 0; - } - - if (evt->type == KeyPress || evt->type == KeyRelease) - { - /* Key handler */ - int ret, down = (evt->type == KeyPress); - KeySym *code = XGetKeyboardMapping(x11.dpy, (KeyCode)evt->xkey.keycode, 1, &ret); - if (*code == XK_Shift_L || *code == XK_Shift_R) nk_input_key(ctx, NK_KEY_SHIFT, down); - else if (*code == XK_Delete) nk_input_key(ctx, NK_KEY_DEL, down); - else if (*code == XK_Return) nk_input_key(ctx, NK_KEY_ENTER, down); - else if (*code == XK_Tab) nk_input_key(ctx, NK_KEY_TAB, down); - else if (*code == XK_Left) nk_input_key(ctx, NK_KEY_LEFT, down); - else if (*code == XK_Right) nk_input_key(ctx, NK_KEY_RIGHT, down); - else if (*code == XK_Up) nk_input_key(ctx, NK_KEY_UP, down); - else if (*code == XK_Down) nk_input_key(ctx, NK_KEY_DOWN, down); - else if (*code == XK_BackSpace) nk_input_key(ctx, NK_KEY_BACKSPACE, down); - else if (*code == XK_space && !down) nk_input_char(ctx, ' '); - else if (*code == XK_Page_Up) nk_input_key(ctx, NK_KEY_SCROLL_UP, down); - else if (*code == XK_Page_Down) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down); - else if (*code == XK_Home) { - nk_input_key(ctx, NK_KEY_TEXT_START, down); - nk_input_key(ctx, NK_KEY_SCROLL_START, down); - } else if (*code == XK_End) { - nk_input_key(ctx, NK_KEY_TEXT_END, down); - nk_input_key(ctx, NK_KEY_SCROLL_END, down); - } else { - if (*code == 'c' && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_COPY, down); - else if (*code == 'v' && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_PASTE, down); - else if (*code == 'x' && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_CUT, down); - else if (*code == 'z' && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_TEXT_UNDO, down); - else if (*code == 'r' && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_TEXT_REDO, down); - else if (*code == XK_Left && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down); - else if (*code == XK_Right && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down); - else if (*code == 'b' && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down); - else if (*code == 'e' && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down); - else { - if (*code == 'i') - nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, down); - else if (*code == 'r') - nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, down); - if (down) { - char buf[32]; - KeySym keysym = 0; - if (XLookupString((XKeyEvent*)evt, buf, 32, &keysym, NULL) != NoSymbol) - nk_input_glyph(ctx, buf); - } - } - } - XFree(code); - return 1; - } else if (evt->type == ButtonPress || evt->type == ButtonRelease) { - /* Button handler */ - int down = (evt->type == ButtonPress); - const int x = evt->xbutton.x, y = evt->xbutton.y; - if (evt->xbutton.button == Button1) { - if (down) { /* Double-Click Button handler */ - long dt = nk_timestamp() - x11.last_button_click; - if (dt > NK_X11_DOUBLE_CLICK_LO && dt < NK_X11_DOUBLE_CLICK_HI) - nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_true); - x11.last_button_click = nk_timestamp(); - } else nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_false); - nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down); - } else if (evt->xbutton.button == Button2) - nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down); - else if (evt->xbutton.button == Button3) - nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down); - else if (evt->xbutton.button == Button4) - nk_input_scroll(ctx, nk_vec2(0,1.0f)); - else if (evt->xbutton.button == Button5) - nk_input_scroll(ctx, nk_vec2(0,-1.0f)); - else return 0; - return 1; - } else if (evt->type == MotionNotify) { - /* Mouse motion handler */ - const int x = evt->xmotion.x, y = evt->xmotion.y; - nk_input_motion(ctx, x, y); - if (ctx->input.mouse.grabbed) { - ctx->input.mouse.pos.x = ctx->input.mouse.prev.x; - ctx->input.mouse.pos.y = ctx->input.mouse.prev.y; - XWarpPointer(x11.dpy, None, x11.win, 0, 0, 0, 0, (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y); - } - return 1; - } else if (evt->type == KeymapNotify) { - XRefreshKeyboardMapping(&evt->xmapping); - return 1; - } - return 0; -} - -NK_API struct nk_context* -nk_x11_init(Display *dpy, Window win) -{ - x11.dpy = dpy; - x11.win = win; - - if (!setlocale(LC_ALL,"")) return 0; - if (!XSupportsLocale()) return 0; - if (!XSetLocaleModifiers("@im=none")) return 0; - - /* create invisible cursor */ - {static XColor dummy; char data[1] = {0}; - Pixmap blank = XCreateBitmapFromData(dpy, win, data, 1, 1); - if (blank == None) return 0; - x11.cursor = XCreatePixmapCursor(dpy, blank, blank, &dummy, &dummy, 0, 0); - XFreePixmap(dpy, blank);} - - nk_buffer_init_default(&x11.ogl.cmds); - nk_init_default(&x11.ctx, 0); - return &x11.ctx; -} - -NK_API void -nk_x11_shutdown(void) -{ - struct nk_x11_device *dev = &x11.ogl; - nk_font_atlas_clear(&x11.atlas); - nk_free(&x11.ctx); - glDeleteTextures(1, &dev->font_tex); - nk_buffer_free(&dev->cmds); - XFreeCursor(x11.dpy, x11.cursor); - memset(&x11, 0, sizeof(x11)); -} - -#endif diff --git a/subprojects/nk_pugl/nuklear/demo/x11_opengl3/Makefile b/subprojects/nk_pugl/nuklear/demo/x11_opengl3/Makefile deleted file mode 100644 index a3d6d32..0000000 --- a/subprojects/nk_pugl/nuklear/demo/x11_opengl3/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -# Install -BIN = demo - -# Compiler -CC = clang -DCC = gcc - -# Flags -CFLAGS += -std=c99 -pedantic -O2 - -SRC = main.c -OBJ = $(SRC:.c=.o) - -# Modes -.PHONY: gcc -gcc: CC = gcc -gcc: $(BIN) - -.PHONY: clang -clang: CC = clang -clang: $(BIN) - -$(BIN): - @mkdir -p bin - rm -f bin/$(BIN) $(OBJS) - $(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) -lX11 -lm -lGL -lm -lGLU diff --git a/subprojects/nk_pugl/nuklear/demo/x11_opengl3/main.c b/subprojects/nk_pugl/nuklear/demo/x11_opengl3/main.c deleted file mode 100644 index 0191f98..0000000 --- a/subprojects/nk_pugl/nuklear/demo/x11_opengl3/main.c +++ /dev/null @@ -1,342 +0,0 @@ -/* nuklear - v1.32.0 - public domain */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_STANDARD_VARARGS -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT -#define NK_INCLUDE_FONT_BAKING -#define NK_INCLUDE_DEFAULT_FONT -#define NK_IMPLEMENTATION -#define NK_XLIB_GL3_IMPLEMENTATION -#define NK_XLIB_LOAD_OPENGL_EXTENSIONS -#include "../../nuklear.h" -#include "nuklear_xlib_gl3.h" - -#define WINDOW_WIDTH 1200 -#define WINDOW_HEIGHT 800 - -#define MAX_VERTEX_BUFFER 512 * 1024 -#define MAX_ELEMENT_BUFFER 128 * 1024 - -/* =============================================================== - * - * EXAMPLE - * - * ===============================================================*/ -/* This are some code examples to provide a small overview of what can be - * done with this library. To try out an example uncomment the defines */ -/*#define INCLUDE_ALL */ -/*#define INCLUDE_STYLE */ -/*#define INCLUDE_CALCULATOR */ -/*#define INCLUDE_OVERVIEW */ -/*#define INCLUDE_NODE_EDITOR */ - -#ifdef INCLUDE_ALL - #define INCLUDE_STYLE - #define INCLUDE_CALCULATOR - #define INCLUDE_OVERVIEW - #define INCLUDE_NODE_EDITOR -#endif - -#ifdef INCLUDE_STYLE - #include "../style.c" -#endif -#ifdef INCLUDE_CALCULATOR - #include "../calculator.c" -#endif -#ifdef INCLUDE_OVERVIEW - #include "../overview.c" -#endif -#ifdef INCLUDE_NODE_EDITOR - #include "../node_editor.c" -#endif - -/* =============================================================== - * - * DEMO - * - * ===============================================================*/ -struct XWindow { - Display *dpy; - Window win; - XVisualInfo *vis; - Colormap cmap; - XSetWindowAttributes swa; - XWindowAttributes attr; - GLXFBConfig fbc; - Atom wm_delete_window; - int width, height; -}; -static int gl_err = nk_false; -static int gl_error_handler(Display *dpy, XErrorEvent *ev) -{NK_UNUSED(dpy); NK_UNUSED(ev); gl_err = nk_true;return 0;} - -static void -die(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fputs("\n", stderr); - exit(EXIT_FAILURE); -} - -static int -has_extension(const char *string, const char *ext) -{ - const char *start, *where, *term; - where = strchr(ext, ' '); - if (where || *ext == '\0') - return nk_false; - - for (start = string;;) { - where = strstr((const char*)start, ext); - if (!where) break; - term = where + strlen(ext); - if (where == start || *(where - 1) == ' ') { - if (*term == ' ' || *term == '\0') - return nk_true; - } - start = term; - } - return nk_false; -} - -int main(void) -{ - /* Platform */ - int running = 1; - struct XWindow win; - GLXContext glContext; - struct nk_context *ctx; - struct nk_colorf bg; - - memset(&win, 0, sizeof(win)); - win.dpy = XOpenDisplay(NULL); - if (!win.dpy) die("Failed to open X display\n"); - { - /* check glx version */ - int glx_major, glx_minor; - if (!glXQueryVersion(win.dpy, &glx_major, &glx_minor)) - die("[X11]: Error: Failed to query OpenGL version\n"); - if ((glx_major == 1 && glx_minor < 3) || (glx_major < 1)) - die("[X11]: Error: Invalid GLX version!\n"); - } - { - /* find and pick matching framebuffer visual */ - int fb_count; - static GLint attr[] = { - GLX_X_RENDERABLE, True, - GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, - GLX_RENDER_TYPE, GLX_RGBA_BIT, - GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, - GLX_RED_SIZE, 8, - GLX_GREEN_SIZE, 8, - GLX_BLUE_SIZE, 8, - GLX_ALPHA_SIZE, 8, - GLX_DEPTH_SIZE, 24, - GLX_STENCIL_SIZE, 8, - GLX_DOUBLEBUFFER, True, - None - }; - GLXFBConfig *fbc; - fbc = glXChooseFBConfig(win.dpy, DefaultScreen(win.dpy), attr, &fb_count); - if (!fbc) die("[X11]: Error: failed to retrieve framebuffer configuration\n"); - { - /* pick framebuffer with most samples per pixel */ - int i; - int fb_best = -1, best_num_samples = -1; - for (i = 0; i < fb_count; ++i) { - XVisualInfo *vi = glXGetVisualFromFBConfig(win.dpy, fbc[i]); - if (vi) { - int sample_buffer, samples; - glXGetFBConfigAttrib(win.dpy, fbc[i], GLX_SAMPLE_BUFFERS, &sample_buffer); - glXGetFBConfigAttrib(win.dpy, fbc[i], GLX_SAMPLES, &samples); - if ((fb_best < 0) || (sample_buffer && samples > best_num_samples)) - fb_best = i, best_num_samples = samples; - } - } - win.fbc = fbc[fb_best]; - XFree(fbc); - win.vis = glXGetVisualFromFBConfig(win.dpy, win.fbc); - } - } - { - /* create window */ - win.cmap = XCreateColormap(win.dpy, RootWindow(win.dpy, win.vis->screen), win.vis->visual, AllocNone); - win.swa.colormap = win.cmap; - win.swa.background_pixmap = None; - win.swa.border_pixel = 0; - win.swa.event_mask = - ExposureMask | KeyPressMask | KeyReleaseMask | - ButtonPress | ButtonReleaseMask| ButtonMotionMask | - Button1MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask| - PointerMotionMask| StructureNotifyMask; - win.win = XCreateWindow(win.dpy, RootWindow(win.dpy, win.vis->screen), 0, 0, - WINDOW_WIDTH, WINDOW_HEIGHT, 0, win.vis->depth, InputOutput, - win.vis->visual, CWBorderPixel|CWColormap|CWEventMask, &win.swa); - if (!win.win) die("[X11]: Failed to create window\n"); - XFree(win.vis); - XStoreName(win.dpy, win.win, "Demo"); - XMapWindow(win.dpy, win.win); - win.wm_delete_window = XInternAtom(win.dpy, "WM_DELETE_WINDOW", False); - XSetWMProtocols(win.dpy, win.win, &win.wm_delete_window, 1); - } - { - /* create opengl context */ - typedef GLXContext(*glxCreateContext)(Display*, GLXFBConfig, GLXContext, Bool, const int*); - int(*old_handler)(Display*, XErrorEvent*) = XSetErrorHandler(gl_error_handler); - const char *extensions_str = glXQueryExtensionsString(win.dpy, DefaultScreen(win.dpy)); - glxCreateContext create_context = (glxCreateContext) - glXGetProcAddressARB((const GLubyte*)"glXCreateContextAttribsARB"); - - gl_err = nk_false; - if (!has_extension(extensions_str, "GLX_ARB_create_context") || !create_context) { - fprintf(stdout, "[X11]: glXCreateContextAttribARB() not found...\n"); - fprintf(stdout, "[X11]: ... using old-style GLX context\n"); - glContext = glXCreateNewContext(win.dpy, win.fbc, GLX_RGBA_TYPE, 0, True); - } else { - GLint attr[] = { - GLX_CONTEXT_MAJOR_VERSION_ARB, 3, - GLX_CONTEXT_MINOR_VERSION_ARB, 0, - None - }; - glContext = create_context(win.dpy, win.fbc, 0, True, attr); - XSync(win.dpy, False); - if (gl_err || !glContext) { - /* Could not create GL 3.0 context. Fallback to old 2.x context. - * If a version below 3.0 is requested, implementations will - * return the newest context version compatible with OpenGL - * version less than version 3.0.*/ - attr[1] = 1; attr[3] = 0; - gl_err = nk_false; - fprintf(stdout, "[X11] Failed to create OpenGL 3.0 context\n"); - fprintf(stdout, "[X11] ... using old-style GLX context!\n"); - glContext = create_context(win.dpy, win.fbc, 0, True, attr); - } - } - XSync(win.dpy, False); - XSetErrorHandler(old_handler); - if (gl_err || !glContext) - die("[X11]: Failed to create an OpenGL context\n"); - glXMakeCurrent(win.dpy, win.win, glContext); - } - - ctx = nk_x11_init(win.dpy, win.win); - /* Load Fonts: if none of these are loaded a default font will be used */ - {struct nk_font_atlas *atlas; - nk_x11_font_stash_begin(&atlas); - /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/ - /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 14, 0);*/ - /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/ - /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/ - /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/ - /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/ - nk_x11_font_stash_end(); - /*nk_style_load_all_cursors(ctx, atlas->cursors);*/ - /*nk_style_set_font(ctx, &droid->handle);*/} - - #ifdef INCLUDE_STYLE - /*set_style(ctx, THEME_WHITE);*/ - /*set_style(ctx, THEME_RED);*/ - /*set_style(ctx, THEME_BLUE);*/ - /*set_style(ctx, THEME_DARK);*/ - #endif - - bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f; - while (running) - { - /* Input */ - XEvent evt; - nk_input_begin(ctx); - while (XPending(win.dpy)) { - XNextEvent(win.dpy, &evt); - if (evt.type == ClientMessage) goto cleanup; - if (XFilterEvent(&evt, win.win)) continue; - nk_x11_handle_event(&evt); - } - nk_input_end(ctx); - - /* GUI */ - if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200), - NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE| - NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) - { - enum {EASY, HARD}; - static int op = EASY; - static int property = 20; - - nk_layout_row_static(ctx, 30, 80, 1); - if (nk_button_label(ctx, "button")) - fprintf(stdout, "button pressed\n"); - nk_layout_row_dynamic(ctx, 30, 2); - if (nk_option_label(ctx, "easy", op == EASY)) op = EASY; - if (nk_option_label(ctx, "hard", op == HARD)) op = HARD; - nk_layout_row_dynamic(ctx, 25, 1); - nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1); - - nk_layout_row_dynamic(ctx, 20, 1); - nk_label(ctx, "background:", NK_TEXT_LEFT); - nk_layout_row_dynamic(ctx, 25, 1); - if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) { - nk_layout_row_dynamic(ctx, 120, 1); - bg = nk_color_picker(ctx, bg, NK_RGBA); - nk_layout_row_dynamic(ctx, 25, 1); - bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f); - bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f); - bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f); - bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f); - nk_combo_end(ctx); - } - } - nk_end(ctx); - - /* -------------- EXAMPLES ---------------- */ - #ifdef INCLUDE_CALCULATOR - calculator(ctx); - #endif - #ifdef INCLUDE_OVERVIEW - overview(ctx); - #endif - #ifdef INCLUDE_NODE_EDITOR - node_editor(ctx); - #endif - /* ----------------------------------------- */ - - /* Draw */ - XGetWindowAttributes(win.dpy, win.win, &win.attr); - glViewport(0, 0, win.width, win.height); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(bg.r, bg.g, bg.b, bg.a); - /* IMPORTANT: `nk_x11_render` modifies some global OpenGL state - * with blending, scissor, face culling, depth test and viewport and - * defaults everything back into a default state. - * Make sure to either a.) save and restore or b.) reset your own state after - * rendering the UI. */ - nk_x11_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER); - glXSwapBuffers(win.dpy, win.win); - } - -cleanup: - nk_x11_shutdown(); - glXMakeCurrent(win.dpy, 0, 0); - glXDestroyContext(win.dpy, glContext); - XUnmapWindow(win.dpy, win.win); - XFreeColormap(win.dpy, win.cmap); - XDestroyWindow(win.dpy, win.win); - XCloseDisplay(win.dpy); - return 0; - -} diff --git a/subprojects/nk_pugl/nuklear/demo/x11_opengl3/nuklear_xlib_gl3.h b/subprojects/nk_pugl/nuklear/demo/x11_opengl3/nuklear_xlib_gl3.h deleted file mode 100644 index 487dbc7..0000000 --- a/subprojects/nk_pugl/nuklear/demo/x11_opengl3/nuklear_xlib_gl3.h +++ /dev/null @@ -1,743 +0,0 @@ -/* - * Nuklear - v1.17 - public domain - * no warrenty implied; use at your own risk. - * authored from 2015-2016 by Micha Mettke - */ -/* - * ============================================================== - * - * API - * - * =============================================================== - */ -#ifndef NK_XLIB_GL3_H_ -#define NK_XLIB_GL3_H_ - -#include -NK_API struct nk_context* nk_x11_init(Display *dpy, Window win); -NK_API void nk_x11_font_stash_begin(struct nk_font_atlas **atlas); -NK_API void nk_x11_font_stash_end(void); -NK_API int nk_x11_handle_event(XEvent *evt); -NK_API void nk_x11_render(enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer); -NK_API void nk_x11_shutdown(void); -NK_API int nk_x11_device_create(void); -NK_API void nk_x11_device_destroy(void); - -#endif -/* - * ============================================================== - * - * IMPLEMENTATION - * - * =============================================================== - */ -#ifdef NK_XLIB_GL3_IMPLEMENTATION -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#ifndef NK_X11_DOUBLE_CLICK_LO -#define NK_X11_DOUBLE_CLICK_LO 20 -#endif -#ifndef NK_X11_DOUBLE_CLICK_HI -#define NK_X11_DOUBLE_CLICK_HI 200 -#endif - -#ifdef NK_XLIB_LOAD_OPENGL_EXTENSIONS -#include - -/* GL_ARB_vertex_buffer_object */ -typedef void(*nkglGenBuffers)(GLsizei, GLuint*); -typedef void(*nkglBindBuffer)(GLenum, GLuint); -typedef void(*nkglBufferData)(GLenum, GLsizeiptr, const GLvoid*, GLenum); -typedef void(*nkglBufferSubData)(GLenum, GLintptr, GLsizeiptr, const GLvoid*); -typedef void*(*nkglMapBuffer)(GLenum, GLenum); -typedef GLboolean(*nkglUnmapBuffer)(GLenum); -typedef void(*nkglDeleteBuffers)(GLsizei, GLuint*); -/* GL_ARB_vertex_array_object */ -typedef void (*nkglGenVertexArrays)(GLsizei, GLuint*); -typedef void (*nkglBindVertexArray)(GLuint); -typedef void (*nkglDeleteVertexArrays)(GLsizei, const GLuint*); -/* GL_ARB_vertex_program / GL_ARB_fragment_program */ -typedef void(*nkglVertexAttribPointer)(GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid*); -typedef void(*nkglEnableVertexAttribArray)(GLuint); -typedef void(*nkglDisableVertexAttribArray)(GLuint); -/* GL_ARB_framebuffer_object */ -typedef void(*nkglGenerateMipmap)(GLenum target); -/* GLSL/OpenGL 2.0 core */ -typedef GLuint(*nkglCreateShader)(GLenum); -typedef void(*nkglShaderSource)(GLuint, GLsizei, const GLchar**, const GLint*); -typedef void(*nkglCompileShader)(GLuint); -typedef void(*nkglGetShaderiv)(GLuint, GLenum, GLint*); -typedef void(*nkglGetShaderInfoLog)(GLuint, GLsizei, GLsizei*, GLchar*); -typedef void(*nkglDeleteShader)(GLuint); -typedef GLuint(*nkglCreateProgram)(void); -typedef void(*nkglAttachShader)(GLuint, GLuint); -typedef void(*nkglDetachShader)(GLuint, GLuint); -typedef void(*nkglLinkProgram)(GLuint); -typedef void(*nkglUseProgram)(GLuint); -typedef void(*nkglGetProgramiv)(GLuint, GLenum, GLint*); -typedef void(*nkglGetProgramInfoLog)(GLuint, GLsizei, GLsizei*, GLchar*); -typedef void(*nkglDeleteProgram)(GLuint); -typedef GLint(*nkglGetUniformLocation)(GLuint, const GLchar*); -typedef GLint(*nkglGetAttribLocation)(GLuint, const GLchar*); -typedef void(*nkglUniform1i)(GLint, GLint); -typedef void(*nkglUniform1f)(GLint, GLfloat); -typedef void(*nkglUniformMatrix3fv)(GLint, GLsizei, GLboolean, const GLfloat*); -typedef void(*nkglUniformMatrix4fv)(GLint, GLsizei, GLboolean, const GLfloat*); - -static nkglGenBuffers glGenBuffers; -static nkglBindBuffer glBindBuffer; -static nkglBufferData glBufferData; -static nkglBufferSubData glBufferSubData; -static nkglMapBuffer glMapBuffer; -static nkglUnmapBuffer glUnmapBuffer; -static nkglDeleteBuffers glDeleteBuffers; -static nkglGenVertexArrays glGenVertexArrays; -static nkglBindVertexArray glBindVertexArray; -static nkglDeleteVertexArrays glDeleteVertexArrays; -static nkglVertexAttribPointer glVertexAttribPointer; -static nkglEnableVertexAttribArray glEnableVertexAttribArray; -static nkglDisableVertexAttribArray glDisableVertexAttribArray; -static nkglGenerateMipmap glGenerateMipmap; -static nkglCreateShader glCreateShader; -static nkglShaderSource glShaderSource; -static nkglCompileShader glCompileShader; -static nkglGetShaderiv glGetShaderiv; -static nkglGetShaderInfoLog glGetShaderInfoLog; -static nkglDeleteShader glDeleteShader; -static nkglCreateProgram glCreateProgram; -static nkglAttachShader glAttachShader; -static nkglDetachShader glDetachShader; -static nkglLinkProgram glLinkProgram; -static nkglUseProgram glUseProgram; -static nkglGetProgramiv glGetProgramiv; -static nkglGetProgramInfoLog glGetProgramInfoLog; -static nkglDeleteProgram glDeleteProgram; -static nkglGetUniformLocation glGetUniformLocation; -static nkglGetAttribLocation glGetAttribLocation; -static nkglUniform1i glUniform1i; -static nkglUniform1f glUniform1f; -static nkglUniformMatrix3fv glUniformMatrix3fv; -static nkglUniformMatrix4fv glUniformMatrix4fv; - -enum graphics_card_vendors { - VENDOR_UNKNOWN, - VENDOR_NVIDIA, - VENDOR_AMD, - VENDOR_INTEL -}; - -struct opengl_info { - /* info */ - const char *vendor_str; - const char *version_str; - const char *extensions_str; - const char *renderer_str; - const char *glsl_version_str; - enum graphics_card_vendors vendor; - /* version */ - float version; - int major_version; - int minor_version; - /* extensions */ - int glsl_available; - int vertex_buffer_obj_available; - int vertex_array_obj_available; - int map_buffer_range_available; - int fragment_program_available; - int frame_buffer_object_available; -}; -#endif - -struct nk_x11_vertex { - float position[2]; - float uv[2]; - nk_byte col[4]; -}; - -struct nk_x11_device { -#ifdef NK_XLIB_LOAD_OPENGL_EXTENSIONS - struct opengl_info info; -#endif - struct nk_buffer cmds; - struct nk_draw_null_texture null; - GLuint vbo, vao, ebo; - GLuint prog; - GLuint vert_shdr; - GLuint frag_shdr; - GLint attrib_pos; - GLint attrib_uv; - GLint attrib_col; - GLint uniform_tex; - GLint uniform_proj; - GLuint font_tex; -}; - -static struct nk_x11 { - struct nk_x11_device ogl; - struct nk_context ctx; - struct nk_font_atlas atlas; - Cursor cursor; - Display *dpy; - Window win; - long last_button_click; -} x11; - -#ifdef __APPLE__ - #define NK_SHADER_VERSION "#version 150\n" -#else - #define NK_SHADER_VERSION "#version 300 es\n" -#endif - -#ifdef NK_XLIB_LOAD_OPENGL_EXTENSIONS -#include - -NK_INTERN long -nk_timestamp(void) -{ - struct timeval tv; - if (gettimeofday(&tv, NULL) < 0) return 0; - return (long)((long)tv.tv_sec * 1000 + (long)tv.tv_usec/1000); -} - -NK_INTERN int -nk_x11_stricmpn(const char *a, const char *b, int len) -{ - int i = 0; - for (i = 0; i < len && a[i] && b[i]; ++i) - if (a[i] != b[i]) return 1; - if (i != len) return 1; - return 0; -} - -NK_INTERN int -nk_x11_check_extension(struct opengl_info *GL, const char *ext) -{ - const char *start, *where, *term; - where = strchr(ext, ' '); - if (where || *ext == '\0') - return nk_false; - - for (start = GL->extensions_str;;) { - where = strstr((const char*)start, ext); - if (!where) break; - term = where + strlen(ext); - if (where == start || *(where - 1) == ' ') { - if (*term == ' ' || *term == '\0') - return nk_true; - } - start = term; - } - return nk_false; -} - -#define GL_EXT(name) (nk##name)nk_gl_ext(#name) -NK_INTERN __GLXextFuncPtr -nk_gl_ext(const char *name) -{ - __GLXextFuncPtr func; - func = glXGetProcAddress((const GLubyte*)name); - if (!func) { - fprintf(stdout, "[GL]: failed to load extension: %s", name); - return NULL; - } - return func; -} - -NK_INTERN int -nk_load_opengl(struct opengl_info *gl) -{ - int failed = nk_false; - gl->version_str = (const char*)glGetString(GL_VERSION); - glGetIntegerv(GL_MAJOR_VERSION, &gl->major_version); - glGetIntegerv(GL_MINOR_VERSION, &gl->minor_version); - if (gl->major_version < 2) { - fprintf(stderr, "[GL]: Graphics card does not fullfill minimum OpenGL 2.0 support\n"); - return 0; - } - gl->version = (float)gl->major_version + (float)gl->minor_version * 0.1f; - gl->renderer_str = (const char*)glGetString(GL_RENDERER); - gl->extensions_str = (const char*)glGetString(GL_EXTENSIONS); - gl->glsl_version_str = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION); - gl->vendor_str = (const char*)glGetString(GL_VENDOR); - if (!nk_x11_stricmpn(gl->vendor_str, "ATI", 4) || - !nk_x11_stricmpn(gl->vendor_str, "AMD", 4)) - gl->vendor = VENDOR_AMD; - else if (!nk_x11_stricmpn(gl->vendor_str, "NVIDIA", 6)) - gl->vendor = VENDOR_NVIDIA; - else if (!nk_x11_stricmpn(gl->vendor_str, "Intel", 5)) - gl->vendor = VENDOR_INTEL; - else gl->vendor = VENDOR_UNKNOWN; - - /* Extensions */ - gl->glsl_available = (gl->version >= 2.0f); - if (gl->glsl_available) { - /* GLSL core in OpenGL > 2 */ - glCreateShader = GL_EXT(glCreateShader); - glShaderSource = GL_EXT(glShaderSource); - glCompileShader = GL_EXT(glCompileShader); - glGetShaderiv = GL_EXT(glGetShaderiv); - glGetShaderInfoLog = GL_EXT(glGetShaderInfoLog); - glDeleteShader = GL_EXT(glDeleteShader); - glCreateProgram = GL_EXT(glCreateProgram); - glAttachShader = GL_EXT(glAttachShader); - glDetachShader = GL_EXT(glDetachShader); - glLinkProgram = GL_EXT(glLinkProgram); - glUseProgram = GL_EXT(glUseProgram); - glGetProgramiv = GL_EXT(glGetProgramiv); - glGetProgramInfoLog = GL_EXT(glGetProgramInfoLog); - glDeleteProgram = GL_EXT(glDeleteProgram); - glGetUniformLocation = GL_EXT(glGetUniformLocation); - glGetAttribLocation = GL_EXT(glGetAttribLocation); - glUniform1i = GL_EXT(glUniform1i); - glUniform1f = GL_EXT(glUniform1f); - glUniformMatrix3fv = GL_EXT(glUniformMatrix3fv); - glUniformMatrix4fv = GL_EXT(glUniformMatrix4fv); - } - gl->vertex_buffer_obj_available = nk_x11_check_extension(gl, "GL_ARB_vertex_buffer_object"); - if (gl->vertex_buffer_obj_available) { - /* GL_ARB_vertex_buffer_object */ - glGenBuffers = GL_EXT(glGenBuffers); - glBindBuffer = GL_EXT(glBindBuffer); - glBufferData = GL_EXT(glBufferData); - glBufferSubData = GL_EXT(glBufferSubData); - glMapBuffer = GL_EXT(glMapBuffer); - glUnmapBuffer = GL_EXT(glUnmapBuffer); - glDeleteBuffers = GL_EXT(glDeleteBuffers); - } - gl->fragment_program_available = nk_x11_check_extension(gl, "GL_ARB_fragment_program"); - if (gl->fragment_program_available) { - /* GL_ARB_vertex_program / GL_ARB_fragment_program */ - glVertexAttribPointer = GL_EXT(glVertexAttribPointer); - glEnableVertexAttribArray = GL_EXT(glEnableVertexAttribArray); - glDisableVertexAttribArray = GL_EXT(glDisableVertexAttribArray); - } - gl->vertex_array_obj_available = nk_x11_check_extension(gl, "GL_ARB_vertex_array_object"); - if (gl->vertex_array_obj_available) { - /* GL_ARB_vertex_array_object */ - glGenVertexArrays = GL_EXT(glGenVertexArrays); - glBindVertexArray = GL_EXT(glBindVertexArray); - glDeleteVertexArrays = GL_EXT(glDeleteVertexArrays); - } - gl->frame_buffer_object_available = nk_x11_check_extension(gl, "GL_ARB_framebuffer_object"); - if (gl->frame_buffer_object_available) { - /* GL_ARB_framebuffer_object */ - glGenerateMipmap = GL_EXT(glGenerateMipmap); - } - if (!gl->vertex_buffer_obj_available) { - fprintf(stdout, "[GL] Error: GL_ARB_vertex_buffer_object is not available!\n"); - failed = nk_true; - } - if (!gl->fragment_program_available) { - fprintf(stdout, "[GL] Error: GL_ARB_fragment_program is not available!\n"); - failed = nk_true; - } - if (!gl->vertex_array_obj_available) { - fprintf(stdout, "[GL] Error: GL_ARB_vertex_array_object is not available!\n"); - failed = nk_true; - } - if (!gl->frame_buffer_object_available) { - fprintf(stdout, "[GL] Error: GL_ARB_framebuffer_object is not available!\n"); - failed = nk_true; - } - return !failed; -} -#endif - -NK_API int -nk_x11_device_create(void) -{ - GLint status; - static const GLchar *vertex_shader = - NK_SHADER_VERSION - "uniform mat4 ProjMtx;\n" - "in vec2 Position;\n" - "in vec2 TexCoord;\n" - "in vec4 Color;\n" - "out vec2 Frag_UV;\n" - "out vec4 Frag_Color;\n" - "void main() {\n" - " Frag_UV = TexCoord;\n" - " Frag_Color = Color;\n" - " gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n" - "}\n"; - static const GLchar *fragment_shader = - NK_SHADER_VERSION - "precision mediump float;\n" - "uniform sampler2D Texture;\n" - "in vec2 Frag_UV;\n" - "in vec4 Frag_Color;\n" - "out vec4 Out_Color;\n" - "void main(){\n" - " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" - "}\n"; - - struct nk_x11_device *dev = &x11.ogl; -#ifdef NK_XLIB_LOAD_OPENGL_EXTENSIONS - if (!nk_load_opengl(&dev->info)) return 0; -#endif - nk_buffer_init_default(&dev->cmds); - - dev->prog = glCreateProgram(); - dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER); - dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0); - glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0); - glCompileShader(dev->vert_shdr); - glCompileShader(dev->frag_shdr); - glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status); - assert(status == GL_TRUE); - glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status); - assert(status == GL_TRUE); - glAttachShader(dev->prog, dev->vert_shdr); - glAttachShader(dev->prog, dev->frag_shdr); - glLinkProgram(dev->prog); - glGetProgramiv(dev->prog, GL_LINK_STATUS, &status); - assert(status == GL_TRUE); - - dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture"); - dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx"); - dev->attrib_pos = glGetAttribLocation(dev->prog, "Position"); - dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord"); - dev->attrib_col = glGetAttribLocation(dev->prog, "Color"); - - { - /* buffer setup */ - GLsizei vs = sizeof(struct nk_x11_vertex); - size_t vp = offsetof(struct nk_x11_vertex, position); - size_t vt = offsetof(struct nk_x11_vertex, uv); - size_t vc = offsetof(struct nk_x11_vertex, col); - - glGenBuffers(1, &dev->vbo); - glGenBuffers(1, &dev->ebo); - glGenVertexArrays(1, &dev->vao); - - glBindVertexArray(dev->vao); - glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); - - glEnableVertexAttribArray((GLuint)dev->attrib_pos); - glEnableVertexAttribArray((GLuint)dev->attrib_uv); - glEnableVertexAttribArray((GLuint)dev->attrib_col); - - glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp); - glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt); - glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc); - } - - glBindTexture(GL_TEXTURE_2D, 0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindVertexArray(0); - return 1; -} - -NK_INTERN void -nk_x11_device_upload_atlas(const void *image, int width, int height) -{ - struct nk_x11_device *dev = &x11.ogl; - glGenTextures(1, &dev->font_tex); - glBindTexture(GL_TEXTURE_2D, dev->font_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, image); -} - -NK_API void -nk_x11_device_destroy(void) -{ - struct nk_x11_device *dev = &x11.ogl; - glDetachShader(dev->prog, dev->vert_shdr); - glDetachShader(dev->prog, dev->frag_shdr); - glDeleteShader(dev->vert_shdr); - glDeleteShader(dev->frag_shdr); - glDeleteProgram(dev->prog); - glDeleteTextures(1, &dev->font_tex); - glDeleteBuffers(1, &dev->vbo); - glDeleteBuffers(1, &dev->ebo); - nk_buffer_free(&dev->cmds); -} - -NK_API void -nk_x11_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer) -{ - int width, height; - XWindowAttributes attr; - struct nk_x11_device *dev = &x11.ogl; - GLfloat ortho[4][4] = { - {2.0f, 0.0f, 0.0f, 0.0f}, - {0.0f,-2.0f, 0.0f, 0.0f}, - {0.0f, 0.0f,-1.0f, 0.0f}, - {-1.0f,1.0f, 0.0f, 1.0f}, - }; - XGetWindowAttributes(x11.dpy, x11.win, &attr); - width = attr.width; - height = attr.height; - - ortho[0][0] /= (GLfloat)width; - ortho[1][1] /= (GLfloat)height; - - /* setup global state */ - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glEnable(GL_SCISSOR_TEST); - glActiveTexture(GL_TEXTURE0); - - /* setup program */ - glUseProgram(dev->prog); - glUniform1i(dev->uniform_tex, 0); - glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]); - glViewport(0,0,(GLsizei)width,(GLsizei)height); - { - /* convert from command queue into draw list and draw to screen */ - const struct nk_draw_command *cmd; - void *vertices, *elements; - const nk_draw_index *offset = NULL; - struct nk_buffer vbuf, ebuf; - - /* allocate vertex and element buffer */ - glBindVertexArray(dev->vao); - glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); - - glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW); - - /* load draw vertices & elements directly into vertex + element buffer */ - vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); - elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY); - { - /* fill convert configuration */ - struct nk_convert_config config; - static const struct nk_draw_vertex_layout_element vertex_layout[] = { - {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_x11_vertex, position)}, - {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_x11_vertex, uv)}, - {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_x11_vertex, col)}, - {NK_VERTEX_LAYOUT_END} - }; - NK_MEMSET(&config, 0, sizeof(config)); - config.vertex_layout = vertex_layout; - config.vertex_size = sizeof(struct nk_x11_vertex); - config.vertex_alignment = NK_ALIGNOF(struct nk_x11_vertex); - config.null = dev->null; - config.circle_segment_count = 22; - config.curve_segment_count = 22; - config.arc_segment_count = 22; - config.global_alpha = 1.0f; - config.shape_AA = AA; - config.line_AA = AA; - - /* setup buffers to load vertices and elements */ - nk_buffer_init_fixed(&vbuf, vertices, (size_t)max_vertex_buffer); - nk_buffer_init_fixed(&ebuf, elements, (size_t)max_element_buffer); - nk_convert(&x11.ctx, &dev->cmds, &vbuf, &ebuf, &config); - } - glUnmapBuffer(GL_ARRAY_BUFFER); - glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); - - /* iterate over and execute each draw command */ - nk_draw_foreach(cmd, &x11.ctx, &dev->cmds) - { - if (!cmd->elem_count) continue; - glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); - glScissor( - (GLint)(cmd->clip_rect.x), - (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h))), - (GLint)(cmd->clip_rect.w), - (GLint)(cmd->clip_rect.h)); - glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); - offset += cmd->elem_count; - } - nk_clear(&x11.ctx); - } - - /* default OpenGL state */ - glUseProgram(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindVertexArray(0); - glDisable(GL_BLEND); - glDisable(GL_SCISSOR_TEST); -} - -NK_API void -nk_x11_font_stash_begin(struct nk_font_atlas **atlas) -{ - nk_font_atlas_init_default(&x11.atlas); - nk_font_atlas_begin(&x11.atlas); - *atlas = &x11.atlas; -} - -NK_API void -nk_x11_font_stash_end(void) -{ - const void *image; int w, h; - image = nk_font_atlas_bake(&x11.atlas, &w, &h, NK_FONT_ATLAS_RGBA32); - nk_x11_device_upload_atlas(image, w, h); - nk_font_atlas_end(&x11.atlas, nk_handle_id((int)x11.ogl.font_tex), &x11.ogl.null); - if (x11.atlas.default_font) - nk_style_set_font(&x11.ctx, &x11.atlas.default_font->handle); -} - -NK_API int -nk_x11_handle_event(XEvent *evt) -{ - struct nk_context *ctx = &x11.ctx; - - /* optional grabbing behavior */ - if (ctx->input.mouse.grab) { - XDefineCursor(x11.dpy, x11.win, x11.cursor); - ctx->input.mouse.grab = 0; - } else if (ctx->input.mouse.ungrab) { - XWarpPointer(x11.dpy, None, x11.win, 0, 0, 0, 0, - (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y); - XUndefineCursor(x11.dpy, x11.win); - ctx->input.mouse.ungrab = 0; - } - - if (evt->type == KeyPress || evt->type == KeyRelease) - { - /* Key handler */ - int ret, down = (evt->type == KeyPress); - KeySym *code = XGetKeyboardMapping(x11.dpy, (KeyCode)evt->xkey.keycode, 1, &ret); - if (*code == XK_Shift_L || *code == XK_Shift_R) nk_input_key(ctx, NK_KEY_SHIFT, down); - else if (*code == XK_Delete) nk_input_key(ctx, NK_KEY_DEL, down); - else if (*code == XK_Return) nk_input_key(ctx, NK_KEY_ENTER, down); - else if (*code == XK_Tab) nk_input_key(ctx, NK_KEY_TAB, down); - else if (*code == XK_Left) nk_input_key(ctx, NK_KEY_LEFT, down); - else if (*code == XK_Right) nk_input_key(ctx, NK_KEY_RIGHT, down); - else if (*code == XK_Up) nk_input_key(ctx, NK_KEY_UP, down); - else if (*code == XK_Down) nk_input_key(ctx, NK_KEY_DOWN, down); - else if (*code == XK_BackSpace) nk_input_key(ctx, NK_KEY_BACKSPACE, down); - else if (*code == XK_space && !down) nk_input_char(ctx, ' '); - else if (*code == XK_Page_Up) nk_input_key(ctx, NK_KEY_SCROLL_UP, down); - else if (*code == XK_Page_Down) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down); - else if (*code == XK_Home) { - nk_input_key(ctx, NK_KEY_TEXT_START, down); - nk_input_key(ctx, NK_KEY_SCROLL_START, down); - } else if (*code == XK_End) { - nk_input_key(ctx, NK_KEY_TEXT_END, down); - nk_input_key(ctx, NK_KEY_SCROLL_END, down); - } else { - if (*code == 'c' && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_COPY, down); - else if (*code == 'v' && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_PASTE, down); - else if (*code == 'x' && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_CUT, down); - else if (*code == 'z' && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_TEXT_UNDO, down); - else if (*code == 'r' && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_TEXT_REDO, down); - else if (*code == XK_Left && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down); - else if (*code == XK_Right && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down); - else if (*code == 'b' && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down); - else if (*code == 'e' && (evt->xkey.state & ControlMask)) - nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down); - else { - if (*code == 'i') - nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, down); - else if (*code == 'r') - nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, down); - if (down) { - char buf[32]; - KeySym keysym = 0; - if (XLookupString((XKeyEvent*)evt, buf, 32, &keysym, NULL) != NoSymbol) - nk_input_glyph(ctx, buf); - } - } - } - XFree(code); - return 1; - } else if (evt->type == ButtonPress || evt->type == ButtonRelease) { - /* Button handler */ - int down = (evt->type == ButtonPress); - const int x = evt->xbutton.x, y = evt->xbutton.y; - if (evt->xbutton.button == Button1) { - if (down) { /* Double-Click Button handler */ - long dt = nk_timestamp() - x11.last_button_click; - if (dt > NK_X11_DOUBLE_CLICK_LO && dt < NK_X11_DOUBLE_CLICK_HI) - nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_true); - x11.last_button_click = nk_timestamp(); - } else nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_false); - nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down); - } else if (evt->xbutton.button == Button2) - nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down); - else if (evt->xbutton.button == Button3) - nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down); - else if (evt->xbutton.button == Button4) - nk_input_scroll(ctx, nk_vec2(0,1.0f)); - else if (evt->xbutton.button == Button5) - nk_input_scroll(ctx, nk_vec2(0,-1.0f)); - else return 0; - return 1; - } else if (evt->type == MotionNotify) { - /* Mouse motion handler */ - const int x = evt->xmotion.x, y = evt->xmotion.y; - nk_input_motion(ctx, x, y); - if (ctx->input.mouse.grabbed) { - ctx->input.mouse.pos.x = ctx->input.mouse.prev.x; - ctx->input.mouse.pos.y = ctx->input.mouse.prev.y; - XWarpPointer(x11.dpy, None, x11.win, 0, 0, 0, 0, (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y); - } - return 1; - } else if (evt->type == KeymapNotify) { - XRefreshKeyboardMapping(&evt->xmapping); - return 1; - } - return 0; -} - -NK_API struct nk_context* -nk_x11_init(Display *dpy, Window win) -{ - if (!setlocale(LC_ALL,"")) return 0; - if (!XSupportsLocale()) return 0; - if (!XSetLocaleModifiers("@im=none")) return 0; - if (!nk_x11_device_create()) return 0; - - x11.dpy = dpy; - x11.win = win; - - /* create invisible cursor */ - {static XColor dummy; char data[1] = {0}; - Pixmap blank = XCreateBitmapFromData(dpy, win, data, 1, 1); - if (blank == None) return 0; - x11.cursor = XCreatePixmapCursor(dpy, blank, blank, &dummy, &dummy, 0, 0); - XFreePixmap(dpy, blank);} - - nk_init_default(&x11.ctx, 0); - return &x11.ctx; -} - -NK_API void -nk_x11_shutdown(void) -{ - nk_font_atlas_clear(&x11.atlas); - nk_free(&x11.ctx); - nk_x11_device_destroy(); - XFreeCursor(x11.dpy, x11.cursor); - memset(&x11, 0, sizeof(x11)); -} - -#endif diff --git a/subprojects/nk_pugl/nuklear/demo/x11_rawfb/Makefile b/subprojects/nk_pugl/nuklear/demo/x11_rawfb/Makefile deleted file mode 100644 index c1a178a..0000000 --- a/subprojects/nk_pugl/nuklear/demo/x11_rawfb/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# Install -BIN = zahnrad - -# Flags -CFLAGS += -std=c89 -pedantic -O2 -Wunused -DRAWFB_XRGB_8888 - -SRC = main.c -OBJ = $(SRC:.c=.o) - -$(BIN): - @mkdir -p bin - rm -f bin/$(BIN) $(OBJS) - $(CC) $(SRC) $(CFLAGS) -D_GNU_SOURCE -D_POSIX_C_SOURCE=200809L -o bin/$(BIN) -lX11 -lXext -lm diff --git a/subprojects/nk_pugl/nuklear/demo/x11_rawfb/main.c b/subprojects/nk_pugl/nuklear/demo/x11_rawfb/main.c deleted file mode 100644 index c70b024..0000000 --- a/subprojects/nk_pugl/nuklear/demo/x11_rawfb/main.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2016-2017 Patrick Rudolph - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Based on x11/main.c. - * -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define RAWFB_RGBX_8888 -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_STANDARD_VARARGS -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_IMPLEMENTATION -#define NK_XLIBSHM_IMPLEMENTATION -#define NK_RAWFB_IMPLEMENTATION -#define NK_INCLUDE_FONT_BAKING -#define NK_INCLUDE_DEFAULT_FONT -#define NK_INCLUDE_SOFTWARE_FONT - -#include "../../nuklear.h" -#include "nuklear_rawfb.h" -#include "nuklear_xlib.h" - -#define DTIME 20 -#define WINDOW_WIDTH 800 -#define WINDOW_HEIGHT 600 - -#define UNUSED(a) (void)a -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#define MAX(a,b) ((a) < (b) ? (b) : (a)) -#define LEN(a) (sizeof(a)/sizeof(a)[0]) - -typedef struct XWindow XWindow; -struct XWindow { - Display *dpy; - Window root; - Visual *vis; - Colormap cmap; - XWindowAttributes attr; - XSetWindowAttributes swa; - Window win; - int screen; - unsigned int width; - unsigned int height; -}; - -static void -die(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fputs("\n", stderr); - exit(EXIT_FAILURE); -} - -static long -timestamp(void) -{ - struct timeval tv; - if (gettimeofday(&tv, NULL) < 0) return 0; - return (long)((long)tv.tv_sec * 1000 + (long)tv.tv_usec/1000); -} - -static void -sleep_for(long t) -{ - struct timespec req; - const time_t sec = (int)(t/1000); - const long ms = t - (sec * 1000); - req.tv_sec = sec; - req.tv_nsec = ms * 1000000L; - while(-1 == nanosleep(&req, &req)); -} - -/* =============================================================== - * - * EXAMPLE - * - * ===============================================================*/ -/* This are some code examples to provide a small overview of what can be - * done with this library. To try out an example uncomment the defines */ -/*#define INCLUDE_ALL */ -/*#define INCLUDE_STYLE */ -/*#define INCLUDE_CALCULATOR */ -/*#define INCLUDE_OVERVIEW */ -/*#define INCLUDE_NODE_EDITOR */ - -#ifdef INCLUDE_ALL - #define INCLUDE_STYLE - #define INCLUDE_CALCULATOR - #define INCLUDE_OVERVIEW - #define INCLUDE_NODE_EDITOR -#endif - -#ifdef INCLUDE_STYLE - #include "../style.c" -#endif -#ifdef INCLUDE_CALCULATOR - #include "../calculator.c" -#endif -#ifdef INCLUDE_OVERVIEW - #include "../overview.c" -#endif -#ifdef INCLUDE_NODE_EDITOR - #include "../node_editor.c" -#endif - -/* =============================================================== - * - * DEMO - * - * ===============================================================*/ -int -main(void) -{ - long dt; - long started; - int running = 1; - int status; - XWindow xw; - struct rawfb_context *rawfb; - void *fb = NULL; - unsigned char tex_scratch[512 * 512]; - - /* X11 */ - memset(&xw, 0, sizeof xw); - xw.dpy = XOpenDisplay(NULL); - if (!xw.dpy) die("Could not open a display; perhaps $DISPLAY is not set?"); - - xw.root = DefaultRootWindow(xw.dpy); - xw.screen = XDefaultScreen(xw.dpy); - xw.vis = XDefaultVisual(xw.dpy, xw.screen); - xw.cmap = XCreateColormap(xw.dpy,xw.root,xw.vis,AllocNone); - xw.swa.colormap = xw.cmap; - xw.swa.event_mask = - ExposureMask | KeyPressMask | KeyReleaseMask | - ButtonPress | ButtonReleaseMask| ButtonMotionMask | - Button1MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask| - PointerMotionMask | KeymapStateMask | EnterWindowMask | LeaveWindowMask; - xw.win = XCreateWindow(xw.dpy, xw.root, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, - XDefaultDepth(xw.dpy, xw.screen), InputOutput, - xw.vis, CWEventMask | CWColormap, &xw.swa); - - XStoreName(xw.dpy, xw.win, "X11"); - XMapWindow(xw.dpy, xw.win); - XGetWindowAttributes(xw.dpy, xw.win, &xw.attr); - xw.width = (unsigned int)xw.attr.width; - xw.height = (unsigned int)xw.attr.height; - - /* Framebuffer emulator */ - status = nk_xlib_init(xw.dpy, xw.vis, xw.screen, xw.win, xw.width, xw.height, &fb); - if (!status || !fb) - return 0; - - /* GUI */ - rawfb = nk_rawfb_init(fb, tex_scratch, xw.width, xw.height, xw.width * 4); - if (!rawfb) running = 0; - - #ifdef INCLUDE_STYLE - /*set_style(ctx, THEME_WHITE);*/ - /*set_style(ctx, THEME_RED);*/ - /*set_style(ctx, THEME_BLUE);*/ - /*set_style(ctx, THEME_DARK);*/ - #endif - - while (running) { - /* Input */ - XEvent evt; - started = timestamp(); - nk_input_begin(&rawfb->ctx); - while (XCheckWindowEvent(xw.dpy, xw.win, xw.swa.event_mask, &evt)) { - if (XFilterEvent(&evt, xw.win)) continue; - nk_xlib_handle_event(xw.dpy, xw.screen, xw.win, &evt, rawfb); - } - nk_input_end(&rawfb->ctx); - - /* GUI */ - if (nk_begin(&rawfb->ctx, "Demo", nk_rect(50, 50, 200, 200), - NK_WINDOW_BORDER|NK_WINDOW_MOVABLE| - NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) { - enum {EASY, HARD}; - static int op = EASY; - static int property = 20; - - nk_layout_row_static(&rawfb->ctx, 30, 80, 1); - if (nk_button_label(&rawfb->ctx, "button")) - fprintf(stdout, "button pressed\n"); - nk_layout_row_dynamic(&rawfb->ctx, 30, 2); - if (nk_option_label(&rawfb->ctx, "easy", op == EASY)) op = EASY; - if (nk_option_label(&rawfb->ctx, "hard", op == HARD)) op = HARD; - nk_layout_row_dynamic(&rawfb->ctx, 25, 1); - nk_property_int(&rawfb->ctx, "Compression:", 0, &property, 100, 10, 1); - } - nk_end(&rawfb->ctx); - if (nk_window_is_closed(&rawfb->ctx, "Demo")) break; - - /* -------------- EXAMPLES ---------------- */ - #ifdef INCLUDE_CALCULATOR - calculator(ctx); - #endif - #ifdef INCLUDE_OVERVIEW - overview(ctx); - #endif - #ifdef INCLUDE_NODE_EDITOR - node_editor(ctx); - #endif - /* ----------------------------------------- */ - - /* Draw framebuffer */ - nk_rawfb_render(rawfb, nk_rgb(30,30,30), 1); - - /* Emulate framebuffer */ - XClearWindow(xw.dpy, xw.win); - nk_xlib_render(xw.win); - XFlush(xw.dpy); - - /* Timing */ - dt = timestamp() - started; - if (dt < DTIME) - sleep_for(DTIME - dt); - } - - nk_rawfb_shutdown(rawfb); - nk_xlib_shutdown(); - XUnmapWindow(xw.dpy, xw.win); - XFreeColormap(xw.dpy, xw.cmap); - XDestroyWindow(xw.dpy, xw.win); - XCloseDisplay(xw.dpy); - return 0; -} - diff --git a/subprojects/nk_pugl/nuklear/demo/x11_rawfb/nuklear_rawfb.h b/subprojects/nk_pugl/nuklear/demo/x11_rawfb/nuklear_rawfb.h deleted file mode 100644 index e518780..0000000 --- a/subprojects/nk_pugl/nuklear/demo/x11_rawfb/nuklear_rawfb.h +++ /dev/null @@ -1,986 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2016-2017 Patrick Rudolph - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. -*/ -/* - * ============================================================== - * - * API - * - * =============================================================== - */ -#ifndef NK_RAWFB_H_ -#define NK_RAWFB_H_ - -struct rawfb_context; - -/* All functions are thread-safe */ -NK_API struct rawfb_context *nk_rawfb_init(void *fb, void *tex_mem, const unsigned int w, const unsigned int h, const unsigned int pitch); -NK_API void nk_rawfb_render(const struct rawfb_context *rawfb, const struct nk_color clear, const unsigned char enable_clear); -NK_API void nk_rawfb_shutdown(struct rawfb_context *rawfb); -NK_API void nk_rawfb_resize_fb(struct rawfb_context *rawfb, void *fb, const unsigned int w, const unsigned int h, const unsigned int pitch); - -#endif -/* - * ============================================================== - * - * IMPLEMENTATION - * - * =============================================================== - */ -#ifdef NK_RAWFB_IMPLEMENTATION - -struct rawfb_image { - void *pixels; - int w, h, pitch; - enum nk_font_atlas_format format; -}; -struct rawfb_context { - struct nk_context ctx; - struct nk_rect scissors; - struct rawfb_image fb; - struct rawfb_image font_tex; - struct nk_font_atlas atlas; -}; - -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif -#ifndef MAX -#define MAX(a,b) ((a) < (b) ? (b) : (a)) -#endif - -static unsigned int -nk_color_from_byte(const nk_byte *c) -{ - unsigned int res = 0; -#if defined(RAWFB_RGBX_8888) - res |= (unsigned int)c[0] << 16; - res |= (unsigned int)c[1] << 8; - res |= (unsigned int)c[2] << 0; -#elif defined(RAWFB_XRGB_8888) - res = ((unsigned int *)c)[0]; -#else -#error Define one of RAWFB_RGBX_8888 , RAWFB_XRGB_8888 -#endif - return (res); -} - -static void -nk_rawfb_setpixel(const struct rawfb_context *rawfb, - const short x0, const short y0, const struct nk_color col) -{ - unsigned int c = nk_color_from_byte(&col.r); - unsigned char *pixels = rawfb->fb.pixels; - unsigned int *ptr; - - pixels += y0 * rawfb->fb.pitch; - ptr = (unsigned int *)pixels; - ptr += x0; - - if (y0 < rawfb->scissors.h && y0 >= rawfb->scissors.y && - x0 >= rawfb->scissors.x && x0 < rawfb->scissors.w) - *ptr = c; -} - -static void -nk_rawfb_line_horizontal(const struct rawfb_context *rawfb, - const short x0, const short y, const short x1, const struct nk_color col) -{ - /* This function is called the most. Try to optimize it a bit... - * It does not check for scissors or image borders. - * The caller has to make sure it does no exceed bounds. */ - unsigned int i, n; - unsigned int c[16]; - unsigned char *pixels = rawfb->fb.pixels; - unsigned int *ptr; - - pixels += y * rawfb->fb.pitch; - ptr = (unsigned int *)pixels; - ptr += x0; - - n = x1 - x0; - for (i = 0; i < sizeof(c) / sizeof(c[0]); i++) - c[i] = nk_color_from_byte(&col.r); - - while (n > 16) { - memcpy((void *)ptr, c, sizeof(c)); - n -= 16; ptr += 16; - } for (i = 0; i < n; i++) - ptr[i] = c[i]; -} - -static void -nk_rawfb_imagesetpixel(const struct rawfb_image *img, - const int x0, const int y0, const struct nk_color col) -{ - unsigned char *ptr; - NK_ASSERT(img); - if (y0 < img->h && y0 > 0 && x0 > 0 && x0 < img->w) { - ptr = img->pixels; - if (img->format == NK_FONT_ATLAS_ALPHA8) { - ptr += img->pitch * y0; - ptr[x0] = col.a; - } else { - ptr += img->pitch * y0; - ((struct nk_color *)ptr)[x0] = col; - } - } -} - -static struct nk_color -nk_image_getpixel(const struct rawfb_image *img, const int x0, const int y0) -{ - struct nk_color col = {0, 0, 0, 0}; - unsigned char *ptr; - NK_ASSERT(img); - if (y0 < img->h && y0 > 0 && x0 > 0 && x0 < img->w) { - ptr = img->pixels; - if (img->format == NK_FONT_ATLAS_ALPHA8) { - ptr += img->pitch * y0; - col.a = ptr[x0]; - col.b = col.g = col.r = 0xff; - } else { - ptr += img->pitch * y0; - col = ((struct nk_color *)ptr)[x0]; - } - } return col; -} - -static void -nk_image_blendpixel(const struct rawfb_image *img, - const int x0, const int y0, struct nk_color col) -{ - struct nk_color col2; - unsigned char inv_a; - if (col.a == 0) - return; - - inv_a = 0xff - col.a; - col2 = nk_image_getpixel(img, x0, y0); - col.r = (col.r * col.a + col2.r * inv_a) >> 8; - col.g = (col.g * col.a + col2.g * inv_a) >> 8; - col.b = (col.b * col.a + col2.b * inv_a) >> 8; - nk_rawfb_imagesetpixel(img, x0, y0, col); -} - -static void -nk_rawfb_scissor(struct rawfb_context *rawfb, - const float x, - const float y, - const float w, - const float h) -{ - rawfb->scissors.x = MIN(MAX(x, 0), rawfb->fb.w); - rawfb->scissors.y = MIN(MAX(y, 0), rawfb->fb.h); - rawfb->scissors.w = MIN(MAX(w + x, 0), rawfb->fb.w); - rawfb->scissors.h = MIN(MAX(h + y, 0), rawfb->fb.h); -} - -static void -nk_rawfb_stroke_line(const struct rawfb_context *rawfb, - short x0, short y0, short x1, short y1, - const unsigned int line_thickness, const struct nk_color col) -{ - short tmp; - int dy, dx, stepx, stepy; - - dy = y1 - y0; - dx = x1 - x0; - - /* fast path */ - if (dy == 0) { - if (dx == 0 || y0 >= rawfb->scissors.h || y0 < rawfb->scissors.y) - return; - - if (dx < 0) { - /* swap x0 and x1 */ - tmp = x1; - x1 = x0; - x0 = tmp; - } - x1 = MIN(rawfb->scissors.w - 1, x1); - x0 = MIN(rawfb->scissors.w - 1, x0); - x1 = MAX(rawfb->scissors.x, x1); - x0 = MAX(rawfb->scissors.x, x0); - nk_rawfb_line_horizontal(rawfb, x0, y0, x1, col); - return; - } - if (dy < 0) { - dy = -dy; - stepy = -1; - } else stepy = 1; - - if (dx < 0) { - dx = -dx; - stepx = -1; - } else stepx = 1; - - dy <<= 1; - dx <<= 1; - - nk_rawfb_setpixel(rawfb, x0, y0, col); - if (dx > dy) { - int fraction = dy - (dx >> 1); - while (x0 != x1) { - if (fraction >= 0) { - y0 += stepy; - fraction -= dx; - } - x0 += stepx; - fraction += dy; - nk_rawfb_setpixel(rawfb, x0, y0, col); - } - } else { - int fraction = dx - (dy >> 1); - while (y0 != y1) { - if (fraction >= 0) { - x0 += stepx; - fraction -= dy; - } - y0 += stepy; - fraction += dx; - nk_rawfb_setpixel(rawfb, x0, y0, col); - } - } -} - -static void -nk_rawfb_fill_polygon(const struct rawfb_context *rawfb, - const struct nk_vec2i *pnts, int count, const struct nk_color col) -{ - int i = 0; - #define MAX_POINTS 64 - int left = 10000, top = 10000, bottom = 0, right = 0; - int nodes, nodeX[MAX_POINTS], pixelX, pixelY, j, swap ; - - if (count == 0) return; - if (count > MAX_POINTS) - count = MAX_POINTS; - - /* Get polygon dimensions */ - for (i = 0; i < count; i++) { - if (left > pnts[i].x) - left = pnts[i].x; - if (right < pnts[i].x) - right = pnts[i].x; - if (top > pnts[i].y) - top = pnts[i].y; - if (bottom < pnts[i].y) - bottom = pnts[i].y; - } bottom++; right++; - - /* Polygon scanline algorithm released under public-domain by Darel Rex Finley, 2007 */ - /* Loop through the rows of the image. */ - for (pixelY = top; pixelY < bottom; pixelY ++) { - nodes = 0; /* Build a list of nodes. */ - j = count - 1; - for (i = 0; i < count; i++) { - if (((pnts[i].y < pixelY) && (pnts[j].y >= pixelY)) || - ((pnts[j].y < pixelY) && (pnts[i].y >= pixelY))) { - nodeX[nodes++]= (int)((float)pnts[i].x - + ((float)pixelY - (float)pnts[i].y) / ((float)pnts[j].y - (float)pnts[i].y) - * ((float)pnts[j].x - (float)pnts[i].x)); - } j = i; - } - - /* Sort the nodes, via a simple “Bubble” sort. */ - i = 0; - while (i < nodes - 1) { - if (nodeX[i] > nodeX[i+1]) { - swap = nodeX[i]; - nodeX[i] = nodeX[i+1]; - nodeX[i+1] = swap; - if (i) i--; - } else i++; - } - /* Fill the pixels between node pairs. */ - for (i = 0; i < nodes; i += 2) { - if (nodeX[i+0] >= right) break; - if (nodeX[i+1] > left) { - if (nodeX[i+0] < left) nodeX[i+0] = left ; - if (nodeX[i+1] > right) nodeX[i+1] = right; - for (pixelX = nodeX[i]; pixelX < nodeX[i + 1]; pixelX++) - nk_rawfb_setpixel(rawfb, pixelX, pixelY, col); - } - } - } - #undef MAX_POINTS -} - -static void -nk_rawfb_stroke_arc(const struct rawfb_context *rawfb, - short x0, short y0, short w, short h, const short s, - const short line_thickness, const struct nk_color col) -{ - /* Bresenham's ellipses - modified to draw one quarter */ - const int a2 = (w * w) / 4; - const int b2 = (h * h) / 4; - const int fa2 = 4 * a2, fb2 = 4 * b2; - int x, y, sigma; - - if (s != 0 && s != 90 && s != 180 && s != 270) return; - if (w < 1 || h < 1) return; - - /* Convert upper left to center */ - h = (h + 1) / 2; - w = (w + 1) / 2; - x0 += w; y0 += h; - - /* First half */ - for (x = 0, y = h, sigma = 2*b2+a2*(1-2*h); b2*x <= a2*y; x++) { - if (s == 180) - nk_rawfb_setpixel(rawfb, x0 + x, y0 + y, col); - else if (s == 270) - nk_rawfb_setpixel(rawfb, x0 - x, y0 + y, col); - else if (s == 0) - nk_rawfb_setpixel(rawfb, x0 + x, y0 - y, col); - else if (s == 90) - nk_rawfb_setpixel(rawfb, x0 - x, y0 - y, col); - if (sigma >= 0) { - sigma += fa2 * (1 - y); - y--; - } sigma += b2 * ((4 * x) + 6); - } - - /* Second half */ - for (x = w, y = 0, sigma = 2*a2+b2*(1-2*w); a2*y <= b2*x; y++) { - if (s == 180) - nk_rawfb_setpixel(rawfb, x0 + x, y0 + y, col); - else if (s == 270) - nk_rawfb_setpixel(rawfb, x0 - x, y0 + y, col); - else if (s == 0) - nk_rawfb_setpixel(rawfb, x0 + x, y0 - y, col); - else if (s == 90) - nk_rawfb_setpixel(rawfb, x0 - x, y0 - y, col); - if (sigma >= 0) { - sigma += fb2 * (1 - x); - x--; - } sigma += a2 * ((4 * y) + 6); - } -} - -static void -nk_rawfb_fill_arc(const struct rawfb_context *rawfb, short x0, short y0, - short w, short h, const short s, const struct nk_color col) -{ - /* Bresenham's ellipses - modified to fill one quarter */ - const int a2 = (w * w) / 4; - const int b2 = (h * h) / 4; - const int fa2 = 4 * a2, fb2 = 4 * b2; - int x, y, sigma; - struct nk_vec2i pnts[3]; - if (w < 1 || h < 1) return; - if (s != 0 && s != 90 && s != 180 && s != 270) - return; - - /* Convert upper left to center */ - h = (h + 1) / 2; - w = (w + 1) / 2; - x0 += w; - y0 += h; - - pnts[0].x = x0; - pnts[0].y = y0; - pnts[2].x = x0; - pnts[2].y = y0; - - /* First half */ - for (x = 0, y = h, sigma = 2*b2+a2*(1-2*h); b2*x <= a2*y; x++) { - if (s == 180) { - pnts[1].x = x0 + x; pnts[1].y = y0 + y; - } else if (s == 270) { - pnts[1].x = x0 - x; pnts[1].y = y0 + y; - } else if (s == 0) { - pnts[1].x = x0 + x; pnts[1].y = y0 - y; - } else if (s == 90) { - pnts[1].x = x0 - x; pnts[1].y = y0 - y; - } - nk_rawfb_fill_polygon(rawfb, pnts, 3, col); - pnts[2] = pnts[1]; - if (sigma >= 0) { - sigma += fa2 * (1 - y); - y--; - } sigma += b2 * ((4 * x) + 6); - } - - /* Second half */ - for (x = w, y = 0, sigma = 2*a2+b2*(1-2*w); a2*y <= b2*x; y++) { - if (s == 180) { - pnts[1].x = x0 + x; pnts[1].y = y0 + y; - } else if (s == 270) { - pnts[1].x = x0 - x; pnts[1].y = y0 + y; - } else if (s == 0) { - pnts[1].x = x0 + x; pnts[1].y = y0 - y; - } else if (s == 90) { - pnts[1].x = x0 - x; pnts[1].y = y0 - y; - } - nk_rawfb_fill_polygon(rawfb, pnts, 3, col); - pnts[2] = pnts[1]; - if (sigma >= 0) { - sigma += fb2 * (1 - x); - x--; - } sigma += a2 * ((4 * y) + 6); - } -} - -static void -nk_rawfb_stroke_rect(const struct rawfb_context *rawfb, - const short x, const short y, const short w, const short h, - const short r, const short line_thickness, const struct nk_color col) -{ - if (r == 0) { - nk_rawfb_stroke_line(rawfb, x, y, x + w, y, line_thickness, col); - nk_rawfb_stroke_line(rawfb, x, y + h, x + w, y + h, line_thickness, col); - nk_rawfb_stroke_line(rawfb, x, y, x, y + h, line_thickness, col); - nk_rawfb_stroke_line(rawfb, x + w, y, x + w, y + h, line_thickness, col); - } else { - const short xc = x + r; - const short yc = y + r; - const short wc = (short)(w - 2 * r); - const short hc = (short)(h - 2 * r); - - nk_rawfb_stroke_line(rawfb, xc, y, xc + wc, y, line_thickness, col); - nk_rawfb_stroke_line(rawfb, x + w, yc, x + w, yc + hc, line_thickness, col); - nk_rawfb_stroke_line(rawfb, xc, y + h, xc + wc, y + h, line_thickness, col); - nk_rawfb_stroke_line(rawfb, x, yc, x, yc + hc, line_thickness, col); - - nk_rawfb_stroke_arc(rawfb, xc + wc - r, y, - (unsigned)r*2, (unsigned)r*2, 0 , line_thickness, col); - nk_rawfb_stroke_arc(rawfb, x, y, - (unsigned)r*2, (unsigned)r*2, 90 , line_thickness, col); - nk_rawfb_stroke_arc(rawfb, x, yc + hc - r, - (unsigned)r*2, (unsigned)r*2, 270 , line_thickness, col); - nk_rawfb_stroke_arc(rawfb, xc + wc - r, yc + hc - r, - (unsigned)r*2, (unsigned)r*2, 180 , line_thickness, col); - } -} - -static void -nk_rawfb_fill_rect(const struct rawfb_context *rawfb, - const short x, const short y, const short w, const short h, - const short r, const struct nk_color col) -{ - int i; - if (r == 0) { - for (i = 0; i < h; i++) - nk_rawfb_stroke_line(rawfb, x, y + i, x + w, y + i, 1, col); - } else { - const short xc = x + r; - const short yc = y + r; - const short wc = (short)(w - 2 * r); - const short hc = (short)(h - 2 * r); - - struct nk_vec2i pnts[12]; - pnts[0].x = x; - pnts[0].y = yc; - pnts[1].x = xc; - pnts[1].y = yc; - pnts[2].x = xc; - pnts[2].y = y; - - pnts[3].x = xc + wc; - pnts[3].y = y; - pnts[4].x = xc + wc; - pnts[4].y = yc; - pnts[5].x = x + w; - pnts[5].y = yc; - - pnts[6].x = x + w; - pnts[6].y = yc + hc; - pnts[7].x = xc + wc; - pnts[7].y = yc + hc; - pnts[8].x = xc + wc; - pnts[8].y = y + h; - - pnts[9].x = xc; - pnts[9].y = y + h; - pnts[10].x = xc; - pnts[10].y = yc + hc; - pnts[11].x = x; - pnts[11].y = yc + hc; - - nk_rawfb_fill_polygon(rawfb, pnts, 12, col); - - nk_rawfb_fill_arc(rawfb, xc + wc - r, y, - (unsigned)r*2, (unsigned)r*2, 0 , col); - nk_rawfb_fill_arc(rawfb, x, y, - (unsigned)r*2, (unsigned)r*2, 90 , col); - nk_rawfb_fill_arc(rawfb, x, yc + hc - r, - (unsigned)r*2, (unsigned)r*2, 270 , col); - nk_rawfb_fill_arc(rawfb, xc + wc - r, yc + hc - r, - (unsigned)r*2, (unsigned)r*2, 180 , col); - } -} - -static void -nk_rawfb_fill_triangle(const struct rawfb_context *rawfb, - const short x0, const short y0, const short x1, const short y1, - const short x2, const short y2, const struct nk_color col) -{ - struct nk_vec2i pnts[3]; - pnts[0].x = x0; - pnts[0].y = y0; - pnts[1].x = x1; - pnts[1].y = y1; - pnts[2].x = x2; - pnts[2].y = y2; - nk_rawfb_fill_polygon(rawfb, pnts, 3, col); -} - -static void -nk_rawfb_stroke_triangle(const struct rawfb_context *rawfb, - const short x0, const short y0, const short x1, const short y1, - const short x2, const short y2, const unsigned short line_thickness, - const struct nk_color col) -{ - nk_rawfb_stroke_line(rawfb, x0, y0, x1, y1, line_thickness, col); - nk_rawfb_stroke_line(rawfb, x1, y1, x2, y2, line_thickness, col); - nk_rawfb_stroke_line(rawfb, x2, y2, x0, y0, line_thickness, col); -} - -static void -nk_rawfb_stroke_polygon(const struct rawfb_context *rawfb, - const struct nk_vec2i *pnts, const int count, - const unsigned short line_thickness, const struct nk_color col) -{ - int i; - for (i = 1; i < count; ++i) - nk_rawfb_stroke_line(rawfb, pnts[i-1].x, pnts[i-1].y, pnts[i].x, - pnts[i].y, line_thickness, col); - nk_rawfb_stroke_line(rawfb, pnts[count-1].x, pnts[count-1].y, - pnts[0].x, pnts[0].y, line_thickness, col); -} - -static void -nk_rawfb_stroke_polyline(const struct rawfb_context *rawfb, - const struct nk_vec2i *pnts, const int count, - const unsigned short line_thickness, const struct nk_color col) -{ - int i; - for (i = 0; i < count-1; ++i) - nk_rawfb_stroke_line(rawfb, pnts[i].x, pnts[i].y, - pnts[i+1].x, pnts[i+1].y, line_thickness, col); -} - -static void -nk_rawfb_fill_circle(const struct rawfb_context *rawfb, - short x0, short y0, short w, short h, const struct nk_color col) -{ - /* Bresenham's ellipses */ - const int a2 = (w * w) / 4; - const int b2 = (h * h) / 4; - const int fa2 = 4 * a2, fb2 = 4 * b2; - int x, y, sigma; - - /* Convert upper left to center */ - h = (h + 1) / 2; - w = (w + 1) / 2; - x0 += w; - y0 += h; - - /* First half */ - for (x = 0, y = h, sigma = 2*b2+a2*(1-2*h); b2*x <= a2*y; x++) { - nk_rawfb_stroke_line(rawfb, x0 - x, y0 + y, x0 + x, y0 + y, 1, col); - nk_rawfb_stroke_line(rawfb, x0 - x, y0 - y, x0 + x, y0 - y, 1, col); - if (sigma >= 0) { - sigma += fa2 * (1 - y); - y--; - } sigma += b2 * ((4 * x) + 6); - } - /* Second half */ - for (x = w, y = 0, sigma = 2*a2+b2*(1-2*w); a2*y <= b2*x; y++) { - nk_rawfb_stroke_line(rawfb, x0 - x, y0 + y, x0 + x, y0 + y, 1, col); - nk_rawfb_stroke_line(rawfb, x0 - x, y0 - y, x0 + x, y0 - y, 1, col); - if (sigma >= 0) { - sigma += fb2 * (1 - x); - x--; - } sigma += a2 * ((4 * y) + 6); - } -} - -static void -nk_rawfb_stroke_circle(const struct rawfb_context *rawfb, - short x0, short y0, short w, short h, const short line_thickness, - const struct nk_color col) -{ - /* Bresenham's ellipses */ - const int a2 = (w * w) / 4; - const int b2 = (h * h) / 4; - const int fa2 = 4 * a2, fb2 = 4 * b2; - int x, y, sigma; - - /* Convert upper left to center */ - h = (h + 1) / 2; - w = (w + 1) / 2; - x0 += w; - y0 += h; - - /* First half */ - for (x = 0, y = h, sigma = 2*b2+a2*(1-2*h); b2*x <= a2*y; x++) { - nk_rawfb_setpixel(rawfb, x0 + x, y0 + y, col); - nk_rawfb_setpixel(rawfb, x0 - x, y0 + y, col); - nk_rawfb_setpixel(rawfb, x0 + x, y0 - y, col); - nk_rawfb_setpixel(rawfb, x0 - x, y0 - y, col); - if (sigma >= 0) { - sigma += fa2 * (1 - y); - y--; - } sigma += b2 * ((4 * x) + 6); - } - /* Second half */ - for (x = w, y = 0, sigma = 2*a2+b2*(1-2*w); a2*y <= b2*x; y++) { - nk_rawfb_setpixel(rawfb, x0 + x, y0 + y, col); - nk_rawfb_setpixel(rawfb, x0 - x, y0 + y, col); - nk_rawfb_setpixel(rawfb, x0 + x, y0 - y, col); - nk_rawfb_setpixel(rawfb, x0 - x, y0 - y, col); - if (sigma >= 0) { - sigma += fb2 * (1 - x); - x--; - } sigma += a2 * ((4 * y) + 6); - } -} - -static void -nk_rawfb_stroke_curve(const struct rawfb_context *rawfb, - const struct nk_vec2i p1, const struct nk_vec2i p2, - const struct nk_vec2i p3, const struct nk_vec2i p4, - const unsigned int num_segments, const unsigned short line_thickness, - const struct nk_color col) -{ - unsigned int i_step, segments; - float t_step; - struct nk_vec2i last = p1; - - segments = MAX(num_segments, 1); - t_step = 1.0f/(float)segments; - for (i_step = 1; i_step <= segments; ++i_step) { - float t = t_step * (float)i_step; - float u = 1.0f - t; - float w1 = u*u*u; - float w2 = 3*u*u*t; - float w3 = 3*u*t*t; - float w4 = t * t *t; - float x = w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x; - float y = w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y; - nk_rawfb_stroke_line(rawfb, last.x, last.y, - (short)x, (short)y, line_thickness,col); - last.x = (short)x; last.y = (short)y; - } -} - -static void -nk_rawfb_clear(const struct rawfb_context *rawfb, const struct nk_color col) -{ - nk_rawfb_fill_rect(rawfb, 0, 0, rawfb->fb.w, rawfb->fb.h, 0, col); -} - -NK_API struct rawfb_context* -nk_rawfb_init(void *fb, void *tex_mem, const unsigned int w, const unsigned int h, - const unsigned int pitch) -{ - const void *tex; - struct rawfb_context *rawfb; - rawfb = malloc(sizeof(struct rawfb_context)); - if (!rawfb) - return NULL; - - nk_memset(rawfb, 0, sizeof(struct rawfb_context)); - rawfb->font_tex.pixels = tex_mem; - rawfb->font_tex.format = NK_FONT_ATLAS_ALPHA8; - rawfb->font_tex.w = rawfb->font_tex.h = 0; - - rawfb->fb.pixels = fb; - rawfb->fb.w= w; - rawfb->fb.h = h; - -#if defined(RAWFB_XRGB_8888) || defined(RAWFB_RGBX_8888) - rawfb->fb.format = NK_FONT_ATLAS_RGBA32; - rawfb->fb.pitch = pitch; -#else - #error Fixme -#endif - - nk_init_default(&rawfb->ctx, 0); - nk_font_atlas_init_default(&rawfb->atlas); - nk_font_atlas_begin(&rawfb->atlas); - tex = nk_font_atlas_bake(&rawfb->atlas, &rawfb->font_tex.w, &rawfb->font_tex.h, rawfb->font_tex.format); - if (!tex) return 0; - - switch(rawfb->font_tex.format) { - case NK_FONT_ATLAS_ALPHA8: - rawfb->font_tex.pitch = rawfb->font_tex.w * 1; - break; - case NK_FONT_ATLAS_RGBA32: - rawfb->font_tex.pitch = rawfb->font_tex.w * 4; - break; - }; - /* Store the font texture in tex scratch memory */ - memcpy(rawfb->font_tex.pixels, tex, rawfb->font_tex.pitch * rawfb->font_tex.h); - nk_font_atlas_end(&rawfb->atlas, nk_handle_ptr(NULL), NULL); - if (rawfb->atlas.default_font) - nk_style_set_font(&rawfb->ctx, &rawfb->atlas.default_font->handle); - nk_style_load_all_cursors(&rawfb->ctx, rawfb->atlas.cursors); - nk_rawfb_scissor(rawfb, 0, 0, rawfb->fb.w, rawfb->fb.h); - return rawfb; -} - -static void -nk_rawfb_stretch_image(const struct rawfb_image *dst, - const struct rawfb_image *src, const struct nk_rect *dst_rect, - const struct nk_rect *src_rect, const struct nk_rect *dst_scissors) -{ - short i, j; - struct nk_color col; - float xinc = src_rect->w / dst_rect->w; - float yinc = src_rect->h / dst_rect->h; - float xoff = src_rect->x, yoff = src_rect->y; - - /* Simple nearest filtering rescaling */ - /* TODO: use bilinear filter */ - for (j = 0; j < (short)dst_rect->h; j++) { - for (i = 0; i < (short)dst_rect->w; i++) { - if (dst_scissors) { - if (i + (int)(dst_rect->x + 0.5f) < dst_scissors->x || i + (int)(dst_rect->x + 0.5f) >= dst_scissors->w) - continue; - if (j + (int)(dst_rect->y + 0.5f) < dst_scissors->y || j + (int)(dst_rect->y + 0.5f) >= dst_scissors->h) - continue; - } - col = nk_image_getpixel(src, (int)xoff, (int) yoff); - nk_image_blendpixel(dst, i + (int)(dst_rect->x + 0.5f), j + (int)(dst_rect->y + 0.5f), col); - xoff += xinc; - } - xoff = src_rect->x; - yoff += yinc; - } -} - -static void -nk_rawfb_font_query_font_glyph(nk_handle handle, const float height, - struct nk_user_font_glyph *glyph, const nk_rune codepoint, - const nk_rune next_codepoint) -{ - float scale; - const struct nk_font_glyph *g; - struct nk_font *font; - NK_ASSERT(glyph); - NK_UNUSED(next_codepoint); - - font = (struct nk_font*)handle.ptr; - NK_ASSERT(font); - NK_ASSERT(font->glyphs); - if (!font || !glyph) - return; - - scale = height/font->info.height; - g = nk_font_find_glyph(font, codepoint); - glyph->width = (g->x1 - g->x0) * scale; - glyph->height = (g->y1 - g->y0) * scale; - glyph->offset = nk_vec2(g->x0 * scale, g->y0 * scale); - glyph->xadvance = (g->xadvance * scale); - glyph->uv[0] = nk_vec2(g->u0, g->v0); - glyph->uv[1] = nk_vec2(g->u1, g->v1); -} - -NK_API void -nk_rawfb_draw_text(const struct rawfb_context *rawfb, - const struct nk_user_font *font, const struct nk_rect rect, - const char *text, const int len, const float font_height, - const struct nk_color fg) -{ - float x = 0; - int text_len = 0; - nk_rune unicode = 0; - nk_rune next = 0; - int glyph_len = 0; - int next_glyph_len = 0; - struct nk_user_font_glyph g; - if (!len || !text) return; - - x = 0; - glyph_len = nk_utf_decode(text, &unicode, len); - if (!glyph_len) return; - - /* draw every glyph image */ - while (text_len < len && glyph_len) { - struct nk_rect src_rect; - struct nk_rect dst_rect; - float char_width = 0; - if (unicode == NK_UTF_INVALID) break; - - /* query currently drawn glyph information */ - next_glyph_len = nk_utf_decode(text + text_len + glyph_len, &next, (int)len - text_len); - nk_rawfb_font_query_font_glyph(font->userdata, font_height, &g, unicode, - (next == NK_UTF_INVALID) ? '\0' : next); - - /* calculate and draw glyph drawing rectangle and image */ - char_width = g.xadvance; - src_rect.x = g.uv[0].x * rawfb->font_tex.w; - src_rect.y = g.uv[0].y * rawfb->font_tex.h; - src_rect.w = g.uv[1].x * rawfb->font_tex.w - g.uv[0].x * rawfb->font_tex.w; - src_rect.h = g.uv[1].y * rawfb->font_tex.h - g.uv[0].y * rawfb->font_tex.h; - - dst_rect.x = x + g.offset.x + rect.x; - dst_rect.y = g.offset.y + rect.y; - dst_rect.w = ceilf(g.width); - dst_rect.h = ceilf(g.height); - - /* TODO: account fg */ - /* Use software rescaling to blit glyph from font_text to framebuffer */ - nk_rawfb_stretch_image(&rawfb->fb, &rawfb->font_tex, &dst_rect, &src_rect, &rawfb->scissors); - - /* offset next glyph */ - text_len += glyph_len; - x += char_width; - glyph_len = next_glyph_len; - unicode = next; - } -} - -NK_API void -nk_rawfb_drawimage(const struct rawfb_context *rawfb, - const int x, const int y, const int w, const int h, - const struct nk_image *img, const struct nk_color *col) -{ - struct nk_rect src_rect; - struct nk_rect dst_rect; - - src_rect.x = img->region[0]; - src_rect.y = img->region[1]; - src_rect.w = img->region[2]; - src_rect.h = img->region[3]; - - dst_rect.x = x; - dst_rect.y = y; - dst_rect.w = w; - dst_rect.h = h; - nk_rawfb_stretch_image(&rawfb->fb, &rawfb->font_tex, &dst_rect, &src_rect, &rawfb->scissors); -} - -NK_API void -nk_rawfb_shutdown(struct rawfb_context *rawfb) -{ - nk_free(&rawfb->ctx); - nk_memset(rawfb, 0, sizeof(struct rawfb_context)); - free(rawfb); -} - -NK_API void -nk_rawfb_resize_fb(struct rawfb_context *rawfb, - void *fb, - const unsigned int w, - const unsigned int h, - const unsigned int pitch) -{ - rawfb->fb.w = w; - rawfb->fb.h = h; - rawfb->fb.pixels = fb; - rawfb->fb.pitch = pitch; -} - -NK_API void -nk_rawfb_render(const struct rawfb_context *rawfb, - const struct nk_color clear, - const unsigned char enable_clear) -{ - const struct nk_command *cmd; - if (enable_clear) - nk_rawfb_clear(rawfb, clear); - - nk_foreach(cmd, (struct nk_context*)&rawfb->ctx) { - switch (cmd->type) { - case NK_COMMAND_NOP: break; - case NK_COMMAND_SCISSOR: { - const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd; - nk_rawfb_scissor((struct rawfb_context *)rawfb, s->x, s->y, s->w, s->h); - } break; - case NK_COMMAND_LINE: { - const struct nk_command_line *l = (const struct nk_command_line *)cmd; - nk_rawfb_stroke_line(rawfb, l->begin.x, l->begin.y, l->end.x, - l->end.y, l->line_thickness, l->color); - } break; - case NK_COMMAND_RECT: { - const struct nk_command_rect *r = (const struct nk_command_rect *)cmd; - nk_rawfb_stroke_rect(rawfb, r->x, r->y, r->w, r->h, - (unsigned short)r->rounding, r->line_thickness, r->color); - } break; - case NK_COMMAND_RECT_FILLED: { - const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd; - nk_rawfb_fill_rect(rawfb, r->x, r->y, r->w, r->h, - (unsigned short)r->rounding, r->color); - } break; - case NK_COMMAND_CIRCLE: { - const struct nk_command_circle *c = (const struct nk_command_circle *)cmd; - nk_rawfb_stroke_circle(rawfb, c->x, c->y, c->w, c->h, c->line_thickness, c->color); - } break; - case NK_COMMAND_CIRCLE_FILLED: { - const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd; - nk_rawfb_fill_circle(rawfb, c->x, c->y, c->w, c->h, c->color); - } break; - case NK_COMMAND_TRIANGLE: { - const struct nk_command_triangle*t = (const struct nk_command_triangle*)cmd; - nk_rawfb_stroke_triangle(rawfb, t->a.x, t->a.y, t->b.x, t->b.y, - t->c.x, t->c.y, t->line_thickness, t->color); - } break; - case NK_COMMAND_TRIANGLE_FILLED: { - const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd; - nk_rawfb_fill_triangle(rawfb, t->a.x, t->a.y, t->b.x, t->b.y, - t->c.x, t->c.y, t->color); - } break; - case NK_COMMAND_POLYGON: { - const struct nk_command_polygon *p =(const struct nk_command_polygon*)cmd; - nk_rawfb_stroke_polygon(rawfb, p->points, p->point_count, p->line_thickness,p->color); - } break; - case NK_COMMAND_POLYGON_FILLED: { - const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd; - nk_rawfb_fill_polygon(rawfb, p->points, p->point_count, p->color); - } break; - case NK_COMMAND_POLYLINE: { - const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd; - nk_rawfb_stroke_polyline(rawfb, p->points, p->point_count, p->line_thickness, p->color); - } break; - case NK_COMMAND_TEXT: { - const struct nk_command_text *t = (const struct nk_command_text*)cmd; - nk_rawfb_draw_text(rawfb, t->font, nk_rect(t->x, t->y, t->w, t->h), - t->string, t->length, t->height, t->foreground); - } break; - case NK_COMMAND_CURVE: { - const struct nk_command_curve *q = (const struct nk_command_curve *)cmd; - nk_rawfb_stroke_curve(rawfb, q->begin, q->ctrl[0], q->ctrl[1], - q->end, 22, q->line_thickness, q->color); - } break; - case NK_COMMAND_RECT_MULTI_COLOR: - case NK_COMMAND_IMAGE: { - const struct nk_command_image *q = (const struct nk_command_image *)cmd; - nk_rawfb_drawimage(rawfb, q->x, q->y, q->w, q->h, &q->img, &q->col); - } break; - case NK_COMMAND_ARC: { - assert(0 && "NK_COMMAND_ARC not implemented\n"); - } break; - case NK_COMMAND_ARC_FILLED: { - assert(0 && "NK_COMMAND_ARC_FILLED not implemented\n"); - } break; - default: break; - } - } nk_clear((struct nk_context*)&rawfb->ctx); -} -#endif - diff --git a/subprojects/nk_pugl/nuklear/demo/x11_rawfb/nuklear_xlib.h b/subprojects/nk_pugl/nuklear/demo/x11_rawfb/nuklear_xlib.h deleted file mode 100644 index 068112f..0000000 --- a/subprojects/nk_pugl/nuklear/demo/x11_rawfb/nuklear_xlib.h +++ /dev/null @@ -1,283 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2016-2017 Patrick Rudolph - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Based on x11/nuklear_xlib.h. -*/ -/* - * ============================================================== - * - * API - * - * =============================================================== - */ -#ifndef NK_XLIBSHM_H_ -#define NK_XLIBSHM_H_ - -#include - -NK_API int nk_xlib_init(Display *dpy, Visual *vis, int screen, Window root, unsigned int w, unsigned int h, void **fb); -NK_API int nk_xlib_handle_event(Display *dpy, int screen, Window win, XEvent *evt, struct rawfb_context *rawfb); -NK_API void nk_xlib_render(Drawable screen); -NK_API void nk_xlib_shutdown(void); - -#endif -/* - * ============================================================== - * - * IMPLEMENTATION - * - * =============================================================== - */ -#ifdef NK_XLIBSHM_IMPLEMENTATION -#include -#include -#include -#include -#include -#include -#include - -static struct { - struct nk_context ctx; - struct XSurface *surf; - Cursor cursor; - Display *dpy; - Window root; - XImage *ximg; - XShmSegmentInfo xsi; - char fallback; - GC gc; -} xlib; - -NK_API int -nk_xlib_init(Display *dpy, Visual *vis, int screen, Window root, - unsigned int w, unsigned int h, void **fb) -{ - unsigned int depth = XDefaultDepth(dpy, screen); - xlib.dpy = dpy; - xlib.root = root; - - if (!setlocale(LC_ALL,"")) return 0; - if (!XSupportsLocale()) return 0; - if (!XSetLocaleModifiers("@im=none")) return 0; - - /* create invisible cursor */ - {static XColor dummy; char data[1] = {0}; - Pixmap blank = XCreateBitmapFromData(dpy, root, data, 1, 1); - if (blank == None) return 0; - xlib.cursor = XCreatePixmapCursor(dpy, blank, blank, &dummy, &dummy, 0, 0); - XFreePixmap(dpy, blank);} - - xlib.fallback = False; - do {/* Initialize shared memory according to: - * https://www.x.org/archive/X11R7.5/doc/Xext/mit-shm.html */ - int status; - if (!XShmQueryExtension(dpy)) { - printf("No XShm Extension available.\n"); - xlib.fallback = True; - break; - } - xlib.ximg = XShmCreateImage(dpy, vis, depth, ZPixmap, NULL, &xlib.xsi, w, h); - if (!xlib.ximg) { - xlib.fallback = True; - break; - } - xlib.xsi.shmid = shmget(IPC_PRIVATE, xlib.ximg->bytes_per_line * xlib.ximg->height, IPC_CREAT | 0777); - if (xlib.xsi.shmid < 0) { - XDestroyImage(xlib.ximg); - xlib.fallback = True; - break; - } - xlib.xsi.shmaddr = xlib.ximg->data = shmat(xlib.xsi.shmid, NULL, 0); - if ((size_t)xlib.xsi.shmaddr < 0) { - XDestroyImage(xlib.ximg); - xlib.fallback = True; - break; - } - xlib.xsi.readOnly = False; - status = XShmAttach(dpy, &xlib.xsi); - if (!status) { - shmdt(xlib.xsi.shmaddr); - XDestroyImage(xlib.ximg); - xlib.fallback = True; - break; - } XSync(dpy, False); - shmctl(xlib.xsi.shmid, IPC_RMID, NULL); - } while(0); - - if (xlib.fallback) { - xlib.ximg = XCreateImage(dpy, vis, depth, ZPixmap, 0, NULL, w, h, 32, 0); - if (!xlib.ximg) return 0; - xlib.ximg->data = malloc(h * xlib.ximg->bytes_per_line); - if (!xlib.ximg->data) - return 0; - } - xlib.gc = XDefaultGC(dpy, screen); - *fb = xlib.ximg->data; - return 1; -} - -NK_API int -nk_xlib_handle_event(Display *dpy, int screen, Window win, XEvent *evt, struct rawfb_context *rawfb) -{ - /* optional grabbing behavior */ - if (rawfb->ctx.input.mouse.grab) { - /* XDefineCursor(xlib.dpy, xlib.root, xlib.cursor); */ - rawfb->ctx.input.mouse.grab = 0; - } else if (rawfb->ctx.input.mouse.ungrab) { - XWarpPointer(xlib.dpy, None, xlib.root, 0, 0, 0, 0, - (int)rawfb->ctx.input.mouse.prev.x, (int)rawfb->ctx.input.mouse.prev.y); - /* XUndefineCursor(xlib.dpy, xlib.root); */ - rawfb->ctx.input.mouse.ungrab = 0; - } - - if (evt->type == KeyPress || evt->type == KeyRelease) - { - /* Key handler */ - int ret, down = (evt->type == KeyPress); - KeySym *code = XGetKeyboardMapping(xlib.dpy, (KeyCode)evt->xkey.keycode, 1, &ret); - if (*code == XK_Shift_L || *code == XK_Shift_R) nk_input_key(&rawfb->ctx, NK_KEY_SHIFT, down); - else if (*code == XK_Delete) nk_input_key(&rawfb->ctx, NK_KEY_DEL, down); - else if (*code == XK_Return) nk_input_key(&rawfb->ctx, NK_KEY_ENTER, down); - else if (*code == XK_Tab) nk_input_key(&rawfb->ctx, NK_KEY_TAB, down); - else if (*code == XK_Left) nk_input_key(&rawfb->ctx, NK_KEY_LEFT, down); - else if (*code == XK_Right) nk_input_key(&rawfb->ctx, NK_KEY_RIGHT, down); - else if (*code == XK_Up) nk_input_key(&rawfb->ctx, NK_KEY_UP, down); - else if (*code == XK_Down) nk_input_key(&rawfb->ctx, NK_KEY_DOWN, down); - else if (*code == XK_BackSpace) nk_input_key(&rawfb->ctx, NK_KEY_BACKSPACE, down); - else if (*code == XK_Escape) nk_input_key(&rawfb->ctx, NK_KEY_TEXT_RESET_MODE, down); - else if (*code == XK_Page_Up) nk_input_key(&rawfb->ctx, NK_KEY_SCROLL_UP, down); - else if (*code == XK_Page_Down) nk_input_key(&rawfb->ctx, NK_KEY_SCROLL_DOWN, down); - else if (*code == XK_Home) { - nk_input_key(&rawfb->ctx, NK_KEY_TEXT_START, down); - nk_input_key(&rawfb->ctx, NK_KEY_SCROLL_START, down); - } else if (*code == XK_End) { - nk_input_key(&rawfb->ctx, NK_KEY_TEXT_END, down); - nk_input_key(&rawfb->ctx, NK_KEY_SCROLL_END, down); - } else { - if (*code == 'c' && (evt->xkey.state & ControlMask)) - nk_input_key(&rawfb->ctx, NK_KEY_COPY, down); - else if (*code == 'v' && (evt->xkey.state & ControlMask)) - nk_input_key(&rawfb->ctx, NK_KEY_PASTE, down); - else if (*code == 'x' && (evt->xkey.state & ControlMask)) - nk_input_key(&rawfb->ctx, NK_KEY_CUT, down); - else if (*code == 'z' && (evt->xkey.state & ControlMask)) - nk_input_key(&rawfb->ctx, NK_KEY_TEXT_UNDO, down); - else if (*code == 'r' && (evt->xkey.state & ControlMask)) - nk_input_key(&rawfb->ctx, NK_KEY_TEXT_REDO, down); - else if (*code == XK_Left && (evt->xkey.state & ControlMask)) - nk_input_key(&rawfb->ctx, NK_KEY_TEXT_WORD_LEFT, down); - else if (*code == XK_Right && (evt->xkey.state & ControlMask)) - nk_input_key(&rawfb->ctx, NK_KEY_TEXT_WORD_RIGHT, down); - else if (*code == 'b' && (evt->xkey.state & ControlMask)) - nk_input_key(&rawfb->ctx, NK_KEY_TEXT_LINE_START, down); - else if (*code == 'e' && (evt->xkey.state & ControlMask)) - nk_input_key(&rawfb->ctx, NK_KEY_TEXT_LINE_END, down); - else { - if (*code == 'i') - nk_input_key(&rawfb->ctx, NK_KEY_TEXT_INSERT_MODE, down); - else if (*code == 'r') - nk_input_key(&rawfb->ctx, NK_KEY_TEXT_REPLACE_MODE, down); - if (down) { - char buf[32]; - KeySym keysym = 0; - if (XLookupString((XKeyEvent*)evt, buf, 32, &keysym, NULL) != NoSymbol) - nk_input_glyph(&rawfb->ctx, buf); - } - } - } XFree(code); - return 1; - } else if (evt->type == ButtonPress || evt->type == ButtonRelease) { - /* Button handler */ - int down = (evt->type == ButtonPress); - const int x = evt->xbutton.x, y = evt->xbutton.y; - if (evt->xbutton.button == Button1) - nk_input_button(&rawfb->ctx, NK_BUTTON_LEFT, x, y, down); - if (evt->xbutton.button == Button2) - nk_input_button(&rawfb->ctx, NK_BUTTON_MIDDLE, x, y, down); - else if (evt->xbutton.button == Button3) - nk_input_button(&rawfb->ctx, NK_BUTTON_RIGHT, x, y, down); - else if (evt->xbutton.button == Button4) - nk_input_scroll(&rawfb->ctx, nk_vec2(0, 1.0f)); - else if (evt->xbutton.button == Button5) - nk_input_scroll(&rawfb->ctx, nk_vec2(0, -1.0f)); - else return 0; - return 1; - } else if (evt->type == MotionNotify) { - /* Mouse motion handler */ - const int x = evt->xmotion.x, y = evt->xmotion.y; - nk_input_motion(&rawfb->ctx, x, y); - if (rawfb->ctx.input.mouse.grabbed) { - rawfb->ctx.input.mouse.pos.x = rawfb->ctx.input.mouse.prev.x; - rawfb->ctx.input.mouse.pos.y = rawfb->ctx.input.mouse.prev.y; - XWarpPointer(xlib.dpy, None, xlib.root, 0, 0, 0, 0, (int)rawfb->ctx.input.mouse.pos.x, (int)rawfb->ctx.input.mouse.pos.y); - } return 1; - } else if (evt->type == Expose || evt->type == ConfigureNotify) { - /* Window resize handler */ - void *fb; - unsigned int width, height; - XWindowAttributes attr; - XGetWindowAttributes(dpy, win, &attr); - - width = (unsigned int)attr.width; - height = (unsigned int)attr.height; - - nk_xlib_shutdown(); - nk_xlib_init(dpy, XDefaultVisual(dpy, screen), screen, win, width, height, &fb); - nk_rawfb_resize_fb(rawfb, fb, width, height, width * 4); - } else if (evt->type == KeymapNotify) { - XRefreshKeyboardMapping(&evt->xmapping); - return 1; - } else if (evt->type == LeaveNotify) { - XUndefineCursor(xlib.dpy, xlib.root); - } else if (evt->type == EnterNotify) { - XDefineCursor(xlib.dpy, xlib.root, xlib.cursor); - } return 0; -} - -NK_API void -nk_xlib_shutdown(void) -{ - XFreeCursor(xlib.dpy, xlib.cursor); - if (xlib.fallback) { - free(xlib.ximg->data); - XDestroyImage(xlib.ximg); - } else { - XShmDetach(xlib.dpy, &xlib.xsi); - XDestroyImage(xlib.ximg); - shmdt(xlib.xsi.shmaddr); - shmctl(xlib.xsi.shmid, IPC_RMID, NULL); - } nk_memset(&xlib, 0, sizeof(xlib)); -} - -NK_API void -nk_xlib_render(Drawable screen) -{ - if (xlib.fallback) - XPutImage(xlib.dpy, screen, xlib.gc, xlib.ximg, - 0, 0, 0, 0, xlib.ximg->width, xlib.ximg->height); - else XShmPutImage(xlib.dpy, screen, xlib.gc, xlib.ximg, - 0, 0, 0, 0, xlib.ximg->width, xlib.ximg->height, False); -} -#endif - diff --git a/subprojects/nk_pugl/nuklear/doc/Makefile b/subprojects/nk_pugl/nuklear/doc/Makefile deleted file mode 100644 index 72a598b..0000000 --- a/subprojects/nk_pugl/nuklear/doc/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -# Install -BIN = doc - -# Flags -CFLAGS += -std=c99 -pedantic -O2 - -SRC = stddoc.c -OBJ = $(SRC:.c=.o) - -ifeq ($(OS),Windows_NT) -BIN := $(BIN).exe -LIBS = -else - UNAME_S := $(shell uname -s) - ifeq ($(UNAME_S),Darwin) - LIBS = - else - LIBS = - endif -endif - -$(BIN): - rm -f $(BIN) $(OBJS) - $(CC) $(SRC) $(CFLAGS) -o $(BIN) diff --git a/subprojects/nk_pugl/nuklear/doc/build.sh b/subprojects/nk_pugl/nuklear/doc/build.sh deleted file mode 100755 index 560dd59..0000000 --- a/subprojects/nk_pugl/nuklear/doc/build.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -cat ../nuklear.h|./doc > nuklear.html - - diff --git a/subprojects/nk_pugl/nuklear/doc/nuklear.html b/subprojects/nk_pugl/nuklear/doc/nuklear.html deleted file mode 100644 index ad0d63b..0000000 --- a/subprojects/nk_pugl/nuklear/doc/nuklear.html +++ /dev/null @@ -1,2533 +0,0 @@ - - -# Nuklear -![](https://cloud.githubusercontent.com/assets/8057201/11761525/ae06f0ca-a0c6-11e5-819d-5610b25f6ef4.gif) -## Contents -1. About section -2. Highlights section -3. Features section -4. Usage section - 1. Flags section - 2. Constants section - 3. Dependencies section -5. Example section -6. API section - 1. Context section - 2. Input section - 3. Drawing section - 4. Window section - 5. Layouting section - 6. Groups section - 7. Tree section - 8. Properties section -7. License section -8. Changelog section -9. Gallery section -10. Credits section -## About -This is a minimal state immediate mode graphical user interface toolkit -written in ANSI C and licensed under public domain. It was designed as a simple -embeddable user interface for application and does not have any dependencies, -a default renderbackend or OS window and input handling but instead provides a very modular -library approach by using simple input state for input and draw -commands describing primitive shapes as output. So instead of providing a -layered library that tries to abstract over a number of platform and -render backends it only focuses on the actual UI. -## Highlights -- Graphical user interface toolkit -- Single header library -- Written in C89 (a.k.a. ANSI C or ISO C90) -- Small codebase (~18kLOC) -- Focus on portability, efficiency and simplicity -- No dependencies (not even the standard library if not wanted) -- Fully skinnable and customizable -- Low memory footprint with total memory control if needed or wanted -- UTF-8 support -- No global or hidden state -- Customizable library modules (you can compile and use only what you need) -- Optional font baker and vertex buffer output -## Features -- Absolutely no platform dependent code -- Memory management control ranging from/to - - Ease of use by allocating everything from standard library - - Control every byte of memory inside the library -- Font handling control ranging from/to - - Use your own font implementation for everything - - Use this libraries internal font baking and handling API -- Drawing output control ranging from/to - - Simple shapes for more high level APIs which already have drawing capabilities - - Hardware accessible anti-aliased vertex buffer output -- Customizable colors and properties ranging from/to - - Simple changes to color by filling a simple color table - - Complete control with ability to use skinning to decorate widgets -- Bendable UI library with widget ranging from/to - - Basic widgets like buttons, checkboxes, slider, ... - - Advanced widget like abstract comboboxes, contextual menus,... -- Compile time configuration to only compile what you need - - Subset which can be used if you do not want to link or use the standard library -- Can be easily modified to only update on user input instead of frame updates -## Usage -This library is self contained in one single header file and can be used either -in header only mode or in implementation mode. The header only mode is used -by default when included and allows including this header in other headers -and does not contain the actual implementation.

-The implementation mode requires to define the preprocessor macro -NK_IMPLEMENTATION in *one* .c/.cpp file before #includeing this file, e.g.: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~C - #define NK_IMPLEMENTATION - #include "nuklear.h" -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Also optionally define the symbols listed in the section "OPTIONAL DEFINES" -below in header and implementation mode if you want to use additional functionality -or need more control over the library. -!!! WARNING - Every time nuklear is included define the same compiler flags. This very important not doing so could lead to compiler errors or even worse stack corruptions. -### Flags -Flag | Description ---------------------------------|------------------------------------------ -NK_PRIVATE | If defined declares all functions as static, so they can only be accessed inside the file that contains the implementation -NK_INCLUDE_FIXED_TYPES | If defined it will include header `` for fixed sized types otherwise nuklear tries to select the correct type. If that fails it will throw a compiler error and you have to select the correct types yourself. -NK_INCLUDE_DEFAULT_ALLOCATOR | If defined it will include header `` and provide additional functions to use this library without caring for memory allocation control and therefore ease memory management. -NK_INCLUDE_STANDARD_IO | If defined it will include header `` and provide additional functions depending on file loading. -NK_INCLUDE_STANDARD_VARARGS | If defined it will include header and provide additional functions depending on file loading. -NK_INCLUDE_VERTEX_BUFFER_OUTPUT | Defining this adds a vertex draw command list backend to this library, which allows you to convert queue commands into vertex draw commands. This is mainly if you need a hardware accessible format for OpenGL, DirectX, Vulkan, Metal,... -NK_INCLUDE_FONT_BAKING | Defining this adds `stb_truetype` and `stb_rect_pack` implementation to this library and provides font baking and rendering. If you already have font handling or do not want to use this font handler you don't have to define it. -NK_INCLUDE_DEFAULT_FONT | Defining this adds the default font: ProggyClean.ttf into this library which can be loaded into a font atlas and allows using this library without having a truetype font -NK_INCLUDE_COMMAND_USERDATA | Defining this adds a userdata pointer into each command. Can be useful for example if you want to provide custom shaders depending on the used widget. Can be combined with the style structures. -NK_BUTTON_TRIGGER_ON_RELEASE | Different platforms require button clicks occurring either on buttons being pressed (up to down) or released (down to up). By default this library will react on buttons being pressed, but if you define this it will only trigger if a button is released. -NK_ZERO_COMMAND_MEMORY | Defining this will zero out memory for each drawing command added to a drawing queue (inside nk_command_buffer_push). Zeroing command memory is very useful for fast checking (using memcmp) if command buffers are equal and avoid drawing frames when nothing on screen has changed since previous frame. -!!! WARNING - The following flags will pull in the standard C library: - - NK_INCLUDE_DEFAULT_ALLOCATOR - - NK_INCLUDE_STANDARD_IO - - NK_INCLUDE_STANDARD_VARARGS -!!! WARNING - The following flags if defined need to be defined for both header and implementation: - - NK_INCLUDE_FIXED_TYPES - - NK_INCLUDE_DEFAULT_ALLOCATOR - - NK_INCLUDE_STANDARD_VARARGS - - NK_INCLUDE_VERTEX_BUFFER_OUTPUT - - NK_INCLUDE_FONT_BAKING - - NK_INCLUDE_DEFAULT_FONT - - NK_INCLUDE_STANDARD_VARARGS - - NK_INCLUDE_COMMAND_USERDATA -### Constants -Define | Description ---------------------------------|--------------------------------------- -NK_BUFFER_DEFAULT_INITIAL_SIZE | Initial buffer size allocated by all buffers while using the default allocator functions included by defining NK_INCLUDE_DEFAULT_ALLOCATOR. If you don't want to allocate the default 4k memory then redefine it. -NK_MAX_NUMBER_BUFFER | Maximum buffer size for the conversion buffer between float and string Under normal circumstances this should be more than sufficient. -NK_INPUT_MAX | Defines the max number of bytes which can be added as text input in one frame. Under normal circumstances this should be more than sufficient. -!!! WARNING - The following constants if defined need to be defined for both header and implementation: - - NK_MAX_NUMBER_BUFFER - - NK_BUFFER_DEFAULT_INITIAL_SIZE - - NK_INPUT_MAX -### Dependencies -Function | Description -------------|--------------------------------------------------------------- -NK_ASSERT | If you don't define this, nuklear will use with assert(). -NK_MEMSET | You can define this to 'memset' or your own memset implementation replacement. If not nuklear will use its own version. -NK_MEMCPY | You can define this to 'memcpy' or your own memcpy implementation replacement. If not nuklear will use its own version. -NK_SQRT | You can define this to 'sqrt' or your own sqrt implementation replacement. If not nuklear will use its own slow and not highly accurate version. -NK_SIN | You can define this to 'sinf' or your own sine implementation replacement. If not nuklear will use its own approximation implementation. -NK_COS | You can define this to 'cosf' or your own cosine implementation replacement. If not nuklear will use its own approximation implementation. -NK_STRTOD | You can define this to `strtod` or your own string to double conversion implementation replacement. If not defined nuklear will use its own imprecise and possibly unsafe version (does not handle nan or infinity!). -NK_DTOA | You can define this to `dtoa` or your own double to string conversion implementation replacement. If not defined nuklear will use its own imprecise and possibly unsafe version (does not handle nan or infinity!). -NK_VSNPRINTF| If you define `NK_INCLUDE_STANDARD_VARARGS` as well as `NK_INCLUDE_STANDARD_IO` and want to be safe define this to `vsnprintf` on compilers supporting later versions of C or C++. By default nuklear will check for your stdlib version in C as well as compiler version in C++. if `vsnprintf` is available it will define it to `vsnprintf` directly. If not defined and if you have older versions of C or C++ it will be defined to `vsprintf` which is unsafe. -!!! WARNING - The following dependencies will pull in the standard C library if not redefined: - - NK_ASSERT -!!! WARNING - The following dependencies if defined need to be defined for both header and implementation: - - NK_ASSERT -!!! WARNING - The following dependencies if defined need to be defined only for the implementation part: - - NK_MEMSET - - NK_MEMCPY - - NK_SQRT - - NK_SIN - - NK_COS - - NK_STRTOD - - NK_DTOA - - NK_VSNPRINTF -## Example -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -// init gui state -enum {EASY, HARD}; -static int op = EASY; -static float value = 0.6f; -static int i = 20; -struct nk_context ctx; -nk_init_fixed(&ctx, calloc(1, MAX_MEMORY), MAX_MEMORY, &font); -if (nk_begin(&ctx, "Show", nk_rect(50, 50, 220, 220), - NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE)) { - // fixed widget pixel width - nk_layout_row_static(&ctx, 30, 80, 1); - if (nk_button_label(&ctx, "button")) { - // event handling - } - // fixed widget window ratio width - nk_layout_row_dynamic(&ctx, 30, 2); - if (nk_option_label(&ctx, "easy", op == EASY)) op = EASY; - if (nk_option_label(&ctx, "hard", op == HARD)) op = HARD; - // custom widget pixel width - nk_layout_row_begin(&ctx, NK_STATIC, 30, 2); - { - nk_layout_row_push(&ctx, 50); - nk_label(&ctx, "Volume:", NK_TEXT_LEFT); - nk_layout_row_push(&ctx, 110); - nk_slider_float(&ctx, 0, &value, 1.0f, 0.1f); - } - nk_layout_row_end(&ctx); -} -nk_end(&ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -![](https://cloud.githubusercontent.com/assets/8057201/10187981/584ecd68-675c-11e5-897c-822ef534a876.png) -## API -### Context -Contexts are the main entry point and the majestro of nuklear and contain all required state. -They are used for window, memory, input, style, stack, commands and time management and need -to be passed into all nuklear GUI specific functions. -#### Usage -To use a context it first has to be initialized which can be achieved by calling -one of either `nk_init_default`, `nk_init_fixed`, `nk_init`, `nk_init_custom`. -Each takes in a font handle and a specific way of handling memory. Memory control -hereby ranges from standard library to just specifying a fixed sized block of memory -which nuklear has to manage itself from. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -struct nk_context ctx; -nk_init_xxx(&ctx, ...); -while (1) { - // [...] - nk_clear(&ctx); -} -nk_free(&ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#### Reference -Function | Description ---------------------|------------------------------------------------------- -__nk_init_default__ | Initializes context with standard library memory allocation (malloc,free) -__nk_init_fixed__ | Initializes context from single fixed size memory block -__nk_init__ | Initializes context with memory allocator callbacks for alloc and free -__nk_init_custom__ | Initializes context from two buffers. One for draw commands the other for window/panel/table allocations -__nk_clear__ | Called at the end of the frame to reset and prepare the context for the next frame -__nk_free__ | Shutdown and free all memory allocated inside the context -__nk_set_user_data__| Utility function to pass user data to draw command -#### nk_init_default -Initializes a `nk_context` struct with a default standard library allocator. -Should be used if you don't want to be bothered with memory management in nuklear. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_init_default(struct nk_context *ctx, const struct nk_user_font *font); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|--------------------------------------------------------------- -__ctx__ | Must point to an either stack or heap allocated `nk_context` struct -__font__ | Must point to a previously initialized font handle for more info look at font documentation -Returns either `false(0)` on failure or `true(1)` on success. -#### nk_init_fixed -Initializes a `nk_context` struct from single fixed size memory block -Should be used if you want complete control over nuklear's memory management. -Especially recommended for system with little memory or systems with virtual memory. -For the later case you can just allocate for example 16MB of virtual memory -and only the required amount of memory will actually be committed. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_init_fixed(struct nk_context *ctx, void *memory, nk_size size, const struct nk_user_font *font); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! Warning - make sure the passed memory block is aligned correctly for `nk_draw_commands`. -Parameter | Description -------------|-------------------------------------------------------------- -__ctx__ | Must point to an either stack or heap allocated `nk_context` struct -__memory__ | Must point to a previously allocated memory block -__size__ | Must contain the total size of __memory__ -__font__ | Must point to a previously initialized font handle for more info look at font documentation -Returns either `false(0)` on failure or `true(1)` on success. -#### nk_init -Initializes a `nk_context` struct with memory allocation callbacks for nuklear to allocate -memory from. Used internally for `nk_init_default` and provides a kitchen sink allocation -interface to nuklear. Can be useful for cases like monitoring memory consumption. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_init(struct nk_context *ctx, struct nk_allocator *alloc, const struct nk_user_font *font); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|--------------------------------------------------------------- -__ctx__ | Must point to an either stack or heap allocated `nk_context` struct -__alloc__ | Must point to a previously allocated memory allocator -__font__ | Must point to a previously initialized font handle for more info look at font documentation -Returns either `false(0)` on failure or `true(1)` on success. -#### nk_init_custom -Initializes a `nk_context` struct from two different either fixed or growing -buffers. The first buffer is for allocating draw commands while the second buffer is -used for allocating windows, panels and state tables. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_init_custom(struct nk_context *ctx, struct nk_buffer *cmds, struct nk_buffer *pool, const struct nk_user_font *font); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|--------------------------------------------------------------- -__ctx__ | Must point to an either stack or heap allocated `nk_context` struct -__cmds__ | Must point to a previously initialized memory buffer either fixed or dynamic to store draw commands into -__pool__ | Must point to a previously initialized memory buffer either fixed or dynamic to store windows, panels and tables -__font__ | Must point to a previously initialized font handle for more info look at font documentation -Returns either `false(0)` on failure or `true(1)` on success. -#### nk_clear -Resets the context state at the end of the frame. This includes mostly -garbage collector tasks like removing windows or table not called and therefore -used anymore. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_clear(struct nk_context *ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to a previously initialized `nk_context` struct -#### nk_free -Frees all memory allocated by nuklear. Not needed if context was -initialized with `nk_init_fixed`. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_free(struct nk_context *ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to a previously initialized `nk_context` struct -#### nk_set_user_data -Sets the currently passed userdata passed down into each draw command. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_set_user_data(struct nk_context *ctx, nk_handle data); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|-------------------------------------------------------------- -__ctx__ | Must point to a previously initialized `nk_context` struct -__data__ | Handle with either pointer or index to be passed into every draw commands -### Input -The input API is responsible for holding the current input state composed of -mouse, key and text input states. -It is worth noting that no direct os or window handling is done in nuklear. -Instead all input state has to be provided by platform specific code. This in one hand -expects more work from the user and complicates usage but on the other hand -provides simple abstraction over a big number of platforms, libraries and other -already provided functionality. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -nk_input_begin(&ctx); -while (GetEvent(&evt)) { - if (evt.type == MOUSE_MOVE) - nk_input_motion(&ctx, evt.motion.x, evt.motion.y); - else if (evt.type == [...]) { - // [...] - } -} nk_input_end(&ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#### Usage -Input state needs to be provided to nuklear by first calling `nk_input_begin` -which resets internal state like delta mouse position and button transistions. -After `nk_input_begin` all current input state needs to be provided. This includes -mouse motion, button and key pressed and released, text input and scrolling. -Both event- or state-based input handling are supported by this API -and should work without problems. Finally after all input state has been -mirrored `nk_input_end` needs to be called to finish input process. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -struct nk_context ctx; -nk_init_xxx(&ctx, ...); -while (1) { - Event evt; - nk_input_begin(&ctx); - while (GetEvent(&evt)) { - if (evt.type == MOUSE_MOVE) - nk_input_motion(&ctx, evt.motion.x, evt.motion.y); - else if (evt.type == [...]) { - // [...] - } - } - nk_input_end(&ctx); - // [...] - nk_clear(&ctx); -} nk_free(&ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#### Reference -Function | Description ---------------------|------------------------------------------------------- -__nk_input_begin__ | Begins the input mirroring process. Needs to be called before all other `nk_input_xxx` calls -__nk_input_motion__ | Mirrors mouse cursor position -__nk_input_key__ | Mirrors key state with either pressed or released -__nk_input_button__ | Mirrors mouse button state with either pressed or released -__nk_input_scroll__ | Mirrors mouse scroll values -__nk_input_char__ | Adds a single ASCII text character into an internal text buffer -__nk_input_glyph__ | Adds a single multi-byte UTF-8 character into an internal text buffer -__nk_input_unicode__| Adds a single unicode rune into an internal text buffer -__nk_input_end__ | Ends the input mirroring process by calculating state changes. Don't call any `nk_input_xxx` function referenced above after this call -#### nk_input_begin -Begins the input mirroring process by resetting text, scroll -mouse previous mouse position and movement as well as key state transitions, -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_input_begin(struct nk_context*); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to a previously initialized `nk_context` struct -#### nk_input_motion -Mirrors current mouse position to nuklear -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_input_motion(struct nk_context *ctx, int x, int y); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to a previously initialized `nk_context` struct -__x__ | Must hold an integer describing the current mouse cursor x-position -__y__ | Must hold an integer describing the current mouse cursor y-position -#### nk_input_key -Mirrors state of a specific key to nuklear -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_input_key(struct nk_context*, enum nk_keys key, int down); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to a previously initialized `nk_context` struct -__key__ | Must be any value specified in enum `nk_keys` that needs to be mirrored -__down__ | Must be 0 for key is up and 1 for key is down -#### nk_input_button -Mirrors the state of a specific mouse button to nuklear -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_input_button(struct nk_context *ctx, enum nk_buttons btn, int x, int y, int down); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to a previously initialized `nk_context` struct -__btn__ | Must be any value specified in enum `nk_buttons` that needs to be mirrored -__x__ | Must contain an integer describing mouse cursor x-position on click up/down -__y__ | Must contain an integer describing mouse cursor y-position on click up/down -__down__ | Must be 0 for key is up and 1 for key is down -#### nk_input_scroll -Copies the last mouse scroll value to nuklear. Is generally -a scroll value. So does not have to come from mouse and could also originate -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_input_scroll(struct nk_context *ctx, struct nk_vec2 val); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to a previously initialized `nk_context` struct -__val__ | vector with both X- as well as Y-scroll value -#### nk_input_char -Copies a single ASCII character into an internal text buffer -This is basically a helper function to quickly push ASCII characters into -nuklear. -!!! Note - Stores up to NK_INPUT_MAX bytes between `nk_input_begin` and `nk_input_end`. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_input_char(struct nk_context *ctx, char c); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to a previously initialized `nk_context` struct -__c__ | Must be a single ASCII character preferable one that can be printed -#### nk_input_glyph -Converts an encoded unicode rune into UTF-8 and copies the result into an -internal text buffer. -!!! Note - Stores up to NK_INPUT_MAX bytes between `nk_input_begin` and `nk_input_end`. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_input_glyph(struct nk_context *ctx, const nk_glyph g); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to a previously initialized `nk_context` struct -__g__ | UTF-32 unicode codepoint -#### nk_input_unicode -Converts a unicode rune into UTF-8 and copies the result -into an internal text buffer. -!!! Note - Stores up to NK_INPUT_MAX bytes between `nk_input_begin` and `nk_input_end`. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_input_unicode(struct nk_context*, nk_rune rune); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to a previously initialized `nk_context` struct -__rune__ | UTF-32 unicode codepoint -#### nk_input_end -End the input mirroring process by resetting mouse grabbing -state to ensure the mouse cursor is not grabbed indefinitely./// -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_input_end(struct nk_context *ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to a previously initialized `nk_context` struct -### Drawing -This library was designed to be render backend agnostic so it does -not draw anything to screen directly. Instead all drawn shapes, widgets -are made of, are buffered into memory and make up a command queue. -Each frame therefore fills the command buffer with draw commands -that then need to be executed by the user and his own render backend. -After that the command buffer needs to be cleared and a new frame can be -started. It is probably important to note that the command buffer is the main -drawing API and the optional vertex buffer API only takes this format and -converts it into a hardware accessible format. -#### Usage -To draw all draw commands accumulated over a frame you need your own render -backend able to draw a number of 2D primitives. This includes at least -filled and stroked rectangles, circles, text, lines, triangles and scissors. -As soon as this criterion is met you can iterate over each draw command -and execute each draw command in a interpreter like fashion: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -const struct nk_command *cmd = 0; -nk_foreach(cmd, &ctx) { - switch (cmd->type) { - case NK_COMMAND_LINE: - your_draw_line_function(...) - break; - case NK_COMMAND_RECT - your_draw_rect_function(...) - break; - case //...: - //[...] - } -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -In program flow context draw commands need to be executed after input has been -gathered and the complete UI with windows and their contained widgets have -been executed and before calling `nk_clear` which frees all previously -allocated draw commands. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -struct nk_context ctx; -nk_init_xxx(&ctx, ...); -while (1) { - Event evt; - nk_input_begin(&ctx); - while (GetEvent(&evt)) { - if (evt.type == MOUSE_MOVE) - nk_input_motion(&ctx, evt.motion.x, evt.motion.y); - else if (evt.type == [...]) { - [...] - } - } - nk_input_end(&ctx); - // - // [...] - // - const struct nk_command *cmd = 0; - nk_foreach(cmd, &ctx) { - switch (cmd->type) { - case NK_COMMAND_LINE: - your_draw_line_function(...) - break; - case NK_COMMAND_RECT - your_draw_rect_function(...) - break; - case ...: - // [...] - } - nk_clear(&ctx); -} -nk_free(&ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You probably noticed that you have to draw all of the UI each frame which is -quite wasteful. While the actual UI updating loop is quite fast rendering -without actually needing it is not. So there are multiple things you could do. -First is only update on input. This of course is only an option if your -application only depends on the UI and does not require any outside calculations. -If you actually only update on input make sure to update the UI two times each -frame and call `nk_clear` directly after the first pass and only draw in -the second pass. In addition it is recommended to also add additional timers -to make sure the UI is not drawn more than a fixed number of frames per second. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -struct nk_context ctx; -nk_init_xxx(&ctx, ...); -while (1) { - // [...wait for input ] - // [...do two UI passes ...] - do_ui(...) - nk_clear(&ctx); - do_ui(...) - // - // draw - const struct nk_command *cmd = 0; - nk_foreach(cmd, &ctx) { - switch (cmd->type) { - case NK_COMMAND_LINE: - your_draw_line_function(...) - break; - case NK_COMMAND_RECT - your_draw_rect_function(...) - break; - case ...: - //[...] - } - nk_clear(&ctx); -} -nk_free(&ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The second probably more applicable trick is to only draw if anything changed. -It is not really useful for applications with continuous draw loop but -quite useful for desktop applications. To actually get nuklear to only -draw on changes you first have to define `NK_ZERO_COMMAND_MEMORY` and -allocate a memory buffer that will store each unique drawing output. -After each frame you compare the draw command memory inside the library -with your allocated buffer by memcmp. If memcmp detects differences -you have to copy the command buffer into the allocated buffer -and then draw like usual (this example uses fixed memory but you could -use dynamically allocated memory). -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -//[... other defines ...] -#define NK_ZERO_COMMAND_MEMORY -#include "nuklear.h" -// -// setup context -struct nk_context ctx; -void *last = calloc(1,64*1024); -void *buf = calloc(1,64*1024); -nk_init_fixed(&ctx, buf, 64*1024); -// -// loop -while (1) { - // [...input...] - // [...ui...] - void *cmds = nk_buffer_memory(&ctx.memory); - if (memcmp(cmds, last, ctx.memory.allocated)) { - memcpy(last,cmds,ctx.memory.allocated); - const struct nk_command *cmd = 0; - nk_foreach(cmd, &ctx) { - switch (cmd->type) { - case NK_COMMAND_LINE: - your_draw_line_function(...) - break; - case NK_COMMAND_RECT - your_draw_rect_function(...) - break; - case ...: - // [...] - } - } - } - nk_clear(&ctx); -} -nk_free(&ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Finally while using draw commands makes sense for higher abstracted platforms like -X11 and Win32 or drawing libraries it is often desirable to use graphics -hardware directly. Therefore it is possible to just define -`NK_INCLUDE_VERTEX_BUFFER_OUTPUT` which includes optional vertex output. -To access the vertex output you first have to convert all draw commands into -vertexes by calling `nk_convert` which takes in your preferred vertex format. -After successfully converting all draw commands just iterate over and execute all -vertex draw commands: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -// fill configuration -struct nk_convert_config cfg = {}; -static const struct nk_draw_vertex_layout_element vertex_layout[] = { - {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct your_vertex, pos)}, - {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct your_vertex, uv)}, - {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct your_vertex, col)}, - {NK_VERTEX_LAYOUT_END} -}; -cfg.shape_AA = NK_ANTI_ALIASING_ON; -cfg.line_AA = NK_ANTI_ALIASING_ON; -cfg.vertex_layout = vertex_layout; -cfg.vertex_size = sizeof(struct your_vertex); -cfg.vertex_alignment = NK_ALIGNOF(struct your_vertex); -cfg.circle_segment_count = 22; -cfg.curve_segment_count = 22; -cfg.arc_segment_count = 22; -cfg.global_alpha = 1.0f; -cfg.null = dev->null; -// -// setup buffers and convert -struct nk_buffer cmds, verts, idx; -nk_buffer_init_default(&cmds); -nk_buffer_init_default(&verts); -nk_buffer_init_default(&idx); -nk_convert(&ctx, &cmds, &verts, &idx, &cfg); -// -// draw -nk_draw_foreach(cmd, &ctx, &cmds) { -if (!cmd->elem_count) continue; - //[...] -} -nk_buffer_free(&cms); -nk_buffer_free(&verts); -nk_buffer_free(&idx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#### Reference -Function | Description ---------------------|------------------------------------------------------- -__nk__begin__ | Returns the first draw command in the context draw command list to be drawn -__nk__next__ | Increments the draw command iterator to the next command inside the context draw command list -__nk_foreach__ | Iterates over each draw command inside the context draw command list -__nk_convert__ | Converts from the abstract draw commands list into a hardware accessible vertex format -__nk_draw_begin__ | Returns the first vertex command in the context vertex draw list to be executed -__nk__draw_next__ | Increments the vertex command iterator to the next command inside the context vertex command list -__nk__draw_end__ | Returns the end of the vertex draw list -__nk_draw_foreach__ | Iterates over each vertex draw command inside the vertex draw list -#### nk__begin -Returns a draw command list iterator to iterate all draw -commands accumulated over one frame. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -const struct nk_command* nk__begin(struct nk_context*); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | must point to an previously initialized `nk_context` struct at the end of a frame -Returns draw command pointer pointing to the first command inside the draw command list -#### nk__next -Returns a draw command list iterator to iterate all draw -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -const struct nk_command* nk__next(struct nk_context*, const struct nk_command*); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct at the end of a frame -__cmd__ | Must point to an previously a draw command either returned by `nk__begin` or `nk__next` -Returns draw command pointer pointing to the next command inside the draw command list -#### nk_foreach -Iterates over each draw command inside the context draw command list -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -#define nk_foreach(c, ctx) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct at the end of a frame -__cmd__ | Command pointer initialized to NULL -Returns draw command pointer pointing to the next command inside the draw command list -#### nk_convert -Converts all internal draw commands into vertex draw commands and fills -three buffers with vertexes, vertex draw commands and vertex indices. The vertex format -as well as some other configuration values have to be configured by filling out a -`nk_convert_config` struct. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -nk_flags nk_convert(struct nk_context *ctx, struct nk_buffer *cmds, -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct at the end of a frame -__cmds__ | Must point to a previously initialized buffer to hold converted vertex draw commands -__vertices__| Must point to a previously initialized buffer to hold all produced vertices -__elements__| Must point to a previously initialized buffer to hold all produced vertex indices -__config__ | Must point to a filled out `nk_config` struct to configure the conversion process -Returns one of enum nk_convert_result error codes -Parameter | Description ---------------------------------|----------------------------------------------------------- -NK_CONVERT_SUCCESS | Signals a successful draw command to vertex buffer conversion -NK_CONVERT_INVALID_PARAM | An invalid argument was passed in the function call -NK_CONVERT_COMMAND_BUFFER_FULL | The provided buffer for storing draw commands is full or failed to allocate more memory -NK_CONVERT_VERTEX_BUFFER_FULL | The provided buffer for storing vertices is full or failed to allocate more memory -NK_CONVERT_ELEMENT_BUFFER_FULL | The provided buffer for storing indicies is full or failed to allocate more memory -#### nk__draw_begin -Returns a draw vertex command buffer iterator to iterate each the vertex draw command buffer -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -const struct nk_draw_command* nk__draw_begin(const struct nk_context*, const struct nk_buffer*); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct at the end of a frame -__buf__ | Must point to an previously by `nk_convert` filled out vertex draw command buffer -Returns vertex draw command pointer pointing to the first command inside the vertex draw command buffer -#### nk__draw_end -Returns the vertex draw command at the end of the vertex draw command buffer -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -const struct nk_draw_command* nk__draw_end(const struct nk_context *ctx, const struct nk_buffer *buf); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct at the end of a frame -__buf__ | Must point to an previously by `nk_convert` filled out vertex draw command buffer -Returns vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer -#### nk__draw_next -Increments the vertex draw command buffer iterator -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -const struct nk_draw_command* nk__draw_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_context*); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__cmd__ | Must point to an previously either by `nk__draw_begin` or `nk__draw_next` returned vertex draw command -__buf__ | Must point to an previously by `nk_convert` filled out vertex draw command buffer -__ctx__ | Must point to an previously initialized `nk_context` struct at the end of a frame -Returns vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer -#### nk_draw_foreach -Iterates over each vertex draw command inside a vertex draw command buffer -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -#define nk_draw_foreach(cmd,ctx, b) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__cmd__ | `nk_draw_command`iterator set to NULL -__buf__ | Must point to an previously by `nk_convert` filled out vertex draw command buffer -__ctx__ | Must point to an previously initialized `nk_context` struct at the end of a frame -### Window -Windows are the main persistent state used inside nuklear and are life time -controlled by simply "retouching" (i.e. calling) each window each frame. -All widgets inside nuklear can only be added inside function pair `nk_begin_xxx` -and `nk_end`. Calling any widgets outside these two functions will result in an -assert in debug or no state change in release mode.

-Each window holds frame persistent state like position, size, flags, state tables, -and some garbage collected internal persistent widget state. Each window -is linked into a window stack list which determines the drawing and overlapping -order. The topmost window thereby is the currently active window.

-To change window position inside the stack occurs either automatically by -user input by being clicked on or programmatically by calling `nk_window_focus`. -Windows by default are visible unless explicitly being defined with flag -`NK_WINDOW_HIDDEN`, the user clicked the close button on windows with flag -`NK_WINDOW_CLOSABLE` or if a window was explicitly hidden by calling -`nk_window_show`. To explicitly close and destroy a window call `nk_window_close`.

-#### Usage -To create and keep a window you have to call one of the two `nk_begin_xxx` -functions to start window declarations and `nk_end` at the end. Furthermore it -is recommended to check the return value of `nk_begin_xxx` and only process -widgets inside the window if the value is not 0. Either way you have to call -`nk_end` at the end of window declarations. Furthermore, do not attempt to -nest `nk_begin_xxx` calls which will hopefully result in an assert or if not -in a segmentation fault. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -if (nk_begin_xxx(...) { - // [... widgets ...] -} -nk_end(ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -In the grand concept window and widget declarations need to occur after input -handling and before drawing to screen. Not doing so can result in higher -latency or at worst invalid behavior. Furthermore make sure that `nk_clear` -is called at the end of the frame. While nuklear's default platform backends -already call `nk_clear` for you if you write your own backend not calling -`nk_clear` can cause asserts or even worse undefined behavior. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -struct nk_context ctx; -nk_init_xxx(&ctx, ...); -while (1) { - Event evt; - nk_input_begin(&ctx); - while (GetEvent(&evt)) { - if (evt.type == MOUSE_MOVE) - nk_input_motion(&ctx, evt.motion.x, evt.motion.y); - else if (evt.type == [...]) { - nk_input_xxx(...); - } - } - nk_input_end(&ctx); - if (nk_begin_xxx(...) { - //[...] - } - nk_end(ctx); - const struct nk_command *cmd = 0; - nk_foreach(cmd, &ctx) { - case NK_COMMAND_LINE: - your_draw_line_function(...) - break; - case NK_COMMAND_RECT - your_draw_rect_function(...) - break; - case //...: - //[...] - } - nk_clear(&ctx); -} -nk_free(&ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#### Reference -Function | Description -------------------------------------|---------------------------------------- -nk_begin | Starts a new window; needs to be called every frame for every window (unless hidden) or otherwise the window gets removed -nk_begin_titled | Extended window start with separated title and identifier to allow multiple windows with same name but not title -nk_end | Needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup -nk_window_find | Finds and returns the window with give name -nk_window_get_bounds | Returns a rectangle with screen position and size of the currently processed window. -nk_window_get_position | Returns the position of the currently processed window -nk_window_get_size | Returns the size with width and height of the currently processed window -nk_window_get_width | Returns the width of the currently processed window -nk_window_get_height | Returns the height of the currently processed window -nk_window_get_panel | Returns the underlying panel which contains all processing state of the current window -nk_window_get_content_region | Returns the position and size of the currently visible and non-clipped space inside the currently processed window -nk_window_get_content_region_min | Returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window -nk_window_get_content_region_max | Returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window -nk_window_get_content_region_size | Returns the size of the currently visible and non-clipped space inside the currently processed window -nk_window_get_canvas | Returns the draw command buffer. Can be used to draw custom widgets -nk_window_has_focus | Returns if the currently processed window is currently active -nk_window_is_collapsed | Returns if the window with given name is currently minimized/collapsed -nk_window_is_closed | Returns if the currently processed window was closed -nk_window_is_hidden | Returns if the currently processed window was hidden -nk_window_is_active | Same as nk_window_has_focus for some reason -nk_window_is_hovered | Returns if the currently processed window is currently being hovered by mouse -nk_window_is_any_hovered | Return if any window currently hovered -nk_item_is_any_active | Returns if any window or widgets is currently hovered or active -nk_window_set_bounds | Updates position and size of the currently processed window -nk_window_set_position | Updates position of the currently process window -nk_window_set_size | Updates the size of the currently processed window -nk_window_set_focus | Set the currently processed window as active window -nk_window_close | Closes the window with given window name which deletes the window at the end of the frame -nk_window_collapse | Collapses the window with given window name -nk_window_collapse_if | Collapses the window with given window name if the given condition was met -nk_window_show | Hides a visible or reshows a hidden window -nk_window_show_if | Hides/shows a window depending on condition -#### nk_panel_flags -Flag | Description -----------------------------|---------------------------------------- -NK_WINDOW_BORDER | Draws a border around the window to visually separate window from the background -NK_WINDOW_MOVABLE | The movable flag indicates that a window can be moved by user input or by dragging the window header -NK_WINDOW_SCALABLE | The scalable flag indicates that a window can be scaled by user input by dragging a scaler icon at the button of the window -NK_WINDOW_CLOSABLE | Adds a closable icon into the header -NK_WINDOW_MINIMIZABLE | Adds a minimize icon into the header -NK_WINDOW_NO_SCROLLBAR | Removes the scrollbar from the window -NK_WINDOW_TITLE | Forces a header at the top at the window showing the title -NK_WINDOW_SCROLL_AUTO_HIDE | Automatically hides the window scrollbar if no user interaction: also requires delta time in `nk_context` to be set each frame -NK_WINDOW_BACKGROUND | Always keep window in the background -NK_WINDOW_SCALE_LEFT | Puts window scaler in the left-ottom corner instead right-bottom -NK_WINDOW_NO_INPUT | Prevents window of scaling, moving or getting focus -#### nk_collapse_states -State | Description -----------------|----------------------------------------------------------- -__NK_MINIMIZED__| UI section is collased and not visibile until maximized -__NK_MAXIMIZED__| UI section is extended and visibile until minimized -

-#### nk_begin -Starts a new window; needs to be called every frame for every -window (unless hidden) or otherwise the window gets removed -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_begin(struct nk_context *ctx, const char *title, struct nk_rect bounds, nk_flags flags); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__title__ | Window title and identifier. Needs to be persistent over frames to identify the window -__bounds__ | Initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame -__flags__ | Window flags defined in the nk_panel_flags section with a number of different window behaviors -Returns `true(1)` if the window can be filled up with widgets from this point -until `nk_end` or `false(0)` otherwise for example if minimized -#### nk_begin_titled -Extended window start with separated title and identifier to allow multiple -windows with same name but not title -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, struct nk_rect bounds, nk_flags flags); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__name__ | Window identifier. Needs to be persistent over frames to identify the window -__title__ | Window title displayed inside header if flag `NK_WINDOW_TITLE` or either `NK_WINDOW_CLOSABLE` or `NK_WINDOW_MINIMIZED` was set -__bounds__ | Initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame -__flags__ | Window flags defined in the nk_panel_flags section with a number of different window behaviors -Returns `true(1)` if the window can be filled up with widgets from this point -until `nk_end` or `false(0)` otherwise for example if minimized -#### nk_end -Needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup. -All widget calls after this functions will result in asserts or no state changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_end(struct nk_context *ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -#### nk_window_find -Finds and returns a window from passed name -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_end(struct nk_context *ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__name__ | Window identifier -Returns a `nk_window` struct pointing to the identified window or NULL if -no window with given name was found -#### nk_window_get_bounds -Returns a rectangle with screen position and size of the currently processed window -!!! WARNING - Only call this function between calls `nk_begin_xxx` and `nk_end` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -struct nk_rect nk_window_get_bounds(const struct nk_context *ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -Returns a `nk_rect` struct with window upper left window position and size -#### nk_window_get_bounds -Returns the position of the currently processed window. -!!! WARNING - Only call this function between calls `nk_begin_xxx` and `nk_end` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -struct nk_vec2 nk_window_get_position(const struct nk_context *ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -Returns a `nk_vec2` struct with window upper left position -#### nk_window_get_size -Returns the size with width and height of the currently processed window. -!!! WARNING - Only call this function between calls `nk_begin_xxx` and `nk_end` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -struct nk_vec2 nk_window_get_size(const struct nk_context *ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -Returns a `nk_vec2` struct with window width and height -#### nk_window_get_width -Returns the width of the currently processed window. -!!! WARNING - Only call this function between calls `nk_begin_xxx` and `nk_end` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -float nk_window_get_width(const struct nk_context *ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -Returns the current window width -#### nk_window_get_height -Returns the height of the currently processed window. -!!! WARNING - Only call this function between calls `nk_begin_xxx` and `nk_end` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -float nk_window_get_height(const struct nk_context *ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -Returns the current window height -#### nk_window_get_panel -Returns the underlying panel which contains all processing state of the current window. -!!! WARNING - Only call this function between calls `nk_begin_xxx` and `nk_end` -!!! WARNING - Do not keep the returned panel pointer around it is only valid until `nk_end` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -struct nk_panel* nk_window_get_panel(struct nk_context *ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -Returns a pointer to window internal `nk_panel` state. -#### nk_window_get_content_region -Returns the position and size of the currently visible and non-clipped space -inside the currently processed window. -!!! WARNING - Only call this function between calls `nk_begin_xxx` and `nk_end` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -struct nk_rect nk_window_get_content_region(struct nk_context *ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -Returns `nk_rect` struct with screen position and size (no scrollbar offset) -of the visible space inside the current window -#### nk_window_get_content_region_min -Returns the upper left position of the currently visible and non-clipped -space inside the currently processed window. -!!! WARNING - Only call this function between calls `nk_begin_xxx` and `nk_end` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -struct nk_vec2 nk_window_get_content_region_min(struct nk_context *ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -returns `nk_vec2` struct with upper left screen position (no scrollbar offset) -of the visible space inside the current window -#### nk_window_get_content_region_max -Returns the lower right screen position of the currently visible and -non-clipped space inside the currently processed window. -!!! WARNING - Only call this function between calls `nk_begin_xxx` and `nk_end` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -struct nk_vec2 nk_window_get_content_region_max(struct nk_context *ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -Returns `nk_vec2` struct with lower right screen position (no scrollbar offset) -of the visible space inside the current window -#### nk_window_get_content_region_size -Returns the size of the currently visible and non-clipped space inside the -currently processed window -!!! WARNING - Only call this function between calls `nk_begin_xxx` and `nk_end` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -struct nk_vec2 nk_window_get_content_region_size(struct nk_context *ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -Returns `nk_vec2` struct with size the visible space inside the current window -#### nk_window_get_canvas -Returns the draw command buffer. Can be used to draw custom widgets -!!! WARNING - Only call this function between calls `nk_begin_xxx` and `nk_end` -!!! WARNING - Do not keep the returned command buffer pointer around it is only valid until `nk_end` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -struct nk_command_buffer* nk_window_get_canvas(struct nk_context *ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -Returns a pointer to window internal `nk_command_buffer` struct used as -drawing canvas. Can be used to do custom drawing. -#### nk_window_has_focus -Returns if the currently processed window is currently active -!!! WARNING - Only call this function between calls `nk_begin_xxx` and `nk_end` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_window_has_focus(const struct nk_context *ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -Returns `false(0)` if current window is not active or `true(1)` if it is -#### nk_window_is_hovered -Return if the current window is being hovered -!!! WARNING - Only call this function between calls `nk_begin_xxx` and `nk_end` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_window_is_hovered(struct nk_context *ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -Returns `true(1)` if current window is hovered or `false(0)` otherwise -#### nk_window_is_collapsed -Returns if the window with given name is currently minimized/collapsed -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_window_is_collapsed(struct nk_context *ctx, const char *name); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__name__ | Identifier of window you want to check if it is collapsed -Returns `true(1)` if current window is minimized and `false(0)` if window not -found or is not minimized -#### nk_window_is_closed -Returns if the window with given name was closed by calling `nk_close` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_window_is_closed(struct nk_context *ctx, const char *name); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__name__ | Identifier of window you want to check if it is closed -Returns `true(1)` if current window was closed or `false(0)` window not found or not closed -#### nk_window_is_hidden -Returns if the window with given name is hidden -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_window_is_hidden(struct nk_context *ctx, const char *name); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__name__ | Identifier of window you want to check if it is hidden -Returns `true(1)` if current window is hidden or `false(0)` window not found or visible -#### nk_window_is_active -Same as nk_window_has_focus for some reason -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_window_is_active(struct nk_context *ctx, const char *name); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__name__ | Identifier of window you want to check if it is active -Returns `true(1)` if current window is active or `false(0)` window not found or not active -#### nk_window_is_any_hovered -Returns if the any window is being hovered -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_window_is_any_hovered(struct nk_context*); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -Returns `true(1)` if any window is hovered or `false(0)` otherwise -#### nk_item_is_any_active -Returns if the any window is being hovered or any widget is currently active. -Can be used to decide if input should be processed by UI or your specific input handling. -Example could be UI and 3D camera to move inside a 3D space. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_item_is_any_active(struct nk_context*); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -Returns `true(1)` if any window is hovered or any item is active or `false(0)` otherwise -#### nk_window_set_bounds -Updates position and size of window with passed in name -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_window_set_bounds(struct nk_context*, const char *name, struct nk_rect bounds); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__name__ | Identifier of the window to modify both position and size -__bounds__ | Must point to a `nk_rect` struct with the new position and size -#### nk_window_set_position -Updates position of window with passed name -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_window_set_position(struct nk_context*, const char *name, struct nk_vec2 pos); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__name__ | Identifier of the window to modify both position -__pos__ | Must point to a `nk_vec2` struct with the new position -#### nk_window_set_size -Updates size of window with passed in name -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_window_set_size(struct nk_context*, const char *name, struct nk_vec2); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__name__ | Identifier of the window to modify both window size -__size__ | Must point to a `nk_vec2` struct with new window size -#### nk_window_set_focus -Sets the window with given name as active -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_window_set_focus(struct nk_context*, const char *name); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__name__ | Identifier of the window to set focus on -#### nk_window_close -Closes a window and marks it for being freed at the end of the frame -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_window_close(struct nk_context *ctx, const char *name); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__name__ | Identifier of the window to close -#### nk_window_collapse -Updates collapse state of a window with given name -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_window_collapse(struct nk_context*, const char *name, enum nk_collapse_states state); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__name__ | Identifier of the window to close -__state__ | value out of nk_collapse_states section -#### nk_window_collapse_if -Updates collapse state of a window with given name if given condition is met -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_window_collapse_if(struct nk_context*, const char *name, enum nk_collapse_states, int cond); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__name__ | Identifier of the window to either collapse or maximize -__state__ | value out of nk_collapse_states section the window should be put into -__cond__ | condition that has to be met to actually commit the collapse state change -#### nk_window_show -updates visibility state of a window with given name -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_window_show(struct nk_context*, const char *name, enum nk_show_states); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__name__ | Identifier of the window to either collapse or maximize -__state__ | state with either visible or hidden to modify the window with -#### nk_window_show_if -Updates visibility state of a window with given name if a given condition is met -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_window_show_if(struct nk_context*, const char *name, enum nk_show_states, int cond); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__name__ | Identifier of the window to either hide or show -__state__ | state with either visible or hidden to modify the window with -__cond__ | condition that has to be met to actually commit the visbility state change -### Layouting -Layouting in general describes placing widget inside a window with position and size. -While in this particular implementation there are five different APIs for layouting -each with different trade offs between control and ease of use.

-All layouting methods in this library are based around the concept of a row. -A row has a height the window content grows by and a number of columns and each -layouting method specifies how each widget is placed inside the row. -After a row has been allocated by calling a layouting functions and then -filled with widgets will advance an internal pointer over the allocated row.

-To actually define a layout you just call the appropriate layouting function -and each subsequent widget call will place the widget as specified. Important -here is that if you define more widgets then columns defined inside the layout -functions it will allocate the next row without you having to make another layouting

-call. -Biggest limitation with using all these APIs outside the `nk_layout_space_xxx` API -is that you have to define the row height for each. However the row height -often depends on the height of the font.

-To fix that internally nuklear uses a minimum row height that is set to the -height plus padding of currently active font and overwrites the row height -value if zero.

-If you manually want to change the minimum row height then -use nk_layout_set_min_row_height, and use nk_layout_reset_min_row_height to -reset it back to be derived from font height.

-Also if you change the font in nuklear it will automatically change the minimum -row height for you and. This means if you change the font but still want -a minimum row height smaller than the font you have to repush your value.

-For actually more advanced UI I would even recommend using the `nk_layout_space_xxx` -layouting method in combination with a cassowary constraint solver (there are -some versions on github with permissive license model) to take over all control over widget -layouting yourself. However for quick and dirty layouting using all the other layouting -functions should be fine. -#### Usage -1. __nk_layout_row_dynamic__

- The easiest layouting function is `nk_layout_row_dynamic`. It provides each - widgets with same horizontal space inside the row and dynamically grows - if the owning window grows in width. So the number of columns dictates - the size of each widget dynamically by formula: - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c - widget_width = (window_width - padding - spacing) * (1/colum_count) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Just like all other layouting APIs if you define more widget than columns this - library will allocate a new row and keep all layouting parameters previously - defined. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c - if (nk_begin_xxx(...) { - // first row with height: 30 composed of two widgets - nk_layout_row_dynamic(&ctx, 30, 2); - nk_widget(...); - nk_widget(...); - // - // second row with same parameter as defined above - nk_widget(...); - nk_widget(...); - // - // third row uses 0 for height which will use auto layouting - nk_layout_row_dynamic(&ctx, 0, 2); - nk_widget(...); - nk_widget(...); - } - nk_end(...); - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -2. __nk_layout_row_static__

- Another easy layouting function is `nk_layout_row_static`. It provides each - widget with same horizontal pixel width inside the row and does not grow - if the owning window scales smaller or bigger. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c - if (nk_begin_xxx(...) { - // first row with height: 30 composed of two widgets with width: 80 - nk_layout_row_static(&ctx, 30, 80, 2); - nk_widget(...); - nk_widget(...); - // - // second row with same parameter as defined above - nk_widget(...); - nk_widget(...); - // - // third row uses 0 for height which will use auto layouting - nk_layout_row_static(&ctx, 0, 80, 2); - nk_widget(...); - nk_widget(...); - } - nk_end(...); - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -3. __nk_layout_row_xxx__

- A little bit more advanced layouting API are functions `nk_layout_row_begin`, - `nk_layout_row_push` and `nk_layout_row_end`. They allow to directly - specify each column pixel or window ratio in a row. It supports either - directly setting per column pixel width or widget window ratio but not - both. Furthermore it is a immediate mode API so each value is directly - pushed before calling a widget. Therefore the layout is not automatically - repeating like the last two layouting functions. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c - if (nk_begin_xxx(...) { - // first row with height: 25 composed of two widgets with width 60 and 40 - nk_layout_row_begin(ctx, NK_STATIC, 25, 2); - nk_layout_row_push(ctx, 60); - nk_widget(...); - nk_layout_row_push(ctx, 40); - nk_widget(...); - nk_layout_row_end(ctx); - // - // second row with height: 25 composed of two widgets with window ratio 0.25 and 0.75 - nk_layout_row_begin(ctx, NK_DYNAMIC, 25, 2); - nk_layout_row_push(ctx, 0.25f); - nk_widget(...); - nk_layout_row_push(ctx, 0.75f); - nk_widget(...); - nk_layout_row_end(ctx); - // - // third row with auto generated height: composed of two widgets with window ratio 0.25 and 0.75 - nk_layout_row_begin(ctx, NK_DYNAMIC, 0, 2); - nk_layout_row_push(ctx, 0.25f); - nk_widget(...); - nk_layout_row_push(ctx, 0.75f); - nk_widget(...); - nk_layout_row_end(ctx); - } - nk_end(...); - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -4. __nk_layout_row__

- The array counterpart to API nk_layout_row_xxx is the single nk_layout_row - functions. Instead of pushing either pixel or window ratio for every widget - it allows to define it by array. The trade of for less control is that - `nk_layout_row` is automatically repeating. Otherwise the behavior is the - same. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c - if (nk_begin_xxx(...) { - // two rows with height: 30 composed of two widgets with width 60 and 40 - const float size[] = {60,40}; - nk_layout_row(ctx, NK_STATIC, 30, 2, ratio); - nk_widget(...); - nk_widget(...); - nk_widget(...); - nk_widget(...); - // - // two rows with height: 30 composed of two widgets with window ratio 0.25 and 0.75 - const float ratio[] = {0.25, 0.75}; - nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratio); - nk_widget(...); - nk_widget(...); - nk_widget(...); - nk_widget(...); - // - // two rows with auto generated height composed of two widgets with window ratio 0.25 and 0.75 - const float ratio[] = {0.25, 0.75}; - nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratio); - nk_widget(...); - nk_widget(...); - nk_widget(...); - nk_widget(...); - } - nk_end(...); - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -5. __nk_layout_row_template_xxx__

- The most complex and second most flexible API is a simplified flexbox version without - line wrapping and weights for dynamic widgets. It is an immediate mode API but - unlike `nk_layout_row_xxx` it has auto repeat behavior and needs to be called - before calling the templated widgets. - The row template layout has three different per widget size specifier. The first - one is the `nk_layout_row_template_push_static` with fixed widget pixel width. - They do not grow if the row grows and will always stay the same. - The second size specifier is `nk_layout_row_template_push_variable` - which defines a minimum widget size but it also can grow if more space is available - not taken by other widgets. - Finally there are dynamic widgets with `nk_layout_row_template_push_dynamic` - which are completely flexible and unlike variable widgets can even shrink - to zero if not enough space is provided. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c - if (nk_begin_xxx(...) { - // two rows with height: 30 composed of three widgets - nk_layout_row_template_begin(ctx, 30); - nk_layout_row_template_push_dynamic(ctx); - nk_layout_row_template_push_variable(ctx, 80); - nk_layout_row_template_push_static(ctx, 80); - nk_layout_row_template_end(ctx); - // - // first row - nk_widget(...); // dynamic widget can go to zero if not enough space - nk_widget(...); // variable widget with min 80 pixel but can grow bigger if enough space - nk_widget(...); // static widget with fixed 80 pixel width - // - // second row same layout - nk_widget(...); - nk_widget(...); - nk_widget(...); - } - nk_end(...); - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -6. __nk_layout_space_xxx__

- Finally the most flexible API directly allows you to place widgets inside the - window. The space layout API is an immediate mode API which does not support - row auto repeat and directly sets position and size of a widget. Position - and size hereby can be either specified as ratio of allocated space or - allocated space local position and pixel size. Since this API is quite - powerful there are a number of utility functions to get the available space - and convert between local allocated space and screen space. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c - if (nk_begin_xxx(...) { - // static row with height: 500 (you can set column count to INT_MAX if you don't want to be bothered) - nk_layout_space_begin(ctx, NK_STATIC, 500, INT_MAX); - nk_layout_space_push(ctx, nk_rect(0,0,150,200)); - nk_widget(...); - nk_layout_space_push(ctx, nk_rect(200,200,100,200)); - nk_widget(...); - nk_layout_space_end(ctx); - // - // dynamic row with height: 500 (you can set column count to INT_MAX if you don't want to be bothered) - nk_layout_space_begin(ctx, NK_DYNAMIC, 500, INT_MAX); - nk_layout_space_push(ctx, nk_rect(0.5,0.5,0.1,0.1)); - nk_widget(...); - nk_layout_space_push(ctx, nk_rect(0.7,0.6,0.1,0.1)); - nk_widget(...); - } - nk_end(...); - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#### Reference -Function | Description -----------------------------------------|------------------------------------ -nk_layout_set_min_row_height | Set the currently used minimum row height to a specified value -nk_layout_reset_min_row_height | Resets the currently used minimum row height to font height -nk_layout_widget_bounds | Calculates current width a static layout row can fit inside a window -nk_layout_ratio_from_pixel | Utility functions to calculate window ratio from pixel size -nk_layout_row_dynamic | Current layout is divided into n same sized growing columns -nk_layout_row_static | Current layout is divided into n same fixed sized columns -nk_layout_row_begin | Starts a new row with given height and number of columns -nk_layout_row_push | Pushes another column with given size or window ratio -nk_layout_row_end | Finished previously started row -nk_layout_row | Specifies row columns in array as either window ratio or size -nk_layout_row_template_begin | Begins the row template declaration -nk_layout_row_template_push_dynamic | Adds a dynamic column that dynamically grows and can go to zero if not enough space -nk_layout_row_template_push_variable | Adds a variable column that dynamically grows but does not shrink below specified pixel width -nk_layout_row_template_push_static | Adds a static column that does not grow and will always have the same size -nk_layout_row_template_end | Marks the end of the row template -nk_layout_space_begin | Begins a new layouting space that allows to specify each widgets position and size -nk_layout_space_push | Pushes position and size of the next widget in own coordinate space either as pixel or ratio -nk_layout_space_end | Marks the end of the layouting space -nk_layout_space_bounds | Callable after nk_layout_space_begin and returns total space allocated -nk_layout_space_to_screen | Converts vector from nk_layout_space coordinate space into screen space -nk_layout_space_to_local | Converts vector from screen space into nk_layout_space coordinates -nk_layout_space_rect_to_screen | Converts rectangle from nk_layout_space coordinate space into screen space -nk_layout_space_rect_to_local | Converts rectangle from screen space into nk_layout_space coordinates -#### nk_layout_set_min_row_height -Sets the currently used minimum row height. -!!! WARNING - The passed height needs to include both your preferred row height - as well as padding. No internal padding is added. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_layout_set_min_row_height(struct nk_context*, float height); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -__height__ | New minimum row height to be used for auto generating the row height -#### nk_layout_reset_min_row_height -Reset the currently used minimum row height back to `font_height + text_padding + padding` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_layout_reset_min_row_height(struct nk_context*); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -#### nk_layout_widget_bounds -Returns the width of the next row allocate by one of the layouting functions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -struct nk_rect nk_layout_widget_bounds(struct nk_context*); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -Return `nk_rect` with both position and size of the next row -#### nk_layout_ratio_from_pixel -Utility functions to calculate window ratio from pixel size -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -float nk_layout_ratio_from_pixel(struct nk_context*, float pixel_width); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -__pixel__ | Pixel_width to convert to window ratio -Returns `nk_rect` with both position and size of the next row -#### nk_layout_row_dynamic -Sets current row layout to share horizontal space -between @cols number of widgets evenly. Once called all subsequent widget -calls greater than @cols will allocate a new row with same layout. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -__height__ | Holds height of each widget in row or zero for auto layouting -__columns__ | Number of widget inside row -#### nk_layout_row_dynamic -Sets current row layout to fill @cols number of widgets -in row with same @item_width horizontal size. Once called all subsequent widget -calls greater than @cols will allocate a new row with same layout. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -__height__ | Holds height of each widget in row or zero for auto layouting -__width__ | Holds pixel width of each widget in the row -__columns__ | Number of widget inside row -#### nk_layout_row_begin -Starts a new dynamic or fixed row with given height and columns. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt, float row_height, int cols); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -__fmt__ | either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns -__height__ | holds height of each widget in row or zero for auto layouting -__columns__ | Number of widget inside row -#### nk_layout_row_push -Specifies either window ratio or width of a single column -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_layout_row_push(struct nk_context*, float value); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -__value__ | either a window ratio or fixed width depending on @fmt in previous `nk_layout_row_begin` call -#### nk_layout_row_end -Finished previously started row -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_layout_row_end(struct nk_context*); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -#### nk_layout_row -Specifies row columns in array as either window ratio or size -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_layout_row(struct nk_context*, enum nk_layout_format, float height, int cols, const float *ratio); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -__fmt__ | Either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns -__height__ | Holds height of each widget in row or zero for auto layouting -__columns__ | Number of widget inside row -#### nk_layout_row_template_begin -Begins the row template declaration -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_layout_row_template_begin(struct nk_context*, float row_height); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -__height__ | Holds height of each widget in row or zero for auto layouting -#### nk_layout_row_template_push_dynamic -Adds a dynamic column that dynamically grows and can go to zero if not enough space -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_layout_row_template_push_dynamic(struct nk_context*); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -__height__ | Holds height of each widget in row or zero for auto layouting -#### nk_layout_row_template_push_variable -Adds a variable column that dynamically grows but does not shrink below specified pixel width -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_layout_row_template_push_variable(struct nk_context*, float min_width); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -__width__ | Holds the minimum pixel width the next column must always be -#### nk_layout_row_template_push_static -Adds a static column that does not grow and will always have the same size -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_layout_row_template_push_static(struct nk_context*, float width); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -__width__ | Holds the absolute pixel width value the next column must be -#### nk_layout_row_template_end -Marks the end of the row template -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_layout_row_template_end(struct nk_context*); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -#### nk_layout_space_begin -Begins a new layouting space that allows to specify each widgets position and size. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_layout_space_begin(struct nk_context*, enum nk_layout_format, float height, int widget_count); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -__fmt__ | Either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns -__height__ | Holds height of each widget in row or zero for auto layouting -__columns__ | Number of widgets inside row -#### nk_layout_space_push -Pushes position and size of the next widget in own coordinate space either as pixel or ratio -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_layout_space_push(struct nk_context *ctx, struct nk_rect bounds); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` -__bounds__ | Position and size in laoyut space local coordinates -#### nk_layout_space_end -Marks the end of the layout space -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_layout_space_end(struct nk_context*); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` -#### nk_layout_space_bounds -Utility function to calculate total space allocated for `nk_layout_space` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -struct nk_rect nk_layout_space_bounds(struct nk_context*); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` -Returns `nk_rect` holding the total space allocated -#### nk_layout_space_to_screen -Converts vector from nk_layout_space coordinate space into screen space -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -struct nk_vec2 nk_layout_space_to_screen(struct nk_context*, struct nk_vec2); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` -__vec__ | Position to convert from layout space into screen coordinate space -Returns transformed `nk_vec2` in screen space coordinates -#### nk_layout_space_to_screen -Converts vector from layout space into screen space -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -struct nk_vec2 nk_layout_space_to_local(struct nk_context*, struct nk_vec2); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` -__vec__ | Position to convert from screen space into layout coordinate space -Returns transformed `nk_vec2` in layout space coordinates -#### nk_layout_space_rect_to_screen -Converts rectangle from screen space into layout space -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -struct nk_rect nk_layout_space_rect_to_screen(struct nk_context*, struct nk_rect); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` -__bounds__ | Rectangle to convert from layout space into screen space -Returns transformed `nk_rect` in screen space coordinates -#### nk_layout_space_rect_to_local -Converts rectangle from layout space into screen space -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -struct nk_rect nk_layout_space_rect_to_local(struct nk_context*, struct nk_rect); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` -__bounds__ | Rectangle to convert from layout space into screen space -Returns transformed `nk_rect` in layout space coordinates -### Groups -Groups are basically windows inside windows. They allow to subdivide space -in a window to layout widgets as a group. Almost all more complex widget -layouting requirements can be solved using groups and basic layouting -fuctionality. Groups just like windows are identified by an unique name and -internally keep track of scrollbar offsets by default. However additional -versions are provided to directly manage the scrollbar. -#### Usage -To create a group you have to call one of the three `nk_group_begin_xxx` -functions to start group declarations and `nk_group_end` at the end. Furthermore it -is required to check the return value of `nk_group_begin_xxx` and only process -widgets inside the window if the value is not 0. -Nesting groups is possible and even encouraged since many layouting schemes -can only be achieved by nesting. Groups, unlike windows, need `nk_group_end` -to be only called if the corosponding `nk_group_begin_xxx` call does not return 0: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -if (nk_group_begin_xxx(ctx, ...) { - // [... widgets ...] - nk_group_end(ctx); -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -In the grand concept groups can be called after starting a window -with `nk_begin_xxx` and before calling `nk_end`: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -struct nk_context ctx; -nk_init_xxx(&ctx, ...); -while (1) { - // Input - Event evt; - nk_input_begin(&ctx); - while (GetEvent(&evt)) { - if (evt.type == MOUSE_MOVE) - nk_input_motion(&ctx, evt.motion.x, evt.motion.y); - else if (evt.type == [...]) { - nk_input_xxx(...); - } - } - nk_input_end(&ctx); - // - // Window - if (nk_begin_xxx(...) { - // [...widgets...] - nk_layout_row_dynamic(...); - if (nk_group_begin_xxx(ctx, ...) { - //[... widgets ...] - nk_group_end(ctx); - } - } - nk_end(ctx); - // - // Draw - const struct nk_command *cmd = 0; - nk_foreach(cmd, &ctx) { - switch (cmd->type) { - case NK_COMMAND_LINE: - your_draw_line_function(...) - break; - case NK_COMMAND_RECT - your_draw_rect_function(...) - break; - case ...: - // [...] - } -} -nk_free(&ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#### Reference -Function | Description ---------------------------------|------------------------------------------- -nk_group_begin | Start a new group with internal scrollbar handling -nk_group_begin_titled | Start a new group with separeted name and title and internal scrollbar handling -nk_group_end | Ends a group. Should only be called if nk_group_begin returned non-zero -nk_group_scrolled_offset_begin | Start a new group with manual separated handling of scrollbar x- and y-offset -nk_group_scrolled_begin | Start a new group with manual scrollbar handling -nk_group_scrolled_end | Ends a group with manual scrollbar handling. Should only be called if nk_group_begin returned non-zero -#### nk_group_begin -Starts a new widget group. Requires a previous layouting function to specify a pos/size. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_group_begin(struct nk_context*, const char *title, nk_flags); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__title__ | Must be an unique identifier for this group that is also used for the group header -__flags__ | Window flags defined in the nk_panel_flags section with a number of different group behaviors -Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -#### nk_group_begin_titled -Starts a new widget group. Requires a previous layouting function to specify a pos/size. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_group_begin_titled(struct nk_context*, const char *name, const char *title, nk_flags); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__id__ | Must be an unique identifier for this group -__title__ | Group header title -__flags__ | Window flags defined in the nk_panel_flags section with a number of different group behaviors -Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -#### nk_group_end -Ends a widget group -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_group_end(struct nk_context*); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -#### nk_group_scrolled_offset_begin -starts a new widget group. requires a previous layouting function to specify -a size. Does not keep track of scrollbar. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_group_scrolled_offset_begin(struct nk_context*, nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__x_offset__| Scrollbar x-offset to offset all widgets inside the group horizontally. -__y_offset__| Scrollbar y-offset to offset all widgets inside the group vertically -__title__ | Window unique group title used to both identify and display in the group header -__flags__ | Window flags from the nk_panel_flags section -Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -#### nk_group_scrolled_begin -Starts a new widget group. requires a previous -layouting function to specify a size. Does not keep track of scrollbar. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_group_scrolled_begin(struct nk_context*, struct nk_scroll *off, const char *title, nk_flags); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__off__ | Both x- and y- scroll offset. Allows for manual scrollbar control -__title__ | Window unique group title used to both identify and display in the group header -__flags__ | Window flags from nk_panel_flags section -Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -#### nk_group_scrolled_end -Ends a widget group after calling nk_group_scrolled_offset_begin or nk_group_scrolled_begin. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_group_scrolled_end(struct nk_context*); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -### Tree -Trees represent two different concept. First the concept of a collapsable -UI section that can be either in a hidden or visibile state. They allow the UI -user to selectively minimize the current set of visible UI to comprehend. -The second concept are tree widgets for visual UI representation of trees.

-Trees thereby can be nested for tree representations and multiple nested -collapsable UI sections. All trees are started by calling of the -`nk_tree_xxx_push_tree` functions and ended by calling one of the -`nk_tree_xxx_pop_xxx()` functions. Each starting functions takes a title label -and optionally an image to be displayed and the initial collapse state from -the nk_collapse_states section.

-The runtime state of the tree is either stored outside the library by the caller -or inside which requires a unique ID. The unique ID can either be generated -automatically from `__FILE__` and `__LINE__` with function `nk_tree_push`, -by `__FILE__` and a user provided ID generated for example by loop index with -function `nk_tree_push_id` or completely provided from outside by user with -function `nk_tree_push_hashed`. -#### Usage -To create a tree you have to call one of the seven `nk_tree_xxx_push_xxx` -functions to start a collapsable UI section and `nk_tree_xxx_pop` to mark the -end. -Each starting function will either return `false(0)` if the tree is collapsed -or hidden and therefore does not need to be filled with content or `true(1)` -if visible and required to be filled. -!!! Note - The tree header does not require and layouting function and instead - calculates a auto height based on the currently used font size -The tree ending functions only need to be called if the tree content is -actually visible. So make sure the tree push function is guarded by `if` -and the pop call is only taken if the tree is visible. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -if (nk_tree_push(ctx, NK_TREE_TAB, "Tree", NK_MINIMIZED)) { - nk_layout_row_dynamic(...); - nk_widget(...); - nk_tree_pop(ctx); -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#### Reference -Function | Description -----------------------------|------------------------------------------- -nk_tree_push | Start a collapsable UI section with internal state management -nk_tree_push_id | Start a collapsable UI section with internal state management callable in a look -nk_tree_push_hashed | Start a collapsable UI section with internal state management with full control over internal unique ID use to store state -nk_tree_image_push | Start a collapsable UI section with image and label header -nk_tree_image_push_id | Start a collapsable UI section with image and label header and internal state management callable in a look -nk_tree_image_push_hashed | Start a collapsable UI section with image and label header and internal state management with full control over internal unique ID use to store state -nk_tree_pop | Ends a collapsable UI section -nk_tree_state_push | Start a collapsable UI section with external state management -nk_tree_state_image_push | Start a collapsable UI section with image and label header and external state management -nk_tree_state_pop | Ends a collapsabale UI section -#### nk_tree_type -Flag | Description -----------------|---------------------------------------- -NK_TREE_NODE | Highlighted tree header to mark a collapsable UI section -NK_TREE_TAB | Non-highighted tree header closer to tree representations -#### nk_tree_push -Starts a collapsable UI section with internal state management -!!! WARNING - To keep track of the runtime tree collapsable state this function uses - defines `__FILE__` and `__LINE__` to generate a unique ID. If you want - to call this function in a loop please use `nk_tree_push_id` or - `nk_tree_push_hashed` instead. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -#define nk_tree_push(ctx, type, title, state) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -__title__ | Label printed in the tree header -__state__ | Initial tree state value out of nk_collapse_states -Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -#### nk_tree_push_id -Starts a collapsable UI section with internal state management callable in a look -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -#define nk_tree_push_id(ctx, type, title, state, id) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -__title__ | Label printed in the tree header -__state__ | Initial tree state value out of nk_collapse_states -__id__ | Loop counter index if this function is called in a loop -Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -#### nk_tree_push_hashed -Start a collapsable UI section with internal state management with full -control over internal unique ID used to store state -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_tree_push_hashed(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -__title__ | Label printed in the tree header -__state__ | Initial tree state value out of nk_collapse_states -__hash__ | Memory block or string to generate the ID from -__len__ | Size of passed memory block or string in __hash__ -__seed__ | Seeding value if this function is called in a loop or default to `0` -Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -#### nk_tree_image_push -Start a collapsable UI section with image and label header -!!! WARNING - To keep track of the runtime tree collapsable state this function uses - defines `__FILE__` and `__LINE__` to generate a unique ID. If you want - to call this function in a loop please use `nk_tree_image_push_id` or - `nk_tree_image_push_hashed` instead. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -#define nk_tree_image_push(ctx, type, img, title, state) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -__img__ | Image to display inside the header on the left of the label -__title__ | Label printed in the tree header -__state__ | Initial tree state value out of nk_collapse_states -Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -#### nk_tree_image_push_id -Start a collapsable UI section with image and label header and internal state -management callable in a look -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -#define nk_tree_image_push_id(ctx, type, img, title, state, id) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -__img__ | Image to display inside the header on the left of the label -__title__ | Label printed in the tree header -__state__ | Initial tree state value out of nk_collapse_states -__id__ | Loop counter index if this function is called in a loop -Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -#### nk_tree_image_push_hashed -Start a collapsable UI section with internal state management with full -control over internal unique ID used to store state -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_tree_image_push_hashed(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct -__type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -__img__ | Image to display inside the header on the left of the label -__title__ | Label printed in the tree header -__state__ | Initial tree state value out of nk_collapse_states -__hash__ | Memory block or string to generate the ID from -__len__ | Size of passed memory block or string in __hash__ -__seed__ | Seeding value if this function is called in a loop or default to `0` -Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -#### nk_tree_pop -Ends a collapsabale UI section -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_tree_pop(struct nk_context*); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx` -#### nk_tree_state_push -Start a collapsable UI section with external state management -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_tree_state_push(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states *state); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx` -__type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -__title__ | Label printed in the tree header -__state__ | Persistent state to update -Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -#### nk_tree_state_image_push -Start a collapsable UI section with image and label header and external state management -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_tree_state_image_push(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states *state); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx` -__img__ | Image to display inside the header on the left of the label -__type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -__title__ | Label printed in the tree header -__state__ | Persistent state to update -Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -#### nk_tree_state_pop -Ends a collapsabale UI section -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_tree_state_pop(struct nk_context*); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description -------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx` -### Properties -Properties are the main value modification widgets in Nuklear. Changing a value -can be achieved by dragging, adding/removing incremental steps on button click -or by directly typing a number. -#### Usage -Each property requires a unique name for identifaction that is also used for -displaying a label. If you want to use the same name multiple times make sure -add a '#' before your name. The '#' will not be shown but will generate a -unique ID. Each propery also takes in a minimum and maximum value. If you want -to make use of the complete number range of a type just use the provided -type limits from `limits.h`. For example `INT_MIN` and `INT_MAX` for -`nk_property_int` and `nk_propertyi`. In additional each property takes in -a increment value that will be added or subtracted if either the increment -decrement button is clicked. Finally there is a value for increment per pixel -dragged that is added or subtracted from the value. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int value = 0; -struct nk_context ctx; -nk_init_xxx(&ctx, ...); -while (1) { - // Input - Event evt; - nk_input_begin(&ctx); - while (GetEvent(&evt)) { - if (evt.type == MOUSE_MOVE) - nk_input_motion(&ctx, evt.motion.x, evt.motion.y); - else if (evt.type == [...]) { - nk_input_xxx(...); - } - } - nk_input_end(&ctx); - // - // Window - if (nk_begin_xxx(...) { - // Property - nk_layout_row_dynamic(...); - nk_property_int(ctx, "ID", INT_MIN, &value, INT_MAX, 1, 1); - } - nk_end(ctx); - // - // Draw - const struct nk_command *cmd = 0; - nk_foreach(cmd, &ctx) { - switch (cmd->type) { - case NK_COMMAND_LINE: - your_draw_line_function(...) - break; - case NK_COMMAND_RECT - your_draw_rect_function(...) - break; - case ...: - // [...] - } -} -nk_free(&ctx); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#### Reference -Function | Description ---------------------|------------------------------------------- -nk_property_int | Integer property directly modifing a passed in value -nk_property_float | Float property directly modifing a passed in value -nk_property_double | Double property directly modifing a passed in value -nk_propertyi | Integer property returning the modified int value -nk_propertyf | Float property returning the modified float value -nk_propertyd | Double property returning the modified double value -#### nk_property_int -Integer property directly modifing a passed in value -!!! WARNING - To generate a unique property ID using the same label make sure to insert - a `#` at the beginning. It will not be shown but guarantees correct behavior. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_property_int(struct nk_context *ctx, const char *name, int min, int *val, int max, int step, float inc_per_pixel); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description ---------------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after calling a layouting function -__name__ | String used both as a label as well as a unique identifier -__min__ | Minimum value not allowed to be underflown -__val__ | Integer pointer to be modified -__max__ | Maximum value not allowed to be overflown -__step__ | Increment added and subtracted on increment and decrement button -__inc_per_pixel__ | Value per pixel added or subtracted on dragging -#### nk_property_float -Float property directly modifing a passed in value -!!! WARNING - To generate a unique property ID using the same label make sure to insert - a `#` at the beginning. It will not be shown but guarantees correct behavior. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_property_float(struct nk_context *ctx, const char *name, float min, float *val, float max, float step, float inc_per_pixel); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description ---------------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after calling a layouting function -__name__ | String used both as a label as well as a unique identifier -__min__ | Minimum value not allowed to be underflown -__val__ | Float pointer to be modified -__max__ | Maximum value not allowed to be overflown -__step__ | Increment added and subtracted on increment and decrement button -__inc_per_pixel__ | Value per pixel added or subtracted on dragging -#### nk_property_double -Double property directly modifing a passed in value -!!! WARNING - To generate a unique property ID using the same label make sure to insert - a `#` at the beginning. It will not be shown but guarantees correct behavior. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -void nk_property_double(struct nk_context *ctx, const char *name, double min, double *val, double max, double step, double inc_per_pixel); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description ---------------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after calling a layouting function -__name__ | String used both as a label as well as a unique identifier -__min__ | Minimum value not allowed to be underflown -__val__ | Double pointer to be modified -__max__ | Maximum value not allowed to be overflown -__step__ | Increment added and subtracted on increment and decrement button -__inc_per_pixel__ | Value per pixel added or subtracted on dragging -#### nk_propertyi -Integer property modifing a passed in value and returning the new value -!!! WARNING - To generate a unique property ID using the same label make sure to insert - a `#` at the beginning. It will not be shown but guarantees correct behavior. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -int nk_propertyi(struct nk_context *ctx, const char *name, int min, int val, int max, int step, float inc_per_pixel); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description ---------------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after calling a layouting function -__name__ | String used both as a label as well as a unique identifier -__min__ | Minimum value not allowed to be underflown -__val__ | Current integer value to be modified and returned -__max__ | Maximum value not allowed to be overflown -__step__ | Increment added and subtracted on increment and decrement button -__inc_per_pixel__ | Value per pixel added or subtracted on dragging -Returns the new modified integer value -#### nk_propertyf -Float property modifing a passed in value and returning the new value -!!! WARNING - To generate a unique property ID using the same label make sure to insert - a `#` at the beginning. It will not be shown but guarantees correct behavior. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -float nk_propertyf(struct nk_context *ctx, const char *name, float min, float val, float max, float step, float inc_per_pixel); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description ---------------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after calling a layouting function -__name__ | String used both as a label as well as a unique identifier -__min__ | Minimum value not allowed to be underflown -__val__ | Current float value to be modified and returned -__max__ | Maximum value not allowed to be overflown -__step__ | Increment added and subtracted on increment and decrement button -__inc_per_pixel__ | Value per pixel added or subtracted on dragging -Returns the new modified float value -#### nk_propertyd -Float property modifing a passed in value and returning the new value -!!! WARNING - To generate a unique property ID using the same label make sure to insert - a `#` at the beginning. It will not be shown but guarantees correct behavior. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -float nk_propertyd(struct nk_context *ctx, const char *name, double min, double val, double max, double step, double inc_per_pixel); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Parameter | Description ---------------------|----------------------------------------------------------- -__ctx__ | Must point to an previously initialized `nk_context` struct after calling a layouting function -__name__ | String used both as a label as well as a unique identifier -__min__ | Minimum value not allowed to be underflown -__val__ | Current double value to be modified and returned -__max__ | Maximum value not allowed to be overflown -__step__ | Increment added and subtracted on increment and decrement button -__inc_per_pixel__ | Value per pixel added or subtracted on dragging -Returns the new modified double value - -XXX.XXX- X...X - X...X -X....X - X....X" -X...XXXXXXXXXXXXX...X - " -## License -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~none - ------------------------------------------------------------------------------ - This software is available under 2 licenses -- choose whichever you prefer. - ------------------------------------------------------------------------------ - ALTERNATIVE A - MIT License - Copyright (c) 2016-2018 Micha Mettke - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is furnished to do - so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - ------------------------------------------------------------------------------ - ALTERNATIVE B - Public Domain (www.unlicense.org) - This is free and unencumbered software released into the public domain. - Anyone is free to copy, modify, publish, use, compile, sell, or distribute this - software, either in source code form or as a compiled binary, for any purpose, - commercial or non-commercial, and by any means. - In jurisdictions that recognize copyright laws, the author or authors of this - software dedicate any and all copyright interest in the software to the public - domain. We make this dedication for the benefit of the public at large and to - the detriment of our heirs and successors. We intend this dedication to be an - overt act of relinquishment in perpetuity of all present and future rights to - this software under copyright law. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------------------------------------------------------------------------------ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -## Changelog -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~none -[date][x.yy.zz]-[description] --[date]: date on which the change has been pushed --[x.yy.zz]: Numerical version string representation. Each version number on the right - resets back to zero if version on the left is incremented. - - [x]: Major version with API and library breaking - - [yy]: Minor version with non-breaking API and library changes - - [zz]: Bug fix version with no direct changes to API -- 2018/01/31 (3.00.5) - Fixed overcalculation of cursor data in font baking process -- 2018/01/31 (3.00.4) - Removed name collision with stb_truetype -- 2018/01/28 (3.00.3) - Fixed panel window border drawing bug -- 2018/01/12 (3.00.2) - Added `nk_group_begin_titled` for separed group identifier and title -- 2018/01/07 (3.00.1) - Started to change documentation style -- 2018/01/05 (3.00.0) - BREAKING CHANGE: The previous color picker API was broken - because of conversions between float and byte color representation. - Color pickers now use floating point values to represent - HSV values. To get back the old behavior I added some additional - color conversion functions to cast between nk_color and - nk_colorf. -- 2017/12/23 (2.00.7) - Fixed small warning -- 2017/12/23 (2.00.7) - Fixed nk_edit_buffer behavior if activated to allow input -- 2017/12/23 (2.00.7) - Fixed modifyable progressbar dragging visuals and input behavior -- 2017/12/04 (2.00.6) - Added formated string tooltip widget -- 2017/11/18 (2.00.5) - Fixed window becoming hidden with flag NK_WINDOW_NO_INPUT -- 2017/11/15 (2.00.4) - Fixed font merging -- 2017/11/07 (2.00.3) - Fixed window size and position modifier functions -- 2017/09/14 (2.00.2) - Fixed nk_edit_buffer and nk_edit_focus behavior -- 2017/09/14 (2.00.1) - Fixed window closing behavior -- 2017/09/14 (2.00.0) - BREAKING CHANGE: Modifing window position and size funtions now - require the name of the window and must happen outside the window - building process (between function call nk_begin and nk_end). -- 2017/09/11 (1.40.9) - Fixed window background flag if background window is declared last -- 2017/08/27 (1.40.8) - Fixed `nk_item_is_any_active` for hidden windows -- 2017/08/27 (1.40.7) - Fixed window background flag -- 2017/07/07 (1.40.6) - Fixed missing clipping rect check for hovering/clicked - query for widgets -- 2017/07/07 (1.40.5) - Fixed drawing bug for vertex output for lines and stroked - and filled rectangles -- 2017/07/07 (1.40.4) - Fixed bug in nk_convert trying to add windows that are in - process of being destroyed. -- 2017/07/07 (1.40.3) - Fixed table internal bug caused by storing table size in - window instead of directly in table. -- 2017/06/30 (1.40.2) - Removed unneeded semicolon in C++ NK_ALIGNOF macro -- 2017/06/30 (1.40.1) - Fixed drawing lines smaller or equal zero -- 2017/06/08 (1.40.0) - Removed the breaking part of last commit. Auto layout now only - comes in effect if you pass in zero was row height argument -- 2017/06/08 (1.40.0) - BREAKING CHANGE: while not directly API breaking it will change - how layouting works. From now there will be an internal minimum - row height derived from font height. If you need a row smaller than - that you can directly set it by `nk_layout_set_min_row_height` and - reset the value back by calling `nk_layout_reset_min_row_height. -- 2017/06/08 (1.39.1) - Fixed property text edit handling bug caused by past `nk_widget` fix -- 2017/06/08 (1.39.0) - Added function to retrieve window space without calling a nk_layout_xxx function -- 2017/06/06 (1.38.5) - Fixed `nk_convert` return flag for command buffer -- 2017/05/23 (1.38.4) - Fixed activation behavior for widgets partially clipped -- 2017/05/10 (1.38.3) - Fixed wrong min window size mouse scaling over boundries -- 2017/05/09 (1.38.2) - Fixed vertical scrollbar drawing with not enough space -- 2017/05/09 (1.38.1) - Fixed scaler dragging behavior if window size hits minimum size -- 2017/05/06 (1.38.0) - Added platform double-click support -- 2017/04/20 (1.37.1) - Fixed key repeat found inside glfw demo backends -- 2017/04/20 (1.37.0) - Extended properties with selection and clipbard support -- 2017/04/20 (1.36.2) - Fixed #405 overlapping rows with zero padding and spacing -- 2017/04/09 (1.36.1) - Fixed #403 with another widget float error -- 2017/04/09 (1.36.0) - Added window `NK_WINDOW_NO_INPUT` and `NK_WINDOW_NOT_INTERACTIVE` flags -- 2017/04/09 (1.35.3) - Fixed buffer heap corruption -- 2017/03/25 (1.35.2) - Fixed popup overlapping for `NK_WINDOW_BACKGROUND` windows -- 2017/03/25 (1.35.1) - Fixed windows closing behavior -- 2017/03/18 (1.35.0) - Added horizontal scroll requested in #377 -- 2017/03/18 (1.34.3) - Fixed long window header titles -- 2017/03/04 (1.34.2) - Fixed text edit filtering -- 2017/03/04 (1.34.1) - Fixed group closable flag -- 2017/02/25 (1.34.0) - Added custom draw command for better language binding support -- 2017/01/24 (1.33.0) - Added programatic way of remove edit focus -- 2017/01/24 (1.32.3) - Fixed wrong define for basic type definitions for windows -- 2017/01/21 (1.32.2) - Fixed input capture from hidden or closed windows -- 2017/01/21 (1.32.1) - Fixed slider behavior and drawing -- 2017/01/13 (1.32.0) - Added flag to put scaler into the bottom left corner -- 2017/01/13 (1.31.0) - Added additional row layouting method to combine both - dynamic and static widgets. -- 2016/12/31 (1.30.0) - Extended scrollbar offset from 16-bit to 32-bit -- 2016/12/31 (1.29.2)- Fixed closing window bug of minimized windows -- 2016/12/03 (1.29.1)- Fixed wrapped text with no seperator and C89 error -- 2016/12/03 (1.29.0) - Changed text wrapping to process words not characters -- 2016/11/22 (1.28.6)- Fixed window minimized closing bug -- 2016/11/19 (1.28.5)- Fixed abstract combo box closing behavior -- 2016/11/19 (1.28.4)- Fixed tooltip flickering -- 2016/11/19 (1.28.3)- Fixed memory leak caused by popup repeated closing -- 2016/11/18 (1.28.2)- Fixed memory leak caused by popup panel allocation -- 2016/11/10 (1.28.1)- Fixed some warnings and C++ error -- 2016/11/10 (1.28.0)- Added additional `nk_button` versions which allows to directly - pass in a style struct to change buttons visual. -- 2016/11/10 (1.27.0)- Added additional 'nk_tree' versions to support external state - storage. Just like last the `nk_group` commit the main - advantage is that you optionally can minimize nuklears runtime - memory consumption or handle hash collisions. -- 2016/11/09 (1.26.0)- Added additional `nk_group` version to support external scrollbar - offset storage. Main advantage is that you can externalize - the memory management for the offset. It could also be helpful - if you have a hash collision in `nk_group_begin` but really - want the name. In addition I added `nk_list_view` which allows - to draw big lists inside a group without actually having to - commit the whole list to nuklear (issue #269). -- 2016/10/30 (1.25.1)- Fixed clipping rectangle bug inside `nk_draw_list` -- 2016/10/29 (1.25.0)- Pulled `nk_panel` memory management into nuklear and out of - the hands of the user. From now on users don't have to care - about panels unless they care about some information. If you - still need the panel just call `nk_window_get_panel`. -- 2016/10/21 (1.24.0)- Changed widget border drawing to stroked rectangle from filled - rectangle for less overdraw and widget background transparency. -- 2016/10/18 (1.23.0)- Added `nk_edit_focus` for manually edit widget focus control -- 2016/09/29 (1.22.7)- Fixed deduction of basic type in non `` compilation -- 2016/09/29 (1.22.6)- Fixed edit widget UTF-8 text cursor drawing bug -- 2016/09/28 (1.22.5)- Fixed edit widget UTF-8 text appending/inserting/removing -- 2016/09/28 (1.22.4)- Fixed drawing bug inside edit widgets which offset all text - text in every edit widget if one of them is scrolled. -- 2016/09/28 (1.22.3)- Fixed small bug in edit widgets if not active. The wrong - text length is passed. It should have been in bytes but - was passed as glyphes. -- 2016/09/20 (1.22.2)- Fixed color button size calculation -- 2016/09/20 (1.22.1)- Fixed some `nk_vsnprintf` behavior bugs and removed - `` again from `NK_INCLUDE_STANDARD_VARARGS`. -- 2016/09/18 (1.22.0)- C89 does not support vsnprintf only C99 and newer as well - as C++11 and newer. In addition to use vsnprintf you have - to include . So just defining `NK_INCLUDE_STD_VAR_ARGS` - is not enough. That behavior is now fixed. By default if - both varargs as well as stdio is selected I try to use - vsnprintf if not possible I will revert to vsprintf. If - varargs but not stdio was defined I will use my own function. -- 2016/09/15 (1.21.2)- Fixed panel `close` behavior for deeper panel levels -- 2016/09/15 (1.21.1)- Fixed C++ errors and wrong argument to `nk_panel_get_xxxx` -- 2016/09/13 (1.21.0) - !BREAKING! Fixed nonblocking popup behavior in menu, combo, - and contextual which prevented closing in y-direction if - popup did not reach max height. - In addition the height parameter was changed into vec2 - for width and height to have more control over the popup size. -- 2016/09/13 (1.20.3) - Cleaned up and extended type selection -- 2016/09/13 (1.20.2)- Fixed slider behavior hopefully for the last time. This time - all calculation are correct so no more hackery. -- 2016/09/13 (1.20.1)- Internal change to divide window/panel flags into panel flags and types. - Suprisinly spend years in C and still happened to confuse types - with flags. Probably something to take note. -- 2016/09/08 (1.20.0)- Added additional helper function to make it easier to just - take the produced buffers from `nk_convert` and unplug the - iteration process from `nk_context`. So now you can - just use the vertex,element and command buffer + two pointer - inside the command buffer retrieved by calls `nk__draw_begin` - and `nk__draw_end` and macro `nk_draw_foreach_bounded`. -- 2016/09/08 (1.19.0)- Added additional asserts to make sure every `nk_xxx_begin` call - for windows, popups, combobox, menu and contextual is guarded by - `if` condition and does not produce false drawing output. -- 2016/09/08 (1.18.0)- Changed confusing name for `NK_SYMBOL_RECT_FILLED`, `NK_SYMBOL_RECT` - to hopefully easier to understand `NK_SYMBOL_RECT_FILLED` and - `NK_SYMBOL_RECT_OUTLINE`. -- 2016/09/08 (1.17.0)- Changed confusing name for `NK_SYMBOL_CIRLCE_FILLED`, `NK_SYMBOL_CIRCLE` - to hopefully easier to understand `NK_SYMBOL_CIRCLE_FILLED` and - `NK_SYMBOL_CIRCLE_OUTLINE`. -- 2016/09/08 (1.16.0)- Added additional checks to select correct types if `NK_INCLUDE_FIXED_TYPES` - is not defined by supporting the biggest compiler GCC, clang and MSVC. -- 2016/09/07 (1.15.3)- Fixed `NK_INCLUDE_COMMAND_USERDATA` define to not cause an error -- 2016/09/04 (1.15.2)- Fixed wrong combobox height calculation -- 2016/09/03 (1.15.1)- Fixed gaps inside combo boxes in OpenGL -- 2016/09/02 (1.15.0) - Changed nuklear to not have any default vertex layout and - instead made it user provided. The range of types to convert - to is quite limited at the moment, but I would be more than - happy to accept PRs to add additional. -- 2016/08/30 (1.14.2) - Removed unused variables -- 2016/08/30 (1.14.1) - Fixed C++ build errors -- 2016/08/30 (1.14.0) - Removed mouse dragging from SDL demo since it does not work correctly -- 2016/08/30 (1.13.4) - Tweaked some default styling variables -- 2016/08/30 (1.13.3) - Hopefully fixed drawing bug in slider, in general I would - refrain from using slider with a big number of steps. -- 2016/08/30 (1.13.2) - Fixed close and minimize button which would fire even if the - window was in Read Only Mode. -- 2016/08/30 (1.13.1) - Fixed popup panel padding handling which was previously just - a hack for combo box and menu. -- 2016/08/30 (1.13.0) - Removed `NK_WINDOW_DYNAMIC` flag from public API since - it is bugged and causes issues in window selection. -- 2016/08/30 (1.12.0) - Removed scaler size. The size of the scaler is now - determined by the scrollbar size -- 2016/08/30 (1.11.2) - Fixed some drawing bugs caused by changes from 1.11 -- 2016/08/30 (1.11.1) - Fixed overlapping minimized window selection -- 2016/08/30 (1.11.0) - Removed some internal complexity and overly complex code - handling panel padding and panel border. -- 2016/08/29 (1.10.0) - Added additional height parameter to `nk_combobox_xxx` -- 2016/08/29 (1.10.0) - Fixed drawing bug in dynamic popups -- 2016/08/29 (1.10.0) - Added experimental mouse scrolling to popups, menus and comboboxes -- 2016/08/26 (1.10.0) - Added window name string prepresentation to account for - hash collisions. Currently limited to NK_WINDOW_MAX_NAME - which in term can be redefined if not big enough. -- 2016/08/26 (1.10.0) - Added stacks for temporary style/UI changes in code -- 2016/08/25 (1.10.0) - Changed `nk_input_is_key_pressed` and 'nk_input_is_key_released' - to account for key press and release happening in one frame. -- 2016/08/25 (1.10.0) - Added additional nk_edit flag to directly jump to the end on activate -- 2016/08/17 (1.09.6)- Removed invalid check for value zero in nk_propertyx -- 2016/08/16 (1.09.5)- Fixed ROM mode for deeper levels of popup windows parents. -- 2016/08/15 (1.09.4)- Editbox are now still active if enter was pressed with flag - `NK_EDIT_SIG_ENTER`. Main reasoning is to be able to keep - typing after commiting. -- 2016/08/15 (1.09.4)- Removed redundant code -- 2016/08/15 (1.09.4)- Fixed negative numbers in `nk_strtoi` and remove unused variable -- 2016/08/15 (1.09.3)- Fixed `NK_WINDOW_BACKGROUND` flag behavior to select a background - window only as selected by hovering and not by clicking. -- 2016/08/14 (1.09.2)- Fixed a bug in font atlas which caused wrong loading - of glyphes for font with multiple ranges. -- 2016/08/12 (1.09.1)- Added additional function to check if window is currently - hidden and therefore not visible. -- 2016/08/12 (1.09.1)- nk_window_is_closed now queries the correct flag `NK_WINDOW_CLOSED` - instead of the old flag `NK_WINDOW_HIDDEN` -- 2016/08/09 (1.09.0) - Added additional double version to nk_property and changed - the underlying implementation to not cast to float and instead - work directly on the given values. -- 2016/08/09 (1.08.0) - Added additional define to overwrite library internal - floating pointer number to string conversion for additional - precision. -- 2016/08/09 (1.08.0) - Added additional define to overwrite library internal - string to floating point number conversion for additional - precision. -- 2016/08/08 (1.07.2)- Fixed compiling error without define NK_INCLUDE_FIXED_TYPE -- 2016/08/08 (1.07.1)- Fixed possible floating point error inside `nk_widget` leading - to wrong wiget width calculation which results in widgets falsly - becomming tagged as not inside window and cannot be accessed. -- 2016/08/08 (1.07.0) - Nuklear now differentiates between hiding a window (NK_WINDOW_HIDDEN) and - closing a window (NK_WINDOW_CLOSED). A window can be hidden/shown - by using `nk_window_show` and closed by either clicking the close - icon in a window or by calling `nk_window_close`. Only closed - windows get removed at the end of the frame while hidden windows - remain. -- 2016/08/08 (1.06.0) - Added `nk_edit_string_zero_terminated` as a second option to - `nk_edit_string` which takes, edits and outputs a '\0' terminated string. -- 2016/08/08 (1.05.4)- Fixed scrollbar auto hiding behavior -- 2016/08/08 (1.05.3)- Fixed wrong panel padding selection in `nk_layout_widget_space` -- 2016/08/07 (1.05.2)- Fixed old bug in dynamic immediate mode layout API, calculating - wrong item spacing and panel width. - define NK_INCLUDE_STANDARD_VARARGS to allow more fine - grained controlled over library includes. -- 2016/08/06 (1.04.5)- Changed memset calls to NK_MEMSET -- 2016/08/04 (1.04.4)- Fixed fast window scaling behavior -- 2016/08/04 (1.04.3)- Fixed window scaling, movement bug which appears if you - move/scale a window and another window is behind it. - If you are fast enough then the window behind gets activated - and the operation is blocked. I now require activating - by hovering only if mouse is not pressed. -- 2016/08/04 (1.04.2)- Fixed changing fonts -- 2016/08/03 (1.04.1)- Fixed `NK_WINDOW_BACKGROUND` behavior -- 2016/08/03 (1.04.0) - Added color parameter to `nk_draw_image` -- 2016/08/03 (1.04.0) - Added additional window padding style attributes for - sub windows (combo, menu, ...) -- 2016/08/03 (1.04.0) - Added functions to show/hide software cursor -- 2016/08/03 (1.04.0) - Added `NK_WINDOW_BACKGROUND` flag to force a window - to be always in the background of the screen -- 2016/08/03 (1.03.2)- Removed invalid assert macro for NK_RGB color picker -- 2016/08/01 (1.03.1)- Added helper macros into header include guard -- 2016/07/29 (1.03.0) - Moved the window/table pool into the header part to - simplify memory management by removing the need to - allocate the pool. -- 2016/07/29 (1.02.0) - Added auto scrollbar hiding window flag which if enabled - will hide the window scrollbar after NK_SCROLLBAR_HIDING_TIMEOUT - seconds without window interaction. To make it work - you have to also set a delta time inside the `nk_context`. -- 2016/07/25 (1.01.1) - Fixed small panel and panel border drawing bugs -- 2016/07/15 (1.01.0) - Added software cursor to `nk_style` and `nk_context` -- 2016/07/15 (1.01.0) - Added const correctness to `nk_buffer_push' data argument -- 2016/07/15 (1.01.0) - Removed internal font baking API and simplified - font atlas memory management by converting pointer - arrays for fonts and font configurations to lists. -- 2016/07/15 (1.00.0) - Changed button API to use context dependend button - behavior instead of passing it for every function call. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -## Gallery -![Figure [blue]: Feature overview with blue color styling](https://cloud.githubusercontent.com/assets/8057201/13538240/acd96876-e249-11e5-9547-5ac0b19667a0.png) -![Figure [red]: Feature overview with red color styling](https://cloud.githubusercontent.com/assets/8057201/13538243/b04acd4c-e249-11e5-8fd2-ad7744a5b446.png) -![Figure [widgets]: Widget overview](https://cloud.githubusercontent.com/assets/8057201/11282359/3325e3c6-8eff-11e5-86cb-cf02b0596087.png) -![Figure [blackwhite]: Black and white](https://cloud.githubusercontent.com/assets/8057201/11033668/59ab5d04-86e5-11e5-8091-c56f16411565.png) -![Figure [filexp]: File explorer](https://cloud.githubusercontent.com/assets/8057201/10718115/02a9ba08-7b6b-11e5-950f-adacdd637739.png) -![Figure [opengl]: OpenGL Editor](https://cloud.githubusercontent.com/assets/8057201/12779619/2a20d72c-ca69-11e5-95fe-4edecf820d5c.png) -![Figure [nodedit]: Node Editor](https://cloud.githubusercontent.com/assets/8057201/9976995/e81ac04a-5ef7-11e5-872b-acd54fbeee03.gif) -![Figure [skinning]: Using skinning in Nuklear](https://cloud.githubusercontent.com/assets/8057201/15991632/76494854-30b8-11e6-9555-a69840d0d50b.png) -![Figure [bf]: Heavy modified version](https://cloud.githubusercontent.com/assets/8057201/14902576/339926a8-0d9c-11e6-9fee-a8b73af04473.png) -## Credits -Developed by Micha Mettke and every direct or indirect github contributor.

-Embeds [stb_texedit](https://github.com/nothings/stb/blob/master/stb_textedit.h), [stb_truetype](https://github.com/nothings/stb/blob/master/stb_truetype.h) and [stb_rectpack](https://github.com/nothings/stb/blob/master/stb_rect_pack.h) by Sean Barret (public domain)
-Uses [stddoc.c](https://github.com/r-lyeh/stddoc.c) from r-lyeh@github.com for documentation generation

-Embeds ProggyClean.ttf font by Tristan Grimmer (MIT license).
-Big thank you to Omar Cornut (ocornut@github) for his [imgui library](https://github.com/ocornut/imgui) and -giving me the inspiration for this library, Casey Muratori for handmade hero -and his original immediate mode graphical user interface idea and Sean -Barret for his amazing single header libraries which restored my faith -in libraries and brought me to create some of my own. - - diff --git a/subprojects/nk_pugl/nuklear/doc/stddoc.c b/subprojects/nk_pugl/nuklear/doc/stddoc.c deleted file mode 100644 index 461ddc1..0000000 --- a/subprojects/nk_pugl/nuklear/doc/stddoc.c +++ /dev/null @@ -1,141 +0,0 @@ -/// ## About -/// - _stddoc.c_ is a tiny documentation generator for 60 programming languages. -/// - This page sample was auto-generated from the code comments found in `stddoc.c` file. -/// -/// ## How does it work? -/// - Markdeep code comments are extracted from stdin and printed into stdout as a HTML file. -/// -/// ## Supported languages -/// - `/// Three slashes comment` [ActionScript, AngelScript, C (C99), C#, C++, ChaiScript, D, -/// GameMonkey, GML, Go, Java, JavaScript, JetScript, jtc, Jx9, Kotlin, Neko, Object Pascal (Delphi), -/// Objective-C, Pawn, PHP, QuakeC, Rust, SASS, Scala, Squirrel, Swift, Vala, Wren, Xojo]. -/// - `--- Three dashes comment` [Ada, AppleScript, Eiffel, Euphoria, Haskell, Lua, Occam, -/// PL/SQL, PSL, SGML, SPARK, SQL, Terra, TSQL, VHDL]. -/// - `### Three hashes comment` [AWK, Bash, Bourne shell, C shell, Cobra, Maple, Maple, -/// Perl, Perl6, PowerShell, Python, R, Ruby, Seed7, Tcl]. -/// -/// ## Usage -/// - `stddoc < source.code > documentation.html` -/// -/// ## Changelog -/// 2018/01/07 -/// : Initial version (_v1.0.0_) -/// -/// ## License -/// - rlyeh, unlicensed (~public domain). - -#include - -int main() { - printf("%s\n", ""); - printf("%s\n", ""); - - for( int fsm_S = 0, fsm_D = 0, fsm_H = 0; !feof(stdin); ) { - int chr = getc(stdin); - if( fsm_S > 3 || fsm_D > 3 || fsm_H > 3 ) { - putc(chr, stdout); - if( chr != '\r' && chr != '\n' ) continue; - } - /**/ if( fsm_S <= 2 && chr == '/' && !fsm_D && !fsm_H ) fsm_S++; - else if( fsm_S == 3 && chr == ' ' && !fsm_D && !fsm_H ) fsm_S++; - else if( fsm_D <= 2 && chr == '-' && !fsm_S && !fsm_H ) fsm_D++; - else if( fsm_D == 3 && chr == ' ' && !fsm_S && !fsm_H ) fsm_D++; - else if( fsm_H <= 2 && chr == '#' && !fsm_S && !fsm_D ) fsm_H++; - else if( fsm_H == 3 && chr == ' ' && !fsm_S && !fsm_D ) fsm_H++; - else fsm_S = fsm_D = fsm_H = 0; - } - - printf("%s\n", ""); - printf("%s\n", ""); -} - -/// -/// ## **Example page!** -/// -/// Imaginary documentation page. Here would be some introduction text. -/// -/// The table of contents that Markdeep produces is stuffed on the right side, -/// if the browser window is wide enough. Otherwise it is hidden. -/// -/// ### Basic Markdeep -/// -/// Regular styling like **bold**, _italics_, ~~strikethrough~~, `inline code`, etc. Lists as: -/// -/// * A -/// * Bullet -/// * List -/// -/// And: -/// -/// 1. A -/// 1. Numbered -/// 1. List! -/// -/// Symbol substitutions: a 45-degree turn; som x -> y arrows; some whoa ==> fancy <==> arrows. -/// -/// Is this a definition list? -/// : Looks like one to me -/// Is that right? -/// : Possibly! -/// -/// And a code listing: -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// int main() -/// { -/// return 1; -/// } -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// -/// ### Tables -/// -/// Thing Name | Description |Notes -/// ------------------------|--------------------|----- -/// Yes | Yup! | -/// No | Nope :( | -/// FileNotFound | Doesn't find files | Pass `-sFIND_FILE=maybe` to maybe find them -/// -/// -/// ### Diagrams -/// -/// ******************************************* Here's a text to the right of the diagram, -/// * +-----------------+ .-. * ain't that fancy. Pretty fancy indeed, I -/// * |\ | .-+ | * must say! Markdeep diagrams are generally -/// * | \ A-B *---+--> .--+ '--. * enclosed into a rectangle full made of `*` -/// * | \ | | Cloud! | * symbols; and are "drawn" using ASCII-art -/// * +---+-------------+ '-------------' * style, with `- | + / \ * o` etc. -/// ******************************************* Suh-weet! -/// -/// Another random diagram, just because: -/// -/// ******************** -/// * +-+-+-+-*-o * -/// * / / ^ / * -/// * / v / / * -/// * +-+-+-+ * -/// ******************** -/// -/// ### Special notes -/// -/// !!! Note -/// Hey I'm a note. Don't mind me, I'm just sitting here. -/// -/// !!! WARNING -/// I'm a warning, perhaps. *Something might happen!* -/// -/// !!! Error: Never Pass `nullptr` to a Shader -/// Invoking a shader with a null argument can seg fault. -/// This is a multi-line admonition. -/// -/// Seriously, don't call shaders like that. -/// -/// ### Embedding HTML -/// -///
-/// This is an embedded html node by the way!
-/// 
-/// -/// ## Credits -/// - API doc style created by [Aras Pranckevičius](https://github.com/aras-p) -/// - Markdeep by [Morgan McGuire](https://casual-effects.com/markdeep/). diff --git a/subprojects/nk_pugl/nuklear/example/Makefile b/subprojects/nk_pugl/nuklear/example/Makefile deleted file mode 100644 index a3ae6f0..0000000 --- a/subprojects/nk_pugl/nuklear/example/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -# Flags -CFLAGS += -std=c99 -pedantic -O2 -LIBS := - -ifeq ($(OS),Windows_NT) -BIN := $(BIN).exe - LIBS := -lglfw3 -lopengl32 -lm -lGLU32 -lGLEW32 -else - UNAME_S := $(shell uname -s) - GLFW3 := $(shell pkg-config --libs glfw3) - ifeq ($(UNAME_S),Darwin) - LIBS := $(GLFW3) -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo -lm -lGLEW -L/usr/local/lib - CFLAGS += -I/usr/local/include - else - LIBS := $(GLFW3) -lGL -lm -lGLU -lGLEW - endif -endif - -all: generate file_browser extended canvas skinning - -generate: clean -ifeq ($(OS),Windows_NT) - @mkdir bin 2> nul || exit 0 -else - @mkdir -p bin -endif - -clean: - @rm -rf bin - -file_browser: generate - $(CC) $(CFLAGS) -o bin/file_browser file_browser.c $(LIBS) - -extended: generate - $(CC) $(CFLAGS) -o bin/extended extended.c $(LIBS) - -canvas: generate - $(CC) $(CFLAGS) -o bin/canvas canvas.c $(LIBS) - -skinning: generate - $(CC) $(CFLAGS) -o bin/skinning skinning.c $(LIBS) - diff --git a/subprojects/nk_pugl/nuklear/example/canvas.c b/subprojects/nk_pugl/nuklear/example/canvas.c deleted file mode 100644 index 2a7f7a2..0000000 --- a/subprojects/nk_pugl/nuklear/example/canvas.c +++ /dev/null @@ -1,489 +0,0 @@ -/* nuklear - v1.05 - public domain */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define NK_PRIVATE -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT -#define NK_INCLUDE_FONT_BAKING -#define NK_INCLUDE_DEFAULT_FONT -#define NK_IMPLEMENTATION -#include "../nuklear.h" - -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" - -/* macros */ -#define WINDOW_WIDTH 1200 -#define WINDOW_HEIGHT 800 - -#define MAX_VERTEX_MEMORY 512 * 1024 -#define MAX_ELEMENT_MEMORY 128 * 1024 - -#define UNUSED(a) (void)a -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#define MAX(a,b) ((a) < (b) ? (b) : (a)) -#define LEN(a) (sizeof(a)/sizeof(a)[0]) - -#define NK_SHADER_VERSION "#version 150\n" - -/* =============================================================== - * - * DEVICE - * - * ===============================================================*/ -struct nk_glfw_vertex { - float position[2]; - float uv[2]; - nk_byte col[4]; -}; - -struct device { - struct nk_buffer cmds; - struct nk_draw_null_texture null; - GLuint vbo, vao, ebo; - GLuint prog; - GLuint vert_shdr; - GLuint frag_shdr; - GLint attrib_pos; - GLint attrib_uv; - GLint attrib_col; - GLint uniform_tex; - GLint uniform_proj; - GLuint font_tex; -}; - -static void -die(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fputs("\n", stderr); - exit(EXIT_FAILURE); -} - -static struct nk_image -icon_load(const char *filename) -{ - int x,y,n; - GLuint tex; - unsigned char *data = stbi_load(filename, &x, &y, &n, 0); - if (!data) die("[SDL]: failed to load image: %s", filename); - - glGenTextures(1, &tex); - glBindTexture(GL_TEXTURE_2D, tex); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - glGenerateMipmap(GL_TEXTURE_2D); - stbi_image_free(data); - return nk_image_id((int)tex); -} - -static void -device_init(struct device *dev) -{ - GLint status; - static const GLchar *vertex_shader = - NK_SHADER_VERSION - "uniform mat4 ProjMtx;\n" - "in vec2 Position;\n" - "in vec2 TexCoord;\n" - "in vec4 Color;\n" - "out vec2 Frag_UV;\n" - "out vec4 Frag_Color;\n" - "void main() {\n" - " Frag_UV = TexCoord;\n" - " Frag_Color = Color;\n" - " gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n" - "}\n"; - static const GLchar *fragment_shader = - NK_SHADER_VERSION - "precision mediump float;\n" - "uniform sampler2D Texture;\n" - "in vec2 Frag_UV;\n" - "in vec4 Frag_Color;\n" - "out vec4 Out_Color;\n" - "void main(){\n" - " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" - "}\n"; - - nk_buffer_init_default(&dev->cmds); - dev->prog = glCreateProgram(); - dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER); - dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0); - glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0); - glCompileShader(dev->vert_shdr); - glCompileShader(dev->frag_shdr); - glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status); - assert(status == GL_TRUE); - glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status); - assert(status == GL_TRUE); - glAttachShader(dev->prog, dev->vert_shdr); - glAttachShader(dev->prog, dev->frag_shdr); - glLinkProgram(dev->prog); - glGetProgramiv(dev->prog, GL_LINK_STATUS, &status); - assert(status == GL_TRUE); - - dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture"); - dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx"); - dev->attrib_pos = glGetAttribLocation(dev->prog, "Position"); - dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord"); - dev->attrib_col = glGetAttribLocation(dev->prog, "Color"); - - { - /* buffer setup */ - GLsizei vs = sizeof(struct nk_glfw_vertex); - size_t vp = offsetof(struct nk_glfw_vertex, position); - size_t vt = offsetof(struct nk_glfw_vertex, uv); - size_t vc = offsetof(struct nk_glfw_vertex, col); - - glGenBuffers(1, &dev->vbo); - glGenBuffers(1, &dev->ebo); - glGenVertexArrays(1, &dev->vao); - - glBindVertexArray(dev->vao); - glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); - - glEnableVertexAttribArray((GLuint)dev->attrib_pos); - glEnableVertexAttribArray((GLuint)dev->attrib_uv); - glEnableVertexAttribArray((GLuint)dev->attrib_col); - - glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp); - glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt); - glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc); - } - - glBindTexture(GL_TEXTURE_2D, 0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindVertexArray(0); -} - -static void -device_upload_atlas(struct device *dev, const void *image, int width, int height) -{ - glGenTextures(1, &dev->font_tex); - glBindTexture(GL_TEXTURE_2D, dev->font_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, image); -} - -static void -device_shutdown(struct device *dev) -{ - glDetachShader(dev->prog, dev->vert_shdr); - glDetachShader(dev->prog, dev->frag_shdr); - glDeleteShader(dev->vert_shdr); - glDeleteShader(dev->frag_shdr); - glDeleteProgram(dev->prog); - glDeleteTextures(1, &dev->font_tex); - glDeleteBuffers(1, &dev->vbo); - glDeleteBuffers(1, &dev->ebo); - nk_buffer_free(&dev->cmds); -} - -static void -device_draw(struct device *dev, struct nk_context *ctx, int width, int height, - enum nk_anti_aliasing AA) -{ - GLfloat ortho[4][4] = { - {2.0f, 0.0f, 0.0f, 0.0f}, - {0.0f,-2.0f, 0.0f, 0.0f}, - {0.0f, 0.0f,-1.0f, 0.0f}, - {-1.0f,1.0f, 0.0f, 1.0f}, - }; - ortho[0][0] /= (GLfloat)width; - ortho[1][1] /= (GLfloat)height; - - /* setup global state */ - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glEnable(GL_SCISSOR_TEST); - glActiveTexture(GL_TEXTURE0); - - /* setup program */ - glUseProgram(dev->prog); - glUniform1i(dev->uniform_tex, 0); - glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]); - { - /* convert from command queue into draw list and draw to screen */ - const struct nk_draw_command *cmd; - void *vertices, *elements; - const nk_draw_index *offset = NULL; - - /* allocate vertex and element buffer */ - glBindVertexArray(dev->vao); - glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); - - glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW); - - /* load draw vertices & elements directly into vertex + element buffer */ - vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); - elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY); - { - /* fill convert configuration */ - struct nk_convert_config config; - static const struct nk_draw_vertex_layout_element vertex_layout[] = { - {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)}, - {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)}, - {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)}, - {NK_VERTEX_LAYOUT_END} - }; - NK_MEMSET(&config, 0, sizeof(config)); - config.vertex_layout = vertex_layout; - config.vertex_size = sizeof(struct nk_glfw_vertex); - config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex); - config.null = dev->null; - config.circle_segment_count = 22; - config.curve_segment_count = 22; - config.arc_segment_count = 22; - config.global_alpha = 1.0f; - config.shape_AA = AA; - config.line_AA = AA; - - /* setup buffers to load vertices and elements */ - {struct nk_buffer vbuf, ebuf; - nk_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY); - nk_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY); - nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);} - } - glUnmapBuffer(GL_ARRAY_BUFFER); - glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); - - /* iterate over and execute each draw command */ - nk_draw_foreach(cmd, ctx, &dev->cmds) - { - if (!cmd->elem_count) continue; - glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); - glScissor( - (GLint)(cmd->clip_rect.x), - (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h))), - (GLint)(cmd->clip_rect.w), - (GLint)(cmd->clip_rect.h)); - glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); - offset += cmd->elem_count; - } - nk_clear(ctx); - } - - /* default OpenGL state */ - glUseProgram(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindVertexArray(0); - glDisable(GL_BLEND); - glDisable(GL_SCISSOR_TEST); -} - -/* glfw callbacks (I don't know if there is a easier way to access text and scroll )*/ -static void error_callback(int e, const char *d){printf("Error %d: %s\n", e, d);} -static void text_input(GLFWwindow *win, unsigned int codepoint) -{nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);} -static void scroll_input(GLFWwindow *win, double _, double yoff) -{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), nk_vec2(0, (float)yoff));} - -static void -pump_input(struct nk_context *ctx, GLFWwindow *win) -{ - double x, y; - nk_input_begin(ctx); - glfwPollEvents(); - - nk_input_key(ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS); - - if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || - glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) { - nk_input_key(ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS); - nk_input_key(ctx, NK_KEY_SHIFT, 1); - } else { - nk_input_key(ctx, NK_KEY_COPY, 0); - nk_input_key(ctx, NK_KEY_PASTE, 0); - nk_input_key(ctx, NK_KEY_CUT, 0); - nk_input_key(ctx, NK_KEY_SHIFT, 0); - } - - glfwGetCursorPos(win, &x, &y); - nk_input_motion(ctx, (int)x, (int)y); - nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); - nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS); - nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS); - nk_input_end(ctx); -} - -struct nk_canvas { - struct nk_command_buffer *painter; - struct nk_vec2 item_spacing; - struct nk_vec2 panel_padding; - struct nk_style_item window_background; -}; - -static void -canvas_begin(struct nk_context *ctx, struct nk_canvas *canvas, nk_flags flags, - int x, int y, int width, int height, struct nk_color background_color) -{ - /* save style properties which will be overwritten */ - canvas->panel_padding = ctx->style.window.padding; - canvas->item_spacing = ctx->style.window.spacing; - canvas->window_background = ctx->style.window.fixed_background; - - /* use the complete window space and set background */ - ctx->style.window.spacing = nk_vec2(0,0); - ctx->style.window.padding = nk_vec2(0,0); - ctx->style.window.fixed_background = nk_style_item_color(background_color); - - /* create/update window and set position + size */ - flags = flags & ~NK_WINDOW_DYNAMIC; - nk_window_set_bounds(ctx, "Window", nk_rect(x, y, width, height)); - nk_begin(ctx, "Window", nk_rect(x, y, width, height), NK_WINDOW_NO_SCROLLBAR|flags); - - /* allocate the complete window space for drawing */ - {struct nk_rect total_space; - total_space = nk_window_get_content_region(ctx); - nk_layout_row_dynamic(ctx, total_space.h, 1); - nk_widget(&total_space, ctx); - canvas->painter = nk_window_get_canvas(ctx);} -} - -static void -canvas_end(struct nk_context *ctx, struct nk_canvas *canvas) -{ - nk_end(ctx); - ctx->style.window.spacing = canvas->panel_padding; - ctx->style.window.padding = canvas->item_spacing; - ctx->style.window.fixed_background = canvas->window_background; -} - -int main(int argc, char *argv[]) -{ - /* Platform */ - static GLFWwindow *win; - int width = 0, height = 0; - - /* GUI */ - struct device device; - struct nk_font_atlas atlas; - struct nk_context ctx; - - /* GLFW */ - glfwSetErrorCallback(error_callback); - if (!glfwInit()) { - fprintf(stdout, "[GFLW] failed to init!\n"); - exit(1); - } - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL); - glfwMakeContextCurrent(win); - glfwSetWindowUserPointer(win, &ctx); - glfwSetCharCallback(win, text_input); - glfwSetScrollCallback(win, scroll_input); - glfwGetWindowSize(win, &width, &height); - - /* OpenGL */ - glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); - glewExperimental = 1; - if (glewInit() != GLEW_OK) { - fprintf(stderr, "Failed to setup GLEW\n"); - exit(1); - } - - /* GUI */ - {device_init(&device); - {const void *image; int w, h; - struct nk_font *font; - nk_font_atlas_init_default(&atlas); - nk_font_atlas_begin(&atlas); - font = nk_font_atlas_add_default(&atlas, 13, 0); - image = nk_font_atlas_bake(&atlas, &w, &h, NK_FONT_ATLAS_RGBA32); - device_upload_atlas(&device, image, w, h); - nk_font_atlas_end(&atlas, nk_handle_id((int)device.font_tex), &device.null); - nk_init_default(&ctx, &font->handle); - - glEnable(GL_TEXTURE_2D); - while (!glfwWindowShouldClose(win)) - { - /* input */ - pump_input(&ctx, win); - - /* draw */ - {struct nk_canvas canvas; - canvas_begin(&ctx, &canvas, 0, 0, 0, width, height, nk_rgb(250,250,250)); - { - nk_fill_rect(canvas.painter, nk_rect(15,15,210,210), 5, nk_rgb(247, 230, 154)); - nk_fill_rect(canvas.painter, nk_rect(20,20,200,200), 5, nk_rgb(188, 174, 118)); - nk_draw_text(canvas.painter, nk_rect(30, 30, 150, 20), "Text to draw", 12, &font->handle, nk_rgb(188,174,118), nk_rgb(0,0,0)); - nk_fill_rect(canvas.painter, nk_rect(250,20,100,100), 0, nk_rgb(0,0,255)); - nk_fill_circle(canvas.painter, nk_rect(20,250,100,100), nk_rgb(255,0,0)); - nk_fill_triangle(canvas.painter, 250, 250, 350, 250, 300, 350, nk_rgb(0,255,0)); - nk_fill_arc(canvas.painter, 300, 180, 50, 0, 3.141592654f * 3.0f / 4.0f, nk_rgb(255,255,0)); - - {float points[12]; - points[0] = 200; points[1] = 250; - points[2] = 250; points[3] = 350; - points[4] = 225; points[5] = 350; - points[6] = 200; points[7] = 300; - points[8] = 175; points[9] = 350; - points[10] = 150; points[11] = 350; - nk_fill_polygon(canvas.painter, points, 6, nk_rgb(0,0,0));} - - nk_stroke_line(canvas.painter, 15, 10, 200, 10, 2.0f, nk_rgb(189,45,75)); - nk_stroke_rect(canvas.painter, nk_rect(370, 20, 100, 100), 10, 3, nk_rgb(0,0,255)); - nk_stroke_curve(canvas.painter, 380, 200, 405, 270, 455, 120, 480, 200, 2, nk_rgb(0,150,220)); - nk_stroke_circle(canvas.painter, nk_rect(20, 370, 100, 100), 5, nk_rgb(0,255,120)); - nk_stroke_triangle(canvas.painter, 370, 250, 470, 250, 420, 350, 6, nk_rgb(255,0,143)); - } - canvas_end(&ctx, &canvas);} - - /* Draw */ - glfwGetWindowSize(win, &width, &height); - glViewport(0, 0, width, height); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(0.2f, 0.2f, 0.2f, 1.0f); - device_draw(&device, &ctx, width, height, NK_ANTI_ALIASING_ON); - glfwSwapBuffers(win); - }}} - nk_font_atlas_clear(&atlas); - nk_free(&ctx); - device_shutdown(&device); - glfwTerminate(); - return 0; -} - diff --git a/subprojects/nk_pugl/nuklear/example/extended.c b/subprojects/nk_pugl/nuklear/example/extended.c deleted file mode 100644 index 003adf3..0000000 --- a/subprojects/nk_pugl/nuklear/example/extended.c +++ /dev/null @@ -1,906 +0,0 @@ -/* nuklear - v1.05 - public domain */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT -#define NK_INCLUDE_FONT_BAKING -#define NK_INCLUDE_DEFAULT_FONT -#define NK_IMPLEMENTATION -#include "../nuklear.h" - -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" - -/* macros */ -#define WINDOW_WIDTH 1200 -#define WINDOW_HEIGHT 800 - -#define MAX_VERTEX_MEMORY 512 * 1024 -#define MAX_ELEMENT_MEMORY 128 * 1024 - -#define UNUSED(a) (void)a -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#define MAX(a,b) ((a) < (b) ? (b) : (a)) -#define LEN(a) (sizeof(a)/sizeof(a)[0]) - -#ifdef __APPLE__ - #define NK_SHADER_VERSION "#version 150\n" -#else - #define NK_SHADER_VERSION "#version 300 es\n" -#endif - -struct media { - struct nk_font *font_14; - struct nk_font *font_18; - struct nk_font *font_20; - struct nk_font *font_22; - - struct nk_image unchecked; - struct nk_image checked; - struct nk_image rocket; - struct nk_image cloud; - struct nk_image pen; - struct nk_image play; - struct nk_image pause; - struct nk_image stop; - struct nk_image prev; - struct nk_image next; - struct nk_image tools; - struct nk_image dir; - struct nk_image copy; - struct nk_image convert; - struct nk_image del; - struct nk_image edit; - struct nk_image images[9]; - struct nk_image menu[6]; -}; - -/* =============================================================== - * - * CUSTOM WIDGET - * - * ===============================================================*/ -static int -ui_piemenu(struct nk_context *ctx, struct nk_vec2 pos, float radius, - struct nk_image *icons, int item_count) -{ - int ret = -1; - struct nk_rect total_space; - struct nk_rect bounds; - int active_item = 0; - - /* pie menu popup */ - struct nk_color border = ctx->style.window.border_color; - struct nk_style_item background = ctx->style.window.fixed_background; - ctx->style.window.fixed_background = nk_style_item_hide(); - ctx->style.window.border_color = nk_rgba(0,0,0,0); - - total_space = nk_window_get_content_region(ctx); - ctx->style.window.spacing = nk_vec2(0,0); - ctx->style.window.padding = nk_vec2(0,0); - - if (nk_popup_begin(ctx, NK_POPUP_STATIC, "piemenu", NK_WINDOW_NO_SCROLLBAR, - nk_rect(pos.x - total_space.x - radius, pos.y - radius - total_space.y, - 2*radius,2*radius))) - { - int i = 0; - struct nk_command_buffer* out = nk_window_get_canvas(ctx); - const struct nk_input *in = &ctx->input; - - total_space = nk_window_get_content_region(ctx); - ctx->style.window.spacing = nk_vec2(4,4); - ctx->style.window.padding = nk_vec2(8,8); - nk_layout_row_dynamic(ctx, total_space.h, 1); - nk_widget(&bounds, ctx); - - /* outer circle */ - nk_fill_circle(out, bounds, nk_rgb(50,50,50)); - { - /* circle buttons */ - float step = (2 * 3.141592654f) / (float)(MAX(1,item_count)); - float a_min = 0; float a_max = step; - - struct nk_vec2 center = nk_vec2(bounds.x + bounds.w / 2.0f, bounds.y + bounds.h / 2.0f); - struct nk_vec2 drag = nk_vec2(in->mouse.pos.x - center.x, in->mouse.pos.y - center.y); - float angle = (float)atan2(drag.y, drag.x); - if (angle < -0.0f) angle += 2.0f * 3.141592654f; - active_item = (int)(angle/step); - - for (i = 0; i < item_count; ++i) { - struct nk_rect content; - float rx, ry, dx, dy, a; - nk_fill_arc(out, center.x, center.y, (bounds.w/2.0f), - a_min, a_max, (active_item == i) ? nk_rgb(45,100,255): nk_rgb(60,60,60)); - - /* separator line */ - rx = bounds.w/2.0f; ry = 0; - dx = rx * (float)cos(a_min) - ry * (float)sin(a_min); - dy = rx * (float)sin(a_min) + ry * (float)cos(a_min); - nk_stroke_line(out, center.x, center.y, - center.x + dx, center.y + dy, 1.0f, nk_rgb(50,50,50)); - - /* button content */ - a = a_min + (a_max - a_min)/2.0f; - rx = bounds.w/2.5f; ry = 0; - content.w = 30; content.h = 30; - content.x = center.x + ((rx * (float)cos(a) - ry * (float)sin(a)) - content.w/2.0f); - content.y = center.y + (rx * (float)sin(a) + ry * (float)cos(a) - content.h/2.0f); - nk_draw_image(out, content, &icons[i], nk_rgb(255,255,255)); - a_min = a_max; a_max += step; - } - } - { - /* inner circle */ - struct nk_rect inner; - inner.x = bounds.x + bounds.w/2 - bounds.w/4; - inner.y = bounds.y + bounds.h/2 - bounds.h/4; - inner.w = bounds.w/2; inner.h = bounds.h/2; - nk_fill_circle(out, inner, nk_rgb(45,45,45)); - - /* active icon content */ - bounds.w = inner.w / 2.0f; - bounds.h = inner.h / 2.0f; - bounds.x = inner.x + inner.w/2 - bounds.w/2; - bounds.y = inner.y + inner.h/2 - bounds.h/2; - nk_draw_image(out, bounds, &icons[active_item], nk_rgb(255,255,255)); - } - nk_layout_space_end(ctx); - if (!nk_input_is_mouse_down(&ctx->input, NK_BUTTON_RIGHT)) { - nk_popup_close(ctx); - ret = active_item; - } - } else ret = -2; - ctx->style.window.spacing = nk_vec2(4,4); - ctx->style.window.padding = nk_vec2(8,8); - nk_popup_end(ctx); - - ctx->style.window.fixed_background = background; - ctx->style.window.border_color = border; - return ret; -} - -/* =============================================================== - * - * GRID - * - * ===============================================================*/ -static void -grid_demo(struct nk_context *ctx, struct media *media) -{ - static char text[3][64]; - static int text_len[3]; - static const char *items[] = {"Item 0","item 1","item 2"}; - static int selected_item = 0; - static int check = 1; - - int i; - nk_style_set_font(ctx, &media->font_20->handle); - if (nk_begin(ctx, "Grid Demo", nk_rect(600, 350, 275, 250), - NK_WINDOW_TITLE|NK_WINDOW_BORDER|NK_WINDOW_MOVABLE| - NK_WINDOW_NO_SCROLLBAR)) - { - nk_style_set_font(ctx, &media->font_18->handle); - nk_layout_row_dynamic(ctx, 30, 2); - nk_label(ctx, "Floating point:", NK_TEXT_RIGHT); - nk_edit_string(ctx, NK_EDIT_FIELD, text[0], &text_len[0], 64, nk_filter_float); - nk_label(ctx, "Hexadecimal:", NK_TEXT_RIGHT); - nk_edit_string(ctx, NK_EDIT_FIELD, text[1], &text_len[1], 64, nk_filter_hex); - nk_label(ctx, "Binary:", NK_TEXT_RIGHT); - nk_edit_string(ctx, NK_EDIT_FIELD, text[2], &text_len[2], 64, nk_filter_binary); - nk_label(ctx, "Checkbox:", NK_TEXT_RIGHT); - nk_checkbox_label(ctx, "Check me", &check); - nk_label(ctx, "Combobox:", NK_TEXT_RIGHT); - if (nk_combo_begin_label(ctx, items[selected_item], nk_vec2(nk_widget_width(ctx), 200))) { - nk_layout_row_dynamic(ctx, 25, 1); - for (i = 0; i < 3; ++i) - if (nk_combo_item_label(ctx, items[i], NK_TEXT_LEFT)) - selected_item = i; - nk_combo_end(ctx); - } - } - nk_end(ctx); - nk_style_set_font(ctx, &media->font_14->handle); -} - -/* =============================================================== - * - * BUTTON DEMO - * - * ===============================================================*/ -static void -ui_header(struct nk_context *ctx, struct media *media, const char *title) -{ - nk_style_set_font(ctx, &media->font_18->handle); - nk_layout_row_dynamic(ctx, 20, 1); - nk_label(ctx, title, NK_TEXT_LEFT); -} - -static void -ui_widget(struct nk_context *ctx, struct media *media, float height) -{ - static const float ratio[] = {0.15f, 0.85f}; - nk_style_set_font(ctx, &media->font_22->handle); - nk_layout_row(ctx, NK_DYNAMIC, height, 2, ratio); - nk_spacing(ctx, 1); -} - -static void -ui_widget_centered(struct nk_context *ctx, struct media *media, float height) -{ - static const float ratio[] = {0.15f, 0.50f, 0.35f}; - nk_style_set_font(ctx, &media->font_22->handle); - nk_layout_row(ctx, NK_DYNAMIC, height, 3, ratio); - nk_spacing(ctx, 1); -} - -static void -button_demo(struct nk_context *ctx, struct media *media) -{ - static int option = 1; - static int toggle0 = 1; - static int toggle1 = 0; - static int toggle2 = 1; - - nk_style_set_font(ctx, &media->font_20->handle); - nk_begin(ctx, "Button Demo", nk_rect(50,50,255,610), - NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_TITLE); - - /*------------------------------------------------ - * MENU - *------------------------------------------------*/ - nk_menubar_begin(ctx); - { - /* toolbar */ - nk_layout_row_static(ctx, 40, 40, 4); - if (nk_menu_begin_image(ctx, "Music", media->play, nk_vec2(110,120))) - { - /* settings */ - nk_layout_row_dynamic(ctx, 25, 1); - nk_menu_item_image_label(ctx, media->play, "Play", NK_TEXT_RIGHT); - nk_menu_item_image_label(ctx, media->stop, "Stop", NK_TEXT_RIGHT); - nk_menu_item_image_label(ctx, media->pause, "Pause", NK_TEXT_RIGHT); - nk_menu_item_image_label(ctx, media->next, "Next", NK_TEXT_RIGHT); - nk_menu_item_image_label(ctx, media->prev, "Prev", NK_TEXT_RIGHT); - nk_menu_end(ctx); - } - nk_button_image(ctx, media->tools); - nk_button_image(ctx, media->cloud); - nk_button_image(ctx, media->pen); - } - nk_menubar_end(ctx); - - /*------------------------------------------------ - * BUTTON - *------------------------------------------------*/ - ui_header(ctx, media, "Push buttons"); - ui_widget(ctx, media, 35); - if (nk_button_label(ctx, "Push me")) - fprintf(stdout, "pushed!\n"); - ui_widget(ctx, media, 35); - if (nk_button_image_label(ctx, media->rocket, "Styled", NK_TEXT_CENTERED)) - fprintf(stdout, "rocket!\n"); - - /*------------------------------------------------ - * REPEATER - *------------------------------------------------*/ - ui_header(ctx, media, "Repeater"); - ui_widget(ctx, media, 35); - if (nk_button_label(ctx, "Press me")) - fprintf(stdout, "pressed!\n"); - - /*------------------------------------------------ - * TOGGLE - *------------------------------------------------*/ - ui_header(ctx, media, "Toggle buttons"); - ui_widget(ctx, media, 35); - if (nk_button_image_label(ctx, (toggle0) ? media->checked: media->unchecked, "Toggle", NK_TEXT_LEFT)) - toggle0 = !toggle0; - - ui_widget(ctx, media, 35); - if (nk_button_image_label(ctx, (toggle1) ? media->checked: media->unchecked, "Toggle", NK_TEXT_LEFT)) - toggle1 = !toggle1; - - ui_widget(ctx, media, 35); - if (nk_button_image_label(ctx, (toggle2) ? media->checked: media->unchecked, "Toggle", NK_TEXT_LEFT)) - toggle2 = !toggle2; - - /*------------------------------------------------ - * RADIO - *------------------------------------------------*/ - ui_header(ctx, media, "Radio buttons"); - ui_widget(ctx, media, 35); - if (nk_button_symbol_label(ctx, (option == 0)?NK_SYMBOL_CIRCLE_OUTLINE:NK_SYMBOL_CIRCLE_SOLID, "Select", NK_TEXT_LEFT)) - option = 0; - ui_widget(ctx, media, 35); - if (nk_button_symbol_label(ctx, (option == 1)?NK_SYMBOL_CIRCLE_OUTLINE:NK_SYMBOL_CIRCLE_SOLID, "Select", NK_TEXT_LEFT)) - option = 1; - ui_widget(ctx, media, 35); - if (nk_button_symbol_label(ctx, (option == 2)?NK_SYMBOL_CIRCLE_OUTLINE:NK_SYMBOL_CIRCLE_SOLID, "Select", NK_TEXT_LEFT)) - option = 2; - - /*------------------------------------------------ - * CONTEXTUAL - *------------------------------------------------*/ - nk_style_set_font(ctx, &media->font_18->handle); - if (nk_contextual_begin(ctx, NK_WINDOW_NO_SCROLLBAR, nk_vec2(150, 300), nk_window_get_bounds(ctx))) { - nk_layout_row_dynamic(ctx, 30, 1); - if (nk_contextual_item_image_label(ctx, media->copy, "Clone", NK_TEXT_RIGHT)) - fprintf(stdout, "pressed clone!\n"); - if (nk_contextual_item_image_label(ctx, media->del, "Delete", NK_TEXT_RIGHT)) - fprintf(stdout, "pressed delete!\n"); - if (nk_contextual_item_image_label(ctx, media->convert, "Convert", NK_TEXT_RIGHT)) - fprintf(stdout, "pressed convert!\n"); - if (nk_contextual_item_image_label(ctx, media->edit, "Edit", NK_TEXT_RIGHT)) - fprintf(stdout, "pressed edit!\n"); - nk_contextual_end(ctx); - } - nk_style_set_font(ctx, &media->font_14->handle); - nk_end(ctx); -} - -/* =============================================================== - * - * BASIC DEMO - * - * ===============================================================*/ -static void -basic_demo(struct nk_context *ctx, struct media *media) -{ - static int image_active; - static int check0 = 1; - static int check1 = 0; - static size_t prog = 80; - static int selected_item = 0; - static int selected_image = 3; - static int selected_icon = 0; - static const char *items[] = {"Item 0","item 1","item 2"}; - static int piemenu_active = 0; - static struct nk_vec2 piemenu_pos; - - int i = 0; - nk_style_set_font(ctx, &media->font_20->handle); - nk_begin(ctx, "Basic Demo", nk_rect(320, 50, 275, 610), - NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_TITLE); - - /*------------------------------------------------ - * POPUP BUTTON - *------------------------------------------------*/ - ui_header(ctx, media, "Popup & Scrollbar & Images"); - ui_widget(ctx, media, 35); - if (nk_button_image_label(ctx, media->dir, "Images", NK_TEXT_CENTERED)) - image_active = !image_active; - - /*------------------------------------------------ - * SELECTED IMAGE - *------------------------------------------------*/ - ui_header(ctx, media, "Selected Image"); - ui_widget_centered(ctx, media, 100); - nk_image(ctx, media->images[selected_image]); - - /*------------------------------------------------ - * IMAGE POPUP - *------------------------------------------------*/ - if (image_active) { - struct nk_panel popup; - if (nk_popup_begin(ctx, NK_POPUP_STATIC, "Image Popup", 0, nk_rect(265, 0, 320, 220))) { - nk_layout_row_static(ctx, 82, 82, 3); - for (i = 0; i < 9; ++i) { - if (nk_button_image(ctx, media->images[i])) { - selected_image = i; - image_active = 0; - nk_popup_close(ctx); - } - } - nk_popup_end(ctx); - } - } - /*------------------------------------------------ - * COMBOBOX - *------------------------------------------------*/ - ui_header(ctx, media, "Combo box"); - ui_widget(ctx, media, 40); - if (nk_combo_begin_label(ctx, items[selected_item], nk_vec2(nk_widget_width(ctx), 200))) { - nk_layout_row_dynamic(ctx, 35, 1); - for (i = 0; i < 3; ++i) - if (nk_combo_item_label(ctx, items[i], NK_TEXT_LEFT)) - selected_item = i; - nk_combo_end(ctx); - } - - ui_widget(ctx, media, 40); - if (nk_combo_begin_image_label(ctx, items[selected_icon], media->images[selected_icon], nk_vec2(nk_widget_width(ctx), 200))) { - nk_layout_row_dynamic(ctx, 35, 1); - for (i = 0; i < 3; ++i) - if (nk_combo_item_image_label(ctx, media->images[i], items[i], NK_TEXT_RIGHT)) - selected_icon = i; - nk_combo_end(ctx); - } - - /*------------------------------------------------ - * CHECKBOX - *------------------------------------------------*/ - ui_header(ctx, media, "Checkbox"); - ui_widget(ctx, media, 30); - nk_checkbox_label(ctx, "Flag 1", &check0); - ui_widget(ctx, media, 30); - nk_checkbox_label(ctx, "Flag 2", &check1); - - /*------------------------------------------------ - * PROGRESSBAR - *------------------------------------------------*/ - ui_header(ctx, media, "Progressbar"); - ui_widget(ctx, media, 35); - nk_progress(ctx, &prog, 100, nk_true); - - /*------------------------------------------------ - * PIEMENU - *------------------------------------------------*/ - if (nk_input_is_mouse_click_down_in_rect(&ctx->input, NK_BUTTON_RIGHT, - nk_window_get_bounds(ctx),nk_true)){ - piemenu_pos = ctx->input.mouse.pos; - piemenu_active = 1; - } - - if (piemenu_active) { - int ret = ui_piemenu(ctx, piemenu_pos, 140, &media->menu[0], 6); - if (ret == -2) piemenu_active = 0; - if (ret != -1) { - fprintf(stdout, "piemenu selected: %d\n", ret); - piemenu_active = 0; - } - } - nk_style_set_font(ctx, &media->font_14->handle); - nk_end(ctx); -} - -/* =============================================================== - * - * DEVICE - * - * ===============================================================*/ -struct nk_glfw_vertex { - float position[2]; - float uv[2]; - nk_byte col[4]; -}; - -struct device { - struct nk_buffer cmds; - struct nk_draw_null_texture null; - GLuint vbo, vao, ebo; - GLuint prog; - GLuint vert_shdr; - GLuint frag_shdr; - GLint attrib_pos; - GLint attrib_uv; - GLint attrib_col; - GLint uniform_tex; - GLint uniform_proj; - GLuint font_tex; -}; - -static void -die(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fputs("\n", stderr); - exit(EXIT_FAILURE); -} - -static struct nk_image -icon_load(const char *filename) -{ - int x,y,n; - GLuint tex; - unsigned char *data = stbi_load(filename, &x, &y, &n, 0); - if (!data) die("[SDL]: failed to load image: %s", filename); - - glGenTextures(1, &tex); - glBindTexture(GL_TEXTURE_2D, tex); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - glGenerateMipmap(GL_TEXTURE_2D); - stbi_image_free(data); - return nk_image_id((int)tex); -} - -static void -device_init(struct device *dev) -{ - GLint status; - static const GLchar *vertex_shader = - NK_SHADER_VERSION - "uniform mat4 ProjMtx;\n" - "in vec2 Position;\n" - "in vec2 TexCoord;\n" - "in vec4 Color;\n" - "out vec2 Frag_UV;\n" - "out vec4 Frag_Color;\n" - "void main() {\n" - " Frag_UV = TexCoord;\n" - " Frag_Color = Color;\n" - " gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n" - "}\n"; - static const GLchar *fragment_shader = - NK_SHADER_VERSION - "precision mediump float;\n" - "uniform sampler2D Texture;\n" - "in vec2 Frag_UV;\n" - "in vec4 Frag_Color;\n" - "out vec4 Out_Color;\n" - "void main(){\n" - " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" - "}\n"; - - nk_buffer_init_default(&dev->cmds); - dev->prog = glCreateProgram(); - dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER); - dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0); - glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0); - glCompileShader(dev->vert_shdr); - glCompileShader(dev->frag_shdr); - glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status); - assert(status == GL_TRUE); - glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status); - assert(status == GL_TRUE); - glAttachShader(dev->prog, dev->vert_shdr); - glAttachShader(dev->prog, dev->frag_shdr); - glLinkProgram(dev->prog); - glGetProgramiv(dev->prog, GL_LINK_STATUS, &status); - assert(status == GL_TRUE); - - dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture"); - dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx"); - dev->attrib_pos = glGetAttribLocation(dev->prog, "Position"); - dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord"); - dev->attrib_col = glGetAttribLocation(dev->prog, "Color"); - - { - /* buffer setup */ - GLsizei vs = sizeof(struct nk_glfw_vertex); - size_t vp = offsetof(struct nk_glfw_vertex, position); - size_t vt = offsetof(struct nk_glfw_vertex, uv); - size_t vc = offsetof(struct nk_glfw_vertex, col); - - glGenBuffers(1, &dev->vbo); - glGenBuffers(1, &dev->ebo); - glGenVertexArrays(1, &dev->vao); - - glBindVertexArray(dev->vao); - glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); - - glEnableVertexAttribArray((GLuint)dev->attrib_pos); - glEnableVertexAttribArray((GLuint)dev->attrib_uv); - glEnableVertexAttribArray((GLuint)dev->attrib_col); - - glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp); - glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt); - glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc); - } - - glBindTexture(GL_TEXTURE_2D, 0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindVertexArray(0); -} - -static void -device_upload_atlas(struct device *dev, const void *image, int width, int height) -{ - glGenTextures(1, &dev->font_tex); - glBindTexture(GL_TEXTURE_2D, dev->font_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, image); -} - -static void -device_shutdown(struct device *dev) -{ - glDetachShader(dev->prog, dev->vert_shdr); - glDetachShader(dev->prog, dev->frag_shdr); - glDeleteShader(dev->vert_shdr); - glDeleteShader(dev->frag_shdr); - glDeleteProgram(dev->prog); - glDeleteTextures(1, &dev->font_tex); - glDeleteBuffers(1, &dev->vbo); - glDeleteBuffers(1, &dev->ebo); - nk_buffer_free(&dev->cmds); -} - -static void -device_draw(struct device *dev, struct nk_context *ctx, int width, int height, - struct nk_vec2 scale, enum nk_anti_aliasing AA) -{ - GLfloat ortho[4][4] = { - {2.0f, 0.0f, 0.0f, 0.0f}, - {0.0f,-2.0f, 0.0f, 0.0f}, - {0.0f, 0.0f,-1.0f, 0.0f}, - {-1.0f,1.0f, 0.0f, 1.0f}, - }; - ortho[0][0] /= (GLfloat)width; - ortho[1][1] /= (GLfloat)height; - - /* setup global state */ - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glEnable(GL_SCISSOR_TEST); - glActiveTexture(GL_TEXTURE0); - - /* setup program */ - glUseProgram(dev->prog); - glUniform1i(dev->uniform_tex, 0); - glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]); - { - /* convert from command queue into draw list and draw to screen */ - const struct nk_draw_command *cmd; - void *vertices, *elements; - const nk_draw_index *offset = NULL; - - /* allocate vertex and element buffer */ - glBindVertexArray(dev->vao); - glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); - - glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW); - - /* load draw vertices & elements directly into vertex + element buffer */ - vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); - elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY); - { - /* fill convert configuration */ - struct nk_convert_config config; - static const struct nk_draw_vertex_layout_element vertex_layout[] = { - {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)}, - {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)}, - {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)}, - {NK_VERTEX_LAYOUT_END} - }; - NK_MEMSET(&config, 0, sizeof(config)); - config.vertex_layout = vertex_layout; - config.vertex_size = sizeof(struct nk_glfw_vertex); - config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex); - config.null = dev->null; - config.circle_segment_count = 22; - config.curve_segment_count = 22; - config.arc_segment_count = 22; - config.global_alpha = 1.0f; - config.shape_AA = AA; - config.line_AA = AA; - - /* setup buffers to load vertices and elements */ - {struct nk_buffer vbuf, ebuf; - nk_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY); - nk_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY); - nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);} - } - glUnmapBuffer(GL_ARRAY_BUFFER); - glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); - - /* iterate over and execute each draw command */ - nk_draw_foreach(cmd, ctx, &dev->cmds) - { - if (!cmd->elem_count) continue; - glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); - glScissor( - (GLint)(cmd->clip_rect.x * scale.x), - (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y), - (GLint)(cmd->clip_rect.w * scale.x), - (GLint)(cmd->clip_rect.h * scale.y)); - glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); - offset += cmd->elem_count; - } - nk_clear(ctx); - } - - /* default OpenGL state */ - glUseProgram(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindVertexArray(0); - glDisable(GL_BLEND); - glDisable(GL_SCISSOR_TEST); -} - -/* glfw callbacks (I don't know if there is a easier way to access text and scroll )*/ -static void error_callback(int e, const char *d){printf("Error %d: %s\n", e, d);} -static void text_input(GLFWwindow *win, unsigned int codepoint) -{nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);} -static void scroll_input(GLFWwindow *win, double _, double yoff) -{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), nk_vec2(0, (float)yoff));} - -int main(int argc, char *argv[]) -{ - /* Platform */ - static GLFWwindow *win; - int width = 0, height = 0; - int display_width=0, display_height=0; - - /* GUI */ - struct device device; - struct nk_font_atlas atlas; - struct media media; - struct nk_context ctx; - - /* GLFW */ - glfwSetErrorCallback(error_callback); - if (!glfwInit()) { - fprintf(stdout, "[GFLW] failed to init!\n"); - exit(1); - } - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); -#ifdef __APPLE__ - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); -#endif - win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL); - glfwMakeContextCurrent(win); - glfwSetWindowUserPointer(win, &ctx); - glfwSetCharCallback(win, text_input); - glfwSetScrollCallback(win, scroll_input); - glfwGetWindowSize(win, &width, &height); - glfwGetFramebufferSize(win, &display_width, &display_height); - - /* OpenGL */ - glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); - glewExperimental = 1; - if (glewInit() != GLEW_OK) { - fprintf(stderr, "Failed to setup GLEW\n"); - exit(1); - } - - {/* GUI */ - device_init(&device); - {const void *image; int w, h; - struct nk_font_config cfg = nk_font_config(0); - cfg.oversample_h = 3; cfg.oversample_v = 2; - /* Loading one font with different heights is only required if you want higher - * quality text otherwise you can just set the font height directly - * e.g.: ctx->style.font.height = 20. */ - nk_font_atlas_init_default(&atlas); - nk_font_atlas_begin(&atlas); - media.font_14 = nk_font_atlas_add_from_file(&atlas, "../../extra_font/Roboto-Regular.ttf", 14.0f, &cfg); - media.font_18 = nk_font_atlas_add_from_file(&atlas, "../../extra_font/Roboto-Regular.ttf", 18.0f, &cfg); - media.font_20 = nk_font_atlas_add_from_file(&atlas, "../../extra_font/Roboto-Regular.ttf", 20.0f, &cfg); - media.font_22 = nk_font_atlas_add_from_file(&atlas, "../../extra_font/Roboto-Regular.ttf", 22.0f, &cfg); - image = nk_font_atlas_bake(&atlas, &w, &h, NK_FONT_ATLAS_RGBA32); - device_upload_atlas(&device, image, w, h); - nk_font_atlas_end(&atlas, nk_handle_id((int)device.font_tex), &device.null);} - nk_init_default(&ctx, &media.font_14->handle);} - - /* icons */ - glEnable(GL_TEXTURE_2D); - media.unchecked = icon_load("../icon/unchecked.png"); - media.checked = icon_load("../icon/checked.png"); - media.rocket = icon_load("../icon/rocket.png"); - media.cloud = icon_load("../icon/cloud.png"); - media.pen = icon_load("../icon/pen.png"); - media.play = icon_load("../icon/play.png"); - media.pause = icon_load("../icon/pause.png"); - media.stop = icon_load("../icon/stop.png"); - media.next = icon_load("../icon/next.png"); - media.prev = icon_load("../icon/prev.png"); - media.tools = icon_load("../icon/tools.png"); - media.dir = icon_load("../icon/directory.png"); - media.copy = icon_load("../icon/copy.png"); - media.convert = icon_load("../icon/export.png"); - media.del = icon_load("../icon/delete.png"); - media.edit = icon_load("../icon/edit.png"); - media.menu[0] = icon_load("../icon/home.png"); - media.menu[1] = icon_load("../icon/phone.png"); - media.menu[2] = icon_load("../icon/plane.png"); - media.menu[3] = icon_load("../icon/wifi.png"); - media.menu[4] = icon_load("../icon/settings.png"); - media.menu[5] = icon_load("../icon/volume.png"); - - {int i; - for (i = 0; i < 9; ++i) { - char buffer[256]; - sprintf(buffer, "../images/image%d.png", (i+1)); - media.images[i] = icon_load(buffer); - }} - - while (!glfwWindowShouldClose(win)) - { - /* High DPI displays */ - struct nk_vec2 scale; - glfwGetWindowSize(win, &width, &height); - glfwGetFramebufferSize(win, &display_width, &display_height); - scale.x = (float)display_width/(float)width; - scale.y = (float)display_height/(float)height; - - /* Input */ - {double x, y; - nk_input_begin(&ctx); - glfwPollEvents(); - nk_input_key(&ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS); - if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || - glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) { - nk_input_key(&ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_SHIFT, 1); - } else { - nk_input_key(&ctx, NK_KEY_COPY, 0); - nk_input_key(&ctx, NK_KEY_PASTE, 0); - nk_input_key(&ctx, NK_KEY_CUT, 0); - nk_input_key(&ctx, NK_KEY_SHIFT, 0); - } - glfwGetCursorPos(win, &x, &y); - nk_input_motion(&ctx, (int)x, (int)y); - nk_input_button(&ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); - nk_input_button(&ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS); - nk_input_button(&ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS); - nk_input_end(&ctx);} - - /* GUI */ - basic_demo(&ctx, &media); - button_demo(&ctx, &media); - grid_demo(&ctx, &media); - - /* Draw */ - glViewport(0, 0, display_width, display_height); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(0.3f, 0.3f, 0.3f, 1.0f); - device_draw(&device, &ctx, width, height, scale, NK_ANTI_ALIASING_ON); - glfwSwapBuffers(win); - } - - glDeleteTextures(1,(const GLuint*)&media.unchecked.handle.id); - glDeleteTextures(1,(const GLuint*)&media.checked.handle.id); - glDeleteTextures(1,(const GLuint*)&media.rocket.handle.id); - glDeleteTextures(1,(const GLuint*)&media.cloud.handle.id); - glDeleteTextures(1,(const GLuint*)&media.pen.handle.id); - glDeleteTextures(1,(const GLuint*)&media.play.handle.id); - glDeleteTextures(1,(const GLuint*)&media.pause.handle.id); - glDeleteTextures(1,(const GLuint*)&media.stop.handle.id); - glDeleteTextures(1,(const GLuint*)&media.next.handle.id); - glDeleteTextures(1,(const GLuint*)&media.prev.handle.id); - glDeleteTextures(1,(const GLuint*)&media.tools.handle.id); - glDeleteTextures(1,(const GLuint*)&media.dir.handle.id); - glDeleteTextures(1,(const GLuint*)&media.del.handle.id); - - nk_font_atlas_clear(&atlas); - nk_free(&ctx); - - device_shutdown(&device); - glfwTerminate(); - return 0; -} - diff --git a/subprojects/nk_pugl/nuklear/example/file_browser.c b/subprojects/nk_pugl/nuklear/example/file_browser.c deleted file mode 100644 index 1945ff5..0000000 --- a/subprojects/nk_pugl/nuklear/example/file_browser.c +++ /dev/null @@ -1,910 +0,0 @@ -/* nuklear - v1.05 - public domain */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT -#define NK_INCLUDE_FONT_BAKING -#define NK_INCLUDE_DEFAULT_FONT -#define NK_IMPLEMENTATION -#include "../nuklear.h" - -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" - -/* macros */ -#define WINDOW_WIDTH 1200 -#define WINDOW_HEIGHT 800 - -#define MAX_VERTEX_MEMORY 512 * 1024 -#define MAX_ELEMENT_MEMORY 128 * 1024 - -#define UNUSED(a) (void)a -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#define MAX(a,b) ((a) < (b) ? (b) : (a)) -#define LEN(a) (sizeof(a)/sizeof(a)[0]) - -#ifdef __APPLE__ - #define NK_SHADER_VERSION "#version 150\n" -#else - #define NK_SHADER_VERSION "#version 300 es\n" -#endif - -/* =============================================================== - * - * GUI - * - * ===============================================================*/ -struct icons { - struct nk_image desktop; - struct nk_image home; - struct nk_image computer; - struct nk_image directory; - - struct nk_image default_file; - struct nk_image text_file; - struct nk_image music_file; - struct nk_image font_file; - struct nk_image img_file; - struct nk_image movie_file; -}; - -enum file_groups { - FILE_GROUP_DEFAULT, - FILE_GROUP_TEXT, - FILE_GROUP_MUSIC, - FILE_GROUP_FONT, - FILE_GROUP_IMAGE, - FILE_GROUP_MOVIE, - FILE_GROUP_MAX -}; - -enum file_types { - FILE_DEFAULT, - FILE_TEXT, - FILE_C_SOURCE, - FILE_CPP_SOURCE, - FILE_HEADER, - FILE_CPP_HEADER, - FILE_MP3, - FILE_WAV, - FILE_OGG, - FILE_TTF, - FILE_BMP, - FILE_PNG, - FILE_JPEG, - FILE_PCX, - FILE_TGA, - FILE_GIF, - FILE_MAX -}; - -struct file_group { - enum file_groups group; - const char *name; - struct nk_image *icon; -}; - -struct file { - enum file_types type; - const char *suffix; - enum file_groups group; -}; - -struct media { - int font; - int icon_sheet; - struct icons icons; - struct file_group group[FILE_GROUP_MAX]; - struct file files[FILE_MAX]; -}; - -#define MAX_PATH_LEN 512 -struct file_browser { - /* path */ - char file[MAX_PATH_LEN]; - char home[MAX_PATH_LEN]; - char desktop[MAX_PATH_LEN]; - char directory[MAX_PATH_LEN]; - - /* directory content */ - char **files; - char **directories; - size_t file_count; - size_t dir_count; - struct media *media; -}; - -#ifdef __unix__ -#include -#include -#endif - -#ifndef _WIN32 -# include -#endif - -static void -die(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fputs("\n", stderr); - exit(EXIT_FAILURE); -} - -static char* -file_load(const char* path, size_t* siz) -{ - char *buf; - FILE *fd = fopen(path, "rb"); - if (!fd) die("Failed to open file: %s\n", path); - fseek(fd, 0, SEEK_END); - *siz = (size_t)ftell(fd); - fseek(fd, 0, SEEK_SET); - buf = (char*)calloc(*siz, 1); - fread(buf, *siz, 1, fd); - fclose(fd); - return buf; -} - -static char* -str_duplicate(const char *src) -{ - char *ret; - size_t len = strlen(src); - if (!len) return 0; - ret = (char*)malloc(len+1); - if (!ret) return 0; - memcpy(ret, src, len); - ret[len] = '\0'; - return ret; -} - -static void -dir_free_list(char **list, size_t size) -{ - size_t i; - for (i = 0; i < size; ++i) - free(list[i]); - free(list); -} - -static char** -dir_list(const char *dir, int return_subdirs, size_t *count) -{ - size_t n = 0; - char buffer[MAX_PATH_LEN]; - char **results = NULL; - const DIR *none = NULL; - size_t capacity = 32; - size_t size; - DIR *z; - - assert(dir); - assert(count); - strncpy(buffer, dir, MAX_PATH_LEN); - n = strlen(buffer); - - if (n > 0 && (buffer[n-1] != '/')) - buffer[n++] = '/'; - - size = 0; - - z = opendir(dir); - if (z != none) { - int nonempty = 1; - struct dirent *data = readdir(z); - nonempty = (data != NULL); - if (!nonempty) return NULL; - - do { - DIR *y; - char *p; - int is_subdir; - if (data->d_name[0] == '.') - continue; - - strncpy(buffer + n, data->d_name, MAX_PATH_LEN-n); - y = opendir(buffer); - is_subdir = (y != NULL); - if (y != NULL) closedir(y); - - if ((return_subdirs && is_subdir) || (!is_subdir && !return_subdirs)){ - if (!size) { - results = (char**)calloc(sizeof(char*), capacity); - } else if (size >= capacity) { - void *old = results; - capacity = capacity * 2; - results = (char**)realloc(results, capacity * sizeof(char*)); - assert(results); - if (!results) free(old); - } - p = str_duplicate(data->d_name); - results[size++] = p; - } - } while ((data = readdir(z)) != NULL); - } - - if (z) closedir(z); - *count = size; - return results; -} - -static struct file_group -FILE_GROUP(enum file_groups group, const char *name, struct nk_image *icon) -{ - struct file_group fg; - fg.group = group; - fg.name = name; - fg.icon = icon; - return fg; -} - -static struct file -FILE_DEF(enum file_types type, const char *suffix, enum file_groups group) -{ - struct file fd; - fd.type = type; - fd.suffix = suffix; - fd.group = group; - return fd; -} - -static struct nk_image* -media_icon_for_file(struct media *media, const char *file) -{ - int i = 0; - const char *s = file; - char suffix[4]; - int found = 0; - memset(suffix, 0, sizeof(suffix)); - - /* extract suffix .xxx from file */ - while (*s++ != '\0') { - if (found && i < 3) - suffix[i++] = *s; - - if (*s == '.') { - if (found){ - found = 0; - break; - } - found = 1; - } - } - - /* check for all file definition of all groups for fitting suffix*/ - for (i = 0; i < FILE_MAX && found; ++i) { - struct file *d = &media->files[i]; - { - const char *f = d->suffix; - s = suffix; - while (f && *f && *s && *s == *f) { - s++; f++; - } - - /* found correct file definition so */ - if (f && *s == '\0' && *f == '\0') - return media->group[d->group].icon; - } - } - return &media->icons.default_file; -} - -static void -media_init(struct media *media) -{ - /* file groups */ - struct icons *icons = &media->icons; - media->group[FILE_GROUP_DEFAULT] = FILE_GROUP(FILE_GROUP_DEFAULT,"default",&icons->default_file); - media->group[FILE_GROUP_TEXT] = FILE_GROUP(FILE_GROUP_TEXT, "textual", &icons->text_file); - media->group[FILE_GROUP_MUSIC] = FILE_GROUP(FILE_GROUP_MUSIC, "music", &icons->music_file); - media->group[FILE_GROUP_FONT] = FILE_GROUP(FILE_GROUP_FONT, "font", &icons->font_file); - media->group[FILE_GROUP_IMAGE] = FILE_GROUP(FILE_GROUP_IMAGE, "image", &icons->img_file); - media->group[FILE_GROUP_MOVIE] = FILE_GROUP(FILE_GROUP_MOVIE, "movie", &icons->movie_file); - - /* files */ - media->files[FILE_DEFAULT] = FILE_DEF(FILE_DEFAULT, NULL, FILE_GROUP_DEFAULT); - media->files[FILE_TEXT] = FILE_DEF(FILE_TEXT, "txt", FILE_GROUP_TEXT); - media->files[FILE_C_SOURCE] = FILE_DEF(FILE_C_SOURCE, "c", FILE_GROUP_TEXT); - media->files[FILE_CPP_SOURCE] = FILE_DEF(FILE_CPP_SOURCE, "cpp", FILE_GROUP_TEXT); - media->files[FILE_HEADER] = FILE_DEF(FILE_HEADER, "h", FILE_GROUP_TEXT); - media->files[FILE_CPP_HEADER] = FILE_DEF(FILE_HEADER, "hpp", FILE_GROUP_TEXT); - media->files[FILE_MP3] = FILE_DEF(FILE_MP3, "mp3", FILE_GROUP_MUSIC); - media->files[FILE_WAV] = FILE_DEF(FILE_WAV, "wav", FILE_GROUP_MUSIC); - media->files[FILE_OGG] = FILE_DEF(FILE_OGG, "ogg", FILE_GROUP_MUSIC); - media->files[FILE_TTF] = FILE_DEF(FILE_TTF, "ttf", FILE_GROUP_FONT); - media->files[FILE_BMP] = FILE_DEF(FILE_BMP, "bmp", FILE_GROUP_IMAGE); - media->files[FILE_PNG] = FILE_DEF(FILE_PNG, "png", FILE_GROUP_IMAGE); - media->files[FILE_JPEG] = FILE_DEF(FILE_JPEG, "jpg", FILE_GROUP_IMAGE); - media->files[FILE_PCX] = FILE_DEF(FILE_PCX, "pcx", FILE_GROUP_IMAGE); - media->files[FILE_TGA] = FILE_DEF(FILE_TGA, "tga", FILE_GROUP_IMAGE); - media->files[FILE_GIF] = FILE_DEF(FILE_GIF, "gif", FILE_GROUP_IMAGE); -} - -static void -file_browser_reload_directory_content(struct file_browser *browser, const char *path) -{ - strncpy(browser->directory, path, MAX_PATH_LEN); - dir_free_list(browser->files, browser->file_count); - dir_free_list(browser->directories, browser->dir_count); - browser->files = dir_list(path, 0, &browser->file_count); - browser->directories = dir_list(path, 1, &browser->dir_count); -} - -static void -file_browser_init(struct file_browser *browser, struct media *media) -{ - memset(browser, 0, sizeof(*browser)); - browser->media = media; - { - /* load files and sub-directory list */ - const char *home = getenv("HOME"); -#ifdef _WIN32 - if (!home) home = getenv("USERPROFILE"); -#else - if (!home) home = getpwuid(getuid())->pw_dir; - { - size_t l; - strncpy(browser->home, home, MAX_PATH_LEN); - l = strlen(browser->home); - strcpy(browser->home + l, "/"); - strcpy(browser->directory, browser->home); - } -#endif - { - size_t l; - strcpy(browser->desktop, browser->home); - l = strlen(browser->desktop); - strcpy(browser->desktop + l, "desktop/"); - } - browser->files = dir_list(browser->directory, 0, &browser->file_count); - browser->directories = dir_list(browser->directory, 1, &browser->dir_count); - } -} - -static void -file_browser_free(struct file_browser *browser) -{ - if (browser->files) - dir_free_list(browser->files, browser->file_count); - if (browser->directories) - dir_free_list(browser->directories, browser->dir_count); - browser->files = NULL; - browser->directories = NULL; - memset(browser, 0, sizeof(*browser)); -} - -static int -file_browser_run(struct file_browser *browser, struct nk_context *ctx) -{ - int ret = 0; - struct media *media = browser->media; - struct nk_rect total_space; - - if (nk_begin(ctx, "File Browser", nk_rect(50, 50, 800, 600), - NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_MOVABLE)) - { - static float ratio[] = {0.25f, NK_UNDEFINED}; - float spacing_x = ctx->style.window.spacing.x; - - /* output path directory selector in the menubar */ - ctx->style.window.spacing.x = 0; - nk_menubar_begin(ctx); - { - char *d = browser->directory; - char *begin = d + 1; - nk_layout_row_dynamic(ctx, 25, 6); - while (*d++) { - if (*d == '/') { - *d = '\0'; - if (nk_button_label(ctx, begin)) { - *d++ = '/'; *d = '\0'; - file_browser_reload_directory_content(browser, browser->directory); - break; - } - *d = '/'; - begin = d + 1; - } - } - } - nk_menubar_end(ctx); - ctx->style.window.spacing.x = spacing_x; - - /* window layout */ - total_space = nk_window_get_content_region(ctx); - nk_layout_row(ctx, NK_DYNAMIC, total_space.h, 2, ratio); - nk_group_begin(ctx, "Special", NK_WINDOW_NO_SCROLLBAR); - { - struct nk_image home = media->icons.home; - struct nk_image desktop = media->icons.desktop; - struct nk_image computer = media->icons.computer; - - nk_layout_row_dynamic(ctx, 40, 1); - if (nk_button_image_label(ctx, home, "home", NK_TEXT_CENTERED)) - file_browser_reload_directory_content(browser, browser->home); - if (nk_button_image_label(ctx,desktop,"desktop",NK_TEXT_CENTERED)) - file_browser_reload_directory_content(browser, browser->desktop); - if (nk_button_image_label(ctx,computer,"computer",NK_TEXT_CENTERED)) - file_browser_reload_directory_content(browser, "/"); - nk_group_end(ctx); - } - - /* output directory content window */ - nk_group_begin(ctx, "Content", 0); - { - int index = -1; - size_t i = 0, j = 0, k = 0; - size_t rows = 0, cols = 0; - size_t count = browser->dir_count + browser->file_count; - - cols = 4; - rows = count / cols; - for (i = 0; i <= rows; i += 1) { - {size_t n = j + cols; - nk_layout_row_dynamic(ctx, 135, (int)cols); - for (; j < count && j < n; ++j) { - /* draw one row of icons */ - if (j < browser->dir_count) { - /* draw and execute directory buttons */ - if (nk_button_image(ctx,media->icons.directory)) - index = (int)j; - } else { - /* draw and execute files buttons */ - struct nk_image *icon; - size_t fileIndex = ((size_t)j - browser->dir_count); - icon = media_icon_for_file(media,browser->files[fileIndex]); - if (nk_button_image(ctx, *icon)) { - strncpy(browser->file, browser->directory, MAX_PATH_LEN); - n = strlen(browser->file); - strncpy(browser->file + n, browser->files[fileIndex], MAX_PATH_LEN - n); - ret = 1; - } - } - }} - {size_t n = k + cols; - nk_layout_row_dynamic(ctx, 20, (int)cols); - for (; k < count && k < n; k++) { - /* draw one row of labels */ - if (k < browser->dir_count) { - nk_label(ctx, browser->directories[k], NK_TEXT_CENTERED); - } else { - size_t t = k-browser->dir_count; - nk_label(ctx,browser->files[t],NK_TEXT_CENTERED); - } - }} - } - - if (index != -1) { - size_t n = strlen(browser->directory); - strncpy(browser->directory + n, browser->directories[index], MAX_PATH_LEN - n); - n = strlen(browser->directory); - if (n < MAX_PATH_LEN - 1) { - browser->directory[n] = '/'; - browser->directory[n+1] = '\0'; - } - file_browser_reload_directory_content(browser, browser->directory); - } - nk_group_end(ctx); - } - } - nk_end(ctx); - return ret; -} - -/* =============================================================== - * - * DEVICE - * - * ===============================================================*/ -struct nk_glfw_vertex { - float position[2]; - float uv[2]; - nk_byte col[4]; -}; - -struct device { - struct nk_buffer cmds; - struct nk_draw_null_texture null; - GLuint vbo, vao, ebo; - GLuint prog; - GLuint vert_shdr; - GLuint frag_shdr; - GLint attrib_pos; - GLint attrib_uv; - GLint attrib_col; - GLint uniform_tex; - GLint uniform_proj; - GLuint font_tex; -}; -static struct nk_image -icon_load(const char *filename) -{ - int x,y,n; - GLuint tex; - unsigned char *data = stbi_load(filename, &x, &y, &n, 0); - if (!data) die("[SDL]: failed to load image: %s", filename); - - glGenTextures(1, &tex); - glBindTexture(GL_TEXTURE_2D, tex); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - glGenerateMipmap(GL_TEXTURE_2D); - stbi_image_free(data); - return nk_image_id((int)tex); -} - -static void -device_init(struct device *dev) -{ - GLint status; - static const GLchar *vertex_shader = - NK_SHADER_VERSION - "uniform mat4 ProjMtx;\n" - "in vec2 Position;\n" - "in vec2 TexCoord;\n" - "in vec4 Color;\n" - "out vec2 Frag_UV;\n" - "out vec4 Frag_Color;\n" - "void main() {\n" - " Frag_UV = TexCoord;\n" - " Frag_Color = Color;\n" - " gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n" - "}\n"; - static const GLchar *fragment_shader = - NK_SHADER_VERSION - "precision mediump float;\n" - "uniform sampler2D Texture;\n" - "in vec2 Frag_UV;\n" - "in vec4 Frag_Color;\n" - "out vec4 Out_Color;\n" - "void main(){\n" - " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" - "}\n"; - - nk_buffer_init_default(&dev->cmds); - dev->prog = glCreateProgram(); - dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER); - dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0); - glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0); - glCompileShader(dev->vert_shdr); - glCompileShader(dev->frag_shdr); - glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status); - assert(status == GL_TRUE); - glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status); - assert(status == GL_TRUE); - glAttachShader(dev->prog, dev->vert_shdr); - glAttachShader(dev->prog, dev->frag_shdr); - glLinkProgram(dev->prog); - glGetProgramiv(dev->prog, GL_LINK_STATUS, &status); - assert(status == GL_TRUE); - - dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture"); - dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx"); - dev->attrib_pos = glGetAttribLocation(dev->prog, "Position"); - dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord"); - dev->attrib_col = glGetAttribLocation(dev->prog, "Color"); - - { - /* buffer setup */ - GLsizei vs = sizeof(struct nk_glfw_vertex); - size_t vp = offsetof(struct nk_glfw_vertex, position); - size_t vt = offsetof(struct nk_glfw_vertex, uv); - size_t vc = offsetof(struct nk_glfw_vertex, col); - - glGenBuffers(1, &dev->vbo); - glGenBuffers(1, &dev->ebo); - glGenVertexArrays(1, &dev->vao); - - glBindVertexArray(dev->vao); - glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); - - glEnableVertexAttribArray((GLuint)dev->attrib_pos); - glEnableVertexAttribArray((GLuint)dev->attrib_uv); - glEnableVertexAttribArray((GLuint)dev->attrib_col); - - glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp); - glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt); - glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc); - } - - glBindTexture(GL_TEXTURE_2D, 0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindVertexArray(0); -} - -static void -device_upload_atlas(struct device *dev, const void *image, int width, int height) -{ - glGenTextures(1, &dev->font_tex); - glBindTexture(GL_TEXTURE_2D, dev->font_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, image); -} - -static void -device_shutdown(struct device *dev) -{ - glDetachShader(dev->prog, dev->vert_shdr); - glDetachShader(dev->prog, dev->frag_shdr); - glDeleteShader(dev->vert_shdr); - glDeleteShader(dev->frag_shdr); - glDeleteProgram(dev->prog); - glDeleteTextures(1, &dev->font_tex); - glDeleteBuffers(1, &dev->vbo); - glDeleteBuffers(1, &dev->ebo); - nk_buffer_free(&dev->cmds); -} - -static void -device_draw(struct device *dev, struct nk_context *ctx, int width, int height, - struct nk_vec2 scale, enum nk_anti_aliasing AA) -{ - GLfloat ortho[4][4] = { - {2.0f, 0.0f, 0.0f, 0.0f}, - {0.0f,-2.0f, 0.0f, 0.0f}, - {0.0f, 0.0f,-1.0f, 0.0f}, - {-1.0f,1.0f, 0.0f, 1.0f}, - }; - ortho[0][0] /= (GLfloat)width; - ortho[1][1] /= (GLfloat)height; - - /* setup global state */ - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glEnable(GL_SCISSOR_TEST); - glActiveTexture(GL_TEXTURE0); - - /* setup program */ - glUseProgram(dev->prog); - glUniform1i(dev->uniform_tex, 0); - glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]); - { - /* convert from command queue into draw list and draw to screen */ - const struct nk_draw_command *cmd; - void *vertices, *elements; - const nk_draw_index *offset = NULL; - - /* allocate vertex and element buffer */ - glBindVertexArray(dev->vao); - glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); - - glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW); - - /* load draw vertices & elements directly into vertex + element buffer */ - vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); - elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY); - { - /* fill convert configuration */ - struct nk_convert_config config; - static const struct nk_draw_vertex_layout_element vertex_layout[] = { - {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)}, - {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)}, - {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)}, - {NK_VERTEX_LAYOUT_END} - }; - NK_MEMSET(&config, 0, sizeof(config)); - config.vertex_layout = vertex_layout; - config.vertex_size = sizeof(struct nk_glfw_vertex); - config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex); - config.null = dev->null; - config.circle_segment_count = 22; - config.curve_segment_count = 22; - config.arc_segment_count = 22; - config.global_alpha = 1.0f; - config.shape_AA = AA; - config.line_AA = AA; - - /* setup buffers to load vertices and elements */ - {struct nk_buffer vbuf, ebuf; - nk_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY); - nk_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY); - nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);} - } - glUnmapBuffer(GL_ARRAY_BUFFER); - glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); - - /* iterate over and execute each draw command */ - nk_draw_foreach(cmd, ctx, &dev->cmds) { - if (!cmd->elem_count) continue; - glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); - glScissor( - (GLint)(cmd->clip_rect.x * scale.x), - (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y), - (GLint)(cmd->clip_rect.w * scale.x), - (GLint)(cmd->clip_rect.h * scale.y)); - glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); - offset += cmd->elem_count; - } - nk_clear(ctx); - } - - /* default OpenGL state */ - glUseProgram(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindVertexArray(0); - glDisable(GL_BLEND); - glDisable(GL_SCISSOR_TEST); -} - - -/* glfw callbacks (I don't know if there is a easier way to access text and scroll )*/ -static void error_callback(int e, const char *d){printf("Error %d: %s\n", e, d);} -static void text_input(GLFWwindow *win, unsigned int codepoint) -{nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);} -static void scroll_input(GLFWwindow *win, double _, double yoff) -{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), nk_vec2(0, (float)yoff));} - -int main(int argc, char *argv[]) -{ - /* Platform */ - static GLFWwindow *win; - int width = 0, height = 0; - int display_width = 0, display_height = 0; - - /* GUI */ - struct device device; - struct nk_context ctx; - struct nk_font *font; - struct nk_font_atlas atlas; - struct file_browser browser; - struct media media; - - /* GLFW */ - glfwSetErrorCallback(error_callback); - if (!glfwInit()) { - fprintf(stdout, "[GFLW] failed to init!\n"); - exit(1); - } - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); -#ifdef __APPLE__ - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); -#endif - win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL); - glfwMakeContextCurrent(win); - glfwSetWindowUserPointer(win, &ctx); - glfwSetCharCallback(win, text_input); - glfwSetScrollCallback(win, scroll_input); - - /* OpenGL */ - glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); - glewExperimental = 1; - if (glewInit() != GLEW_OK) { - fprintf(stderr, "Failed to setup GLEW\n"); - exit(1); - } - - {/* GUI */ - device_init(&device); - {const void *image; int w, h; - const char *font_path = (argc > 1) ? argv[1]: 0; - nk_font_atlas_init_default(&atlas); - nk_font_atlas_begin(&atlas); - if (font_path) font = nk_font_atlas_add_from_file(&atlas, font_path, 13.0f, NULL); - else font = nk_font_atlas_add_default(&atlas, 13.0f, NULL); - image = nk_font_atlas_bake(&atlas, &w, &h, NK_FONT_ATLAS_RGBA32); - device_upload_atlas(&device, image, w, h); - nk_font_atlas_end(&atlas, nk_handle_id((int)device.font_tex), &device.null);} - nk_init_default(&ctx, &font->handle);} - - /* icons */ - glEnable(GL_TEXTURE_2D); - media.icons.home = icon_load("../icon/home.png"); - media.icons.directory = icon_load("../icon/directory.png"); - media.icons.computer = icon_load("../icon/computer.png"); - media.icons.desktop = icon_load("../icon/desktop.png"); - media.icons.default_file = icon_load("../icon/default.png"); - media.icons.text_file = icon_load("../icon/text.png"); - media.icons.music_file = icon_load("../icon/music.png"); - media.icons.font_file = icon_load("../icon/font.png"); - media.icons.img_file = icon_load("../icon/img.png"); - media.icons.movie_file = icon_load("../icon/movie.png"); - media_init(&media); - - file_browser_init(&browser, &media); - while (!glfwWindowShouldClose(win)) - { - /* High DPI displays */ - struct nk_vec2 scale; - glfwGetWindowSize(win, &width, &height); - glfwGetFramebufferSize(win, &display_width, &display_height); - scale.x = (float)display_width/(float)width; - scale.y = (float)display_height/(float)height; - - /* Input */ - {double x, y; - nk_input_begin(&ctx); - glfwPollEvents(); - nk_input_key(&ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS); - if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || - glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) { - nk_input_key(&ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_SHIFT, 1); - } else { - nk_input_key(&ctx, NK_KEY_COPY, 0); - nk_input_key(&ctx, NK_KEY_PASTE, 0); - nk_input_key(&ctx, NK_KEY_CUT, 0); - nk_input_key(&ctx, NK_KEY_SHIFT, 0); - } - glfwGetCursorPos(win, &x, &y); - nk_input_motion(&ctx, (int)x, (int)y); - nk_input_button(&ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); - nk_input_button(&ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS); - nk_input_button(&ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS); - nk_input_end(&ctx);} - - /* GUI */ - file_browser_run(&browser, &ctx); - - /* Draw */ - glViewport(0, 0, display_width, display_height); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(0.2f, 0.2f, 0.2f, 1.0f); - device_draw(&device, &ctx, width, height, scale, NK_ANTI_ALIASING_ON); - glfwSwapBuffers(win); - } - - glDeleteTextures(1,(const GLuint*)&media.icons.home.handle.id); - glDeleteTextures(1,(const GLuint*)&media.icons.directory.handle.id); - glDeleteTextures(1,(const GLuint*)&media.icons.computer.handle.id); - glDeleteTextures(1,(const GLuint*)&media.icons.desktop.handle.id); - glDeleteTextures(1,(const GLuint*)&media.icons.default_file.handle.id); - glDeleteTextures(1,(const GLuint*)&media.icons.text_file.handle.id); - glDeleteTextures(1,(const GLuint*)&media.icons.music_file.handle.id); - glDeleteTextures(1,(const GLuint*)&media.icons.font_file.handle.id); - glDeleteTextures(1,(const GLuint*)&media.icons.img_file.handle.id); - glDeleteTextures(1,(const GLuint*)&media.icons.movie_file.handle.id); - - file_browser_free(&browser); - nk_font_atlas_clear(&atlas); - nk_free(&ctx); - device_shutdown(&device); - glfwTerminate(); - return 0; -} - - diff --git a/subprojects/nk_pugl/nuklear/example/icon/checked.png b/subprojects/nk_pugl/nuklear/example/icon/checked.png deleted file mode 100644 index e4e05b29fb20e2e32363896950ca4cfea31f8542..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1813 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 diff --git a/subprojects/nk_pugl/nuklear/example/icon/default.png b/subprojects/nk_pugl/nuklear/example/icon/default.png deleted file mode 100644 index c11145a007eacd369dc85b41b4c9aa006d098fd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 460 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 diff --git a/subprojects/nk_pugl/nuklear/example/icon/export.png b/subprojects/nk_pugl/nuklear/example/icon/export.png deleted file mode 100644 index ff6b5aa4acf440c4de50f709cd7bfc477344af9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13336 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 a2tchy{5>J5&Rg;Y9sGf#_7#8mUj9G(d|q+@ diff --git a/subprojects/nk_pugl/nuklear/example/icon/font.png b/subprojects/nk_pugl/nuklear/example/icon/font.png deleted file mode 100644 index 918e9bfe1ea44c569be31bf73f6af53b301c3edf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 561 zcmV-10?z%3P)FwDX-&%Eb7XN0nx!k!fNT3xAtIlwhQ0}6Yl6y9k2d>T0z@MA8M6_9RJIE|*dT*MP5-ipS%zF~*oM49#Y!P(Txl$RR?)7?& z`Fx)KY`5DvfQ8s^*LBm2!+k`*gcq8jVKDSr+^^U;_LS5&Hc;gTVl; zHE%zEsrd1bqp&92H>vCCu~W}8q1zCQbM_|vmDXG^oX zeex85TQ{$B|K6R0-*O7HnOS{3dj`P#^t{%gDmoOAN{3c;?kY1>O659wS(P$WN}-g( zbzL0Cxim1>|4yf4tgE`w$ZEISu~;mG|3<$7k0ygyH7*Qe00000NkvXXu0mjfN^t?l diff --git a/subprojects/nk_pugl/nuklear/example/icon/home.png b/subprojects/nk_pugl/nuklear/example/icon/home.png deleted file mode 100644 index 85606267225863537d186d63ebb2ed7014c9e4ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 819 zcmV-31I+x1P)DW` zK~y-))s)Rk8+jPVKflb3^Frfhou&!xCQPQuB1mvSij7Ed!HanI5;P|d{ssOMUiRe4 z9`>?(2v)qgu$hZ^$jNQNlp^#cjOY>rotVTO>*TkGWkW%?EqmI1ZVx=qhv)SR|8)~z z5EC08ACE3CFHu#MSSy6(p zW?2@BqTE{H5a@XxJKNht-7epcKV)kD2^T@YZ;dxJn@tuM7ZF0BCk zcso1HJR&h5HZE^m{$NYW3;$dg!{2 zuIs3(O1s@=VqyYSRdHSSx#Ku^o+oYqGuZ-<9)AbG-Me?_cKiHs;j>?_p=lb2hliY; zoM78FD=RAi1VO<1`ufeYky3ImnLwqDN}F!r6NTrD*>})&o&EiN`u#rTa+xp;sn_dl zZf@fH{_U@qN~I*g=;$bhVQ_waPCA`N2*KRk9Hml;g@px7)1+7|GB!3wCX*rl)6e{9 z=!9V?Zu{lY+1c6P^z;@B7qhH423S&1MtN^T_3L)a&)Hf%jjkHo06b_u95?DwPV2MuWY* xJv2?@`1m*j`2SYsikVDCX0urdOz^+9KLMDz1_tX?-dO+u002ovPDHLkV1nUi5sZRGrF2`gX~#oqZIdO5p8Ue_nBnoA@63DeE9i&piJhJ} z5YlHafn$IL=)e}RIV!2}AvWT-PNUjbfT+pQ2*1=&Miy5#UoMlac9UlBX*x0Gyec;(9)h9S#u= zS^KKM(haWNxl5^3qTOx_zXDj3lan%+%TcLR4sJXPuy0T@zZ2Lgo6U{@KSb~RAL6(WSdwr%WCi1_$8N-3nSV;GXX z9T2->{|{krceuiXrhTxy%p>_9|hmOcMGwxu{|2$Z&!Kv=r;d~!}f*aILgma i2BFjG9I>zeAHM*|L6h|(d1^HP0000mI)V diff --git a/subprojects/nk_pugl/nuklear/example/icon/movie.png b/subprojects/nk_pugl/nuklear/example/icon/movie.png deleted file mode 100644 index 5227883e6c4d28773043acce6ededc1fe34ded22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 626 zcmV-&0*(ENP)T{#D-;S&%1S2+M3;h&CNB|?Xn2J@MjBouU8Fn!Jt9)lf)J5N z?utl}k|tUMo6Xu+Tv+j+hrS}K(a z#u$plBA(}=l%m`1(r7feyu9S}^mGGIe)<@gODU<wdVf*o?frV$;k=h@i^_p z^*%gwQ&PauXoT-rtCIF5HdU;n550eUjt_y-pF9RL6T M07*qoM6N<$f_*?A&j0`b diff --git a/subprojects/nk_pugl/nuklear/example/icon/music.png b/subprojects/nk_pugl/nuklear/example/icon/music.png deleted file mode 100644 index 0f1415c8756311c4852151f1a0f4055e08b26b97..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 610 zcmV-o0-gPdP)I`orN2EPQ-(&Md=rc&3|7-y16j#sR2} zVjD0z1Y|idTPZd6Jg*!C0T^RR0odwM6q(6nV&%aL04{URr@dZ}h=_dOr^RAHT5DRZ zR;0D2<#L%S&+{k?iR~nSlWw=`4u?YkK)>Hdr_+J!x+s-OP)b2c2`MFn5Rg*lTE)OZ zqtUoJ8jX^V<#IU%5JF)1=4pCnjO79W0Q31AzVBl&7{GO1)a!NFww*G2^!Q;4aEVoO zfd)Xx7(=VoLc86DloG{a5su@)w(SH60B0Y9#JX0i?KJ!y>&I7BN~H{i5CD*zv)9cU z{yi82$8nOOXBPorCoF4d7-Jx!1dv@w4BQ3VT1srFlu8UgoqWXc``0-AJjT~=X9s`1 zLf#XIZC<>6h99#jlvJ4h{EpKvV|Z7tT^txEwtIQ}9KV8daK$b^vLfjn~6dME_I22d}m^c_!)PC=b zm*Z={ym!9; zr=IE@nC9GR!1pKJ$18j7?|_%w^?mMtpRhC4|LwVztRZ;J_id(y;Jy1(wr|eL*Kpy; zW%zy2;(3AP=6$~(b_(2La8Y0oMLNQwB4Lv5pnWa8YRZ+rV(E0d5Yaz8zvv1Aq(%CZ-7u3@;TK7+V;ekbU36 z@F`#N>C`F~jyC^>f*-r@PQHHp^!Fxp2aAeuh96Q2k~WNo4hk#C?2%=t;hn%UkKy5i zSjGq04JjX3IM{(YK9n(hFm*7hU}|aZ7gvz2`NGFgm%+>+uf_0TArpiA9_9x5TMP%< zxfp6bh+>s7J7D7b^!CI44>i^8ix>}VXJ+tcc%U5Icl{GO7%dUxFNcuMknA8|N MUHx3vIVCg!0CE}m3jhEB diff --git a/subprojects/nk_pugl/nuklear/example/icon/pause.png b/subprojects/nk_pugl/nuklear/example/icon/pause.png deleted file mode 100644 index 7d6367e1ab0943e76984dfa115111f2cdea3983e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1338 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSY)RhkE)0?&_*lPgGf;%Hz$3Dl zfq`2Xgc%uT&5-~KvX^-Jy0YKrVdoK2UtIszj)8&YxTlL_NX4zUGj97!yNk4+cX0HG zaq6hhU`k$)*{CLX0IIqv^lKqB>Ra5tvO>|=I-FbAvB9BG}w}1l@ahKGS zxi$%8{JPNeX+qe_z1F*L-2a}DnO0x??DLzMp$8KJ6zVk>uy8QIVC6CPIPN7|#gYv*Lmml@>iudtPES_nXVJPLC%##hH;W&u%x?Ui!+<_`F-X?Zlt4 z8s_#aZ3;(HGF-^vf27dMj{*@ zfq@h6-MxEtnbH2Zm@A!cU9Qa(?rb@i%~<#Eqx#*tx3hGMuU@-$>QDaXK5>(j$X{8} zv$t&7mSQ{o{PW2(UrNrM&J=NQfn42}3)d{I?Osoq{#jpE`^Dsf2!2+kZRaX~pUbT@ z{O;D*^npPYRiCpNVNmaT zR{!|*!^EG(_4cnTAAQ`h@eKd|N|lv+_udg*uyW0gn1BAcmtpqnS0T%iU%!4GdopIaYub6P51z%Fix$sFO-+^T z|NG)os%UhlzN(>A}ptTfraWyiPo=6Ves9oKGsV|AbJzI6Nc zaLbvNDaF(61UpYm|NegWuAl2T7EBQm4BX$>f7|H(r%RLWyxOyL&N&+qjvL>&qGKWo zzLijMzz}Nck-5h4d(4e3sn-BK9vwzu}vz*?fGSlbSol}42OAGL@9Zh~Q^=Yc-(r@SM zc9g92vRktLYxv0$`fECVp asvjJlZhq71=yzZ#$KdJe=d#Wzp$P!D%r+4K diff --git a/subprojects/nk_pugl/nuklear/example/icon/pen.png b/subprojects/nk_pugl/nuklear/example/icon/pen.png deleted file mode 100644 index 10c851c120a04bccb59284c56fb5f9ee63a64c8c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5949 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 f@cMrjjL|;VS-kN)MtPUEC7M2r+ diff --git a/subprojects/nk_pugl/nuklear/example/icon/phone.png b/subprojects/nk_pugl/nuklear/example/icon/phone.png deleted file mode 100644 index 5e6f6133d76019c8814a310ae138a12e0e516b65..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15778 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 RNWOApZ{uuTbu{45{{^G)Zw>$e diff --git a/subprojects/nk_pugl/nuklear/example/icon/play.png b/subprojects/nk_pugl/nuklear/example/icon/play.png deleted file mode 100644 index 9c9e8f0a4e853acd8a5e6f370bbc8ecfd994af8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 566 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSY)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP~w+J^s3-|UzTYy5cnIRD+&iT2ysd*(pE(3#eQEFmI zYKlU6W=V#EyQgnJie4%^0|VnMPZ!6Kid%2*UhHi)5Md1zUh1f|^vDHA7nLUp=VuDd zxcOV>Y4UNf5fI{mT;Jm#Ke)~({NDbh_P)8482^J)@p}ZscpqHfDSjv>?jF0?gN;sW z9c>sCS^OI|CoryQWN1-fP^@6CkdI)<2C^&|&o!}bU}F+!5`LhAM@VTK!!-v6rvj!q ztlSB_ED9`)90#Qj{64@G!3<<^7KrIIm^WVyG;}BS)*5C*(7pdc-Oq z{+@*Z>wYZ5qs5E@@^*|*+{GJyWH20Q_hF(L)?yQeHq3~sF2w-Nzp}-=*#KG9Y;KXq9 zMC$q3dE0OA{kHq{S1ZeFkAssp9ZmjqcJYJs1M^#XY8UK3v}jAy|LfmRRiEGX?N=7_ z9_e{zFPQ7P4?8nP-QB73f_>kyL{*2^x6}?wB$qr4=$m)*ThqpKuO7`XKDgeFRi-jf zH^6@S;`7HQ9|-tx`m5J^>mcr)LcX$wfDbGj?EVbO=Y=xvztlN!Q~aRZ?Y)8z`plUQ zTxU2S%uvC^kk8H#&&=S@@PLzHk1RtCFM|zZ16caygT<^2b|DN8n#&nJI7>792w-gB z7iIYIK$hXp1vapZGf+VVJA?fesEi;(T?R9QycWZUgUSql5*QEgivdkUgo7e1SWfI@ z{a{)o)xhG$!1;zDUP$1ekO#|rrXE(N3}z;QMg|v!hQAFAw;Dijs$y!1~ZAkhRyaVKlzn18VUqC z1nyO^aO5*HwR8tmg--r|Qrek?S74XC&UJ0ue+=dSEpity9&*)izd!Tczm4azW<9U` zdN?fpDciq)dnTVO=i_J1P-Og(-0@+ub7(`D_>?*&o20-fCYJg+e;0iFb(XE-s@;X- tSuMJ9yICfDK2pp8jeDq{Crqee(n$!Ju=$t7Bw#{g@O1TaS?83{1ON?E{p0`u diff --git a/subprojects/nk_pugl/nuklear/example/icon/rocket.png b/subprojects/nk_pugl/nuklear/example/icon/rocket.png deleted file mode 100644 index ea8e187c9f0e50de6dcd87fe823cd2761a510c83..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1121 zcmV-n1fKheP)WFU8GbZ8()Nlj2>E@cM*00YHIL_t(|+U=dolG-p3 zMJ2-zYT*qZ=#3Zp!NAO7pfW`PW6OH>J-tdQmBiz7`XN~u?+B%sVvN_vZ$bzs&pojb zF~+ZyzlQ(=#yrob%jNPf$G?RDhO-+10RAyT2>#6N)`I>V2p|X@0RWEx>fjMT82ay+ zK%@(w3Lp#~0mQ-60)X$FV<%7+dsQ|*6j{rOF zkyZE%fudPY1pqz*e2RIVPgZ}n-vb~5yop>VZm9s2egpu1-@!(Z5d7!G~$%H(#1HWuPR0 zubo{RETy!Co*86=_t^f>X4Al3wY?U;a%0KhjGTieqF{PgJcR;u0Pyp|A4&k= z=Z8Pi5Xfg3f8b|-&@~N`{WtJC=bXFAWfrBsOz9t@0s#MKN3rDLQx7D)tj{I@@W+OK zNC4oE4?lSZu>2Y|CHTn|fb6#cKS==K+kwAZ0N~q#ze@n%+k>Ax1QIsjZ>|7jzfJg? z1OR?^@Q2RuRTTjEHnV<{0Km5opCM2j{@V&b_G`d@DFEp2WP56fdc#e6VPfB06W&wUy0bcDf#2Bx@*IfnN0N;PG6DSP7 zXbZ49BwB(`1rUc{tO8ifev9x+4}pNE1pr^J1z0Kn3h=1_;_wlGKmY_t?DISg6cykv z@JjttPJn0lQ~@CY_Q0kJ7!%+f{7;~fz=!}T@R7iX06BVmiPxJFjhBHtGn*skBMQ*N zH(C*m1o-qCxKx-(FpvPHj&~!$00NZW+zBCg2E##zz>FDuqZ;%nK-H&%N9GACNdW;` ze3EC61P|~mG4n+ihe97vU(Fx1ib?|f^#<@7Ab{Pl1&sR1UZknG3Lp@GuqZ&wlRdqi zFTB6Xl~q73_|Ly?+0zy0iOE9N=K!ZVOrBe1d`}RRR}$ye&|5-a30XjZl+q6T0R$*D zsRO@l_?Ans+#oj07+rl^hx9VAb{3NLod`h57u^R~mgNk5(HWp7gdTPj5#XNj>$+aK n#bPr6nI|Ryzy$;VvfcOwuWa|S&Zx)400000NkvXXu0mjffwSmT diff --git a/subprojects/nk_pugl/nuklear/example/icon/settings.png b/subprojects/nk_pugl/nuklear/example/icon/settings.png deleted file mode 100644 index e6e13f8564624244f56dbd51b10f4655a9014c27..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15671 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 diff --git a/subprojects/nk_pugl/nuklear/example/icon/stop.png b/subprojects/nk_pugl/nuklear/example/icon/stop.png deleted file mode 100644 index 6742baf9aa961f5381beda98bf3fe79aa5ae9a70..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 520 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSY)RhkE)0?&_*lPgGf;%Hz$3Dl zfq`2Xgc%uT&5-~KvX^-Jy0YKrVdoLy+VD&4ECU1MR8JSjkcwMxZ(J;7R^)MTOt{3N z8zk`7N|EH<*pXt)$d&^v*j2Wm>d{57#I~8SQ;1t`u@%P$5ec7y5Sz_ zms??@y3sINZ;eXvxsr-R-59_lkDaQ_hGaJ+DN z{}-+Xg?k^S|7UAZxc0$YbLqEx+iP}OK0n>@PWI2Y|4cc}66Z^Avu)r_l3Ah5;IN~- uTaK0CNbU7!iy6Mu#IZ7iLlo*M)tB-K*K*4nlP`NS0D-5gpUXO@geCwHd!8!* diff --git a/subprojects/nk_pugl/nuklear/example/icon/text.png b/subprojects/nk_pugl/nuklear/example/icon/text.png deleted file mode 100644 index 136e534a50c2fd4319d63324d09d83933e7f28f8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 601 zcmV-f0;c_mP)|W zK~y-))s(%;;y@IJ-x-}5R{Vij7(}d0Bgk4g^9{M~N1e=Zga0synw49#W}hG8I|&qD|S&N(>eV2put{~5KOeT|;&qjq`D;A4z z90x)OWHK2DA>N`(5&{5%AV4mc!(cGLdcD3Q3(u8G1>^DfC7~vSKx+-oIr{zn-9*Fu zi0s*>AP52oA>cR;R;yKv?CS%6hcLR#7{hQlyrZL({_`$JhP_@7p6A8Lo>4tjsZ>(? z{a$Z28+|w&w3JdSrSvP6%Vm|^-}pjP8kP90Oxw0$+xGW_rfI71XW;w3en&~dSPy;Q nm$h2$$JYUUr`zo&@n7i!nhp9}Dig&U00000NkvXXu0mjfhOhtA diff --git a/subprojects/nk_pugl/nuklear/example/icon/tools.png b/subprojects/nk_pugl/nuklear/example/icon/tools.png deleted file mode 100644 index 412ff85367fb30e6a6cfa298cb08f6d1578ea379..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24483 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 oPhZ3!@B4q_UQp{I*uNX4zUcP@q=HV|-i z^pxEtv1))1r#?*X9c4#8C67-R#c|7AJECcK;xjRXL1@KPWRjly10h;LKvf zWRc>c@WwDfqHY6YgRX)hL-|_GcmEQY8(!!peErU__);R18N&xX2T-J3<7{|d4^;M@ zfr){GL4l!xfg}cr%84@Hn~!}9wWEi#1G z{`>R)qC11&fxGn&8EO`V@yQ;R-^FNAGpTL=pBJ9!T@ zCVpT&a4_)$^SX!oUUliQh14t&Vc-b;xa_KSh$zp0+cr~~qPbE9vl-r0F8=cTfPmGX z<>n003~zpR*i5q1`EZ{1fEvT^y8{2eD!KsOu#2&Sq0Rn>paYA+A0`DRi5f-$CZ7Ea zK*4y17KUbh2Bn6F{`?IB2_IM;I1GL;DX@W*F!StX=wND#V-Rp_=3_ty7wQ;JwZv>Z SBD6mPB<1Pq=d#Wzp$PzHUm*(s diff --git a/subprojects/nk_pugl/nuklear/example/icon/volume.png b/subprojects/nk_pugl/nuklear/example/icon/volume.png deleted file mode 100644 index 8e86fa992953cdb490433a92d087b4a8907a343a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25438 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 diff --git a/subprojects/nk_pugl/nuklear/example/icon/wifi.png b/subprojects/nk_pugl/nuklear/example/icon/wifi.png deleted file mode 100644 index 270d55d767315891992c70b8d12d8b1f21f49667..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18857 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

*c)4>O8CxLPg6)1 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
a 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 bl?+z44X@Wq_TA!Ntb!m1AAj6U2i^MEhH2N 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 ZHCn=r=SOS`WUL7IrK+TLCCC diff --git a/subprojects/nk_pugl/nuklear/example/images/image5.png b/subprojects/nk_pugl/nuklear/example/images/image5.png deleted file mode 100644 index 852fd70ff011df703ab768aa21dbfe31aeab617c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 98475 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Ώ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�r7tee#*+q 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 Jp)@bv{y#y7xVHcR diff --git a/subprojects/nk_pugl/nuklear/example/images/image9.png b/subprojects/nk_pugl/nuklear/example/images/image9.png deleted file mode 100644 index 516929ea6d6c9f734452ca3c675f5f6798d744c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30759 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 diff --git a/subprojects/nk_pugl/nuklear/example/skinning.c b/subprojects/nk_pugl/nuklear/example/skinning.c deleted file mode 100644 index 4020aec..0000000 --- a/subprojects/nk_pugl/nuklear/example/skinning.c +++ /dev/null @@ -1,824 +0,0 @@ -/* nuklear - v1.05 - public domain */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define NK_INCLUDE_FIXED_TYPES -#define NK_INCLUDE_STANDARD_IO -#define NK_INCLUDE_DEFAULT_ALLOCATOR -#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT -#define NK_INCLUDE_FONT_BAKING -#define NK_INCLUDE_DEFAULT_FONT -#define NK_IMPLEMENTATION -#include "../nuklear.h" - -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" - -/* macros */ -#define WINDOW_WIDTH 1200 -#define WINDOW_HEIGHT 800 - -#define MAX_VERTEX_MEMORY 512 * 1024 -#define MAX_ELEMENT_MEMORY 128 * 1024 - -#define UNUSED(a) (void)a -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#define MAX(a,b) ((a) < (b) ? (b) : (a)) -#define LEN(a) (sizeof(a)/sizeof(a)[0]) - -#ifdef __APPLE__ - #define NK_SHADER_VERSION "#version 150\n" -#else - #define NK_SHADER_VERSION "#version 300 es\n" -#endif - -struct media { - GLint skin; - struct nk_image menu; - struct nk_image check; - struct nk_image check_cursor; - struct nk_image option; - struct nk_image option_cursor; - struct nk_image header; - struct nk_image window; - struct nk_image scrollbar_inc_button; - struct nk_image scrollbar_inc_button_hover; - struct nk_image scrollbar_dec_button; - struct nk_image scrollbar_dec_button_hover; - struct nk_image button; - struct nk_image button_hover; - struct nk_image button_active; - struct nk_image tab_minimize; - struct nk_image tab_maximize; - struct nk_image slider; - struct nk_image slider_hover; - struct nk_image slider_active; -}; - - -/* =============================================================== - * - * DEVICE - * - * ===============================================================*/ -struct nk_glfw_vertex { - float position[2]; - float uv[2]; - nk_byte col[4]; -}; - -struct device { - struct nk_buffer cmds; - struct nk_draw_null_texture null; - GLuint vbo, vao, ebo; - GLuint prog; - GLuint vert_shdr; - GLuint frag_shdr; - GLint attrib_pos; - GLint attrib_uv; - GLint attrib_col; - GLint uniform_tex; - GLint uniform_proj; - GLuint font_tex; -}; - -static void -die(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fputs("\n", stderr); - exit(EXIT_FAILURE); -} - -static GLuint -image_load(const char *filename) -{ - int x,y,n; - GLuint tex; - unsigned char *data = stbi_load(filename, &x, &y, &n, 0); - if (!data) die("failed to load image: %s", filename); - - glGenTextures(1, &tex); - glBindTexture(GL_TEXTURE_2D, tex); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - glGenerateMipmap(GL_TEXTURE_2D); - stbi_image_free(data); - return tex; -} - -static void -device_init(struct device *dev) -{ - GLint status; - static const GLchar *vertex_shader = - NK_SHADER_VERSION - "uniform mat4 ProjMtx;\n" - "in vec2 Position;\n" - "in vec2 TexCoord;\n" - "in vec4 Color;\n" - "out vec2 Frag_UV;\n" - "out vec4 Frag_Color;\n" - "void main() {\n" - " Frag_UV = TexCoord;\n" - " Frag_Color = Color;\n" - " gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n" - "}\n"; - static const GLchar *fragment_shader = - NK_SHADER_VERSION - "precision mediump float;\n" - "uniform sampler2D Texture;\n" - "in vec2 Frag_UV;\n" - "in vec4 Frag_Color;\n" - "out vec4 Out_Color;\n" - "void main(){\n" - " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" - "}\n"; - - nk_buffer_init_default(&dev->cmds); - dev->prog = glCreateProgram(); - dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER); - dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0); - glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0); - glCompileShader(dev->vert_shdr); - glCompileShader(dev->frag_shdr); - glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status); - assert(status == GL_TRUE); - glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status); - assert(status == GL_TRUE); - glAttachShader(dev->prog, dev->vert_shdr); - glAttachShader(dev->prog, dev->frag_shdr); - glLinkProgram(dev->prog); - glGetProgramiv(dev->prog, GL_LINK_STATUS, &status); - assert(status == GL_TRUE); - - dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture"); - dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx"); - dev->attrib_pos = glGetAttribLocation(dev->prog, "Position"); - dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord"); - dev->attrib_col = glGetAttribLocation(dev->prog, "Color"); - - { - /* buffer setup */ - GLsizei vs = sizeof(struct nk_glfw_vertex); - size_t vp = offsetof(struct nk_glfw_vertex, position); - size_t vt = offsetof(struct nk_glfw_vertex, uv); - size_t vc = offsetof(struct nk_glfw_vertex, col); - - glGenBuffers(1, &dev->vbo); - glGenBuffers(1, &dev->ebo); - glGenVertexArrays(1, &dev->vao); - - glBindVertexArray(dev->vao); - glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); - - glEnableVertexAttribArray((GLuint)dev->attrib_pos); - glEnableVertexAttribArray((GLuint)dev->attrib_uv); - glEnableVertexAttribArray((GLuint)dev->attrib_col); - - glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp); - glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt); - glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc); - } - - glBindTexture(GL_TEXTURE_2D, 0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindVertexArray(0); -} - -static void -device_upload_atlas(struct device *dev, const void *image, int width, int height) -{ - glGenTextures(1, &dev->font_tex); - glBindTexture(GL_TEXTURE_2D, dev->font_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, image); -} - -static void -device_shutdown(struct device *dev) -{ - glDetachShader(dev->prog, dev->vert_shdr); - glDetachShader(dev->prog, dev->frag_shdr); - glDeleteShader(dev->vert_shdr); - glDeleteShader(dev->frag_shdr); - glDeleteProgram(dev->prog); - glDeleteTextures(1, &dev->font_tex); - glDeleteBuffers(1, &dev->vbo); - glDeleteBuffers(1, &dev->ebo); - nk_buffer_free(&dev->cmds); -} - -static void -device_draw(struct device *dev, struct nk_context *ctx, int width, int height, - struct nk_vec2 scale, enum nk_anti_aliasing AA) -{ - GLfloat ortho[4][4] = { - {2.0f, 0.0f, 0.0f, 0.0f}, - {0.0f,-2.0f, 0.0f, 0.0f}, - {0.0f, 0.0f,-1.0f, 0.0f}, - {-1.0f,1.0f, 0.0f, 1.0f}, - }; - ortho[0][0] /= (GLfloat)width; - ortho[1][1] /= (GLfloat)height; - - /* setup global state */ - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glEnable(GL_SCISSOR_TEST); - glActiveTexture(GL_TEXTURE0); - - /* setup program */ - glUseProgram(dev->prog); - glUniform1i(dev->uniform_tex, 0); - glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]); - { - /* convert from command queue into draw list and draw to screen */ - const struct nk_draw_command *cmd; - void *vertices, *elements; - const nk_draw_index *offset = NULL; - - /* allocate vertex and element buffer */ - glBindVertexArray(dev->vao); - glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); - - glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW); - - /* load draw vertices & elements directly into vertex + element buffer */ - vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); - elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY); - { - /* fill convert configuration */ - struct nk_convert_config config; - static const struct nk_draw_vertex_layout_element vertex_layout[] = { - {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)}, - {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)}, - {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)}, - {NK_VERTEX_LAYOUT_END} - }; - NK_MEMSET(&config, 0, sizeof(config)); - config.vertex_layout = vertex_layout; - config.vertex_size = sizeof(struct nk_glfw_vertex); - config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex); - config.null = dev->null; - config.circle_segment_count = 22; - config.curve_segment_count = 22; - config.arc_segment_count = 22; - config.global_alpha = 1.0f; - config.shape_AA = AA; - config.line_AA = AA; - - /* setup buffers to load vertices and elements */ - {struct nk_buffer vbuf, ebuf; - nk_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY); - nk_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY); - nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);} - } - glUnmapBuffer(GL_ARRAY_BUFFER); - glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); - - /* iterate over and execute each draw command */ - nk_draw_foreach(cmd, ctx, &dev->cmds) - { - if (!cmd->elem_count) continue; - glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); - glScissor( - (GLint)(cmd->clip_rect.x * scale.x), - (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y), - (GLint)(cmd->clip_rect.w * scale.x), - (GLint)(cmd->clip_rect.h * scale.y)); - glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); - offset += cmd->elem_count; - } - nk_clear(ctx); - } - - /* default OpenGL state */ - glUseProgram(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindVertexArray(0); - glDisable(GL_BLEND); - glDisable(GL_SCISSOR_TEST); -} - -/* glfw callbacks (I don't know if there is a easier way to access text and scroll )*/ -static void error_callback(int e, const char *d){printf("Error %d: %s\n", e, d);} -static void text_input(GLFWwindow *win, unsigned int codepoint) -{nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);} -static void scroll_input(GLFWwindow *win, double _, double yoff) -{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), nk_vec2(0, (float)yoff));} - -int main(int argc, char *argv[]) -{ - /* Platform */ - static GLFWwindow *win; - int width = 0, height = 0; - int display_width=0, display_height=0; - - /* GUI */ - struct device device; - struct nk_font_atlas atlas; - struct media media; - struct nk_context ctx; - struct nk_font *font; - - /* GLFW */ - glfwSetErrorCallback(error_callback); - if (!glfwInit()) { - fprintf(stdout, "[GFLW] failed to init!\n"); - exit(1); - } - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); -#ifdef __APPLE__ - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); -#endif - win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL); - glfwMakeContextCurrent(win); - glfwSetWindowUserPointer(win, &ctx); - glfwSetCharCallback(win, text_input); - glfwSetScrollCallback(win, scroll_input); - glfwGetWindowSize(win, &width, &height); - glfwGetFramebufferSize(win, &display_width, &display_height); - - /* OpenGL */ - glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); - glewExperimental = 1; - if (glewInit() != GLEW_OK) { - fprintf(stderr, "Failed to setup GLEW\n"); - exit(1); - } - - /* GUI */ - {device_init(&device); - {const void *image; int w, h; - const char *font_path = (argc > 1) ? argv[1]: 0; - nk_font_atlas_init_default(&atlas); - nk_font_atlas_begin(&atlas); - if (font_path) font = nk_font_atlas_add_from_file(&atlas, font_path, 13.0f, NULL); - else font = nk_font_atlas_add_default(&atlas, 13.0f, NULL); - image = nk_font_atlas_bake(&atlas, &w, &h, NK_FONT_ATLAS_RGBA32); - device_upload_atlas(&device, image, w, h); - nk_font_atlas_end(&atlas, nk_handle_id((int)device.font_tex), &device.null);} - nk_init_default(&ctx, &font->handle);} - - { /* skin */ - glEnable(GL_TEXTURE_2D); - media.skin = image_load("../skins/gwen.png"); - media.check = nk_subimage_id(media.skin, 512,512, nk_rect(464,32,15,15)); - media.check_cursor = nk_subimage_id(media.skin, 512,512, nk_rect(450,34,11,11)); - media.option = nk_subimage_id(media.skin, 512,512, nk_rect(464,64,15,15)); - media.option_cursor = nk_subimage_id(media.skin, 512,512, nk_rect(451,67,9,9)); - media.header = nk_subimage_id(media.skin, 512,512, nk_rect(128,0,127,24)); - media.window = nk_subimage_id(media.skin, 512,512, nk_rect(128,23,127,104)); - media.scrollbar_inc_button = nk_subimage_id(media.skin, 512,512, nk_rect(464,256,15,15)); - media.scrollbar_inc_button_hover = nk_subimage_id(media.skin, 512,512, nk_rect(464,320,15,15)); - media.scrollbar_dec_button = nk_subimage_id(media.skin, 512,512, nk_rect(464,224,15,15)); - media.scrollbar_dec_button_hover = nk_subimage_id(media.skin, 512,512, nk_rect(464,288,15,15)); - media.button = nk_subimage_id(media.skin, 512,512, nk_rect(384,336,127,31)); - media.button_hover = nk_subimage_id(media.skin, 512,512, nk_rect(384,368,127,31)); - media.button_active = nk_subimage_id(media.skin, 512,512, nk_rect(384,400,127,31)); - media.tab_minimize = nk_subimage_id(media.skin, 512,512, nk_rect(451, 99, 9, 9)); - media.tab_maximize = nk_subimage_id(media.skin, 512,512, nk_rect(467,99,9,9)); - media.slider = nk_subimage_id(media.skin, 512,512, nk_rect(418,33,11,14)); - media.slider_hover = nk_subimage_id(media.skin, 512,512, nk_rect(418,49,11,14)); - media.slider_active = nk_subimage_id(media.skin, 512,512, nk_rect(418,64,11,14)); - - /* window */ - ctx.style.window.background = nk_rgb(204,204,204); - ctx.style.window.fixed_background = nk_style_item_image(media.window); - ctx.style.window.border_color = nk_rgb(67,67,67); - ctx.style.window.combo_border_color = nk_rgb(67,67,67); - ctx.style.window.contextual_border_color = nk_rgb(67,67,67); - ctx.style.window.menu_border_color = nk_rgb(67,67,67); - ctx.style.window.group_border_color = nk_rgb(67,67,67); - ctx.style.window.tooltip_border_color = nk_rgb(67,67,67); - ctx.style.window.scrollbar_size = nk_vec2(16,16); - ctx.style.window.border_color = nk_rgba(0,0,0,0); - ctx.style.window.padding = nk_vec2(8,4); - ctx.style.window.border = 3; - - /* window header */ - ctx.style.window.header.normal = nk_style_item_image(media.header); - ctx.style.window.header.hover = nk_style_item_image(media.header); - ctx.style.window.header.active = nk_style_item_image(media.header); - ctx.style.window.header.label_normal = nk_rgb(95,95,95); - ctx.style.window.header.label_hover = nk_rgb(95,95,95); - ctx.style.window.header.label_active = nk_rgb(95,95,95); - - /* scrollbar */ - ctx.style.scrollv.normal = nk_style_item_color(nk_rgb(184,184,184)); - ctx.style.scrollv.hover = nk_style_item_color(nk_rgb(184,184,184)); - ctx.style.scrollv.active = nk_style_item_color(nk_rgb(184,184,184)); - ctx.style.scrollv.cursor_normal = nk_style_item_color(nk_rgb(220,220,220)); - ctx.style.scrollv.cursor_hover = nk_style_item_color(nk_rgb(235,235,235)); - ctx.style.scrollv.cursor_active = nk_style_item_color(nk_rgb(99,202,255)); - ctx.style.scrollv.dec_symbol = NK_SYMBOL_NONE; - ctx.style.scrollv.inc_symbol = NK_SYMBOL_NONE; - ctx.style.scrollv.show_buttons = nk_true; - ctx.style.scrollv.border_color = nk_rgb(81,81,81); - ctx.style.scrollv.cursor_border_color = nk_rgb(81,81,81); - ctx.style.scrollv.border = 1; - ctx.style.scrollv.rounding = 0; - ctx.style.scrollv.border_cursor = 1; - ctx.style.scrollv.rounding_cursor = 2; - - /* scrollbar buttons */ - ctx.style.scrollv.inc_button.normal = nk_style_item_image(media.scrollbar_inc_button); - ctx.style.scrollv.inc_button.hover = nk_style_item_image(media.scrollbar_inc_button_hover); - ctx.style.scrollv.inc_button.active = nk_style_item_image(media.scrollbar_inc_button_hover); - ctx.style.scrollv.inc_button.border_color = nk_rgba(0,0,0,0); - ctx.style.scrollv.inc_button.text_background = nk_rgba(0,0,0,0); - ctx.style.scrollv.inc_button.text_normal = nk_rgba(0,0,0,0); - ctx.style.scrollv.inc_button.text_hover = nk_rgba(0,0,0,0); - ctx.style.scrollv.inc_button.text_active = nk_rgba(0,0,0,0); - ctx.style.scrollv.inc_button.border = 0.0f; - - ctx.style.scrollv.dec_button.normal = nk_style_item_image(media.scrollbar_dec_button); - ctx.style.scrollv.dec_button.hover = nk_style_item_image(media.scrollbar_dec_button_hover); - ctx.style.scrollv.dec_button.active = nk_style_item_image(media.scrollbar_dec_button_hover); - ctx.style.scrollv.dec_button.border_color = nk_rgba(0,0,0,0); - ctx.style.scrollv.dec_button.text_background = nk_rgba(0,0,0,0); - ctx.style.scrollv.dec_button.text_normal = nk_rgba(0,0,0,0); - ctx.style.scrollv.dec_button.text_hover = nk_rgba(0,0,0,0); - ctx.style.scrollv.dec_button.text_active = nk_rgba(0,0,0,0); - ctx.style.scrollv.dec_button.border = 0.0f; - - /* checkbox toggle */ - {struct nk_style_toggle *toggle; - toggle = &ctx.style.checkbox; - toggle->normal = nk_style_item_image(media.check); - toggle->hover = nk_style_item_image(media.check); - toggle->active = nk_style_item_image(media.check); - toggle->cursor_normal = nk_style_item_image(media.check_cursor); - toggle->cursor_hover = nk_style_item_image(media.check_cursor); - toggle->text_normal = nk_rgb(95,95,95); - toggle->text_hover = nk_rgb(95,95,95); - toggle->text_active = nk_rgb(95,95,95);} - - /* option toggle */ - {struct nk_style_toggle *toggle; - toggle = &ctx.style.option; - toggle->normal = nk_style_item_image(media.option); - toggle->hover = nk_style_item_image(media.option); - toggle->active = nk_style_item_image(media.option); - toggle->cursor_normal = nk_style_item_image(media.option_cursor); - toggle->cursor_hover = nk_style_item_image(media.option_cursor); - toggle->text_normal = nk_rgb(95,95,95); - toggle->text_hover = nk_rgb(95,95,95); - toggle->text_active = nk_rgb(95,95,95);} - - /* default button */ - ctx.style.button.normal = nk_style_item_image(media.button); - ctx.style.button.hover = nk_style_item_image(media.button_hover); - ctx.style.button.active = nk_style_item_image(media.button_active); - ctx.style.button.border_color = nk_rgba(0,0,0,0); - ctx.style.button.text_background = nk_rgba(0,0,0,0); - ctx.style.button.text_normal = nk_rgb(95,95,95); - ctx.style.button.text_hover = nk_rgb(95,95,95); - ctx.style.button.text_active = nk_rgb(95,95,95); - - /* default text */ - ctx.style.text.color = nk_rgb(95,95,95); - - /* contextual button */ - ctx.style.contextual_button.normal = nk_style_item_color(nk_rgb(206,206,206)); - ctx.style.contextual_button.hover = nk_style_item_color(nk_rgb(229,229,229)); - ctx.style.contextual_button.active = nk_style_item_color(nk_rgb(99,202,255)); - ctx.style.contextual_button.border_color = nk_rgba(0,0,0,0); - ctx.style.contextual_button.text_background = nk_rgba(0,0,0,0); - ctx.style.contextual_button.text_normal = nk_rgb(95,95,95); - ctx.style.contextual_button.text_hover = nk_rgb(95,95,95); - ctx.style.contextual_button.text_active = nk_rgb(95,95,95); - - /* menu button */ - ctx.style.menu_button.normal = nk_style_item_color(nk_rgb(206,206,206)); - ctx.style.menu_button.hover = nk_style_item_color(nk_rgb(229,229,229)); - ctx.style.menu_button.active = nk_style_item_color(nk_rgb(99,202,255)); - ctx.style.menu_button.border_color = nk_rgba(0,0,0,0); - ctx.style.menu_button.text_background = nk_rgba(0,0,0,0); - ctx.style.menu_button.text_normal = nk_rgb(95,95,95); - ctx.style.menu_button.text_hover = nk_rgb(95,95,95); - ctx.style.menu_button.text_active = nk_rgb(95,95,95); - - /* tree */ - ctx.style.tab.text = nk_rgb(95,95,95); - ctx.style.tab.tab_minimize_button.normal = nk_style_item_image(media.tab_minimize); - ctx.style.tab.tab_minimize_button.hover = nk_style_item_image(media.tab_minimize); - ctx.style.tab.tab_minimize_button.active = nk_style_item_image(media.tab_minimize); - ctx.style.tab.tab_minimize_button.text_background = nk_rgba(0,0,0,0); - ctx.style.tab.tab_minimize_button.text_normal = nk_rgba(0,0,0,0); - ctx.style.tab.tab_minimize_button.text_hover = nk_rgba(0,0,0,0); - ctx.style.tab.tab_minimize_button.text_active = nk_rgba(0,0,0,0); - - ctx.style.tab.tab_maximize_button.normal = nk_style_item_image(media.tab_maximize); - ctx.style.tab.tab_maximize_button.hover = nk_style_item_image(media.tab_maximize); - ctx.style.tab.tab_maximize_button.active = nk_style_item_image(media.tab_maximize); - ctx.style.tab.tab_maximize_button.text_background = nk_rgba(0,0,0,0); - ctx.style.tab.tab_maximize_button.text_normal = nk_rgba(0,0,0,0); - ctx.style.tab.tab_maximize_button.text_hover = nk_rgba(0,0,0,0); - ctx.style.tab.tab_maximize_button.text_active = nk_rgba(0,0,0,0); - - ctx.style.tab.node_minimize_button.normal = nk_style_item_image(media.tab_minimize); - ctx.style.tab.node_minimize_button.hover = nk_style_item_image(media.tab_minimize); - ctx.style.tab.node_minimize_button.active = nk_style_item_image(media.tab_minimize); - ctx.style.tab.node_minimize_button.text_background = nk_rgba(0,0,0,0); - ctx.style.tab.node_minimize_button.text_normal = nk_rgba(0,0,0,0); - ctx.style.tab.node_minimize_button.text_hover = nk_rgba(0,0,0,0); - ctx.style.tab.node_minimize_button.text_active = nk_rgba(0,0,0,0); - - ctx.style.tab.node_maximize_button.normal = nk_style_item_image(media.tab_maximize); - ctx.style.tab.node_maximize_button.hover = nk_style_item_image(media.tab_maximize); - ctx.style.tab.node_maximize_button.active = nk_style_item_image(media.tab_maximize); - ctx.style.tab.node_maximize_button.text_background = nk_rgba(0,0,0,0); - ctx.style.tab.node_maximize_button.text_normal = nk_rgba(0,0,0,0); - ctx.style.tab.node_maximize_button.text_hover = nk_rgba(0,0,0,0); - ctx.style.tab.node_maximize_button.text_active = nk_rgba(0,0,0,0); - - /* selectable */ - ctx.style.selectable.normal = nk_style_item_color(nk_rgb(206,206,206)); - ctx.style.selectable.hover = nk_style_item_color(nk_rgb(206,206,206)); - ctx.style.selectable.pressed = nk_style_item_color(nk_rgb(206,206,206)); - ctx.style.selectable.normal_active = nk_style_item_color(nk_rgb(185,205,248)); - ctx.style.selectable.hover_active = nk_style_item_color(nk_rgb(185,205,248)); - ctx.style.selectable.pressed_active = nk_style_item_color(nk_rgb(185,205,248)); - ctx.style.selectable.text_normal = nk_rgb(95,95,95); - ctx.style.selectable.text_hover = nk_rgb(95,95,95); - ctx.style.selectable.text_pressed = nk_rgb(95,95,95); - ctx.style.selectable.text_normal_active = nk_rgb(95,95,95); - ctx.style.selectable.text_hover_active = nk_rgb(95,95,95); - ctx.style.selectable.text_pressed_active = nk_rgb(95,95,95); - - /* slider */ - ctx.style.slider.normal = nk_style_item_hide(); - ctx.style.slider.hover = nk_style_item_hide(); - ctx.style.slider.active = nk_style_item_hide(); - ctx.style.slider.bar_normal = nk_rgb(156,156,156); - ctx.style.slider.bar_hover = nk_rgb(156,156,156); - ctx.style.slider.bar_active = nk_rgb(156,156,156); - ctx.style.slider.bar_filled = nk_rgb(156,156,156); - ctx.style.slider.cursor_normal = nk_style_item_image(media.slider); - ctx.style.slider.cursor_hover = nk_style_item_image(media.slider_hover); - ctx.style.slider.cursor_active = nk_style_item_image(media.slider_active); - ctx.style.slider.cursor_size = nk_vec2(16.5f,21); - ctx.style.slider.bar_height = 1; - - /* progressbar */ - ctx.style.progress.normal = nk_style_item_color(nk_rgb(231,231,231)); - ctx.style.progress.hover = nk_style_item_color(nk_rgb(231,231,231)); - ctx.style.progress.active = nk_style_item_color(nk_rgb(231,231,231)); - ctx.style.progress.cursor_normal = nk_style_item_color(nk_rgb(63,242,93)); - ctx.style.progress.cursor_hover = nk_style_item_color(nk_rgb(63,242,93)); - ctx.style.progress.cursor_active = nk_style_item_color(nk_rgb(63,242,93)); - ctx.style.progress.border_color = nk_rgb(114,116,115); - ctx.style.progress.padding = nk_vec2(0,0); - ctx.style.progress.border = 2; - ctx.style.progress.rounding = 1; - - /* combo */ - ctx.style.combo.normal = nk_style_item_color(nk_rgb(216,216,216)); - ctx.style.combo.hover = nk_style_item_color(nk_rgb(216,216,216)); - ctx.style.combo.active = nk_style_item_color(nk_rgb(216,216,216)); - ctx.style.combo.border_color = nk_rgb(95,95,95); - ctx.style.combo.label_normal = nk_rgb(95,95,95); - ctx.style.combo.label_hover = nk_rgb(95,95,95); - ctx.style.combo.label_active = nk_rgb(95,95,95); - ctx.style.combo.border = 1; - ctx.style.combo.rounding = 1; - - /* combo button */ - ctx.style.combo.button.normal = nk_style_item_color(nk_rgb(216,216,216)); - ctx.style.combo.button.hover = nk_style_item_color(nk_rgb(216,216,216)); - ctx.style.combo.button.active = nk_style_item_color(nk_rgb(216,216,216)); - ctx.style.combo.button.text_background = nk_rgb(216,216,216); - ctx.style.combo.button.text_normal = nk_rgb(95,95,95); - ctx.style.combo.button.text_hover = nk_rgb(95,95,95); - ctx.style.combo.button.text_active = nk_rgb(95,95,95); - - /* property */ - ctx.style.property.normal = nk_style_item_color(nk_rgb(216,216,216)); - ctx.style.property.hover = nk_style_item_color(nk_rgb(216,216,216)); - ctx.style.property.active = nk_style_item_color(nk_rgb(216,216,216)); - ctx.style.property.border_color = nk_rgb(81,81,81); - ctx.style.property.label_normal = nk_rgb(95,95,95); - ctx.style.property.label_hover = nk_rgb(95,95,95); - ctx.style.property.label_active = nk_rgb(95,95,95); - ctx.style.property.sym_left = NK_SYMBOL_TRIANGLE_LEFT; - ctx.style.property.sym_right = NK_SYMBOL_TRIANGLE_RIGHT; - ctx.style.property.rounding = 10; - ctx.style.property.border = 1; - - /* edit */ - ctx.style.edit.normal = nk_style_item_color(nk_rgb(240,240,240)); - ctx.style.edit.hover = nk_style_item_color(nk_rgb(240,240,240)); - ctx.style.edit.active = nk_style_item_color(nk_rgb(240,240,240)); - ctx.style.edit.border_color = nk_rgb(62,62,62); - ctx.style.edit.cursor_normal = nk_rgb(99,202,255); - ctx.style.edit.cursor_hover = nk_rgb(99,202,255); - ctx.style.edit.cursor_text_normal = nk_rgb(95,95,95); - ctx.style.edit.cursor_text_hover = nk_rgb(95,95,95); - ctx.style.edit.text_normal = nk_rgb(95,95,95); - ctx.style.edit.text_hover = nk_rgb(95,95,95); - ctx.style.edit.text_active = nk_rgb(95,95,95); - ctx.style.edit.selected_normal = nk_rgb(99,202,255); - ctx.style.edit.selected_hover = nk_rgb(99,202,255); - ctx.style.edit.selected_text_normal = nk_rgb(95,95,95); - ctx.style.edit.selected_text_hover = nk_rgb(95,95,95); - ctx.style.edit.border = 1; - ctx.style.edit.rounding = 2; - - /* property buttons */ - ctx.style.property.dec_button.normal = nk_style_item_color(nk_rgb(216,216,216)); - ctx.style.property.dec_button.hover = nk_style_item_color(nk_rgb(216,216,216)); - ctx.style.property.dec_button.active = nk_style_item_color(nk_rgb(216,216,216)); - ctx.style.property.dec_button.text_background = nk_rgba(0,0,0,0); - ctx.style.property.dec_button.text_normal = nk_rgb(95,95,95); - ctx.style.property.dec_button.text_hover = nk_rgb(95,95,95); - ctx.style.property.dec_button.text_active = nk_rgb(95,95,95); - ctx.style.property.inc_button = ctx.style.property.dec_button; - - /* property edit */ - ctx.style.property.edit.normal = nk_style_item_color(nk_rgb(216,216,216)); - ctx.style.property.edit.hover = nk_style_item_color(nk_rgb(216,216,216)); - ctx.style.property.edit.active = nk_style_item_color(nk_rgb(216,216,216)); - ctx.style.property.edit.border_color = nk_rgba(0,0,0,0); - ctx.style.property.edit.cursor_normal = nk_rgb(95,95,95); - ctx.style.property.edit.cursor_hover = nk_rgb(95,95,95); - ctx.style.property.edit.cursor_text_normal = nk_rgb(216,216,216); - ctx.style.property.edit.cursor_text_hover = nk_rgb(216,216,216); - ctx.style.property.edit.text_normal = nk_rgb(95,95,95); - ctx.style.property.edit.text_hover = nk_rgb(95,95,95); - ctx.style.property.edit.text_active = nk_rgb(95,95,95); - ctx.style.property.edit.selected_normal = nk_rgb(95,95,95); - ctx.style.property.edit.selected_hover = nk_rgb(95,95,95); - ctx.style.property.edit.selected_text_normal = nk_rgb(216,216,216); - ctx.style.property.edit.selected_text_hover = nk_rgb(216,216,216); - - /* chart */ - ctx.style.chart.background = nk_style_item_color(nk_rgb(216,216,216)); - ctx.style.chart.border_color = nk_rgb(81,81,81); - ctx.style.chart.color = nk_rgb(95,95,95); - ctx.style.chart.selected_color = nk_rgb(255,0,0); - ctx.style.chart.border = 1; - } - - while (!glfwWindowShouldClose(win)) - { - /* High DPI displays */ - struct nk_vec2 scale; - glfwGetWindowSize(win, &width, &height); - glfwGetFramebufferSize(win, &display_width, &display_height); - scale.x = (float)display_width/(float)width; - scale.y = (float)display_height/(float)height; - - /* Input */ - {double x, y; - nk_input_begin(&ctx); - glfwPollEvents(); - nk_input_key(&ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS); - if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || - glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) { - nk_input_key(&ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS); - nk_input_key(&ctx, NK_KEY_SHIFT, 1); - } else { - nk_input_key(&ctx, NK_KEY_COPY, 0); - nk_input_key(&ctx, NK_KEY_PASTE, 0); - nk_input_key(&ctx, NK_KEY_CUT, 0); - nk_input_key(&ctx, NK_KEY_SHIFT, 0); - } - glfwGetCursorPos(win, &x, &y); - nk_input_motion(&ctx, (int)x, (int)y); - nk_input_button(&ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); - nk_input_button(&ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS); - nk_input_button(&ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS); - nk_input_end(&ctx);} - - /* GUI */ - {struct nk_panel layout, tab; - if (nk_begin(&ctx, "Demo", nk_rect(50, 50, 300, 400), - NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_TITLE)) - { - int i; - float id; - static int slider = 10; - static int field_len; - static nk_size prog_value = 60; - static int current_weapon = 0; - static char field_buffer[64]; - static float pos; - static const char *weapons[] = {"Fist","Pistol","Shotgun","Plasma","BFG"}; - const float step = (2*3.141592654f) / 32; - - nk_layout_row_static(&ctx, 30, 120, 1); - if (nk_button_label(&ctx, "button")) - fprintf(stdout, "button pressed\n"); - - nk_layout_row_dynamic(&ctx, 20, 1); - nk_label(&ctx, "Label", NK_TEXT_LEFT); - nk_layout_row_dynamic(&ctx, 30, 2); - nk_check_label(&ctx, "inactive", 0); - nk_check_label(&ctx, "active", 1); - nk_option_label(&ctx, "active", 1); - nk_option_label(&ctx, "inactive", 0); - - nk_layout_row_dynamic(&ctx, 30, 1); - nk_slider_int(&ctx, 0, &slider, 16, 1); - nk_layout_row_dynamic(&ctx, 20, 1); - nk_progress(&ctx, &prog_value, 100, NK_MODIFIABLE); - - nk_layout_row_dynamic(&ctx, 25, 1); - nk_edit_string(&ctx, NK_EDIT_FIELD, field_buffer, &field_len, 64, nk_filter_default); - nk_property_float(&ctx, "#X:", -1024.0f, &pos, 1024.0f, 1, 1); - current_weapon = nk_combo(&ctx, weapons, LEN(weapons), current_weapon, 25, nk_vec2(nk_widget_width(&ctx),200)); - - nk_layout_row_dynamic(&ctx, 100, 1); - if (nk_chart_begin_colored(&ctx, NK_CHART_LINES, nk_rgb(255,0,0), nk_rgb(150,0,0), 32, 0.0f, 1.0f)) { - nk_chart_add_slot_colored(&ctx, NK_CHART_LINES, nk_rgb(0,0,255), nk_rgb(0,0,150),32, -1.0f, 1.0f); - nk_chart_add_slot_colored(&ctx, NK_CHART_LINES, nk_rgb(0,255,0), nk_rgb(0,150,0), 32, -1.0f, 1.0f); - for (id = 0, i = 0; i < 32; ++i) { - nk_chart_push_slot(&ctx, (float)fabs(sin(id)), 0); - nk_chart_push_slot(&ctx, (float)cos(id), 1); - nk_chart_push_slot(&ctx, (float)sin(id), 2); - id += step; - } - } - nk_chart_end(&ctx); - - nk_layout_row_dynamic(&ctx, 250, 1); - if (nk_group_begin(&ctx, "Standard", NK_WINDOW_BORDER|NK_WINDOW_BORDER)) - { - if (nk_tree_push(&ctx, NK_TREE_NODE, "Window", NK_MAXIMIZED)) { - static int selected[8]; - if (nk_tree_push(&ctx, NK_TREE_NODE, "Next", NK_MAXIMIZED)) { - nk_layout_row_dynamic(&ctx, 20, 1); - for (i = 0; i < 4; ++i) - nk_selectable_label(&ctx, (selected[i]) ? "Selected": "Unselected", NK_TEXT_LEFT, &selected[i]); - nk_tree_pop(&ctx); - } - if (nk_tree_push(&ctx, NK_TREE_NODE, "Previous", NK_MAXIMIZED)) { - nk_layout_row_dynamic(&ctx, 20, 1); - for (i = 4; i < 8; ++i) - nk_selectable_label(&ctx, (selected[i]) ? "Selected": "Unselected", NK_TEXT_LEFT, &selected[i]); - nk_tree_pop(&ctx); - } - nk_tree_pop(&ctx); - } - nk_group_end(&ctx); - } - } - nk_end(&ctx);} - - /* Draw */ - glViewport(0, 0, display_width, display_height); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(0.5882, 0.6666, 0.6666, 1.0f); - device_draw(&device, &ctx, width, height, scale, NK_ANTI_ALIASING_ON); - glfwSwapBuffers(win); - } - glDeleteTextures(1,(const GLuint*)&media.skin); - nk_font_atlas_clear(&atlas); - nk_free(&ctx); - device_shutdown(&device); - glfwTerminate(); - return 0; -} - diff --git a/subprojects/nk_pugl/nuklear/example/skins/gwen.png b/subprojects/nk_pugl/nuklear/example/skins/gwen.png deleted file mode 100644 index 40956c9411c4c59a9b5001589ae0fa2a6e2258c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24565 zcmY)W2O!noA3u)2?zQ(`B_p#GLdd!|l~IJuGDAk$d*7>!Y^m&>QY558#=Xi&vJvQgIW4<(>(QJ<9%?(mpPKc_cY6OQ>vF& z2l-`%m{#bgc+x7mm^@54{i1RV$a^;p=rw{gZzN}>-L4AiM{{1CkR43DufS@+c>DUKTlgD^5m zqr5BLtrhbVuQZdEu6WOl(oQNs8V@!q9zuBA#lF}4WZ3L0-fl1t33MY5Zp9rIQtz|a zhY)*ag5#qOqJ%Cl+|?ESuKipzfvkcX+e4p941+k92g@gfMRn3W6wru-9DFjjXUFQo z-?Fw@S^aC>x3@pfsS%`d{AePJX;e!89+h0JwI1hmo^T2*5j<)kSd`WOPH#J7o%?Vn z^!r|tag^(_Cc`-tRP)=1v&|nBLAGxC4q6+lxc|M*t~I{)G&V0x(KDrn(3;iz`fc#N zCH{BsiCXhxU5A>dmiRY+BT~vy!urIE^QS$hxAi;&MwHK^gR6mX)&{Lnp?6Y>?r5h7 zM4*Xx-El2?2JA%dxI*z35fPELgb+d;=S3yLW4VDMOuyv4CjrZ0y+h(S=Nhw{v5bv%tqPClZh?KX)NxaZ&nMt12c-3El6w}xvV<{+L zP%4a|=|N|f1gC~#3z5_Y0ukZ~euSWN(UX5rxC62tcA{C~1fQ(O>gU1f)#?e!-Q(cp zVT`F8SI%om(Y#4(lc5gcyEM$e)d}zQJUB<}5^D7_`N#8AI*$tvJ0H_KJ}Ye--<%k? z@~gl}K)v+nb6WT(y2t=_0sK7o1p*u76cc}99G8^C%F(3k=?9PvWzVDLiwJes zS5&v}QuIpAXVZ=oFc)k5|G5rf!gQr3=Bx(C6i@l;@+ors!Q?u7og4C~=kRA};Gr5X zUz+8rolJEP;I@#0b31iu-?1^@sEyKucKiqg(uyAO6#2wph_W0aMfXPyS1)|k5_Ans za4MV#Dh+#PTK|oIXFiGghguVcmw`IytxR^#KS?M^gJwJHF+Eya2reLZ7AnyoNA9W8 zO)O{EVKZUWkHXX}xW?+$PocNnDCX+BnglQ0@9c1C`!UWs>}wn zfiusYx*sN#gOc-petVNi0X9{JpG-MMi1vVrQSD zs+U5o8P?6%ZdPn$eLoA`fwQ0|dr-JAzEhC8R##^D#$b>$1yx+qpIV+NywI-uk0RWo zOs2dVGFEaUYGd+@Cmrh@S6xv_=dC%9@^7Ogt&0&{qk?B3Hg=+u0Xl#Ijo9ID%+n!5 zQn%CeCb6^hj2uM9VNwN7t>UZh!@n88d%apt!#0j7G%5cfkE|ox2AjHP==M93r|yIT zfq0Z!P5FN(t6mxt62LTd7iitTNHD90p?l0B!UjtCiH-V#D-2APTCkQ)KL*NkCH@a*CuU`!nd22W^>q!Wk@;|tDe6s?lnN{?v3>%Hm z>1m`8U_M1);zAMq%2b>oYQYHZHgYFl_zPnmIQ*trInjoVS!OXQDDWdclYI@@^m>%} z%c&@3qn&}L-;(lELp%Zye}wMPS@#aTIlCneKUv5jCs9iXs%L>}JBtv6I-=L)8V1vb z8KkV43V;8z(Td=u<%oIvt-O_;7@&g`CPRx;BA2~?Zz$!%1R|JIIM|XI4VfQt=eIdR zkIf0RlHDs}rC#~_7%^#lw*$`w%b2eol6b_4av911JS*JD~|W4=^of_bVl zaG3!TjL^qlrcfT3E|28>eQtbW%k+0o2H|leLJ`kjHNYQO`NB*?AjK&<3BG}lICbFU zOV7T^Ev-RXzx{9OqHB1&DHEyg1h&yFrkrt8#$S8$Tw&Fy+c`BR9C7FHQ;#JJ)1PdF z{#NYM_=N~5i}GRR3ojr|J{I*i=%~$`4m)wkl(D4XbQ^WWz6C@6?YOC$Xm=WRorRz^ z^2vlE{srSb7U+h7Ku1Q_DS?2Cl>aHO*a**-LDMr)xxV!?Y&;P~SoNgCXp|ztH9pUw zuYOvcERKo^DhfUO+VJyF#B)kC3(0I)%$It<6bJD^)k};|G4xlQzFLb&kCn4JtLITq zg>@$N5kicwW!uqweVQVA=kL=4SvZnfPx-0P;BDt6|0(JcWB;FMq-c{91EEj9q6Q(H^3l1pNb6gZBSQEl%iTgc zRLxVW{jIc5E7a;-@K{lTYdl2KLvps$v18#in;KZMG4T}2lNQyp{PbJ7hSPlYSYiI^ z&9G;4yHthU~G*<*R3k0ay?K-5fggCO^Kf>lKwnIZ)!mJq^E`1o7C8@ zYOC92-;s=Ee#pO*hmt!))%Awfo9$WRDBMTy*_si$9MMtQVh zJ;?Got|mX>yV+C4DoIEYejo*x4n6cC!0B7-)*DX;s6P0~&iS-ys6J4ZF5KQ4e_0oq zJ)QTrZlS60Vo3KrN~C}fJ393$wF1P_G9mTjZUY4<6#5r+?uwr~ZEe#KYNdpDm7kyA z$yF#ch~dMyFXH3z_>dC57+g+=8@T|*bos88OXw~gCbi;G898@3OdksPRtPh=apifs z_a^*CrQW(@(e$?XUh4;x`lg;Uxd6xX1fkqFU}1v21;V-BC@MhTtA?G8Mcwv?7Y&_0 zk`>>>)7#Q-GUa|y80a==kvy7S?`~leofD0aq~X;gM>51gxEAXK%@MojwtB5tqEIP(A#~Hqkx6I#=+Io z+nr@@rK9ImWBm_aw>W>5TbU_UgKc=m8xc(EidbOKCsWw(Og#b4L^3MI7goWmpLt3* zz_$?k8Zhe0`IcPU?nAMt`x?f^1E-+ZJa`={G!Ik(s?GiRUl~HX6Q~v#WGTBbJpW$} zx<50DF#BP5k?g%FUlP`^8$ra!K{sX02n~XKxk zLZ-}K#zX+xmo4efreR5!h$9uQ^9Y=jGc?CZM3$sveISbi)+;v zx3Pzh72?OocS>{d?RF0anYt|a(Nc{{(mRo9R#p`GdVe%w8@76t^N#u}+MMl0xFbY4 zOV0NeA{7D$TdSF2tQlLA*S^3>2S%cWN>XW_-sigq=~z_Sw)iFN^YJ6XRKEJJGsd;B z?p83#@nX>uRFk>EYfXR3%!`l6Rn~T(?d4Jc= z`}gnbY!X)fIR-5EmE?m-BLsw=_`DYG(ZeSwuU zs14bjX9~-CyLwtBo^@lHU^cOZP8yWoI=|O?&#Ut}c4aqlm|BFlKNsVIh7=$DdCwBV zmu8KJP2vx>znw2QtMIYOZ$tHdF*FN8)7)qg0*2W30Vhq#> zQNEye5+X2#ti#ef9V}ncDZ`dj)&sU59G|Wu(6q~oK0h}d8?H{BuJfj7J5`t_Ffb6e zR9X%i9ZD*+rqJq9%c4}hhJX%UdEQsUz<@>4@@r8Rke2T=8*YW|K(Q>T<%uC6FUB6P zm7z=Q?Ci*tBKc`ceSNfDTOw>+Fq9?^gE$6D3g*P7b4Zx{j$BtLG#w#?Pfh2Q86WjM zgaSxjxJz=GIGvE01ciIIvlUrv;rQv$>1LYx&DPTwA<>5-U(7DJ#y>%LCFkWOxnqtw z{puQMusISY?-k#^Ykz%pgS2=J|gbc-O3;-JQO)v?PiW#=6K;-CG+N7|?A@ zt@~rIHuTk3B4}?V#%=6tq)O1vLbze^?SijgzfxdvV3I2_e!NVUMCK3cfenJq{5^qU z$nmOyu72@jxEXP^6s0cX0{836y!pGc*nJFyqp5?<1XaE$U@rK`pR@@EKO??_tt*EwLQY{Wwn!^J=$?Ks?L#(Adlnh6Z^VedXNEiA@GbYL7j5PPbA_I8rp9 z@zl(YVdtarhClF0nhBwq#j4{G`T4%4E!(`Kz>kCkOJc-A%+H@UCD16C^qEGEEn9si zEaN2C%a<=NuIe%gOdnF+Rrr7QFVj?1+hH5#Ify_g4~%VcrM`Iat8O}0V)|Zh_o`o7 zj*{;~lWW(W(2UQ9jAW@P(4WlZ527VE*(HYfS*W~)p?VBT8tFHAd%+=Ouh$Vf`r!Ws zAtK(TOfVwJI&k)-ldEgXaFydLKD(Jnjh(NBTtT}_kx@}mi)yeWWmO26Z$xo7;Ud~7 zDRQo*(a!Qe@BG*ahDW!`Cg^h{yhDqGpLVN*QTg#}{ZP>orAc(>r7$1=yEP70(E1(~ z=7-bAvQ`bpgEmh?^-I5QvFFOaOYHvVGzLFd-j~UsJue{arWXx!NnwA@Vjf8%=u#%eC-BMmGlH=_9hD=@Piq`R2QGH9fU2xz+7| zfkUUoIxXeT_Reg@Vfdb;KF|Ig*3x{unANX}rad>yFyF3|EAc}Dl!z7_DCi!`9-qIeug%kGV>8_&XHHX1p6N@gz|C{~Yw{coKXckY zn?l;*c)M!(+y1h_Z=vfrSwX^ZYxWPWr(B={S+?f4*>vbq^SO|n;v|ssezVKO@u;)9D#2-|E;AM1&i*F0 z9@t!1|15#yNUM!odt>J}ZK7~k(|ox&t+00A>VZUT zN>$Dc;1a<{B-=r`Rz9%f{DuNG=nt}EI$A9jaU zCPfyCYr=N6i=PW?D}3X6#WDK66TcYeRF( zW$Wnu+~X$hIl94n2f44f=ML9r zu(=)EhuEz{ybobPYE$0Az#4t2n4IwtFr4*B)U?lSyzd)#ihUS-nD!6=5) zZvVqr2`1&a=GewT>+`W&^?+|0mFq*hQV{`$DMfu+-jV)3_<2^9W+tp}itw=~C_>g( zwx23Q3csWkgsCI7QU=Kv=J25tbZ?nUXpIe^0xK#CR0x>pcp#Wgo!6`xmC;)4!K|u9 zpxwRmj=$d;h(K1nszIMzcNTiZrKH*}4_Z7a#}I;yTwPb+o>BJ0vq8#ev4;;Io|22e zkYnQzxF#kSg)twt54CfrcGf5OeSLjjH4+Y&4V3-Y=!;0p@i;UV(oDQixAjv()}#w{ zylfr4Hr^1-fmWMyv3x5I(pzlk-ZqG*nC+}_dZfqQ1LcDQ9b`Cj;cqE|Isk0T$!rAR z`DxzKruc#&Q>v8zq=j^&w2A{cloM1C{3ahPoXs18c6DEAB%CraG@PMk zB@!S4euke|v(u~Dz(${`BT6kO9k5|T&#TD1KOQVaDs+Q)2Ta{hUGe%?F;?e))SqSv zvK%2XoTtFF+zQgCyuL`TRXJEbW-ZKa4A~C zeUwL(APTt?@bd_%(2XW4vXN@Ou~^kaRc-?%xc^Qa86@pJrvoa>zLyfF1U{^A9xe;2 zKlp8^_wsgz4244#52!xvwaVOw`1wM2475^=zB+VfA`e}jZv{f)duI$+uKaCE-{tR4 zDF}+EBtN`@<=O+VQ_hR*h?GEA$4~P2KsC2a>OsZl!kI z%AWHItIbTyU6M%aRu~Dq!A5j>Z$o4WE1E?d-VIuw8N%$^!O(iv3gD6M*`2LHX^&>}Ls0c2sH`?()v7m>vE$==Y%)&)$%A9Rr9OfMQkmk*GfA{nO-Zu^&kj=-Q z%2C*z-Z%zxIjvvYf%&rj_Ue=Ru>2*P9m<2u?m-Cp+0g-WmqJ0@##UB*#`q^46ZSGw znU6lu+|D!pb>>QZhjdubwk@|cG4KYfdIR-!oH#`MGWn7i5{}L%?)nl+*8NZm52Jf5 z*#%N*lE-9X%g;rXynVgPpKC@j$q9*!ef1@S%pd3TGjg;nJwCxQoFr16fjZtIpC~=M6s>vR-{{QHPW56vplPakLmO#JAhf z@3A&|r98zyR*h$ZBj*DIWg}30P}gC=}cx3gaC z-0hT}&H7uCLY}^*>-52$vi{m3tH~AbTpsWn#md!@DyWtBLw#k}zFTM0lko?XYZ4f# zhw@2`n?X^3|K7tY*D^uBfB*TTo;q7YkG{}>J6tY*((iwP3|U!x0(wLgrN^|5U-|3R z?nyJJvi;z}R?NOgn+R|4yb~QdCR5!Z_0xb3^hSkEQb}@pq;or=J-s?oin8f1`3 zxmChN^Djf8*C5zrLT8r3x^=bN8PLIuy7}9*+#tH&HejzAa|=-6t3O;S9cm1%Qw^cc z|Ff=QnPk)VkrVl0zOBB`+Io>WcCx&cJxAbZ9hq8aXK&3%Ju1N_(<`Yxv(96Q1G7MFF z%%d=Q8|Y3i>wHV&%-l<0dUH1_#iHb3!IVa8UuT=YxK|$pEh~pyBtE&+Co*=e;?0{k zZXh)cmRmI(wt&sczoNIZpI&`JSpb?QMgKKkMn09NATl$JRJ#va(An&-jroF%Q%@KG z&)giUwEF_0$E*5!-j)hTEH=0jDvW%wV0g7XJi)_2vkf{4aW2h3^0J;guL2qFjH+6M&n+MoJ z3)N__|42j19&XoabX=07%o3qDZro_z0iDesopSM;8Vtw{ z#|*<~f>I^mRv@?{RU>2L7QBpJj?(3e{alh}75N}BzkdDtOJCm|pXEOc;C3gFuzlA? zYYiBqXYx2NnAuQmG=GbvJN;i02V0tHk&ajy9uCVYM z<77-r9GAj%wppE&0X68vxq+0xW8Z-wbFDj9^)hB&ojO}B^pvr&@&9cBvz2_8_Nb>P z__29l6V*(~V-lOZ4_e$P(Ed-k6ZhOb7kUIo3a&-F-K(%^s)(fHQhMBsL7)-)>l2ur zqX}Y|)?s1cS#}PNsglwU-<}C+x`66J!Pv-%-n>4bQiv;TglCxyTkj=SetiyRbLDh3 zfL4T6gZCmjW@DWo05s4LKQ+XpN2jKyK0Z7=+%G99Y1IK;tz$YVBLtm{XOt%s6Fo!4;RSN*;}{9FjC0}4pq z#Mn5p{F}mOU`Zf3qNYb_LX3`B5_8m|OiU$6Uy>dozQuTp!A0}+^3=YN%wo5AeXMT( zsoC^;F^Wi77${9ED=f5qDEXrH_c$j^s^kpfar$c~fI!2HL-~ zO^u;Pa44HkY>9BMI0Ln@SNh>AEyTA+8q{CC?VgDVXSQ1DE&E$RH365(e-VC|b&=4q zlq<;(c!0RRy)?BNK7;)N#0P7v);vffQ`;FUczY1yIZX#4Jv}c?uFf(+uVQ0kS(W%E zyuJx}6}bFbbmEXHPt4=$hzevW6l2R5rv(WIZftxDnCWNQ@j%L(TU%QYlxC4uI5&lw zc=#EP^q-hxogjMJRhm8Srz(W*UWVR%)!!)mduiMDSXN5?qb|;3_Z_R2Ai1zMuw5>X zrQhcOSQhGjSuv+8rM_Op=cC`_j+xkWO|eH}5V~U)j;*<_$Dj? zW#5GEgBfhsHg@kq=+;(^|1y)@<;x;ID)ZfWOt<+JTXiOgdOx6z!jkfOGkJjZcs-5T z-QB%dR#q1Na_4bN-RI97q@N*C4c5Ri6Q7De4@F*GXbt$u!;Nq1#$vZYOU`9R*F*eC z$fV+`KhAP*grNuVi+Z^#89gz71_!B%yU(*qmHdi(@Ev4V(MIi{)@+r)kAS;zOFBa* zS@>L!7b0-W{(1TAhbtM~i~Ys-Ki?Zs0RXXuB-ia+m0`FI9ys;)H1@C=F!nI&-wzfD zndcVjVSeB$zGg&UIvhKFyQQWKFTb<+hYIol{+X@l`K{4o>f3n~@SwwE%_P2rWtHWn zC6BFt+DFqZait%74+nWEuyh5L+qT2fQtDn<@)dIF)+vwdhJekpzZ_&Gt?H?xzfUoZ ztj8zc&Q|tk)J){PYH4Yi6^-!9e;Edf1{w4b2ETQyt>9XkCXBw}p}5-`N;b;svRuV# zPr)@spM_*HtRcY_M8H(osI|HI@G`j2VA;7GV= z23i$_qH6qZIckj5y>7%1o46NK)^1dTwR{CGWr14gDd6hPL%7$0yxCi3uJCVmwrSC4 zdbHMCF$}M`w7h(I5N=i<;Awf|M$0Y;JW}!s3L}R*i%&pIGAlEwv5*AXpK6X_16sWI z2&UMTeZ_Do%UnPRkZ33&UeD8zl~F3Am5>ZD9PA*mw|F`EKt!9$pXa zdrUzmIyg9}M*q(K9c4PkvF03aoJ?*7YdO^o>Sqw(ZQCb`g~ z;hy?c%w4b>p+knH^J(iYRqbf{n62D6 zCvT|ACH~@GL^3V_G+uUu08qzV?0czpI{lc7fi}9bIkz?3R*#zI!9a;I%S6^CJB`2n zj+qgI@X4a{!|f8LqCxj_3cjZ)3ku8EiVr!*Kot*)CsIR$x9oBjUp>&PLQ=<&Fzn+0 z@^!^5;#KFeQ^B!Wpm3)A3B){#aO3uJ>9l^|FC$7P2IM4JeSyBWNL)$n$$Bj zn0X4)dLZe^1e!~iQ z;+!ERY>3(h5ArT!6b9qdv57tMZnX-P?!^OW^t2Yj_3x)AXDZ|0=w|IP0X*lp{F7XV z?13S};e~TG#`$f=>+v6_ErPfDw@ds%NVAPa(V!8q8d_{#2$3od_2a0Kc#XT}-WfTM z&p{!R4}FuPaM4Bk#}mEHC?zQP@bABjBRW6mj=YpS0AP;5wqNnk^X$os&~a$_5m|uj zvwf-$CfCTv_fcmL{K+@1pBL5M%k7xwtYU(`;|{NM`}}J=bUc2Z*a_zE7Pm*pt~8xU zjR@yv6V9*pjqpmBcl|2?W}TCJesh0w`<&sM7q9?(P?TJ}Leg_RP!d2(g})WFwYVx> zdC9MrCC?DXmM=)i6U$h)haMQd(aER*JD^k_x?tXH<__XvdXv^&*?e%BsM%U93VYDL*3>^*8` zj>}m%d|U@vL}j$zBVJH~E}vz(0gFI0!lAV8UM`xAJgLV^AwOT7%Ywx--2CDUa)PC#X+9xA`i1_ZANG?x z=kvw&MPTCSIoN4INR#Z?~0Reo*1s>hlf*a0UPku_)p`iVW*F zF}GUhx2g_y%!IXVkC*ESb)ekL%*>oT9Q*|se`6}2x-QoEuDCKB?HNk0&y2l^Zkye{ zV@y#}NZvIfc86iZ@3u1ax(=G5X(H>2T{&am#6GI#>f7xGH=&LGH@bA%>qiL3%>=kp zHO`;>7j&Mqg=9YF=HClIjNXReeYq<=7JhBg&6}4mU%o%nnqXG#X32)8otTRS8)7FH z0+i3d!s6HA;NqrbjR%ZB3@11qIG=+&mWcH-N+}8>k>pqc7B10FDqCY%oJ@>ATN%H2 zmE6Nbn@`ID&@iK^IL3tq{PBI%jm<8q;*!quzYp_MAD%%!5_+8{ySMaooj=Gzj^3gy zG1^}yKNtw~FE##?bARDn-V;#)!|C;fkfn~kYfHX7%GHt#)^M~CGkv=BeRTwMYwApi zK5d~XFXRVLue$#|>J=dYurBW(pMFmOBuYPa2+&S9{MDbnP7zLkGuuKt{d9a&Q^e!g zLL(h8M1K`ZY0DpO`!2c2fVnZaQb~na5llP+O+o;`8r`S$&ennC(@r^g1IozetA%0N z0C%*yiV`q+n90rpB`NYX=YwKD2GlK81csjy<@INw$;IM4$tMc%9e?PjnatPMd{`7& zdR555RuD7#G;m(5f_rIllT#h3$3T!BbebS!i!&J^PhDhtKG&tj#jIM5D3iC z(K?3s2zqWNBL_t++{TXxS-oR!^m*!ds+k{ZWjv!KCqS5@M2jN%r}^>Rmu$($QN-iQ z3q0y%NO3|d*hmro)zLxs6v2QdFd)Oi)FAec_S6iJ_C0Lh#W{B3r#RGP`V;;pQ31>O z>oQ^l!de{dS62U;C_o6Z`jf_-VoN5_A#*F-M|^YsI4l++SaiI>2^HWB@ic-O z@lXY|)|<$@X}wLc2x&N29y#mL@ZL%a001h5>A%hAp{zdIw#2@M zoFM8J%&VuU;H`YzbLtoLr{t&;5)v-ZJdw8l!3=SegL$=IvTFkCMyYE#NMrW?KDt0b znh2YEyaP1XmD52}NYer)OMNL5hMQtS{V0vNdhqYL-klFYC-W|P0!ZR!jUiV+MGamN z%*n!COhu;bHvlr4e#KkV94t@$X)go1#WsB4VI+99+ZV!mYGGP!aD8^-3e)y0@T?Sh z=mg!&Sk_qPHa4Ex3{ZNH^NvSE<}s(JlL6XMyZz%~m#ASE2Xf>*3)+PiaWbcNK{5et zR$*=0QDQNyM`4&Y&r$hbUg>n+Vlsk(Oi=f z0TO~*3t?Cxzq*_b7+WmrLmVQSDn)KpstTw9Ao{n!pkLSlmrT3tsaHIB zj*s|FN+!Pe)Kt#Yh^yRcA&L+^Jb(^ZWB>U=`U5s~FOE}CpBu{qM+C`kW}40ssZW*) z2zo%?nDLf8hw%TqmZw)Qk&Saqp9uS$<;BE*e1xE`RNNh4+7ZdTGEhkgzzDHQn~OEr zlu@Md08-TupCJ1y38=GI4w7~3ve!=j6eHDkVwqQ*Ahm;kZ1VdwEr{=d_9ew&w#=-( z&|9Z}9N*p+CQhf9{5(27V~9V8k4R1j2MLxE<*>Gu;Dt;P)?%fiTHruMcaJ~F=|A5{ zGL1!Mxe%}=U_pmPu8h@jL5!62zzD7aVE4U=gpMd11GN4#}oZd5jo+T3iikX8!$^LFy8Vcr@BgWG2P}+H4I6^Z7!UGRBWq96e#GCxF-u~TDu*W2=6+@xS|gX@Y>u`goSq$BCpA! zDuAM5%Kg$pw)&=DL-L-Nk$sYzv)rTw^t^b%$o*KCku$=8TOmLgXsU)+x&T+Kl4QX< zLvr5;5C%Vr{;i+LBbb~>i)MU9>|{Y8z?_&Bvn~0FcAM^pMKA*z;(tLP9%BA>i7>3A z3C8Gwk{Qq8*@>fUVDjo9rd=w+oem_K3Q5g<=l`lx$0EE+PqaaLLz3_=iWEDX3z|G} z+bNzvzS7yahYAocJvSg_s`FjPI1Oxq7RpRIg8RAH7h;&8DVZE6Bjl}40*f1cr<(>K zUpEN9OAnRTZ^hcYW46^<@vA$7&Jnq<^9$;!dtYVE$LyRFP^kAtFRyE;;%dQx5I73( z5oSYWwit*hCA1s)p%-lC@L%`r@+wQ37)|U=IPk(`r}Tcf8UZH!71{T?-2VI+59hR5VRK ztfv~5{NPG)#Dw^C9-RRkxR7u&1SnbQopZ_JP_I~Q;ip^Jb0;Awksd9q4G;pD5SAJp z=A2af>ck6_WFdmH`SCuH2iD_HE|78f8aJPctFjXi6c!=r6xHU`PKx7lP|>wm1j&|2 z-$wwAfKX3TAFvN8rbM7vW>OI8epreanbv!bqy`S`%mI=?OWr>f2GEL5-GekrHb5v> z)FS0Lc9gA4F6n^7|CB`v+z6_cyihW&H|Ypeo^!#do9v8g7cIK1I@JHk! zKcT3wsC)96XE9=PVC`yN{U^obFaRKkG>Ul56c!ZR?;#u?4MGc-0s1lsYQg(e!xv)M z{{k#wiVZbrSv?ln##bX%uw$5)-A)a}=BQ+;$>KwcXlEu(;i{dT9RL9x3V!E>;Wnn6 zoSkEo8@ex$_wDnjux9bnT$ikO5KL|?DiSW3+0URr1%do%@zsY0U|Sz{0H`fUMC@Th zof@e>eVwL*@2ogz-<|dBL)mI=ni{_Z@lTs{rH8J8F^4*}*#%B&LG>@1g#)vU!+NZ6 zlQ@by*^46_unosGYjF(&_CIeETa;ezcF=^0gTUGW3<`i9^}Bz})8(A+j6MrTi)a1% zQFYVo0QG0G(m6@}wshz>N~8h%kB__y3|#}zZXD*rIl}M+!klCZTAAbnE>X;IKpDdV z5nb|K`W*p6<4VFQd3gOPgT&M@~F<~PbAuK|GY(8t@22s}8 zmo}+}Xp;5uBNzK>B?*g5$m`U#@gu9P@jS9U0KzTms~e@A>nuSA61_;~yG}iw*BLs) z0g8jeXAgKxN;xq2S*c4t3q2A2!S+l5uB>pGk{J#8-U(_E{|H3Zbl%Fme>15hQCE@# z`$VyYHo&GpMZ-I~)+~zi4j$EKryw47ciSwf8a``kVqe;vuhgwKL zRCJLy|3-=Br%5)a;0v`;vd}JaBuD>?$5o33VNZ16Lk@CC1amkQ8jXu~A3Qtp(77s4 zB77$vO3r2{>b#kiMvR{l5bhsZ^#gX{15nX-J5rbfdA{IDHFm!*_V^)iTHqwFYCm3D zdME+;wk4jSDW9W)j;v7aw8-PhS4=54^+=9+66uA5Me{8y4?@c^FFw}>ocN~ZzV7R{ zAQEUZJr~ovT~ppD*gl(Kt?kfAkb5OfFzUevE~mCu?5IHu>tLpzWVtA?3> zJ7SN)U3W93g3`znZ!``(20p~3y~EQJ@f`wrTeBH4E*KAl??so^!GSw2DWTO)0fbg6 z?G#|&GBjn9{y)M*+an&U(CMU{vkz7g4W~rg>)@`mV(iv6skJYH*3qr{H0F5Keaf%y zzPuQxQ+4`9k6H`dfH&QwSFO#ZV)p<6P*giDH>ghM-LA?nKGF5ZC!j!MhIgb%wSkNf zGux4NjT-j6ojos5Izuo5*)mPL^4Ii9YzqgoI@aZ8_gK&=sPNWix8DnawCICg0p^sT z2T<}|Pe$^m$srn5#(6O*~Y=&C*`KjRt-IS^1AIeHwsycFSZ%KooTS#s$pqBiSOK3;nVxQBUybqNlp5Uo{CJvYOrLp z&WSOc5jp>f*wylJnV;T-gR1Y;S_D3IGkt!=|K3rJJxnsbVA2KSj(F zNJ*aAk`DFJxjzTwZfb3@Rfg_jrFt-=&p84wDVhtXiAzelnI7hjUATM2jpTX?>9~F% z7@1M;`7Yh_ImE!F=dvTubN_2xz=~yb0scC_S2VGIcq^wW5HAN^_n$5=ZiLleMry6e z1aAF{gIE(L%u7m3DIogb1u^Z{dM$Ubq+FFpvDt0>1WB#U-Lc(`$V*0#tolJ7#-^s` zFtZXXvkd*iw26?@kOj#XfGsP%aGoU9LxMrCDl0F2I0k9~y@=n+5X;Boom!mR;=K9A zfR*s0jV4Y0qJK5Dq*kZch9rb~NlI(b72L{N?RB7`*K;4xnppBG-br_cwEngrGDIF; zX$7r?mSzhmBi%@SB4X_|`r26vPP#w!2eeAF=6zq-rGd3Q#TEBoSa^3*108dtb+hE} zgVY4D{i&Du_a^yEIp;}{lTJGY*r#JI1k_+Sowq6;&H`E|AVVHt6-o2C!Hgi}zth4N z=Y_@&(>Z)!^m!w~iu})4)wMDegLcGC%IX&NMgFWk@q0OZKVnn9%z!DZvJ!oYfg%-7!EBB|C$nC=_$CVuFA%3C#a;9G z!&qo#xQYt;Qe}VVR)v9y@nw&0L_poZ!vu+j!V(YXqVDQ9eu|`6k&de>Ms>v?AftLP z>*^qt-2VeL2u^qZ!GzIc54Pt4u}jV6@27V(NQzsczNA9|4dw0^(ab@9an?hjk6@ro z{=ETmVHGp|&#l=GCbi?8{_pbcDzFNbf7hLz0B3{VpQQND@t>0%849KjkPtnvTvM{}Bdfz6~-z@lX0b}yH5 zgP;K@Y_knP=xv#nmIr{B>-iB5up3E4a@&`?NOw9$#PS$Kj$liub{{C6wq6frUg()sw{bv%pb3tKrQPdy zko{9`oy4Su%kK;Zc;k~!hq#Auu<2%HRY$ozZaFyD@NQqH#kO~~Z5%V%;yJi&^*Z30SV)qb zd10`eAIi7JgavH1ivh>9-P=mzptzm(7&!KmEy65>2LA;(?8$n3eevnS&y%BH5k=75 z)Pj=pxnYOS7JzFNaJX0uezd=vC>1LZ3@Fo_rWaZhzH8j~Y_WY?LYuUr-Ld(Ri6n)T zvnqT{pt=j&tIDHzbN@DZbsIzJK&&;)Ih?+BTFwAa3~INzBy zm_a&DN8O%?tJ}J@W#A;Cvyh8ld|3>-2UEZ|F|e}A)jtI23c%1v2OpoSn+yKFb>7G{ zgl$)=rJ#TPMOqr57__OH0=zKnXJQT;jD@5#r0+X)YzGsJIu0UNuhzsO!jp+GfeII2 z+@2BWufb47v}^)frv_Y~(*XFfwvox`3#|cCq;_`i;Fp|yf9&$>CGl(w=0eBN=SN(pPM?0RM4r|8 zg#nu+H~!bHdZg{Y*%xu&XK^|#e^b;v;STMsj--9U9R)y0%b_ny6Mp|0+c^#2Qt`v+ zvt}3CJNrt-X#wpv3h>s7lA7GA6(DY={HE%6Fl@ktACU6XaH&4$C0$)=d&ngJh-~ax zT3Xr*7-)96LEmum)~yjc_!6W;J_$+p?qft(z^Z#+_q0_dB)^!389k4kri$ye7|Y(k zlaTim;dtIFtkH~TVuRfv1~z@NeAD;G01;i_(vP$`mz;QEC&FHtHUCS=IL+hH7!-no zg#2+!+d%9$w3iF|pk#>T`IYR{k-5pu%qG1KqF6Mpt+z-fL&x>rQP?Ke*-%%RQ{Zn? zDC!${T)q{qzd)lM?+`3Y>l(?Nlft$H7;iw6Vq<~HBy%Vb6aH>t_Io527)_akIh$1{ z6ExSEG8?7tEf92^|y8a8~IO^#KGm=fBF z%!}$4VOsafpX_fom>fUCzAY%{*xmXvIoNbmzm1_#9$i99ZezSfIIe6|+P9}f^mk_| zbOSg1o6zZS>*h+zC8*u)mP4KnF|RB1&RweelvrtXJ*~`U>rSb5&4M!NHM!0`2OEO_ zQsj+>mK2d&zX3y~5KuVQcEAP`@QRqs*dH*G34*)4YUo@eId@b3I!dM|g|Vs^42CePPvaSC@%w%uOzm~T(!vogN%pMvcNq^> zX#|1U3Pey3=dLs(L463$uztNn=0TR=E*EsPB*yKyUruXgXh?Q9RZx5Jx$}Qs%#mKt zwx3;<_oRQe`O49i_3LVHz|l+UaLYQsDZr;7S$hPtvn=et@q$^#gYgN=r^vo50lfUw z;AM5Q8#4FXP<;YQ>Da#gD=(LuOQ&V$$o`j8|Wa8dva0a zUtt4m4R&RP;v}o2WH|MEPW5i;%sp-`>fZd4r2r@oE)L2In|kI#&P|{~&K{&L(+MmDrg-FJD?;j{j#l6JbZLHxskAfg0|d-?_)6zC)a43c}XOBXNEMuUmIVV9e=9 zh=AZvcj5n=-pBX~YPpdt!L1oA~exV`~a}OJ#x}>Fw?3EzH5bB)O)Z1vr^YO zJC(I6`kV%oUPBGR3jfzqz*Wv5Pff36IX2Ldi?GlDEd#P5708JlJB)Z26Den zLf{sgR{dTrVlpN7X|$37`)FmPT54PzO9p*2C6;cx{x7|dPFeOM*suDEIevZ>|#mv671mR8{&6Ci!n$p%@Jr^epV` zeF4 z`=dMgYSUn_+sTVejKy&w4Y)`9>)bJ}>0HQ*Lt-G`;yfup9#&GYMsbeu4V+=pwXrHo za_V?!1|7R2qci4k!A{eQ(dTI>+oYgvt0ydi;O3`Ko-4(RLs5U)E=2{LC%6R7By}5n zu{Zf`;611=E!YuE+F8fLllG^ic&G7Wplb7^;*}$$P~-ZQ9J?B=5yf4}q4L8}kC$eT zAQRR89Cy$vef+beKh-!b5)OGQ;`$K{CGzrl6vvmbcyD&D+H4iM0CYL5yNlm>1R=e) z66rDJW~;9$O@55`K1{myj`XJk@-t{$<*nv8hb&(aY zn^{k@9@@q+<9L7n{^RW|5xM4Qm?ce5_q#arS4c}R8R3-nF6dIOHal=w>_K3XRNQy& zhvx;btwG;f_$1bF#hJXi1 zNOTlG^?=T01esM;{BR86g8;1GLU4pIE)E<7Qrp!2*h*-#ZgYjN2Z(u|X12*pM*VhD++DHf}YJS^-fWX0KMzm)B{;Np0JD&Zh_lE zMrieW>`IKiVg^wFIhG^`P^O%T!fX^x%jd^*0G`d?wlPkWoP!BKVx5tK*4>(?h?Wpd`2 z9?HwxJEo7mE@f6Fv@^-TCK;6=)xfpp5T;?+hM zJgR^@knVwR;hSMxA;dyzvJkfsynSgO&S`KL5{81R4X|CKm$q;S9Bb|wyF{Zk4v8;h zuN@za5~oBT+e)Xij_<-eT^Ou4+Wo!S09m19m-lqxb-eRQfmP$)I<3Uiwz@BPWr}?@ zgoF{9?7JJKhL5;CN5wMOoEu|01S80eS?SH(1I z7Q*=-x`1N&_pKwu%*^xdz?I~1L;ySsw4Ht@LI+8b?COek>ho;bn1A|@$TnyR%iO}l zw_Tj0&r`aluJvtMr^X^Yj*s12BSjx#*xdi0N9CYpVjsV-zERhF;{>OQQ&5>jkkQIX zY0iV!8mOabV5#uar+2jHvTvkgC#2>XjVx^62V>lRmp^Z<*V(BD50Dn0&VCW*gycf% zi2F8CVU<3Y7X+h*Rurp?L>A52vfcRmF_^@=JppMAD6k|1k_VU7O(ik~8x(^Vh~KzT ztEbopX)9=2AOe>Qe3-YWTA+qudLV$Uu8TE@ZUUkULD;yAET?dtn1}KDD*nG^V`?Uz*GD;OFnVulze~e>-x2ery#8Zr!?CossZj zOH+TR`O)d6Xk&x0SUk^R;rlI`2;Y?$>u5VqB7af^v#WE!q1)yew-wdSqvv6tH1WCvWcEg4`uJwqq`n|%vIIFwC7HneIh#onIOr23UT<;~Jm%M* z{>7hS;nGElT^VhE6x7X>#vT|gec~(n5+gLDMSMDk==K!G`n$RXm1kGecJDjv64b-9 zyG?_E63oNX7dr&qcK^Y96&n_ zoJv=f|GDHK`VWb~9{HqmsDOugu1-bdpIZ-nBKz;K3m}0T@I(AvIoyBO`>qiF&(%XA z(68Rm-GEM#)PNio0~s=J^k2z9IugX5xni`k$?LQA zcxMN56*h;Dw|c#6g6RQ0Ws?{Ht$d<{pHdHP_|YxhXI~zl1ihL3anpp> zlG!8I*cZ;aRJ`Z32UxljG8VN#Al0mx2Q3g&Bwqw}5zq;+CWoOx)JCw`50H_Amh5`R zqWH*`oC#C3cOkT+0U048t>~CPDIZ0|n0S#d19;Bm@m8lczPs?ILp0{ zx@hi%hirC>LW*{WT1ab%R0&1uSlEKPQ^jS9x@3VL?OISB@021Q*tN0U7 z9$*Nc&bqToUg<8ZuOE|LoSTyu6&1z0`uG%Gx^m^^cmi8~QIUfWtV{9s@X!dIXnQnR zS68=ecsO9@Q;IynIQOhKo@;G=T`t8K(_5W%N|M9m1In|!qGEj{E-vo0q$-A(7tud4 zsxaePJohR)+x7F**mXxg$Z4(j^YQV~y*AM{AIBqIF$#&J2Y7gRBF+_9HIjH|KP)!E zc8R0;#l=?_=I6=3=;xT5nSC6CB)n-dx#r6lR$C;*&fY#=1bZOPkZ*2ouH^gIuLo!6 z=gXtfi7-)lN`g|D^KYsZkdmZS=C~@>uJ&rnCXU=|g>ku@oSX=0X2ue7&l|g!R#$_* zG&Ja)JN&3h!t(-rE_drleF=MBJSDO;by$Q29Mc&a8mgX*mrlk^!Coc_@KJwgCa%4` z{XX20N8rO}Wm8~>7VYzy|y+t6}#mnL}qQgdFT!u_T6R;-IXA24A7Fak{} z(am-*JpoMQ@H&rom$Tv;_5r0yYOr20^Oe{s<=&0RMFyaUw9w0@r8J_W&_E6W05=X< z1SWzw0sSl3Fk=<(upz+2P=sII z)|C;wP6QkFw~$iXXBA)7lJ4J>LSM8~OG`^m#DQCf5jN5psQpOLc86ZY5q2urf%Tsa zQ_OK=WN9=q`bY`_*qozKC?zK0vG`IRRy~czv6V3VG8(vYis}x_6`Ve+Tze`0AB-bB zDS#Wdboqmzm=+SLG}C#3wy1UeOk}vzj}rgdeI=1;gpSosD#f%rcf@IRD zO&Q-J54agwn_d7nyO2h3n$EDObe?DYIZB-DBaW^AjC{%+?~^VlqLRr{d!*AjU00DY z8tBQeHh47L9rjzTd-hMn5kfX9?v~TFM1`tP(s8W!lTVZ(fgY6yMP%fF4gfX!PD!B=Jo3pql8W&Vf^F;vUoi zb^w%8!F)sm?g*j(^_6D)YX#X&kDK2_m`aybOYVFn$#+w_jd+2xHp1f%>p*m)%8=2w zc5ZUadP{e36Tu;v%i*&oM-v-)kduWGh>=+J&T;C?+xK*C$U0 z{a+&Aj)($hT}0+yg92nxqW7Y01B|A5NE?(*cH*?F$;s1Lya9>~7j``wJYp-mL$Ns4z8E*N@W{eI~}&Bfc6X;ZZSr~1SE zSd%0v3|;A;1|u19N;OLq5@kgIqZ)Ke^`(TcBw~*=Yg=$Utm1u9Ur)P^N$BATK8#T6 zAo-(jqQS2Z)z$WrYerr#)r*cEE`T=rBL;M`V3E4GwV$02g|%j(!ct{1B4}b=KZV=d;0F1^2 z5`WPUKmtIgG!fXb1tli|nDC6Dh<0e6;E;Eda%y`9gGh(cfiIi?yzjO}AV5pN(M*3i zgnW!{HZ*^%dI%P(12;ScS~07a&w(tB0dz`&;<@nl%V$rX44yzf{3Y|$^wV|6GfA+) z$br1PJhMfHM>Afy7ET08POf)#wVeLGq%3zFiWtmS`u@G<$-|FMVy-!cTnY~U{%Q-l zv6Q(FdyA+NnB!3z{=9|OUl|hI!H`6RfJEn(;2h?<0HRXGKPcZatG1OyWo4xWOB)#(IW=_O@bG;) zLA?mZFK%$cvw{KwgU62@TXw^!@^z9P=R{*1QQ@T{nwRlYBdQ-7gxz^+Ih|z@Yp^R7 zJuHK{5>;*OA{*2sugO^zL51X1^(0-X0#t&pv?N8px0{)TB^kwrxgFBHs!ckA0U%RG zFy0yyZh7_`KBhiZw;t1b|BFZYvqeR6ECVRj-EXp;k#jfaOJqW4pB#so$pSU;r1S7$ zM*w7!RtI`1p>-Y0CInh??wy1_3IMSe5HhxGU09VbeVD0Y2Ob!B5_8(W{E)kmf}C|$FnRshA*@=2`|oE|HB zMPapO1wOBUn1fF;3$TDH53InVRy28&FmfdVzi#Pq&9P-`TVY^SSC7eA_%-9do2M&l zqX5_se%(+Ul6kUzDNwTEE2&|99U%wiE`M}iCXB){Tq;>Z<(@nX3}6YT_Vp5OCL7kv zl18yd9`t6%FSu`ucyHMeSsq0A1qW9Y*VJU-OAU`beVo(IkpeCgw-hMfzh2y|s7P4b zs@L1u+*_MyB++H`DoeiTsN~G_?Lu&wE%wsGXkQ;uy&rc!y8QLt$vp9=5=?r>$1~p; zC5=i=>2ECF?ul*@-ebe}BO@6fJ!J><_%(RM=<683)*+cd^I@RE#Jc@46hj|YDA&)l z@{BD%PSs$HRVg;J?>+ve`JS7_x&t#BU93r9F8M6CB95^kQjfVKMwbOgb`=GwngHhv zzstwM^g!&@M=*~6PYD_|0nm14Da9gW`Fsh z%|bhlak2^5Fy9#4*VaNM7em8bYVszhDks5YJ2vNxVYVgDf>avuod`kzaNRaj_ZxM{ zFDaqD&M`|;Ga)`}U6+z{O#Z5_q0uG7`r zd5H%ewSw21V~lHmr09mlu>l;%W3e7xzzvUx#hK9+gGm1j*SM#s7@{q1D(qs<>iYV+ zD3jS3Ic3F(?HRQZ`!3;f7JnF`_bO{!L4;Ek2BWl|+W-aeXd*!U{F-GTo$>|cn? zQ{NzyoqJYGu14*g?OAlJ%+6ThxPlaKYW;sc{x@m zToY+rzg+tvbB1O`8FXScQylzL$ZRc6zbxm8&uyXuTrh-!z75XUnL!N!4h0^ZvTIwY zj2(_vs7K-$L8+y*BWO^8hhV%4&+@UzSkR#2@%V;)9)5oNG9a;{pCMtT{!br)v5xkp zo8mqmuuY(>RWgjxKD`gTLBc|WJ|<$iweijyTI;tlCUY8bFO6S=Qi6V~<-h&5TUSVf zl5RQGe?yU<-J#|~#Fo$as!#ns%#EQ0*Ea+HJ*z&gGwxblv@=fgoZ1g*PGtvMX^&dh zpd|gGyhBnyU#@piKtkEm{WX00tIlwc2>*7kYj@h;dua?u0zM3JR&~zP4`5E38x|Wl G-~10fwS(yZ diff --git a/subprojects/nk_pugl/nuklear/example/stb_image.h b/subprojects/nk_pugl/nuklear/example/stb_image.h deleted file mode 100644 index 0a9de39..0000000 --- a/subprojects/nk_pugl/nuklear/example/stb_image.h +++ /dev/null @@ -1,6509 +0,0 @@ -/* stb_image - v2.08 - public domain image loader - http://nothings.org/stb_image.h - no warranty implied; use at your own risk - - Do this: - #define STB_IMAGE_IMPLEMENTATION - before you include this file in *one* C or C++ file to create the implementation. - - // i.e. it should look like this: - #include ... - #include ... - #include ... - #define STB_IMAGE_IMPLEMENTATION - #include "stb_image.h" - - You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. - And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free - - - QUICK NOTES: - Primarily of interest to game developers and other people who can - avoid problematic images and only need the trivial interface - - JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) - PNG 1/2/4/8-bit-per-channel (16 bpc not supported) - - TGA (not sure what subset, if a subset) - BMP non-1bpp, non-RLE - PSD (composited view only, no extra channels, 8/16 bit-per-channel) - - GIF (*comp always reports as 4-channel) - HDR (radiance rgbE format) - PIC (Softimage PIC) - PNM (PPM and PGM binary only) - - Animated GIF still needs a proper API, but here's one way to do it: - http://gist.github.com/urraka/685d9a6340b26b830d49 - - - decode from memory or through FILE (define STBI_NO_STDIO to remove code) - - decode from arbitrary I/O callbacks - - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) - - Full documentation under "DOCUMENTATION" below. - - - Revision 2.00 release notes: - - - Progressive JPEG is now supported. - - - PPM and PGM binary formats are now supported, thanks to Ken Miller. - - - x86 platforms now make use of SSE2 SIMD instructions for - JPEG decoding, and ARM platforms can use NEON SIMD if requested. - This work was done by Fabian "ryg" Giesen. SSE2 is used by - default, but NEON must be enabled explicitly; see docs. - - With other JPEG optimizations included in this version, we see - 2x speedup on a JPEG on an x86 machine, and a 1.5x speedup - on a JPEG on an ARM machine, relative to previous versions of this - library. The same results will not obtain for all JPGs and for all - x86/ARM machines. (Note that progressive JPEGs are significantly - slower to decode than regular JPEGs.) This doesn't mean that this - is the fastest JPEG decoder in the land; rather, it brings it - closer to parity with standard libraries. If you want the fastest - decode, look elsewhere. (See "Philosophy" section of docs below.) - - See final bullet items below for more info on SIMD. - - - Added STBI_MALLOC, STBI_REALLOC, and STBI_FREE macros for replacing - the memory allocator. Unlike other STBI libraries, these macros don't - support a context parameter, so if you need to pass a context in to - the allocator, you'll have to store it in a global or a thread-local - variable. - - - Split existing STBI_NO_HDR flag into two flags, STBI_NO_HDR and - STBI_NO_LINEAR. - STBI_NO_HDR: suppress implementation of .hdr reader format - STBI_NO_LINEAR: suppress high-dynamic-range light-linear float API - - - You can suppress implementation of any of the decoders to reduce - your code footprint by #defining one or more of the following - symbols before creating the implementation. - - STBI_NO_JPEG - STBI_NO_PNG - STBI_NO_BMP - STBI_NO_PSD - STBI_NO_TGA - STBI_NO_GIF - STBI_NO_HDR - STBI_NO_PIC - STBI_NO_PNM (.ppm and .pgm) - - - You can request *only* certain decoders and suppress all other ones - (this will be more forward-compatible, as addition of new decoders - doesn't require you to disable them explicitly): - - STBI_ONLY_JPEG - STBI_ONLY_PNG - STBI_ONLY_BMP - STBI_ONLY_PSD - STBI_ONLY_TGA - STBI_ONLY_GIF - STBI_ONLY_HDR - STBI_ONLY_PIC - STBI_ONLY_PNM (.ppm and .pgm) - - Note that you can define multiples of these, and you will get all - of them ("only x" and "only y" is interpreted to mean "only x&y"). - - - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still - want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB - - - Compilation of all SIMD code can be suppressed with - #define STBI_NO_SIMD - It should not be necessary to disable SIMD unless you have issues - compiling (e.g. using an x86 compiler which doesn't support SSE - intrinsics or that doesn't support the method used to detect - SSE2 support at run-time), and even those can be reported as - bugs so I can refine the built-in compile-time checking to be - smarter. - - - The old STBI_SIMD system which allowed installing a user-defined - IDCT etc. has been removed. If you need this, don't upgrade. My - assumption is that almost nobody was doing this, and those who - were will find the built-in SIMD more satisfactory anyway. - - - RGB values computed for JPEG images are slightly different from - previous versions of stb_image. (This is due to using less - integer precision in SIMD.) The C code has been adjusted so - that the same RGB values will be computed regardless of whether - SIMD support is available, so your app should always produce - consistent results. But these results are slightly different from - previous versions. (Specifically, about 3% of available YCbCr values - will compute different RGB results from pre-1.49 versions by +-1; - most of the deviating values are one smaller in the G channel.) - - - If you must produce consistent results with previous versions of - stb_image, #define STBI_JPEG_OLD and you will get the same results - you used to; however, you will not get the SIMD speedups for - the YCbCr-to-RGB conversion step (although you should still see - significant JPEG speedup from the other changes). - - Please note that STBI_JPEG_OLD is a temporary feature; it will be - removed in future versions of the library. It is only intended for - near-term back-compatibility use. - - - Latest revision history: - 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA - 2.07 (2015-09-13) partial animated GIF support - limited 16-bit PSD support - minor bugs, code cleanup, and compiler warnings - 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value - 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning - 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit - 2.03 (2015-04-12) additional corruption checking - stbi_set_flip_vertically_on_load - fix NEON support; fix mingw support - 2.02 (2015-01-19) fix incorrect assert, fix warning - 2.01 (2015-01-17) fix various warnings - 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG - 2.00 (2014-12-25) optimize JPEG, including x86 SSE2 & ARM NEON SIMD - progressive JPEG - PGM/PPM support - STBI_MALLOC,STBI_REALLOC,STBI_FREE - STBI_NO_*, STBI_ONLY_* - GIF bugfix - 1.48 (2014-12-14) fix incorrectly-named assert() - 1.47 (2014-12-14) 1/2/4-bit PNG support (both grayscale and paletted) - optimize PNG - fix bug in interlaced PNG with user-specified channel count - - See end of file for full revision history. - - - ============================ Contributors ========================= - - Image formats Bug fixes & warning fixes - Sean Barrett (jpeg, png, bmp) Marc LeBlanc - Nicolas Schulz (hdr, psd) Christpher Lloyd - Jonathan Dummer (tga) Dave Moore - Jean-Marc Lienher (gif) Won Chun - Tom Seddon (pic) the Horde3D community - Thatcher Ulrich (psd) Janez Zemva - Ken Miller (pgm, ppm) Jonathan Blow - urraka@github (animated gif) Laurent Gomila - Aruelien Pocheville - Ryamond Barbiero - David Woo - Extensions, features Martin Golini - Jetro Lauha (stbi_info) Roy Eltham - Martin "SpartanJ" Golini (stbi_info) Luke Graham - James "moose2000" Brown (iPhone PNG) Thomas Ruf - Ben "Disch" Wenger (io callbacks) John Bartholomew - Omar Cornut (1/2/4-bit PNG) Ken Hamada - Nicolas Guillemot (vertical flip) Cort Stratton - Richard Mitton (16-bit PSD) Blazej Dariusz Roszkowski - Thibault Reuille - Paul Du Bois - Guillaume George - Jerry Jansson - Hayaki Saito - Johan Duparc - Ronny Chevalier - Optimizations & bugfixes Michal Cichon - Fabian "ryg" Giesen Tero Hanninen - Arseny Kapoulkine Sergio Gonzalez - Cass Everitt - Engin Manap - If your name should be here but Martins Mozeiko - isn't, let Sean know. Joseph Thomson - Phil Jordan - Nathan Reed - Michaelangel007@github - Nick Verigakis - -LICENSE - -This software is in the public domain. Where that dedication is not -recognized, you are granted a perpetual, irrevocable license to copy, -distribute, and modify this file as you see fit. - -*/ - -#ifndef STBI_INCLUDE_STB_IMAGE_H -#define STBI_INCLUDE_STB_IMAGE_H - -// DOCUMENTATION -// -// Limitations: -// - no 16-bit-per-channel PNG -// - no 12-bit-per-channel JPEG -// - no JPEGs with arithmetic coding -// - no 1-bit BMP -// - GIF always returns *comp=4 -// -// Basic usage (see HDR discussion below for HDR usage): -// int x,y,n; -// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); -// // ... process data if not NULL ... -// // ... x = width, y = height, n = # 8-bit components per pixel ... -// // ... replace '0' with '1'..'4' to force that many components per pixel -// // ... but 'n' will always be the number that it would have been if you said 0 -// stbi_image_free(data) -// -// Standard parameters: -// int *x -- outputs image width in pixels -// int *y -- outputs image height in pixels -// int *comp -- outputs # of image components in image file -// int req_comp -- if non-zero, # of image components requested in result -// -// The return value from an image loader is an 'unsigned char *' which points -// to the pixel data, or NULL on an allocation failure or if the image is -// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, -// with each pixel consisting of N interleaved 8-bit components; the first -// pixel pointed to is top-left-most in the image. There is no padding between -// image scanlines or between pixels, regardless of format. The number of -// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise. -// If req_comp is non-zero, *comp has the number of components that _would_ -// have been output otherwise. E.g. if you set req_comp to 4, you will always -// get RGBA output, but you can check *comp to see if it's trivially opaque -// because e.g. there were only 3 channels in the source image. -// -// An output image with N components has the following components interleaved -// in this order in each pixel: -// -// N=#comp components -// 1 grey -// 2 grey, alpha -// 3 red, green, blue -// 4 red, green, blue, alpha -// -// If image loading fails for any reason, the return value will be NULL, -// and *x, *y, *comp will be unchanged. The function stbi_failure_reason() -// can be queried for an extremely brief, end-user unfriendly explanation -// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid -// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly -// more user-friendly ones. -// -// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. -// -// =========================================================================== -// -// Philosophy -// -// stb libraries are designed with the following priorities: -// -// 1. easy to use -// 2. easy to maintain -// 3. good performance -// -// Sometimes I let "good performance" creep up in priority over "easy to maintain", -// and for best performance I may provide less-easy-to-use APIs that give higher -// performance, in addition to the easy to use ones. Nevertheless, it's important -// to keep in mind that from the standpoint of you, a client of this library, -// all you care about is #1 and #3, and stb libraries do not emphasize #3 above all. -// -// Some secondary priorities arise directly from the first two, some of which -// make more explicit reasons why performance can't be emphasized. -// -// - Portable ("ease of use") -// - Small footprint ("easy to maintain") -// - No dependencies ("ease of use") -// -// =========================================================================== -// -// I/O callbacks -// -// I/O callbacks allow you to read from arbitrary sources, like packaged -// files or some other source. Data read from callbacks are processed -// through a small internal buffer (currently 128 bytes) to try to reduce -// overhead. -// -// The three functions you must define are "read" (reads some bytes of data), -// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). -// -// =========================================================================== -// -// SIMD support -// -// The JPEG decoder will try to automatically use SIMD kernels on x86 when -// supported by the compiler. For ARM Neon support, you must explicitly -// request it. -// -// (The old do-it-yourself SIMD API is no longer supported in the current -// code.) -// -// On x86, SSE2 will automatically be used when available based on a run-time -// test; if not, the generic C versions are used as a fall-back. On ARM targets, -// the typical path is to have separate builds for NEON and non-NEON devices -// (at least this is true for iOS and Android). Therefore, the NEON support is -// toggled by a build flag: define STBI_NEON to get NEON loops. -// -// The output of the JPEG decoder is slightly different from versions where -// SIMD support was introduced (that is, for versions before 1.49). The -// difference is only +-1 in the 8-bit RGB channels, and only on a small -// fraction of pixels. You can force the pre-1.49 behavior by defining -// STBI_JPEG_OLD, but this will disable some of the SIMD decoding path -// and hence cost some performance. -// -// If for some reason you do not want to use any of SIMD code, or if -// you have issues compiling it, you can disable it entirely by -// defining STBI_NO_SIMD. -// -// =========================================================================== -// -// HDR image support (disable by defining STBI_NO_HDR) -// -// stb_image now supports loading HDR images in general, and currently -// the Radiance .HDR file format, although the support is provided -// generically. You can still load any file through the existing interface; -// if you attempt to load an HDR file, it will be automatically remapped to -// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; -// both of these constants can be reconfigured through this interface: -// -// stbi_hdr_to_ldr_gamma(2.2f); -// stbi_hdr_to_ldr_scale(1.0f); -// -// (note, do not use _inverse_ constants; stbi_image will invert them -// appropriately). -// -// Additionally, there is a new, parallel interface for loading files as -// (linear) floats to preserve the full dynamic range: -// -// float *data = stbi_loadf(filename, &x, &y, &n, 0); -// -// If you load LDR images through this interface, those images will -// be promoted to floating point values, run through the inverse of -// constants corresponding to the above: -// -// stbi_ldr_to_hdr_scale(1.0f); -// stbi_ldr_to_hdr_gamma(2.2f); -// -// Finally, given a filename (or an open file or memory block--see header -// file for details) containing image data, you can query for the "most -// appropriate" interface to use (that is, whether the image is HDR or -// not), using: -// -// stbi_is_hdr(char *filename); -// -// =========================================================================== -// -// iPhone PNG support: -// -// By default we convert iphone-formatted PNGs back to RGB, even though -// they are internally encoded differently. You can disable this conversion -// by by calling stbi_convert_iphone_png_to_rgb(0), in which case -// you will always just get the native iphone "format" through (which -// is BGR stored in RGB). -// -// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per -// pixel to remove any premultiplied alpha *only* if the image file explicitly -// says there's premultiplied data (currently only happens in iPhone images, -// and only if iPhone convert-to-rgb processing is on). -// - - -#ifndef STBI_NO_STDIO -#include -#endif // STBI_NO_STDIO - -#define STBI_VERSION 1 - -enum -{ - STBI_default = 0, // only used for req_comp - - STBI_grey = 1, - STBI_grey_alpha = 2, - STBI_rgb = 3, - STBI_rgb_alpha = 4 -}; - -typedef unsigned char stbi_uc; - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef STB_IMAGE_STATIC -#define STBIDEF static -#else -#define STBIDEF extern -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// PRIMARY API - works on images of any type -// - -// -// load image by filename, open file, or memory buffer -// - -typedef struct -{ - int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read - void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative - int (*eof) (void *user); // returns nonzero if we are at end of file/data -} stbi_io_callbacks; - -STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp); -STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *comp, int req_comp); -STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *comp, int req_comp); - -#ifndef STBI_NO_STDIO -STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); -// for stbi_load_from_file, file pointer is left pointing immediately after image -#endif - -#ifndef STBI_NO_LINEAR - STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp); - STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); - STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); - - #ifndef STBI_NO_STDIO - STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); - #endif -#endif - -#ifndef STBI_NO_HDR - STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); - STBIDEF void stbi_hdr_to_ldr_scale(float scale); -#endif - -#ifndef STBI_NO_LINEAR - STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); - STBIDEF void stbi_ldr_to_hdr_scale(float scale); -#endif // STBI_NO_HDR - -// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR -STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); -STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); -#ifndef STBI_NO_STDIO -STBIDEF int stbi_is_hdr (char const *filename); -STBIDEF int stbi_is_hdr_from_file(FILE *f); -#endif // STBI_NO_STDIO - - -// get a VERY brief reason for failure -// NOT THREADSAFE -STBIDEF const char *stbi_failure_reason (void); - -// free the loaded image -- this is just free() -STBIDEF void stbi_image_free (void *retval_from_stbi_load); - -// get image dimensions & components without fully decoding -STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); -STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); - -#ifndef STBI_NO_STDIO -STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); -STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); - -#endif - - - -// for image formats that explicitly notate that they have premultiplied alpha, -// we just return the colors as stored in the file. set this flag to force -// unpremultiplication. results are undefined if the unpremultiply overflow. -STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); - -// indicate whether we should process iphone images back to canonical format, -// or just pass them through "as-is" -STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); - -// flip the image vertically, so the first pixel in the output array is the bottom left -STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); - -// ZLIB client - used by PNG, available for other purposes - -STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); -STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); -STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); -STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); - -STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); -STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); - - -#ifdef __cplusplus -} -#endif - -// -// -//// end header file ///////////////////////////////////////////////////// -#endif // STBI_INCLUDE_STB_IMAGE_H - -#ifdef STB_IMAGE_IMPLEMENTATION - -#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ - || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ - || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ - || defined(STBI_ONLY_ZLIB) - #ifndef STBI_ONLY_JPEG - #define STBI_NO_JPEG - #endif - #ifndef STBI_ONLY_PNG - #define STBI_NO_PNG - #endif - #ifndef STBI_ONLY_BMP - #define STBI_NO_BMP - #endif - #ifndef STBI_ONLY_PSD - #define STBI_NO_PSD - #endif - #ifndef STBI_ONLY_TGA - #define STBI_NO_TGA - #endif - #ifndef STBI_ONLY_GIF - #define STBI_NO_GIF - #endif - #ifndef STBI_ONLY_HDR - #define STBI_NO_HDR - #endif - #ifndef STBI_ONLY_PIC - #define STBI_NO_PIC - #endif - #ifndef STBI_ONLY_PNM - #define STBI_NO_PNM - #endif -#endif - -#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) -#define STBI_NO_ZLIB -#endif - - -#include -#include // ptrdiff_t on osx -#include -#include - -#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) -#include // ldexp -#endif - -#ifndef STBI_NO_STDIO -#include -#endif - -#ifndef STBI_ASSERT -#include -#define STBI_ASSERT(x) assert(x) -#endif - - -#ifndef _MSC_VER - #ifdef __cplusplus - #define stbi_inline inline - #else - #define stbi_inline - #endif -#else - #define stbi_inline __forceinline -#endif - - -#ifdef _MSC_VER -typedef unsigned short stbi__uint16; -typedef signed short stbi__int16; -typedef unsigned int stbi__uint32; -typedef signed int stbi__int32; -#else -#include -typedef uint16_t stbi__uint16; -typedef int16_t stbi__int16; -typedef uint32_t stbi__uint32; -typedef int32_t stbi__int32; -#endif - -// should produce compiler error if size is wrong -typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; - -#ifdef _MSC_VER -#define STBI_NOTUSED(v) (void)(v) -#else -#define STBI_NOTUSED(v) (void)sizeof(v) -#endif - -#ifdef _MSC_VER -#define STBI_HAS_LROTL -#endif - -#ifdef STBI_HAS_LROTL - #define stbi_lrot(x,y) _lrotl(x,y) -#else - #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) -#endif - -#if defined(STBI_MALLOC) && defined(STBI_FREE) && defined(STBI_REALLOC) -// ok -#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) -// ok -#else -#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC." -#endif - -#ifndef STBI_MALLOC -#define STBI_MALLOC(sz) malloc(sz) -#define STBI_REALLOC(p,sz) realloc(p,sz) -#define STBI_FREE(p) free(p) -#endif - -// x86/x64 detection -#if defined(__x86_64__) || defined(_M_X64) -#define STBI__X64_TARGET -#elif defined(__i386) || defined(_M_IX86) -#define STBI__X86_TARGET -#endif - -#if defined(__GNUC__) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) -// NOTE: not clear do we actually need this for the 64-bit path? -// gcc doesn't support sse2 intrinsics unless you compile with -msse2, -// (but compiling with -msse2 allows the compiler to use SSE2 everywhere; -// this is just broken and gcc are jerks for not fixing it properly -// http://www.virtualdub.org/blog/pivot/entry.php?id=363 ) -#define STBI_NO_SIMD -#endif - -#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) -// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET -// -// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the -// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. -// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not -// simultaneously enabling "-mstackrealign". -// -// See https://github.com/nothings/stb/issues/81 for more information. -// -// So default to no SSE2 on 32-bit MinGW. If you've read this far and added -// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. -#define STBI_NO_SIMD -#endif - -#if !defined(STBI_NO_SIMD) && defined(STBI__X86_TARGET) -#define STBI_SSE2 -#include - -#ifdef _MSC_VER - -#if _MSC_VER >= 1400 // not VC6 -#include // __cpuid -static int stbi__cpuid3(void) -{ - int info[4]; - __cpuid(info,1); - return info[3]; -} -#else -static int stbi__cpuid3(void) -{ - int res; - __asm { - mov eax,1 - cpuid - mov res,edx - } - return res; -} -#endif - -#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name - -static int stbi__sse2_available() -{ - int info3 = stbi__cpuid3(); - return ((info3 >> 26) & 1) != 0; -} -#else // assume GCC-style if not VC++ -#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) - -static int stbi__sse2_available() -{ -#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 // GCC 4.8 or later - // GCC 4.8+ has a nice way to do this - return __builtin_cpu_supports("sse2"); -#else - // portable way to do this, preferably without using GCC inline ASM? - // just bail for now. - return 0; -#endif -} -#endif -#endif - -// ARM NEON -#if defined(STBI_NO_SIMD) && defined(STBI_NEON) -#undef STBI_NEON -#endif - -#ifdef STBI_NEON -#include -// assume GCC or Clang on ARM targets -#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) -#endif - -#ifndef STBI_SIMD_ALIGN -#define STBI_SIMD_ALIGN(type, name) type name -#endif - -/////////////////////////////////////////////// -// -// stbi__context struct and start_xxx functions - -// stbi__context structure is our basic context used by all images, so it -// contains all the IO context, plus some basic image information -typedef struct -{ - stbi__uint32 img_x, img_y; - int img_n, img_out_n; - - stbi_io_callbacks io; - void *io_user_data; - - int read_from_callbacks; - int buflen; - stbi_uc buffer_start[128]; - - stbi_uc *img_buffer, *img_buffer_end; - stbi_uc *img_buffer_original, *img_buffer_original_end; -} stbi__context; - - -static void stbi__refill_buffer(stbi__context *s); - -// initialize a memory-decode context -static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) -{ - s->io.read = NULL; - s->read_from_callbacks = 0; - s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; - s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; -} - -// initialize a callback-based context -static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) -{ - s->io = *c; - s->io_user_data = user; - s->buflen = sizeof(s->buffer_start); - s->read_from_callbacks = 1; - s->img_buffer_original = s->buffer_start; - stbi__refill_buffer(s); - s->img_buffer_original_end = s->img_buffer_end; -} - -#ifndef STBI_NO_STDIO - -static int stbi__stdio_read(void *user, char *data, int size) -{ - return (int) fread(data,1,size,(FILE*) user); -} - -static void stbi__stdio_skip(void *user, int n) -{ - fseek((FILE*) user, n, SEEK_CUR); -} - -static int stbi__stdio_eof(void *user) -{ - return feof((FILE*) user); -} - -static stbi_io_callbacks stbi__stdio_callbacks = -{ - stbi__stdio_read, - stbi__stdio_skip, - stbi__stdio_eof, -}; - -static void stbi__start_file(stbi__context *s, FILE *f) -{ - stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); -} - -//static void stop_file(stbi__context *s) { } - -#endif // !STBI_NO_STDIO - -static void stbi__rewind(stbi__context *s) -{ - // conceptually rewind SHOULD rewind to the beginning of the stream, - // but we just rewind to the beginning of the initial buffer, because - // we only use it after doing 'test', which only ever looks at at most 92 bytes - s->img_buffer = s->img_buffer_original; - s->img_buffer_end = s->img_buffer_original_end; -} - -#ifndef STBI_NO_JPEG -static int stbi__jpeg_test(stbi__context *s); -static stbi_uc *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_PNG -static int stbi__png_test(stbi__context *s); -static stbi_uc *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_BMP -static int stbi__bmp_test(stbi__context *s); -static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_TGA -static int stbi__tga_test(stbi__context *s); -static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_PSD -static int stbi__psd_test(stbi__context *s); -static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_HDR -static int stbi__hdr_test(stbi__context *s); -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_PIC -static int stbi__pic_test(stbi__context *s); -static stbi_uc *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_GIF -static int stbi__gif_test(stbi__context *s); -static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_PNM -static int stbi__pnm_test(stbi__context *s); -static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -// this is not threadsafe -static const char *stbi__g_failure_reason; - -STBIDEF const char *stbi_failure_reason(void) -{ - return stbi__g_failure_reason; -} - -static int stbi__err(const char *str) -{ - stbi__g_failure_reason = str; - return 0; -} - -static void *stbi__malloc(size_t size) -{ - return STBI_MALLOC(size); -} - -// stbi__err - error -// stbi__errpf - error returning pointer to float -// stbi__errpuc - error returning pointer to unsigned char - -#ifdef STBI_NO_FAILURE_STRINGS - #define stbi__err(x,y) 0 -#elif defined(STBI_FAILURE_USERMSG) - #define stbi__err(x,y) stbi__err(y) -#else - #define stbi__err(x,y) stbi__err(x) -#endif - -#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) -#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) - -STBIDEF void stbi_image_free(void *retval_from_stbi_load) -{ - STBI_FREE(retval_from_stbi_load); -} - -#ifndef STBI_NO_LINEAR -static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); -#endif - -#ifndef STBI_NO_HDR -static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); -#endif - -static int stbi__vertically_flip_on_load = 0; - -STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) -{ - stbi__vertically_flip_on_load = flag_true_if_should_flip; -} - -static unsigned char *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - #ifndef STBI_NO_JPEG - if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp); - #endif - #ifndef STBI_NO_PNG - if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp); - #endif - #ifndef STBI_NO_BMP - if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp); - #endif - #ifndef STBI_NO_GIF - if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp); - #endif - #ifndef STBI_NO_PSD - if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp); - #endif - #ifndef STBI_NO_PIC - if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp); - #endif - #ifndef STBI_NO_PNM - if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp); - #endif - - #ifndef STBI_NO_HDR - if (stbi__hdr_test(s)) { - float *hdr = stbi__hdr_load(s, x,y,comp,req_comp); - return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); - } - #endif - - #ifndef STBI_NO_TGA - // test tga last because it's a crappy test! - if (stbi__tga_test(s)) - return stbi__tga_load(s,x,y,comp,req_comp); - #endif - - return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); -} - -static unsigned char *stbi__load_flip(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *result = stbi__load_main(s, x, y, comp, req_comp); - - if (stbi__vertically_flip_on_load && result != NULL) { - int w = *x, h = *y; - int depth = req_comp ? req_comp : *comp; - int row,col,z; - stbi_uc temp; - - // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once - for (row = 0; row < (h>>1); row++) { - for (col = 0; col < w; col++) { - for (z = 0; z < depth; z++) { - temp = result[(row * w + col) * depth + z]; - result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z]; - result[((h - row - 1) * w + col) * depth + z] = temp; - } - } - } - } - - return result; -} - -#ifndef STBI_NO_HDR -static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) -{ - if (stbi__vertically_flip_on_load && result != NULL) { - int w = *x, h = *y; - int depth = req_comp ? req_comp : *comp; - int row,col,z; - float temp; - - // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once - for (row = 0; row < (h>>1); row++) { - for (col = 0; col < w; col++) { - for (z = 0; z < depth; z++) { - temp = result[(row * w + col) * depth + z]; - result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z]; - result[((h - row - 1) * w + col) * depth + z] = temp; - } - } - } - } -} -#endif - -#ifndef STBI_NO_STDIO - -static FILE *stbi__fopen(char const *filename, char const *mode) -{ - FILE *f; -#if defined(_MSC_VER) && _MSC_VER >= 1400 - if (0 != fopen_s(&f, filename, mode)) - f=0; -#else - f = fopen(filename, mode); -#endif - return f; -} - - -STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - unsigned char *result; - if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); - result = stbi_load_from_file(f,x,y,comp,req_comp); - fclose(f); - return result; -} - -STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *result; - stbi__context s; - stbi__start_file(&s,f); - result = stbi__load_flip(&s,x,y,comp,req_comp); - if (result) { - // need to 'unget' all the characters in the IO buffer - fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); - } - return result; -} -#endif //!STBI_NO_STDIO - -STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__load_flip(&s,x,y,comp,req_comp); -} - -STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__load_flip(&s,x,y,comp,req_comp); -} - -#ifndef STBI_NO_LINEAR -static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *data; - #ifndef STBI_NO_HDR - if (stbi__hdr_test(s)) { - float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp); - if (hdr_data) - stbi__float_postprocess(hdr_data,x,y,comp,req_comp); - return hdr_data; - } - #endif - data = stbi__load_flip(s, x, y, comp, req_comp); - if (data) - return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); - return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); -} - -STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__loadf_main(&s,x,y,comp,req_comp); -} - -STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__loadf_main(&s,x,y,comp,req_comp); -} - -#ifndef STBI_NO_STDIO -STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - float *result; - FILE *f = stbi__fopen(filename, "rb"); - if (!f) return stbi__errpf("can't fopen", "Unable to open file"); - result = stbi_loadf_from_file(f,x,y,comp,req_comp); - fclose(f); - return result; -} - -STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_file(&s,f); - return stbi__loadf_main(&s,x,y,comp,req_comp); -} -#endif // !STBI_NO_STDIO - -#endif // !STBI_NO_LINEAR - -// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is -// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always -// reports false! - -STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) -{ - #ifndef STBI_NO_HDR - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__hdr_test(&s); - #else - STBI_NOTUSED(buffer); - STBI_NOTUSED(len); - return 0; - #endif -} - -#ifndef STBI_NO_STDIO -STBIDEF int stbi_is_hdr (char const *filename) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result=0; - if (f) { - result = stbi_is_hdr_from_file(f); - fclose(f); - } - return result; -} - -STBIDEF int stbi_is_hdr_from_file(FILE *f) -{ - #ifndef STBI_NO_HDR - stbi__context s; - stbi__start_file(&s,f); - return stbi__hdr_test(&s); - #else - STBI_NOTUSED(f); - return 0; - #endif -} -#endif // !STBI_NO_STDIO - -STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) -{ - #ifndef STBI_NO_HDR - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__hdr_test(&s); - #else - STBI_NOTUSED(clbk); - STBI_NOTUSED(user); - return 0; - #endif -} - -static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; -static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; - -#ifndef STBI_NO_LINEAR -STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } -STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } -#endif - -STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } -STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } - - -////////////////////////////////////////////////////////////////////////////// -// -// Common code used by all image loaders -// - -enum -{ - STBI__SCAN_load=0, - STBI__SCAN_type, - STBI__SCAN_header -}; - -static void stbi__refill_buffer(stbi__context *s) -{ - int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); - if (n == 0) { - // at end of file, treat same as if from memory, but need to handle case - // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file - s->read_from_callbacks = 0; - s->img_buffer = s->buffer_start; - s->img_buffer_end = s->buffer_start+1; - *s->img_buffer = 0; - } else { - s->img_buffer = s->buffer_start; - s->img_buffer_end = s->buffer_start + n; - } -} - -stbi_inline static stbi_uc stbi__get8(stbi__context *s) -{ - if (s->img_buffer < s->img_buffer_end) - return *s->img_buffer++; - if (s->read_from_callbacks) { - stbi__refill_buffer(s); - return *s->img_buffer++; - } - return 0; -} - -stbi_inline static int stbi__at_eof(stbi__context *s) -{ - if (s->io.read) { - if (!(s->io.eof)(s->io_user_data)) return 0; - // if feof() is true, check if buffer = end - // special case: we've only got the special 0 character at the end - if (s->read_from_callbacks == 0) return 1; - } - - return s->img_buffer >= s->img_buffer_end; -} - -static void stbi__skip(stbi__context *s, int n) -{ - if (n < 0) { - s->img_buffer = s->img_buffer_end; - return; - } - if (s->io.read) { - int blen = (int) (s->img_buffer_end - s->img_buffer); - if (blen < n) { - s->img_buffer = s->img_buffer_end; - (s->io.skip)(s->io_user_data, n - blen); - return; - } - } - s->img_buffer += n; -} - -static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) -{ - if (s->io.read) { - int blen = (int) (s->img_buffer_end - s->img_buffer); - if (blen < n) { - int res, count; - - memcpy(buffer, s->img_buffer, blen); - - count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); - res = (count == (n-blen)); - s->img_buffer = s->img_buffer_end; - return res; - } - } - - if (s->img_buffer+n <= s->img_buffer_end) { - memcpy(buffer, s->img_buffer, n); - s->img_buffer += n; - return 1; - } else - return 0; -} - -static int stbi__get16be(stbi__context *s) -{ - int z = stbi__get8(s); - return (z << 8) + stbi__get8(s); -} - -static stbi__uint32 stbi__get32be(stbi__context *s) -{ - stbi__uint32 z = stbi__get16be(s); - return (z << 16) + stbi__get16be(s); -} - -#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) -// nothing -#else -static int stbi__get16le(stbi__context *s) -{ - int z = stbi__get8(s); - return z + (stbi__get8(s) << 8); -} -#endif - -#ifndef STBI_NO_BMP -static stbi__uint32 stbi__get32le(stbi__context *s) -{ - stbi__uint32 z = stbi__get16le(s); - return z + (stbi__get16le(s) << 16); -} -#endif - -#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings - - -////////////////////////////////////////////////////////////////////////////// -// -// generic converter from built-in img_n to req_comp -// individual types do this automatically as much as possible (e.g. jpeg -// does all cases internally since it needs to colorspace convert anyway, -// and it never has alpha, so very few cases ). png can automatically -// interleave an alpha=255 channel, but falls back to this for other cases -// -// assume data buffer is malloced, so malloc a new one and free that one -// only failure mode is malloc failing - -static stbi_uc stbi__compute_y(int r, int g, int b) -{ - return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); -} - -static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) -{ - int i,j; - unsigned char *good; - - if (req_comp == img_n) return data; - STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - - good = (unsigned char *) stbi__malloc(req_comp * x * y); - if (good == NULL) { - STBI_FREE(data); - return stbi__errpuc("outofmem", "Out of memory"); - } - - for (j=0; j < (int) y; ++j) { - unsigned char *src = data + j * x * img_n ; - unsigned char *dest = good + j * x * req_comp; - - #define COMBO(a,b) ((a)*8+(b)) - #define CASE(a,b) case COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) - // convert source image with img_n components to one with req_comp components; - // avoid switch per pixel, so use switch per scanline and massive macros - switch (COMBO(img_n, req_comp)) { - CASE(1,2) dest[0]=src[0], dest[1]=255; break; - CASE(1,3) dest[0]=dest[1]=dest[2]=src[0]; break; - CASE(1,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; break; - CASE(2,1) dest[0]=src[0]; break; - CASE(2,3) dest[0]=dest[1]=dest[2]=src[0]; break; - CASE(2,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; break; - CASE(3,4) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; break; - CASE(3,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break; - CASE(3,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; break; - CASE(4,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break; - CASE(4,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; break; - CASE(4,3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break; - default: STBI_ASSERT(0); - } - #undef CASE - } - - STBI_FREE(data); - return good; -} - -#ifndef STBI_NO_LINEAR -static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) -{ - int i,k,n; - float *output = (float *) stbi__malloc(x * y * comp * sizeof(float)); - if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } - // compute number of non-alpha components - if (comp & 1) n = comp; else n = comp-1; - for (i=0; i < x*y; ++i) { - for (k=0; k < n; ++k) { - output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); - } - if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; - } - STBI_FREE(data); - return output; -} -#endif - -#ifndef STBI_NO_HDR -#define stbi__float2int(x) ((int) (x)) -static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) -{ - int i,k,n; - stbi_uc *output = (stbi_uc *) stbi__malloc(x * y * comp); - if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } - // compute number of non-alpha components - if (comp & 1) n = comp; else n = comp-1; - for (i=0; i < x*y; ++i) { - for (k=0; k < n; ++k) { - float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; - if (z < 0) z = 0; - if (z > 255) z = 255; - output[i*comp + k] = (stbi_uc) stbi__float2int(z); - } - if (k < comp) { - float z = data[i*comp+k] * 255 + 0.5f; - if (z < 0) z = 0; - if (z > 255) z = 255; - output[i*comp + k] = (stbi_uc) stbi__float2int(z); - } - } - STBI_FREE(data); - return output; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// "baseline" JPEG/JFIF decoder -// -// simple implementation -// - doesn't support delayed output of y-dimension -// - simple interface (only one output format: 8-bit interleaved RGB) -// - doesn't try to recover corrupt jpegs -// - doesn't allow partial loading, loading multiple at once -// - still fast on x86 (copying globals into locals doesn't help x86) -// - allocates lots of intermediate memory (full size of all components) -// - non-interleaved case requires this anyway -// - allows good upsampling (see next) -// high-quality -// - upsampled channels are bilinearly interpolated, even across blocks -// - quality integer IDCT derived from IJG's 'slow' -// performance -// - fast huffman; reasonable integer IDCT -// - some SIMD kernels for common paths on targets with SSE2/NEON -// - uses a lot of intermediate memory, could cache poorly - -#ifndef STBI_NO_JPEG - -// huffman decoding acceleration -#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache - -typedef struct -{ - stbi_uc fast[1 << FAST_BITS]; - // weirdly, repacking this into AoS is a 10% speed loss, instead of a win - stbi__uint16 code[256]; - stbi_uc values[256]; - stbi_uc size[257]; - unsigned int maxcode[18]; - int delta[17]; // old 'firstsymbol' - old 'firstcode' -} stbi__huffman; - -typedef struct -{ - stbi__context *s; - stbi__huffman huff_dc[4]; - stbi__huffman huff_ac[4]; - stbi_uc dequant[4][64]; - stbi__int16 fast_ac[4][1 << FAST_BITS]; - -// sizes for components, interleaved MCUs - int img_h_max, img_v_max; - int img_mcu_x, img_mcu_y; - int img_mcu_w, img_mcu_h; - -// definition of jpeg image component - struct - { - int id; - int h,v; - int tq; - int hd,ha; - int dc_pred; - - int x,y,w2,h2; - stbi_uc *data; - void *raw_data, *raw_coeff; - stbi_uc *linebuf; - short *coeff; // progressive only - int coeff_w, coeff_h; // number of 8x8 coefficient blocks - } img_comp[4]; - - stbi__uint32 code_buffer; // jpeg entropy-coded buffer - int code_bits; // number of valid bits - unsigned char marker; // marker seen while filling entropy buffer - int nomore; // flag if we saw a marker so must stop - - int progressive; - int spec_start; - int spec_end; - int succ_high; - int succ_low; - int eob_run; - - int scan_n, order[4]; - int restart_interval, todo; - -// kernels - void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); - void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); - stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); -} stbi__jpeg; - -static int stbi__build_huffman(stbi__huffman *h, int *count) -{ - int i,j,k=0,code; - // build size list for each symbol (from JPEG spec) - for (i=0; i < 16; ++i) - for (j=0; j < count[i]; ++j) - h->size[k++] = (stbi_uc) (i+1); - h->size[k] = 0; - - // compute actual symbols (from jpeg spec) - code = 0; - k = 0; - for(j=1; j <= 16; ++j) { - // compute delta to add to code to compute symbol id - h->delta[j] = k - code; - if (h->size[k] == j) { - while (h->size[k] == j) - h->code[k++] = (stbi__uint16) (code++); - if (code-1 >= (1 << j)) return stbi__err("bad code lengths","Corrupt JPEG"); - } - // compute largest code + 1 for this size, preshifted as needed later - h->maxcode[j] = code << (16-j); - code <<= 1; - } - h->maxcode[j] = 0xffffffff; - - // build non-spec acceleration table; 255 is flag for not-accelerated - memset(h->fast, 255, 1 << FAST_BITS); - for (i=0; i < k; ++i) { - int s = h->size[i]; - if (s <= FAST_BITS) { - int c = h->code[i] << (FAST_BITS-s); - int m = 1 << (FAST_BITS-s); - for (j=0; j < m; ++j) { - h->fast[c+j] = (stbi_uc) i; - } - } - } - return 1; -} - -// build a table that decodes both magnitude and value of small ACs in -// one go. -static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) -{ - int i; - for (i=0; i < (1 << FAST_BITS); ++i) { - stbi_uc fast = h->fast[i]; - fast_ac[i] = 0; - if (fast < 255) { - int rs = h->values[fast]; - int run = (rs >> 4) & 15; - int magbits = rs & 15; - int len = h->size[fast]; - - if (magbits && len + magbits <= FAST_BITS) { - // magnitude code followed by receive_extend code - int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); - int m = 1 << (magbits - 1); - if (k < m) k += (-1 << magbits) + 1; - // if the result is small enough, we can fit it in fast_ac table - if (k >= -128 && k <= 127) - fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits)); - } - } - } -} - -static void stbi__grow_buffer_unsafe(stbi__jpeg *j) -{ - do { - int b = j->nomore ? 0 : stbi__get8(j->s); - if (b == 0xff) { - int c = stbi__get8(j->s); - if (c != 0) { - j->marker = (unsigned char) c; - j->nomore = 1; - return; - } - } - j->code_buffer |= b << (24 - j->code_bits); - j->code_bits += 8; - } while (j->code_bits <= 24); -} - -// (1 << n) - 1 -static stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; - -// decode a jpeg huffman value from the bitstream -stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) -{ - unsigned int temp; - int c,k; - - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - - // look at the top FAST_BITS and determine what symbol ID it is, - // if the code is <= FAST_BITS - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - k = h->fast[c]; - if (k < 255) { - int s = h->size[k]; - if (s > j->code_bits) - return -1; - j->code_buffer <<= s; - j->code_bits -= s; - return h->values[k]; - } - - // naive test is to shift the code_buffer down so k bits are - // valid, then test against maxcode. To speed this up, we've - // preshifted maxcode left so that it has (16-k) 0s at the - // end; in other words, regardless of the number of bits, it - // wants to be compared against something shifted to have 16; - // that way we don't need to shift inside the loop. - temp = j->code_buffer >> 16; - for (k=FAST_BITS+1 ; ; ++k) - if (temp < h->maxcode[k]) - break; - if (k == 17) { - // error! code not found - j->code_bits -= 16; - return -1; - } - - if (k > j->code_bits) - return -1; - - // convert the huffman code to the symbol id - c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; - STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); - - // convert the id to a symbol - j->code_bits -= k; - j->code_buffer <<= k; - return h->values[c]; -} - -// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); - - sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB - k = stbi_lrot(j->code_buffer, n); - STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))); - j->code_buffer = k & ~stbi__bmask[n]; - k &= stbi__bmask[n]; - j->code_bits -= n; - return k + (stbi__jbias[n] & ~sgn); -} - -// get some unsigned bits -stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) -{ - unsigned int k; - if (j->code_bits < n) stbi__grow_buffer_unsafe(j); - k = stbi_lrot(j->code_buffer, n); - j->code_buffer = k & ~stbi__bmask[n]; - k &= stbi__bmask[n]; - j->code_bits -= n; - return k; -} - -stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) -{ - unsigned int k; - if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); - k = j->code_buffer; - j->code_buffer <<= 1; - --j->code_bits; - return k & 0x80000000; -} - -// given a value that's at position X in the zigzag stream, -// where does it appear in the 8x8 matrix coded as row-major? -static stbi_uc stbi__jpeg_dezigzag[64+15] = -{ - 0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, - 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, - 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, - 53, 60, 61, 54, 47, 55, 62, 63, - // let corrupt input sample past end - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63 -}; - -// decode one 64-entry block-- -static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi_uc *dequant) -{ - int diff,dc,k; - int t; - - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - t = stbi__jpeg_huff_decode(j, hdc); - if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - - // 0 all the ac values now so we can do it 32-bits at a time - memset(data,0,64*sizeof(data[0])); - - diff = t ? stbi__extend_receive(j, t) : 0; - dc = j->img_comp[b].dc_pred + diff; - j->img_comp[b].dc_pred = dc; - data[0] = (short) (dc * dequant[0]); - - // decode AC components, see JPEG spec - k = 1; - do { - unsigned int zig; - int c,r,s; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - r = fac[c]; - if (r) { // fast-AC path - k += (r >> 4) & 15; // run - s = r & 15; // combined length - j->code_buffer <<= s; - j->code_bits -= s; - // decode into unzigzag'd location - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) * dequant[zig]); - } else { - int rs = stbi__jpeg_huff_decode(j, hac); - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (rs != 0xf0) break; // end block - k += 16; - } else { - k += r; - // decode into unzigzag'd location - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); - } - } - } while (k < 64); - return 1; -} - -static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) -{ - int diff,dc; - int t; - if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - - if (j->succ_high == 0) { - // first scan for DC coefficient, must be first - memset(data,0,64*sizeof(data[0])); // 0 all the ac values now - t = stbi__jpeg_huff_decode(j, hdc); - diff = t ? stbi__extend_receive(j, t) : 0; - - dc = j->img_comp[b].dc_pred + diff; - j->img_comp[b].dc_pred = dc; - data[0] = (short) (dc << j->succ_low); - } else { - // refinement scan for DC coefficient - if (stbi__jpeg_get_bit(j)) - data[0] += (short) (1 << j->succ_low); - } - return 1; -} - -// @OPTIMIZE: store non-zigzagged during the decode passes, -// and only de-zigzag when dequantizing -static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) -{ - int k; - if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - - if (j->succ_high == 0) { - int shift = j->succ_low; - - if (j->eob_run) { - --j->eob_run; - return 1; - } - - k = j->spec_start; - do { - unsigned int zig; - int c,r,s; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - r = fac[c]; - if (r) { // fast-AC path - k += (r >> 4) & 15; // run - s = r & 15; // combined length - j->code_buffer <<= s; - j->code_bits -= s; - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) << shift); - } else { - int rs = stbi__jpeg_huff_decode(j, hac); - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (r < 15) { - j->eob_run = (1 << r); - if (r) - j->eob_run += stbi__jpeg_get_bits(j, r); - --j->eob_run; - break; - } - k += 16; - } else { - k += r; - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) << shift); - } - } - } while (k <= j->spec_end); - } else { - // refinement scan for these AC coefficients - - short bit = (short) (1 << j->succ_low); - - if (j->eob_run) { - --j->eob_run; - for (k = j->spec_start; k <= j->spec_end; ++k) { - short *p = &data[stbi__jpeg_dezigzag[k]]; - if (*p != 0) - if (stbi__jpeg_get_bit(j)) - if ((*p & bit)==0) { - if (*p > 0) - *p += bit; - else - *p -= bit; - } - } - } else { - k = j->spec_start; - do { - int r,s; - int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (r < 15) { - j->eob_run = (1 << r) - 1; - if (r) - j->eob_run += stbi__jpeg_get_bits(j, r); - r = 64; // force end of block - } else { - // r=15 s=0 should write 16 0s, so we just do - // a run of 15 0s and then write s (which is 0), - // so we don't have to do anything special here - } - } else { - if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); - // sign bit - if (stbi__jpeg_get_bit(j)) - s = bit; - else - s = -bit; - } - - // advance by r - while (k <= j->spec_end) { - short *p = &data[stbi__jpeg_dezigzag[k++]]; - if (*p != 0) { - if (stbi__jpeg_get_bit(j)) - if ((*p & bit)==0) { - if (*p > 0) - *p += bit; - else - *p -= bit; - } - } else { - if (r == 0) { - *p = (short) s; - break; - } - --r; - } - } - } while (k <= j->spec_end); - } - } - return 1; -} - -// take a -128..127 value and stbi__clamp it and convert to 0..255 -stbi_inline static stbi_uc stbi__clamp(int x) -{ - // trick to use a single test to catch both cases - if ((unsigned int) x > 255) { - if (x < 0) return 0; - if (x > 255) return 255; - } - return (stbi_uc) x; -} - -#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) -#define stbi__fsh(x) ((x) << 12) - -// derived from jidctint -- DCT_ISLOW -#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ - int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ - p2 = s2; \ - p3 = s6; \ - p1 = (p2+p3) * stbi__f2f(0.5411961f); \ - t2 = p1 + p3*stbi__f2f(-1.847759065f); \ - t3 = p1 + p2*stbi__f2f( 0.765366865f); \ - p2 = s0; \ - p3 = s4; \ - t0 = stbi__fsh(p2+p3); \ - t1 = stbi__fsh(p2-p3); \ - x0 = t0+t3; \ - x3 = t0-t3; \ - x1 = t1+t2; \ - x2 = t1-t2; \ - t0 = s7; \ - t1 = s5; \ - t2 = s3; \ - t3 = s1; \ - p3 = t0+t2; \ - p4 = t1+t3; \ - p1 = t0+t3; \ - p2 = t1+t2; \ - p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ - t0 = t0*stbi__f2f( 0.298631336f); \ - t1 = t1*stbi__f2f( 2.053119869f); \ - t2 = t2*stbi__f2f( 3.072711026f); \ - t3 = t3*stbi__f2f( 1.501321110f); \ - p1 = p5 + p1*stbi__f2f(-0.899976223f); \ - p2 = p5 + p2*stbi__f2f(-2.562915447f); \ - p3 = p3*stbi__f2f(-1.961570560f); \ - p4 = p4*stbi__f2f(-0.390180644f); \ - t3 += p1+p4; \ - t2 += p2+p3; \ - t1 += p2+p4; \ - t0 += p1+p3; - -static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) -{ - int i,val[64],*v=val; - stbi_uc *o; - short *d = data; - - // columns - for (i=0; i < 8; ++i,++d, ++v) { - // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing - if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 - && d[40]==0 && d[48]==0 && d[56]==0) { - // no shortcut 0 seconds - // (1|2|3|4|5|6|7)==0 0 seconds - // all separate -0.047 seconds - // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds - int dcterm = d[0] << 2; - v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; - } else { - STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) - // constants scaled things up by 1<<12; let's bring them back - // down, but keep 2 extra bits of precision - x0 += 512; x1 += 512; x2 += 512; x3 += 512; - v[ 0] = (x0+t3) >> 10; - v[56] = (x0-t3) >> 10; - v[ 8] = (x1+t2) >> 10; - v[48] = (x1-t2) >> 10; - v[16] = (x2+t1) >> 10; - v[40] = (x2-t1) >> 10; - v[24] = (x3+t0) >> 10; - v[32] = (x3-t0) >> 10; - } - } - - for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { - // no fast case since the first 1D IDCT spread components out - STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) - // constants scaled things up by 1<<12, plus we had 1<<2 from first - // loop, plus horizontal and vertical each scale by sqrt(8) so together - // we've got an extra 1<<3, so 1<<17 total we need to remove. - // so we want to round that, which means adding 0.5 * 1<<17, - // aka 65536. Also, we'll end up with -128 to 127 that we want - // to encode as 0..255 by adding 128, so we'll add that before the shift - x0 += 65536 + (128<<17); - x1 += 65536 + (128<<17); - x2 += 65536 + (128<<17); - x3 += 65536 + (128<<17); - // tried computing the shifts into temps, or'ing the temps to see - // if any were out of range, but that was slower - o[0] = stbi__clamp((x0+t3) >> 17); - o[7] = stbi__clamp((x0-t3) >> 17); - o[1] = stbi__clamp((x1+t2) >> 17); - o[6] = stbi__clamp((x1-t2) >> 17); - o[2] = stbi__clamp((x2+t1) >> 17); - o[5] = stbi__clamp((x2-t1) >> 17); - o[3] = stbi__clamp((x3+t0) >> 17); - o[4] = stbi__clamp((x3-t0) >> 17); - } -} - -#ifdef STBI_SSE2 -// sse2 integer IDCT. not the fastest possible implementation but it -// produces bit-identical results to the generic C version so it's -// fully "transparent". -static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) -{ - // This is constructed to match our regular (generic) integer IDCT exactly. - __m128i row0, row1, row2, row3, row4, row5, row6, row7; - __m128i tmp; - - // dot product constant: even elems=x, odd elems=y - #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) - - // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) - // out(1) = c1[even]*x + c1[odd]*y - #define dct_rot(out0,out1, x,y,c0,c1) \ - __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ - __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ - __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ - __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ - __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ - __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) - - // out = in << 12 (in 16-bit, out 32-bit) - #define dct_widen(out, in) \ - __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ - __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) - - // wide add - #define dct_wadd(out, a, b) \ - __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ - __m128i out##_h = _mm_add_epi32(a##_h, b##_h) - - // wide sub - #define dct_wsub(out, a, b) \ - __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ - __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) - - // butterfly a/b, add bias, then shift by "s" and pack - #define dct_bfly32o(out0, out1, a,b,bias,s) \ - { \ - __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ - __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ - dct_wadd(sum, abiased, b); \ - dct_wsub(dif, abiased, b); \ - out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ - out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ - } - - // 8-bit interleave step (for transposes) - #define dct_interleave8(a, b) \ - tmp = a; \ - a = _mm_unpacklo_epi8(a, b); \ - b = _mm_unpackhi_epi8(tmp, b) - - // 16-bit interleave step (for transposes) - #define dct_interleave16(a, b) \ - tmp = a; \ - a = _mm_unpacklo_epi16(a, b); \ - b = _mm_unpackhi_epi16(tmp, b) - - #define dct_pass(bias,shift) \ - { \ - /* even part */ \ - dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ - __m128i sum04 = _mm_add_epi16(row0, row4); \ - __m128i dif04 = _mm_sub_epi16(row0, row4); \ - dct_widen(t0e, sum04); \ - dct_widen(t1e, dif04); \ - dct_wadd(x0, t0e, t3e); \ - dct_wsub(x3, t0e, t3e); \ - dct_wadd(x1, t1e, t2e); \ - dct_wsub(x2, t1e, t2e); \ - /* odd part */ \ - dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ - dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ - __m128i sum17 = _mm_add_epi16(row1, row7); \ - __m128i sum35 = _mm_add_epi16(row3, row5); \ - dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ - dct_wadd(x4, y0o, y4o); \ - dct_wadd(x5, y1o, y5o); \ - dct_wadd(x6, y2o, y5o); \ - dct_wadd(x7, y3o, y4o); \ - dct_bfly32o(row0,row7, x0,x7,bias,shift); \ - dct_bfly32o(row1,row6, x1,x6,bias,shift); \ - dct_bfly32o(row2,row5, x2,x5,bias,shift); \ - dct_bfly32o(row3,row4, x3,x4,bias,shift); \ - } - - __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); - __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); - __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); - __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); - __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); - __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); - __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); - __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); - - // rounding biases in column/row passes, see stbi__idct_block for explanation. - __m128i bias_0 = _mm_set1_epi32(512); - __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); - - // load - row0 = _mm_load_si128((const __m128i *) (data + 0*8)); - row1 = _mm_load_si128((const __m128i *) (data + 1*8)); - row2 = _mm_load_si128((const __m128i *) (data + 2*8)); - row3 = _mm_load_si128((const __m128i *) (data + 3*8)); - row4 = _mm_load_si128((const __m128i *) (data + 4*8)); - row5 = _mm_load_si128((const __m128i *) (data + 5*8)); - row6 = _mm_load_si128((const __m128i *) (data + 6*8)); - row7 = _mm_load_si128((const __m128i *) (data + 7*8)); - - // column pass - dct_pass(bias_0, 10); - - { - // 16bit 8x8 transpose pass 1 - dct_interleave16(row0, row4); - dct_interleave16(row1, row5); - dct_interleave16(row2, row6); - dct_interleave16(row3, row7); - - // transpose pass 2 - dct_interleave16(row0, row2); - dct_interleave16(row1, row3); - dct_interleave16(row4, row6); - dct_interleave16(row5, row7); - - // transpose pass 3 - dct_interleave16(row0, row1); - dct_interleave16(row2, row3); - dct_interleave16(row4, row5); - dct_interleave16(row6, row7); - } - - // row pass - dct_pass(bias_1, 17); - - { - // pack - __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 - __m128i p1 = _mm_packus_epi16(row2, row3); - __m128i p2 = _mm_packus_epi16(row4, row5); - __m128i p3 = _mm_packus_epi16(row6, row7); - - // 8bit 8x8 transpose pass 1 - dct_interleave8(p0, p2); // a0e0a1e1... - dct_interleave8(p1, p3); // c0g0c1g1... - - // transpose pass 2 - dct_interleave8(p0, p1); // a0c0e0g0... - dct_interleave8(p2, p3); // b0d0f0h0... - - // transpose pass 3 - dct_interleave8(p0, p2); // a0b0c0d0... - dct_interleave8(p1, p3); // a4b4c4d4... - - // store - _mm_storel_epi64((__m128i *) out, p0); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p2); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p1); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p3); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); - } - -#undef dct_const -#undef dct_rot -#undef dct_widen -#undef dct_wadd -#undef dct_wsub -#undef dct_bfly32o -#undef dct_interleave8 -#undef dct_interleave16 -#undef dct_pass -} - -#endif // STBI_SSE2 - -#ifdef STBI_NEON - -// NEON integer IDCT. should produce bit-identical -// results to the generic C version. -static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) -{ - int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; - - int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); - int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); - int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); - int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); - int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); - int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); - int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); - int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); - int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); - int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); - int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); - int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); - -#define dct_long_mul(out, inq, coeff) \ - int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ - int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) - -#define dct_long_mac(out, acc, inq, coeff) \ - int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ - int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) - -#define dct_widen(out, inq) \ - int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ - int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) - -// wide add -#define dct_wadd(out, a, b) \ - int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ - int32x4_t out##_h = vaddq_s32(a##_h, b##_h) - -// wide sub -#define dct_wsub(out, a, b) \ - int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ - int32x4_t out##_h = vsubq_s32(a##_h, b##_h) - -// butterfly a/b, then shift using "shiftop" by "s" and pack -#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ - { \ - dct_wadd(sum, a, b); \ - dct_wsub(dif, a, b); \ - out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ - out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ - } - -#define dct_pass(shiftop, shift) \ - { \ - /* even part */ \ - int16x8_t sum26 = vaddq_s16(row2, row6); \ - dct_long_mul(p1e, sum26, rot0_0); \ - dct_long_mac(t2e, p1e, row6, rot0_1); \ - dct_long_mac(t3e, p1e, row2, rot0_2); \ - int16x8_t sum04 = vaddq_s16(row0, row4); \ - int16x8_t dif04 = vsubq_s16(row0, row4); \ - dct_widen(t0e, sum04); \ - dct_widen(t1e, dif04); \ - dct_wadd(x0, t0e, t3e); \ - dct_wsub(x3, t0e, t3e); \ - dct_wadd(x1, t1e, t2e); \ - dct_wsub(x2, t1e, t2e); \ - /* odd part */ \ - int16x8_t sum15 = vaddq_s16(row1, row5); \ - int16x8_t sum17 = vaddq_s16(row1, row7); \ - int16x8_t sum35 = vaddq_s16(row3, row5); \ - int16x8_t sum37 = vaddq_s16(row3, row7); \ - int16x8_t sumodd = vaddq_s16(sum17, sum35); \ - dct_long_mul(p5o, sumodd, rot1_0); \ - dct_long_mac(p1o, p5o, sum17, rot1_1); \ - dct_long_mac(p2o, p5o, sum35, rot1_2); \ - dct_long_mul(p3o, sum37, rot2_0); \ - dct_long_mul(p4o, sum15, rot2_1); \ - dct_wadd(sump13o, p1o, p3o); \ - dct_wadd(sump24o, p2o, p4o); \ - dct_wadd(sump23o, p2o, p3o); \ - dct_wadd(sump14o, p1o, p4o); \ - dct_long_mac(x4, sump13o, row7, rot3_0); \ - dct_long_mac(x5, sump24o, row5, rot3_1); \ - dct_long_mac(x6, sump23o, row3, rot3_2); \ - dct_long_mac(x7, sump14o, row1, rot3_3); \ - dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ - dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ - dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ - dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ - } - - // load - row0 = vld1q_s16(data + 0*8); - row1 = vld1q_s16(data + 1*8); - row2 = vld1q_s16(data + 2*8); - row3 = vld1q_s16(data + 3*8); - row4 = vld1q_s16(data + 4*8); - row5 = vld1q_s16(data + 5*8); - row6 = vld1q_s16(data + 6*8); - row7 = vld1q_s16(data + 7*8); - - // add DC bias - row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); - - // column pass - dct_pass(vrshrn_n_s32, 10); - - // 16bit 8x8 transpose - { -// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. -// whether compilers actually get this is another story, sadly. -#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } -#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } -#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } - - // pass 1 - dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 - dct_trn16(row2, row3); - dct_trn16(row4, row5); - dct_trn16(row6, row7); - - // pass 2 - dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 - dct_trn32(row1, row3); - dct_trn32(row4, row6); - dct_trn32(row5, row7); - - // pass 3 - dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 - dct_trn64(row1, row5); - dct_trn64(row2, row6); - dct_trn64(row3, row7); - -#undef dct_trn16 -#undef dct_trn32 -#undef dct_trn64 - } - - // row pass - // vrshrn_n_s32 only supports shifts up to 16, we need - // 17. so do a non-rounding shift of 16 first then follow - // up with a rounding shift by 1. - dct_pass(vshrn_n_s32, 16); - - { - // pack and round - uint8x8_t p0 = vqrshrun_n_s16(row0, 1); - uint8x8_t p1 = vqrshrun_n_s16(row1, 1); - uint8x8_t p2 = vqrshrun_n_s16(row2, 1); - uint8x8_t p3 = vqrshrun_n_s16(row3, 1); - uint8x8_t p4 = vqrshrun_n_s16(row4, 1); - uint8x8_t p5 = vqrshrun_n_s16(row5, 1); - uint8x8_t p6 = vqrshrun_n_s16(row6, 1); - uint8x8_t p7 = vqrshrun_n_s16(row7, 1); - - // again, these can translate into one instruction, but often don't. -#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } -#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } -#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } - - // sadly can't use interleaved stores here since we only write - // 8 bytes to each scan line! - - // 8x8 8-bit transpose pass 1 - dct_trn8_8(p0, p1); - dct_trn8_8(p2, p3); - dct_trn8_8(p4, p5); - dct_trn8_8(p6, p7); - - // pass 2 - dct_trn8_16(p0, p2); - dct_trn8_16(p1, p3); - dct_trn8_16(p4, p6); - dct_trn8_16(p5, p7); - - // pass 3 - dct_trn8_32(p0, p4); - dct_trn8_32(p1, p5); - dct_trn8_32(p2, p6); - dct_trn8_32(p3, p7); - - // store - vst1_u8(out, p0); out += out_stride; - vst1_u8(out, p1); out += out_stride; - vst1_u8(out, p2); out += out_stride; - vst1_u8(out, p3); out += out_stride; - vst1_u8(out, p4); out += out_stride; - vst1_u8(out, p5); out += out_stride; - vst1_u8(out, p6); out += out_stride; - vst1_u8(out, p7); - -#undef dct_trn8_8 -#undef dct_trn8_16 -#undef dct_trn8_32 - } - -#undef dct_long_mul -#undef dct_long_mac -#undef dct_widen -#undef dct_wadd -#undef dct_wsub -#undef dct_bfly32o -#undef dct_pass -} - -#endif // STBI_NEON - -#define STBI__MARKER_none 0xff -// if there's a pending marker from the entropy stream, return that -// otherwise, fetch from the stream and get a marker. if there's no -// marker, return 0xff, which is never a valid marker value -static stbi_uc stbi__get_marker(stbi__jpeg *j) -{ - stbi_uc x; - if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } - x = stbi__get8(j->s); - if (x != 0xff) return STBI__MARKER_none; - while (x == 0xff) - x = stbi__get8(j->s); - return x; -} - -// in each scan, we'll have scan_n components, and the order -// of the components is specified by order[] -#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) - -// after a restart interval, stbi__jpeg_reset the entropy decoder and -// the dc prediction -static void stbi__jpeg_reset(stbi__jpeg *j) -{ - j->code_bits = 0; - j->code_buffer = 0; - j->nomore = 0; - j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0; - j->marker = STBI__MARKER_none; - j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; - j->eob_run = 0; - // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, - // since we don't even allow 1<<30 pixels -} - -static int stbi__parse_entropy_coded_data(stbi__jpeg *z) -{ - stbi__jpeg_reset(z); - if (!z->progressive) { - if (z->scan_n == 1) { - int i,j; - STBI_SIMD_ALIGN(short, data[64]); - int n = z->order[0]; - // non-interleaved data, we just need to process one block at a time, - // in trivial scanline order - // number of blocks to do just depends on how many actual "pixels" this - // component has, independent of interleaved MCU blocking and such - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); - // every data block is an MCU, so countdown the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - // if it's NOT a restart, then just bail, so we get corrupt data - // rather than no data - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } else { // interleaved - int i,j,k,x,y; - STBI_SIMD_ALIGN(short, data[64]); - for (j=0; j < z->img_mcu_y; ++j) { - for (i=0; i < z->img_mcu_x; ++i) { - // scan an interleaved mcu... process scan_n components in order - for (k=0; k < z->scan_n; ++k) { - int n = z->order[k]; - // scan out an mcu's worth of this component; that's just determined - // by the basic H and V specified for the component - for (y=0; y < z->img_comp[n].v; ++y) { - for (x=0; x < z->img_comp[n].h; ++x) { - int x2 = (i*z->img_comp[n].h + x)*8; - int y2 = (j*z->img_comp[n].v + y)*8; - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); - } - } - } - // after all interleaved components, that's an interleaved MCU, - // so now count down the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } - } else { - if (z->scan_n == 1) { - int i,j; - int n = z->order[0]; - // non-interleaved data, we just need to process one block at a time, - // in trivial scanline order - // number of blocks to do just depends on how many actual "pixels" this - // component has, independent of interleaved MCU blocking and such - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); - if (z->spec_start == 0) { - if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) - return 0; - } else { - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) - return 0; - } - // every data block is an MCU, so countdown the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } else { // interleaved - int i,j,k,x,y; - for (j=0; j < z->img_mcu_y; ++j) { - for (i=0; i < z->img_mcu_x; ++i) { - // scan an interleaved mcu... process scan_n components in order - for (k=0; k < z->scan_n; ++k) { - int n = z->order[k]; - // scan out an mcu's worth of this component; that's just determined - // by the basic H and V specified for the component - for (y=0; y < z->img_comp[n].v; ++y) { - for (x=0; x < z->img_comp[n].h; ++x) { - int x2 = (i*z->img_comp[n].h + x); - int y2 = (j*z->img_comp[n].v + y); - short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); - if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) - return 0; - } - } - } - // after all interleaved components, that's an interleaved MCU, - // so now count down the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } - } -} - -static void stbi__jpeg_dequantize(short *data, stbi_uc *dequant) -{ - int i; - for (i=0; i < 64; ++i) - data[i] *= dequant[i]; -} - -static void stbi__jpeg_finish(stbi__jpeg *z) -{ - if (z->progressive) { - // dequantize and idct the data - int i,j,n; - for (n=0; n < z->s->img_n; ++n) { - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); - stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); - } - } - } - } -} - -static int stbi__process_marker(stbi__jpeg *z, int m) -{ - int L; - switch (m) { - case STBI__MARKER_none: // no marker found - return stbi__err("expected marker","Corrupt JPEG"); - - case 0xDD: // DRI - specify restart interval - if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); - z->restart_interval = stbi__get16be(z->s); - return 1; - - case 0xDB: // DQT - define quantization table - L = stbi__get16be(z->s)-2; - while (L > 0) { - int q = stbi__get8(z->s); - int p = q >> 4; - int t = q & 15,i; - if (p != 0) return stbi__err("bad DQT type","Corrupt JPEG"); - if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); - for (i=0; i < 64; ++i) - z->dequant[t][stbi__jpeg_dezigzag[i]] = stbi__get8(z->s); - L -= 65; - } - return L==0; - - case 0xC4: // DHT - define huffman table - L = stbi__get16be(z->s)-2; - while (L > 0) { - stbi_uc *v; - int sizes[16],i,n=0; - int q = stbi__get8(z->s); - int tc = q >> 4; - int th = q & 15; - if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); - for (i=0; i < 16; ++i) { - sizes[i] = stbi__get8(z->s); - n += sizes[i]; - } - L -= 17; - if (tc == 0) { - if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; - v = z->huff_dc[th].values; - } else { - if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; - v = z->huff_ac[th].values; - } - for (i=0; i < n; ++i) - v[i] = stbi__get8(z->s); - if (tc != 0) - stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); - L -= n; - } - return L==0; - } - // check for comment block or APP blocks - if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { - stbi__skip(z->s, stbi__get16be(z->s)-2); - return 1; - } - return 0; -} - -// after we see SOS -static int stbi__process_scan_header(stbi__jpeg *z) -{ - int i; - int Ls = stbi__get16be(z->s); - z->scan_n = stbi__get8(z->s); - if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); - if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); - for (i=0; i < z->scan_n; ++i) { - int id = stbi__get8(z->s), which; - int q = stbi__get8(z->s); - for (which = 0; which < z->s->img_n; ++which) - if (z->img_comp[which].id == id) - break; - if (which == z->s->img_n) return 0; // no match - z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); - z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); - z->order[i] = which; - } - - { - int aa; - z->spec_start = stbi__get8(z->s); - z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 - aa = stbi__get8(z->s); - z->succ_high = (aa >> 4); - z->succ_low = (aa & 15); - if (z->progressive) { - if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) - return stbi__err("bad SOS", "Corrupt JPEG"); - } else { - if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); - if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); - z->spec_end = 63; - } - } - - return 1; -} - -static int stbi__process_frame_header(stbi__jpeg *z, int scan) -{ - stbi__context *s = z->s; - int Lf,p,i,q, h_max=1,v_max=1,c; - Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG - p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline - s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG - s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires - c = stbi__get8(s); - if (c != 3 && c != 1) return stbi__err("bad component count","Corrupt JPEG"); // JFIF requires - s->img_n = c; - for (i=0; i < c; ++i) { - z->img_comp[i].data = NULL; - z->img_comp[i].linebuf = NULL; - } - - if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); - - for (i=0; i < s->img_n; ++i) { - z->img_comp[i].id = stbi__get8(s); - if (z->img_comp[i].id != i+1) // JFIF requires - if (z->img_comp[i].id != i) // some version of jpegtran outputs non-JFIF-compliant files! - return stbi__err("bad component ID","Corrupt JPEG"); - q = stbi__get8(s); - z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); - z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); - z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); - } - - if (scan != STBI__SCAN_load) return 1; - - if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); - - for (i=0; i < s->img_n; ++i) { - if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; - if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; - } - - // compute interleaved mcu info - z->img_h_max = h_max; - z->img_v_max = v_max; - z->img_mcu_w = h_max * 8; - z->img_mcu_h = v_max * 8; - z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; - z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; - - for (i=0; i < s->img_n; ++i) { - // number of effective pixels (e.g. for non-interleaved MCU) - z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; - z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; - // to simplify generation, we'll allocate enough memory to decode - // the bogus oversized data from using interleaved MCUs and their - // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't - // discard the extra data until colorspace conversion - z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; - z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; - z->img_comp[i].raw_data = stbi__malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15); - - if (z->img_comp[i].raw_data == NULL) { - for(--i; i >= 0; --i) { - STBI_FREE(z->img_comp[i].raw_data); - z->img_comp[i].raw_data = NULL; - } - return stbi__err("outofmem", "Out of memory"); - } - // align blocks for idct using mmx/sse - z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); - z->img_comp[i].linebuf = NULL; - if (z->progressive) { - z->img_comp[i].coeff_w = (z->img_comp[i].w2 + 7) >> 3; - z->img_comp[i].coeff_h = (z->img_comp[i].h2 + 7) >> 3; - z->img_comp[i].raw_coeff = STBI_MALLOC(z->img_comp[i].coeff_w * z->img_comp[i].coeff_h * 64 * sizeof(short) + 15); - z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); - } else { - z->img_comp[i].coeff = 0; - z->img_comp[i].raw_coeff = 0; - } - } - - return 1; -} - -// use comparisons since in some cases we handle more than one case (e.g. SOF) -#define stbi__DNL(x) ((x) == 0xdc) -#define stbi__SOI(x) ((x) == 0xd8) -#define stbi__EOI(x) ((x) == 0xd9) -#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) -#define stbi__SOS(x) ((x) == 0xda) - -#define stbi__SOF_progressive(x) ((x) == 0xc2) - -static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) -{ - int m; - z->marker = STBI__MARKER_none; // initialize cached marker to empty - m = stbi__get_marker(z); - if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); - if (scan == STBI__SCAN_type) return 1; - m = stbi__get_marker(z); - while (!stbi__SOF(m)) { - if (!stbi__process_marker(z,m)) return 0; - m = stbi__get_marker(z); - while (m == STBI__MARKER_none) { - // some files have extra padding after their blocks, so ok, we'll scan - if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); - m = stbi__get_marker(z); - } - } - z->progressive = stbi__SOF_progressive(m); - if (!stbi__process_frame_header(z, scan)) return 0; - return 1; -} - -// decode image to YCbCr format -static int stbi__decode_jpeg_image(stbi__jpeg *j) -{ - int m; - for (m = 0; m < 4; m++) { - j->img_comp[m].raw_data = NULL; - j->img_comp[m].raw_coeff = NULL; - } - j->restart_interval = 0; - if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; - m = stbi__get_marker(j); - while (!stbi__EOI(m)) { - if (stbi__SOS(m)) { - if (!stbi__process_scan_header(j)) return 0; - if (!stbi__parse_entropy_coded_data(j)) return 0; - if (j->marker == STBI__MARKER_none ) { - // handle 0s at the end of image data from IP Kamera 9060 - while (!stbi__at_eof(j->s)) { - int x = stbi__get8(j->s); - if (x == 255) { - j->marker = stbi__get8(j->s); - break; - } else if (x != 0) { - return stbi__err("junk before marker", "Corrupt JPEG"); - } - } - // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 - } - } else { - if (!stbi__process_marker(j, m)) return 0; - } - m = stbi__get_marker(j); - } - if (j->progressive) - stbi__jpeg_finish(j); - return 1; -} - -// static jfif-centered resampling (across block boundaries) - -typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, - int w, int hs); - -#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) - -static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - STBI_NOTUSED(out); - STBI_NOTUSED(in_far); - STBI_NOTUSED(w); - STBI_NOTUSED(hs); - return in_near; -} - -static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate two samples vertically for every one in input - int i; - STBI_NOTUSED(hs); - for (i=0; i < w; ++i) - out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); - return out; -} - -static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate two samples horizontally for every one in input - int i; - stbi_uc *input = in_near; - - if (w == 1) { - // if only one sample, can't do any interpolation - out[0] = out[1] = input[0]; - return out; - } - - out[0] = input[0]; - out[1] = stbi__div4(input[0]*3 + input[1] + 2); - for (i=1; i < w-1; ++i) { - int n = 3*input[i]+2; - out[i*2+0] = stbi__div4(n+input[i-1]); - out[i*2+1] = stbi__div4(n+input[i+1]); - } - out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); - out[i*2+1] = input[w-1]; - - STBI_NOTUSED(in_far); - STBI_NOTUSED(hs); - - return out; -} - -#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) - -static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate 2x2 samples for every one in input - int i,t0,t1; - if (w == 1) { - out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); - return out; - } - - t1 = 3*in_near[0] + in_far[0]; - out[0] = stbi__div4(t1+2); - for (i=1; i < w; ++i) { - t0 = t1; - t1 = 3*in_near[i]+in_far[i]; - out[i*2-1] = stbi__div16(3*t0 + t1 + 8); - out[i*2 ] = stbi__div16(3*t1 + t0 + 8); - } - out[w*2-1] = stbi__div4(t1+2); - - STBI_NOTUSED(hs); - - return out; -} - -#if defined(STBI_SSE2) || defined(STBI_NEON) -static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate 2x2 samples for every one in input - int i=0,t0,t1; - - if (w == 1) { - out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); - return out; - } - - t1 = 3*in_near[0] + in_far[0]; - // process groups of 8 pixels for as long as we can. - // note we can't handle the last pixel in a row in this loop - // because we need to handle the filter boundary conditions. - for (; i < ((w-1) & ~7); i += 8) { -#if defined(STBI_SSE2) - // load and perform the vertical filtering pass - // this uses 3*x + y = 4*x + (y - x) - __m128i zero = _mm_setzero_si128(); - __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); - __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); - __m128i farw = _mm_unpacklo_epi8(farb, zero); - __m128i nearw = _mm_unpacklo_epi8(nearb, zero); - __m128i diff = _mm_sub_epi16(farw, nearw); - __m128i nears = _mm_slli_epi16(nearw, 2); - __m128i curr = _mm_add_epi16(nears, diff); // current row - - // horizontal filter works the same based on shifted vers of current - // row. "prev" is current row shifted right by 1 pixel; we need to - // insert the previous pixel value (from t1). - // "next" is current row shifted left by 1 pixel, with first pixel - // of next block of 8 pixels added in. - __m128i prv0 = _mm_slli_si128(curr, 2); - __m128i nxt0 = _mm_srli_si128(curr, 2); - __m128i prev = _mm_insert_epi16(prv0, t1, 0); - __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); - - // horizontal filter, polyphase implementation since it's convenient: - // even pixels = 3*cur + prev = cur*4 + (prev - cur) - // odd pixels = 3*cur + next = cur*4 + (next - cur) - // note the shared term. - __m128i bias = _mm_set1_epi16(8); - __m128i curs = _mm_slli_epi16(curr, 2); - __m128i prvd = _mm_sub_epi16(prev, curr); - __m128i nxtd = _mm_sub_epi16(next, curr); - __m128i curb = _mm_add_epi16(curs, bias); - __m128i even = _mm_add_epi16(prvd, curb); - __m128i odd = _mm_add_epi16(nxtd, curb); - - // interleave even and odd pixels, then undo scaling. - __m128i int0 = _mm_unpacklo_epi16(even, odd); - __m128i int1 = _mm_unpackhi_epi16(even, odd); - __m128i de0 = _mm_srli_epi16(int0, 4); - __m128i de1 = _mm_srli_epi16(int1, 4); - - // pack and write output - __m128i outv = _mm_packus_epi16(de0, de1); - _mm_storeu_si128((__m128i *) (out + i*2), outv); -#elif defined(STBI_NEON) - // load and perform the vertical filtering pass - // this uses 3*x + y = 4*x + (y - x) - uint8x8_t farb = vld1_u8(in_far + i); - uint8x8_t nearb = vld1_u8(in_near + i); - int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); - int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); - int16x8_t curr = vaddq_s16(nears, diff); // current row - - // horizontal filter works the same based on shifted vers of current - // row. "prev" is current row shifted right by 1 pixel; we need to - // insert the previous pixel value (from t1). - // "next" is current row shifted left by 1 pixel, with first pixel - // of next block of 8 pixels added in. - int16x8_t prv0 = vextq_s16(curr, curr, 7); - int16x8_t nxt0 = vextq_s16(curr, curr, 1); - int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); - int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); - - // horizontal filter, polyphase implementation since it's convenient: - // even pixels = 3*cur + prev = cur*4 + (prev - cur) - // odd pixels = 3*cur + next = cur*4 + (next - cur) - // note the shared term. - int16x8_t curs = vshlq_n_s16(curr, 2); - int16x8_t prvd = vsubq_s16(prev, curr); - int16x8_t nxtd = vsubq_s16(next, curr); - int16x8_t even = vaddq_s16(curs, prvd); - int16x8_t odd = vaddq_s16(curs, nxtd); - - // undo scaling and round, then store with even/odd phases interleaved - uint8x8x2_t o; - o.val[0] = vqrshrun_n_s16(even, 4); - o.val[1] = vqrshrun_n_s16(odd, 4); - vst2_u8(out + i*2, o); -#endif - - // "previous" value for next iter - t1 = 3*in_near[i+7] + in_far[i+7]; - } - - t0 = t1; - t1 = 3*in_near[i] + in_far[i]; - out[i*2] = stbi__div16(3*t1 + t0 + 8); - - for (++i; i < w; ++i) { - t0 = t1; - t1 = 3*in_near[i]+in_far[i]; - out[i*2-1] = stbi__div16(3*t0 + t1 + 8); - out[i*2 ] = stbi__div16(3*t1 + t0 + 8); - } - out[w*2-1] = stbi__div4(t1+2); - - STBI_NOTUSED(hs); - - return out; -} -#endif - -static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // resample with nearest-neighbor - int i,j; - STBI_NOTUSED(in_far); - for (i=0; i < w; ++i) - for (j=0; j < hs; ++j) - out[i*hs+j] = in_near[i]; - return out; -} - -#ifdef STBI_JPEG_OLD -// this is the same YCbCr-to-RGB calculation that stb_image has used -// historically before the algorithm changes in 1.49 -#define float2fixed(x) ((int) ((x) * 65536 + 0.5)) -static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) -{ - int i; - for (i=0; i < count; ++i) { - int y_fixed = (y[i] << 16) + 32768; // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr*float2fixed(1.40200f); - g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f); - b = y_fixed + cb*float2fixed(1.77200f); - r >>= 16; - g >>= 16; - b >>= 16; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi_uc)r; - out[1] = (stbi_uc)g; - out[2] = (stbi_uc)b; - out[3] = 255; - out += step; - } -} -#else -// this is a reduced-precision calculation of YCbCr-to-RGB introduced -// to make sure the code produces the same results in both SIMD and scalar -#define float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) -static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) -{ - int i; - for (i=0; i < count; ++i) { - int y_fixed = (y[i] << 20) + (1<<19); // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr* float2fixed(1.40200f); - g = y_fixed + (cr*-float2fixed(0.71414f)) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); - b = y_fixed + cb* float2fixed(1.77200f); - r >>= 20; - g >>= 20; - b >>= 20; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi_uc)r; - out[1] = (stbi_uc)g; - out[2] = (stbi_uc)b; - out[3] = 255; - out += step; - } -} -#endif - -#if defined(STBI_SSE2) || defined(STBI_NEON) -static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) -{ - int i = 0; - -#ifdef STBI_SSE2 - // step == 3 is pretty ugly on the final interleave, and i'm not convinced - // it's useful in practice (you wouldn't use it for textures, for example). - // so just accelerate step == 4 case. - if (step == 4) { - // this is a fairly straightforward implementation and not super-optimized. - __m128i signflip = _mm_set1_epi8(-0x80); - __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); - __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); - __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); - __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); - __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); - __m128i xw = _mm_set1_epi16(255); // alpha channel - - for (; i+7 < count; i += 8) { - // load - __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); - __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); - __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); - __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 - __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 - - // unpack to short (and left-shift cr, cb by 8) - __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); - __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); - __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); - - // color transform - __m128i yws = _mm_srli_epi16(yw, 4); - __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); - __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); - __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); - __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); - __m128i rws = _mm_add_epi16(cr0, yws); - __m128i gwt = _mm_add_epi16(cb0, yws); - __m128i bws = _mm_add_epi16(yws, cb1); - __m128i gws = _mm_add_epi16(gwt, cr1); - - // descale - __m128i rw = _mm_srai_epi16(rws, 4); - __m128i bw = _mm_srai_epi16(bws, 4); - __m128i gw = _mm_srai_epi16(gws, 4); - - // back to byte, set up for transpose - __m128i brb = _mm_packus_epi16(rw, bw); - __m128i gxb = _mm_packus_epi16(gw, xw); - - // transpose to interleave channels - __m128i t0 = _mm_unpacklo_epi8(brb, gxb); - __m128i t1 = _mm_unpackhi_epi8(brb, gxb); - __m128i o0 = _mm_unpacklo_epi16(t0, t1); - __m128i o1 = _mm_unpackhi_epi16(t0, t1); - - // store - _mm_storeu_si128((__m128i *) (out + 0), o0); - _mm_storeu_si128((__m128i *) (out + 16), o1); - out += 32; - } - } -#endif - -#ifdef STBI_NEON - // in this version, step=3 support would be easy to add. but is there demand? - if (step == 4) { - // this is a fairly straightforward implementation and not super-optimized. - uint8x8_t signflip = vdup_n_u8(0x80); - int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); - int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); - int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); - int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); - - for (; i+7 < count; i += 8) { - // load - uint8x8_t y_bytes = vld1_u8(y + i); - uint8x8_t cr_bytes = vld1_u8(pcr + i); - uint8x8_t cb_bytes = vld1_u8(pcb + i); - int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); - int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); - - // expand to s16 - int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); - int16x8_t crw = vshll_n_s8(cr_biased, 7); - int16x8_t cbw = vshll_n_s8(cb_biased, 7); - - // color transform - int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); - int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); - int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); - int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); - int16x8_t rws = vaddq_s16(yws, cr0); - int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); - int16x8_t bws = vaddq_s16(yws, cb1); - - // undo scaling, round, convert to byte - uint8x8x4_t o; - o.val[0] = vqrshrun_n_s16(rws, 4); - o.val[1] = vqrshrun_n_s16(gws, 4); - o.val[2] = vqrshrun_n_s16(bws, 4); - o.val[3] = vdup_n_u8(255); - - // store, interleaving r/g/b/a - vst4_u8(out, o); - out += 8*4; - } - } -#endif - - for (; i < count; ++i) { - int y_fixed = (y[i] << 20) + (1<<19); // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr* float2fixed(1.40200f); - g = y_fixed + cr*-float2fixed(0.71414f) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); - b = y_fixed + cb* float2fixed(1.77200f); - r >>= 20; - g >>= 20; - b >>= 20; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi_uc)r; - out[1] = (stbi_uc)g; - out[2] = (stbi_uc)b; - out[3] = 255; - out += step; - } -} -#endif - -// set up the kernels -static void stbi__setup_jpeg(stbi__jpeg *j) -{ - j->idct_block_kernel = stbi__idct_block; - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; - -#ifdef STBI_SSE2 - if (stbi__sse2_available()) { - j->idct_block_kernel = stbi__idct_simd; - #ifndef STBI_JPEG_OLD - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; - #endif - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; - } -#endif - -#ifdef STBI_NEON - j->idct_block_kernel = stbi__idct_simd; - #ifndef STBI_JPEG_OLD - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; - #endif - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; -#endif -} - -// clean up the temporary component buffers -static void stbi__cleanup_jpeg(stbi__jpeg *j) -{ - int i; - for (i=0; i < j->s->img_n; ++i) { - if (j->img_comp[i].raw_data) { - STBI_FREE(j->img_comp[i].raw_data); - j->img_comp[i].raw_data = NULL; - j->img_comp[i].data = NULL; - } - if (j->img_comp[i].raw_coeff) { - STBI_FREE(j->img_comp[i].raw_coeff); - j->img_comp[i].raw_coeff = 0; - j->img_comp[i].coeff = 0; - } - if (j->img_comp[i].linebuf) { - STBI_FREE(j->img_comp[i].linebuf); - j->img_comp[i].linebuf = NULL; - } - } -} - -typedef struct -{ - resample_row_func resample; - stbi_uc *line0,*line1; - int hs,vs; // expansion factor in each axis - int w_lores; // horizontal pixels pre-expansion - int ystep; // how far through vertical expansion we are - int ypos; // which pre-expansion row we're on -} stbi__resample; - -static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) -{ - int n, decode_n; - z->s->img_n = 0; // make stbi__cleanup_jpeg safe - - // validate req_comp - if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); - - // load a jpeg image from whichever source, but leave in YCbCr format - if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } - - // determine actual number of components to generate - n = req_comp ? req_comp : z->s->img_n; - - if (z->s->img_n == 3 && n < 3) - decode_n = 1; - else - decode_n = z->s->img_n; - - // resample and color-convert - { - int k; - unsigned int i,j; - stbi_uc *output; - stbi_uc *coutput[4]; - - stbi__resample res_comp[4]; - - for (k=0; k < decode_n; ++k) { - stbi__resample *r = &res_comp[k]; - - // allocate line buffer big enough for upsampling off the edges - // with upsample factor of 4 - z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); - if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } - - r->hs = z->img_h_max / z->img_comp[k].h; - r->vs = z->img_v_max / z->img_comp[k].v; - r->ystep = r->vs >> 1; - r->w_lores = (z->s->img_x + r->hs-1) / r->hs; - r->ypos = 0; - r->line0 = r->line1 = z->img_comp[k].data; - - if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; - else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; - else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; - else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; - else r->resample = stbi__resample_row_generic; - } - - // can't error after this so, this is safe - output = (stbi_uc *) stbi__malloc(n * z->s->img_x * z->s->img_y + 1); - if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } - - // now go ahead and resample - for (j=0; j < z->s->img_y; ++j) { - stbi_uc *out = output + n * z->s->img_x * j; - for (k=0; k < decode_n; ++k) { - stbi__resample *r = &res_comp[k]; - int y_bot = r->ystep >= (r->vs >> 1); - coutput[k] = r->resample(z->img_comp[k].linebuf, - y_bot ? r->line1 : r->line0, - y_bot ? r->line0 : r->line1, - r->w_lores, r->hs); - if (++r->ystep >= r->vs) { - r->ystep = 0; - r->line0 = r->line1; - if (++r->ypos < z->img_comp[k].y) - r->line1 += z->img_comp[k].w2; - } - } - if (n >= 3) { - stbi_uc *y = coutput[0]; - if (z->s->img_n == 3) { - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - } else - for (i=0; i < z->s->img_x; ++i) { - out[0] = out[1] = out[2] = y[i]; - out[3] = 255; // not used if n==3 - out += n; - } - } else { - stbi_uc *y = coutput[0]; - if (n == 1) - for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; - else - for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; - } - } - stbi__cleanup_jpeg(z); - *out_x = z->s->img_x; - *out_y = z->s->img_y; - if (comp) *comp = z->s->img_n; // report original components, not output - return output; - } -} - -static unsigned char *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi__jpeg j; - j.s = s; - stbi__setup_jpeg(&j); - return load_jpeg_image(&j, x,y,comp,req_comp); -} - -static int stbi__jpeg_test(stbi__context *s) -{ - int r; - stbi__jpeg j; - j.s = s; - stbi__setup_jpeg(&j); - r = stbi__decode_jpeg_header(&j, STBI__SCAN_type); - stbi__rewind(s); - return r; -} - -static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) -{ - if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { - stbi__rewind( j->s ); - return 0; - } - if (x) *x = j->s->img_x; - if (y) *y = j->s->img_y; - if (comp) *comp = j->s->img_n; - return 1; -} - -static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) -{ - stbi__jpeg j; - j.s = s; - return stbi__jpeg_info_raw(&j, x, y, comp); -} -#endif - -// public domain zlib decode v0.2 Sean Barrett 2006-11-18 -// simple implementation -// - all input must be provided in an upfront buffer -// - all output is written to a single output buffer (can malloc/realloc) -// performance -// - fast huffman - -#ifndef STBI_NO_ZLIB - -// fast-way is faster to check than jpeg huffman, but slow way is slower -#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables -#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) - -// zlib-style huffman encoding -// (jpegs packs from left, zlib from right, so can't share code) -typedef struct -{ - stbi__uint16 fast[1 << STBI__ZFAST_BITS]; - stbi__uint16 firstcode[16]; - int maxcode[17]; - stbi__uint16 firstsymbol[16]; - stbi_uc size[288]; - stbi__uint16 value[288]; -} stbi__zhuffman; - -stbi_inline static int stbi__bitreverse16(int n) -{ - n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); - n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); - n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); - n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); - return n; -} - -stbi_inline static int stbi__bit_reverse(int v, int bits) -{ - STBI_ASSERT(bits <= 16); - // to bit reverse n bits, reverse 16 and shift - // e.g. 11 bits, bit reverse and shift away 5 - return stbi__bitreverse16(v) >> (16-bits); -} - -static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) -{ - int i,k=0; - int code, next_code[16], sizes[17]; - - // DEFLATE spec for generating codes - memset(sizes, 0, sizeof(sizes)); - memset(z->fast, 0, sizeof(z->fast)); - for (i=0; i < num; ++i) - ++sizes[sizelist[i]]; - sizes[0] = 0; - for (i=1; i < 16; ++i) - if (sizes[i] > (1 << i)) - return stbi__err("bad sizes", "Corrupt PNG"); - code = 0; - for (i=1; i < 16; ++i) { - next_code[i] = code; - z->firstcode[i] = (stbi__uint16) code; - z->firstsymbol[i] = (stbi__uint16) k; - code = (code + sizes[i]); - if (sizes[i]) - if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); - z->maxcode[i] = code << (16-i); // preshift for inner loop - code <<= 1; - k += sizes[i]; - } - z->maxcode[16] = 0x10000; // sentinel - for (i=0; i < num; ++i) { - int s = sizelist[i]; - if (s) { - int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; - stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); - z->size [c] = (stbi_uc ) s; - z->value[c] = (stbi__uint16) i; - if (s <= STBI__ZFAST_BITS) { - int j = stbi__bit_reverse(next_code[s],s); - while (j < (1 << STBI__ZFAST_BITS)) { - z->fast[j] = fastv; - j += (1 << s); - } - } - ++next_code[s]; - } - } - return 1; -} - -// zlib-from-memory implementation for PNG reading -// because PNG allows splitting the zlib stream arbitrarily, -// and it's annoying structurally to have PNG call ZLIB call PNG, -// we require PNG read all the IDATs and combine them into a single -// memory buffer - -typedef struct -{ - stbi_uc *zbuffer, *zbuffer_end; - int num_bits; - stbi__uint32 code_buffer; - - char *zout; - char *zout_start; - char *zout_end; - int z_expandable; - - stbi__zhuffman z_length, z_distance; -} stbi__zbuf; - -stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) -{ - if (z->zbuffer >= z->zbuffer_end) return 0; - return *z->zbuffer++; -} - -static void stbi__fill_bits(stbi__zbuf *z) -{ - do { - STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); - z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; - z->num_bits += 8; - } while (z->num_bits <= 24); -} - -stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) -{ - unsigned int k; - if (z->num_bits < n) stbi__fill_bits(z); - k = z->code_buffer & ((1 << n) - 1); - z->code_buffer >>= n; - z->num_bits -= n; - return k; -} - -static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) -{ - int b,s,k; - // not resolved by fast table, so compute it the slow way - // use jpeg approach, which requires MSbits at top - k = stbi__bit_reverse(a->code_buffer, 16); - for (s=STBI__ZFAST_BITS+1; ; ++s) - if (k < z->maxcode[s]) - break; - if (s == 16) return -1; // invalid code! - // code size is s, so: - b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; - STBI_ASSERT(z->size[b] == s); - a->code_buffer >>= s; - a->num_bits -= s; - return z->value[b]; -} - -stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) -{ - int b,s; - if (a->num_bits < 16) stbi__fill_bits(a); - b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; - if (b) { - s = b >> 9; - a->code_buffer >>= s; - a->num_bits -= s; - return b & 511; - } - return stbi__zhuffman_decode_slowpath(a, z); -} - -static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes -{ - char *q; - int cur, limit; - z->zout = zout; - if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); - cur = (int) (z->zout - z->zout_start); - limit = (int) (z->zout_end - z->zout_start); - while (cur + n > limit) - limit *= 2; - q = (char *) STBI_REALLOC(z->zout_start, limit); - if (q == NULL) return stbi__err("outofmem", "Out of memory"); - z->zout_start = q; - z->zout = q + cur; - z->zout_end = q + limit; - return 1; -} - -static int stbi__zlength_base[31] = { - 3,4,5,6,7,8,9,10,11,13, - 15,17,19,23,27,31,35,43,51,59, - 67,83,99,115,131,163,195,227,258,0,0 }; - -static int stbi__zlength_extra[31]= -{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; - -static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, -257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; - -static int stbi__zdist_extra[32] = -{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -static int stbi__parse_huffman_block(stbi__zbuf *a) -{ - char *zout = a->zout; - for(;;) { - int z = stbi__zhuffman_decode(a, &a->z_length); - if (z < 256) { - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes - if (zout >= a->zout_end) { - if (!stbi__zexpand(a, zout, 1)) return 0; - zout = a->zout; - } - *zout++ = (char) z; - } else { - stbi_uc *p; - int len,dist; - if (z == 256) { - a->zout = zout; - return 1; - } - z -= 257; - len = stbi__zlength_base[z]; - if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); - z = stbi__zhuffman_decode(a, &a->z_distance); - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); - dist = stbi__zdist_base[z]; - if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); - if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); - if (zout + len > a->zout_end) { - if (!stbi__zexpand(a, zout, len)) return 0; - zout = a->zout; - } - p = (stbi_uc *) (zout - dist); - if (dist == 1) { // run of one byte; common in images. - stbi_uc v = *p; - if (len) { do *zout++ = v; while (--len); } - } else { - if (len) { do *zout++ = *p++; while (--len); } - } - } - } -} - -static int stbi__compute_huffman_codes(stbi__zbuf *a) -{ - static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; - stbi__zhuffman z_codelength; - stbi_uc lencodes[286+32+137];//padding for maximum single op - stbi_uc codelength_sizes[19]; - int i,n; - - int hlit = stbi__zreceive(a,5) + 257; - int hdist = stbi__zreceive(a,5) + 1; - int hclen = stbi__zreceive(a,4) + 4; - - memset(codelength_sizes, 0, sizeof(codelength_sizes)); - for (i=0; i < hclen; ++i) { - int s = stbi__zreceive(a,3); - codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; - } - if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; - - n = 0; - while (n < hlit + hdist) { - int c = stbi__zhuffman_decode(a, &z_codelength); - if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); - if (c < 16) - lencodes[n++] = (stbi_uc) c; - else if (c == 16) { - c = stbi__zreceive(a,2)+3; - memset(lencodes+n, lencodes[n-1], c); - n += c; - } else if (c == 17) { - c = stbi__zreceive(a,3)+3; - memset(lencodes+n, 0, c); - n += c; - } else { - STBI_ASSERT(c == 18); - c = stbi__zreceive(a,7)+11; - memset(lencodes+n, 0, c); - n += c; - } - } - if (n != hlit+hdist) return stbi__err("bad codelengths","Corrupt PNG"); - if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; - if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; - return 1; -} - -static int stbi__parse_uncomperssed_block(stbi__zbuf *a) -{ - stbi_uc header[4]; - int len,nlen,k; - if (a->num_bits & 7) - stbi__zreceive(a, a->num_bits & 7); // discard - // drain the bit-packed data into header - k = 0; - while (a->num_bits > 0) { - header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check - a->code_buffer >>= 8; - a->num_bits -= 8; - } - STBI_ASSERT(a->num_bits == 0); - // now fill header the normal way - while (k < 4) - header[k++] = stbi__zget8(a); - len = header[1] * 256 + header[0]; - nlen = header[3] * 256 + header[2]; - if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); - if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); - if (a->zout + len > a->zout_end) - if (!stbi__zexpand(a, a->zout, len)) return 0; - memcpy(a->zout, a->zbuffer, len); - a->zbuffer += len; - a->zout += len; - return 1; -} - -static int stbi__parse_zlib_header(stbi__zbuf *a) -{ - int cmf = stbi__zget8(a); - int cm = cmf & 15; - /* int cinfo = cmf >> 4; */ - int flg = stbi__zget8(a); - if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec - if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png - if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png - // window = 1 << (8 + cinfo)... but who cares, we fully buffer output - return 1; -} - -// @TODO: should statically initialize these for optimal thread safety -static stbi_uc stbi__zdefault_length[288], stbi__zdefault_distance[32]; -static void stbi__init_zdefaults(void) -{ - int i; // use <= to match clearly with spec - for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; - for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; - for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; - for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; - - for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; -} - -static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) -{ - int final, type; - if (parse_header) - if (!stbi__parse_zlib_header(a)) return 0; - a->num_bits = 0; - a->code_buffer = 0; - do { - final = stbi__zreceive(a,1); - type = stbi__zreceive(a,2); - if (type == 0) { - if (!stbi__parse_uncomperssed_block(a)) return 0; - } else if (type == 3) { - return 0; - } else { - if (type == 1) { - // use fixed code lengths - if (!stbi__zdefault_distance[31]) stbi__init_zdefaults(); - if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; - if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; - } else { - if (!stbi__compute_huffman_codes(a)) return 0; - } - if (!stbi__parse_huffman_block(a)) return 0; - } - } while (!final); - return 1; -} - -static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) -{ - a->zout_start = obuf; - a->zout = obuf; - a->zout_end = obuf + olen; - a->z_expandable = exp; - - return stbi__parse_zlib(a, parse_header); -} - -STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(initial_size); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer + len; - if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } -} - -STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) -{ - return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); -} - -STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(initial_size); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer + len; - if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } -} - -STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) -{ - stbi__zbuf a; - a.zbuffer = (stbi_uc *) ibuffer; - a.zbuffer_end = (stbi_uc *) ibuffer + ilen; - if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) - return (int) (a.zout - a.zout_start); - else - return -1; -} - -STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(16384); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer+len; - if (stbi__do_zlib(&a, p, 16384, 1, 0)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } -} - -STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) -{ - stbi__zbuf a; - a.zbuffer = (stbi_uc *) ibuffer; - a.zbuffer_end = (stbi_uc *) ibuffer + ilen; - if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) - return (int) (a.zout - a.zout_start); - else - return -1; -} -#endif - -// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 -// simple implementation -// - only 8-bit samples -// - no CRC checking -// - allocates lots of intermediate memory -// - avoids problem of streaming data between subsystems -// - avoids explicit window management -// performance -// - uses stb_zlib, a PD zlib implementation with fast huffman decoding - -#ifndef STBI_NO_PNG -typedef struct -{ - stbi__uint32 length; - stbi__uint32 type; -} stbi__pngchunk; - -static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) -{ - stbi__pngchunk c; - c.length = stbi__get32be(s); - c.type = stbi__get32be(s); - return c; -} - -static int stbi__check_png_header(stbi__context *s) -{ - static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; - int i; - for (i=0; i < 8; ++i) - if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); - return 1; -} - -typedef struct -{ - stbi__context *s; - stbi_uc *idata, *expanded, *out; -} stbi__png; - - -enum { - STBI__F_none=0, - STBI__F_sub=1, - STBI__F_up=2, - STBI__F_avg=3, - STBI__F_paeth=4, - // synthetic filters used for first scanline to avoid needing a dummy row of 0s - STBI__F_avg_first, - STBI__F_paeth_first -}; - -static stbi_uc first_row_filter[5] = -{ - STBI__F_none, - STBI__F_sub, - STBI__F_none, - STBI__F_avg_first, - STBI__F_paeth_first -}; - -static int stbi__paeth(int a, int b, int c) -{ - int p = a + b - c; - int pa = abs(p-a); - int pb = abs(p-b); - int pc = abs(p-c); - if (pa <= pb && pa <= pc) return a; - if (pb <= pc) return b; - return c; -} - -static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; - -// create the png data from post-deflated data -static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) -{ - stbi__context *s = a->s; - stbi__uint32 i,j,stride = x*out_n; - stbi__uint32 img_len, img_width_bytes; - int k; - int img_n = s->img_n; // copy it into a local for later - - STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); - a->out = (stbi_uc *) stbi__malloc(x * y * out_n); // extra bytes to write off the end into - if (!a->out) return stbi__err("outofmem", "Out of memory"); - - img_width_bytes = (((img_n * x * depth) + 7) >> 3); - img_len = (img_width_bytes + 1) * y; - if (s->img_x == x && s->img_y == y) { - if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG"); - } else { // interlaced: - if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); - } - - for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *prior = cur - stride; - int filter = *raw++; - int filter_bytes = img_n; - int width = x; - if (filter > 4) - return stbi__err("invalid filter","Corrupt PNG"); - - if (depth < 8) { - STBI_ASSERT(img_width_bytes <= x); - cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place - filter_bytes = 1; - width = img_width_bytes; - } - - // if first row, use special filter that doesn't sample previous row - if (j == 0) filter = first_row_filter[filter]; - - // handle first byte explicitly - for (k=0; k < filter_bytes; ++k) { - switch (filter) { - case STBI__F_none : cur[k] = raw[k]; break; - case STBI__F_sub : cur[k] = raw[k]; break; - case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; - case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; - case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; - case STBI__F_avg_first : cur[k] = raw[k]; break; - case STBI__F_paeth_first: cur[k] = raw[k]; break; - } - } - - if (depth == 8) { - if (img_n != out_n) - cur[img_n] = 255; // first pixel - raw += img_n; - cur += out_n; - prior += out_n; - } else { - raw += 1; - cur += 1; - prior += 1; - } - - // this is a little gross, so that we don't switch per-pixel or per-component - if (depth < 8 || img_n == out_n) { - int nk = (width - 1)*img_n; - #define CASE(f) \ - case f: \ - for (k=0; k < nk; ++k) - switch (filter) { - // "none" filter turns into a memcpy here; make that explicit. - case STBI__F_none: memcpy(cur, raw, nk); break; - CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); break; - CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; - CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); break; - CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); break; - CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); break; - CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); break; - } - #undef CASE - raw += nk; - } else { - STBI_ASSERT(img_n+1 == out_n); - #define CASE(f) \ - case f: \ - for (i=x-1; i >= 1; --i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \ - for (k=0; k < img_n; ++k) - switch (filter) { - CASE(STBI__F_none) cur[k] = raw[k]; break; - CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-out_n]); break; - CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; - CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-out_n])>>1)); break; - CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],prior[k],prior[k-out_n])); break; - CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-out_n] >> 1)); break; - CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],0,0)); break; - } - #undef CASE - } - } - - // we make a separate pass to expand bits to pixels; for performance, - // this could run two scanlines behind the above code, so it won't - // intefere with filtering but will still be in the cache. - if (depth < 8) { - for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; - // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit - // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop - stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range - - // note that the final byte might overshoot and write more data than desired. - // we can allocate enough data that this never writes out of memory, but it - // could also overwrite the next scanline. can it overwrite non-empty data - // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. - // so we need to explicitly clamp the final ones - - if (depth == 4) { - for (k=x*img_n; k >= 2; k-=2, ++in) { - *cur++ = scale * ((*in >> 4) ); - *cur++ = scale * ((*in ) & 0x0f); - } - if (k > 0) *cur++ = scale * ((*in >> 4) ); - } else if (depth == 2) { - for (k=x*img_n; k >= 4; k-=4, ++in) { - *cur++ = scale * ((*in >> 6) ); - *cur++ = scale * ((*in >> 4) & 0x03); - *cur++ = scale * ((*in >> 2) & 0x03); - *cur++ = scale * ((*in ) & 0x03); - } - if (k > 0) *cur++ = scale * ((*in >> 6) ); - if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); - if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); - } else if (depth == 1) { - for (k=x*img_n; k >= 8; k-=8, ++in) { - *cur++ = scale * ((*in >> 7) ); - *cur++ = scale * ((*in >> 6) & 0x01); - *cur++ = scale * ((*in >> 5) & 0x01); - *cur++ = scale * ((*in >> 4) & 0x01); - *cur++ = scale * ((*in >> 3) & 0x01); - *cur++ = scale * ((*in >> 2) & 0x01); - *cur++ = scale * ((*in >> 1) & 0x01); - *cur++ = scale * ((*in ) & 0x01); - } - if (k > 0) *cur++ = scale * ((*in >> 7) ); - if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); - if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); - if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); - if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); - if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); - if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); - } - if (img_n != out_n) { - int q; - // insert alpha = 255 - cur = a->out + stride*j; - if (img_n == 1) { - for (q=x-1; q >= 0; --q) { - cur[q*2+1] = 255; - cur[q*2+0] = cur[q]; - } - } else { - STBI_ASSERT(img_n == 3); - for (q=x-1; q >= 0; --q) { - cur[q*4+3] = 255; - cur[q*4+2] = cur[q*3+2]; - cur[q*4+1] = cur[q*3+1]; - cur[q*4+0] = cur[q*3+0]; - } - } - } - } - } - - return 1; -} - -static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) -{ - stbi_uc *final; - int p; - if (!interlaced) - return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); - - // de-interlacing - final = (stbi_uc *) stbi__malloc(a->s->img_x * a->s->img_y * out_n); - for (p=0; p < 7; ++p) { - int xorig[] = { 0,4,0,2,0,1,0 }; - int yorig[] = { 0,0,4,0,2,0,1 }; - int xspc[] = { 8,8,4,4,2,2,1 }; - int yspc[] = { 8,8,8,4,4,2,2 }; - int i,j,x,y; - // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 - x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; - y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; - if (x && y) { - stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; - if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { - STBI_FREE(final); - return 0; - } - for (j=0; j < y; ++j) { - for (i=0; i < x; ++i) { - int out_y = j*yspc[p]+yorig[p]; - int out_x = i*xspc[p]+xorig[p]; - memcpy(final + out_y*a->s->img_x*out_n + out_x*out_n, - a->out + (j*x+i)*out_n, out_n); - } - } - STBI_FREE(a->out); - image_data += img_len; - image_data_len -= img_len; - } - } - a->out = final; - - return 1; -} - -static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi_uc *p = z->out; - - // compute color-based transparency, assuming we've - // already got 255 as the alpha value in the output - STBI_ASSERT(out_n == 2 || out_n == 4); - - if (out_n == 2) { - for (i=0; i < pixel_count; ++i) { - p[1] = (p[0] == tc[0] ? 0 : 255); - p += 2; - } - } else { - for (i=0; i < pixel_count; ++i) { - if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) - p[3] = 0; - p += 4; - } - } - return 1; -} - -static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) -{ - stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; - stbi_uc *p, *temp_out, *orig = a->out; - - p = (stbi_uc *) stbi__malloc(pixel_count * pal_img_n); - if (p == NULL) return stbi__err("outofmem", "Out of memory"); - - // between here and free(out) below, exitting would leak - temp_out = p; - - if (pal_img_n == 3) { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p += 3; - } - } else { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p[3] = palette[n+3]; - p += 4; - } - } - STBI_FREE(a->out); - a->out = temp_out; - - STBI_NOTUSED(len); - - return 1; -} - -static int stbi__unpremultiply_on_load = 0; -static int stbi__de_iphone_flag = 0; - -STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) -{ - stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; -} - -STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) -{ - stbi__de_iphone_flag = flag_true_if_should_convert; -} - -static void stbi__de_iphone(stbi__png *z) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi_uc *p = z->out; - - if (s->img_out_n == 3) { // convert bgr to rgb - for (i=0; i < pixel_count; ++i) { - stbi_uc t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 3; - } - } else { - STBI_ASSERT(s->img_out_n == 4); - if (stbi__unpremultiply_on_load) { - // convert bgr to rgb and unpremultiply - for (i=0; i < pixel_count; ++i) { - stbi_uc a = p[3]; - stbi_uc t = p[0]; - if (a) { - p[0] = p[2] * 255 / a; - p[1] = p[1] * 255 / a; - p[2] = t * 255 / a; - } else { - p[0] = p[2]; - p[2] = t; - } - p += 4; - } - } else { - // convert bgr to rgb - for (i=0; i < pixel_count; ++i) { - stbi_uc t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 4; - } - } - } -} - -#define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) - -static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) -{ - stbi_uc palette[1024], pal_img_n=0; - stbi_uc has_trans=0, tc[3]; - stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; - int first=1,k,interlace=0, color=0, depth=0, is_iphone=0; - stbi__context *s = z->s; - - z->expanded = NULL; - z->idata = NULL; - z->out = NULL; - - if (!stbi__check_png_header(s)) return 0; - - if (scan == STBI__SCAN_type) return 1; - - for (;;) { - stbi__pngchunk c = stbi__get_chunk_header(s); - switch (c.type) { - case STBI__PNG_TYPE('C','g','B','I'): - is_iphone = 1; - stbi__skip(s, c.length); - break; - case STBI__PNG_TYPE('I','H','D','R'): { - int comp,filter; - if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); - first = 0; - if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); - s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - depth = stbi__get8(s); if (depth != 1 && depth != 2 && depth != 4 && depth != 8) return stbi__err("1/2/4/8-bit only","PNG not supported: 1/2/4/8-bit only"); - color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); - comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); - filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); - interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); - if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); - if (!pal_img_n) { - s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); - if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); - if (scan == STBI__SCAN_header) return 1; - } else { - // if paletted, then pal_n is our final components, and - // img_n is # components to decompress/filter. - s->img_n = 1; - if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); - // if SCAN_header, have to scan to see if we have a tRNS - } - break; - } - - case STBI__PNG_TYPE('P','L','T','E'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); - pal_len = c.length / 3; - if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); - for (i=0; i < pal_len; ++i) { - palette[i*4+0] = stbi__get8(s); - palette[i*4+1] = stbi__get8(s); - palette[i*4+2] = stbi__get8(s); - palette[i*4+3] = 255; - } - break; - } - - case STBI__PNG_TYPE('t','R','N','S'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); - if (pal_img_n) { - if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } - if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); - if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); - pal_img_n = 4; - for (i=0; i < c.length; ++i) - palette[i*4+3] = stbi__get8(s); - } else { - if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); - if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); - has_trans = 1; - for (k=0; k < s->img_n; ++k) - tc[k] = (stbi_uc) (stbi__get16be(s) & 255) * stbi__depth_scale_table[depth]; // non 8-bit images will be larger - } - break; - } - - case STBI__PNG_TYPE('I','D','A','T'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); - if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } - if ((int)(ioff + c.length) < (int)ioff) return 0; - if (ioff + c.length > idata_limit) { - stbi_uc *p; - if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; - while (ioff + c.length > idata_limit) - idata_limit *= 2; - p = (stbi_uc *) STBI_REALLOC(z->idata, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); - z->idata = p; - } - if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); - ioff += c.length; - break; - } - - case STBI__PNG_TYPE('I','E','N','D'): { - stbi__uint32 raw_len, bpl; - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (scan != STBI__SCAN_load) return 1; - if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); - // initial guess for decoded data size to avoid unnecessary reallocs - bpl = (s->img_x * depth + 7) / 8; // bytes per line, per component - raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; - z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); - if (z->expanded == NULL) return 0; // zlib should set error - STBI_FREE(z->idata); z->idata = NULL; - if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) - s->img_out_n = s->img_n+1; - else - s->img_out_n = s->img_n; - if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, depth, color, interlace)) return 0; - if (has_trans) - if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; - if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) - stbi__de_iphone(z); - if (pal_img_n) { - // pal_img_n == 3 or 4 - s->img_n = pal_img_n; // record the actual colors we had - s->img_out_n = pal_img_n; - if (req_comp >= 3) s->img_out_n = req_comp; - if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) - return 0; - } - STBI_FREE(z->expanded); z->expanded = NULL; - return 1; - } - - default: - // if critical, fail - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if ((c.type & (1 << 29)) == 0) { - #ifndef STBI_NO_FAILURE_STRINGS - // not threadsafe - static char invalid_chunk[] = "XXXX PNG chunk not known"; - invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); - invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); - invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); - invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); - #endif - return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); - } - stbi__skip(s, c.length); - break; - } - // end of PNG chunk, read and skip CRC - stbi__get32be(s); - } -} - -static unsigned char *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp) -{ - unsigned char *result=NULL; - if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); - if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { - result = p->out; - p->out = NULL; - if (req_comp && req_comp != p->s->img_out_n) { - result = stbi__convert_format(result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); - p->s->img_out_n = req_comp; - if (result == NULL) return result; - } - *x = p->s->img_x; - *y = p->s->img_y; - if (n) *n = p->s->img_out_n; - } - STBI_FREE(p->out); p->out = NULL; - STBI_FREE(p->expanded); p->expanded = NULL; - STBI_FREE(p->idata); p->idata = NULL; - - return result; -} - -static unsigned char *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi__png p; - p.s = s; - return stbi__do_png(&p, x,y,comp,req_comp); -} - -static int stbi__png_test(stbi__context *s) -{ - int r; - r = stbi__check_png_header(s); - stbi__rewind(s); - return r; -} - -static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) -{ - if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { - stbi__rewind( p->s ); - return 0; - } - if (x) *x = p->s->img_x; - if (y) *y = p->s->img_y; - if (comp) *comp = p->s->img_n; - return 1; -} - -static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) -{ - stbi__png p; - p.s = s; - return stbi__png_info_raw(&p, x, y, comp); -} -#endif - -// Microsoft/Windows BMP image - -#ifndef STBI_NO_BMP -static int stbi__bmp_test_raw(stbi__context *s) -{ - int r; - int sz; - if (stbi__get8(s) != 'B') return 0; - if (stbi__get8(s) != 'M') return 0; - stbi__get32le(s); // discard filesize - stbi__get16le(s); // discard reserved - stbi__get16le(s); // discard reserved - stbi__get32le(s); // discard data offset - sz = stbi__get32le(s); - r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); - return r; -} - -static int stbi__bmp_test(stbi__context *s) -{ - int r = stbi__bmp_test_raw(s); - stbi__rewind(s); - return r; -} - - -// returns 0..31 for the highest set bit -static int stbi__high_bit(unsigned int z) -{ - int n=0; - if (z == 0) return -1; - if (z >= 0x10000) n += 16, z >>= 16; - if (z >= 0x00100) n += 8, z >>= 8; - if (z >= 0x00010) n += 4, z >>= 4; - if (z >= 0x00004) n += 2, z >>= 2; - if (z >= 0x00002) n += 1, z >>= 1; - return n; -} - -static int stbi__bitcount(unsigned int a) -{ - a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 - a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 - a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits - a = (a + (a >> 8)); // max 16 per 8 bits - a = (a + (a >> 16)); // max 32 per 8 bits - return a & 0xff; -} - -static int stbi__shiftsigned(int v, int shift, int bits) -{ - int result; - int z=0; - - if (shift < 0) v <<= -shift; - else v >>= shift; - result = v; - - z = bits; - while (z < 8) { - result += v >> z; - z += bits; - } - return result; -} - -static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi_uc *out; - unsigned int mr=0,mg=0,mb=0,ma=0, all_a=255; - stbi_uc pal[256][4]; - int psize=0,i,j,compress=0,width; - int bpp, flip_vertically, pad, target, offset, hsz; - if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); - stbi__get32le(s); // discard filesize - stbi__get16le(s); // discard reserved - stbi__get16le(s); // discard reserved - offset = stbi__get32le(s); - hsz = stbi__get32le(s); - if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); - if (hsz == 12) { - s->img_x = stbi__get16le(s); - s->img_y = stbi__get16le(s); - } else { - s->img_x = stbi__get32le(s); - s->img_y = stbi__get32le(s); - } - if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); - bpp = stbi__get16le(s); - if (bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit"); - flip_vertically = ((int) s->img_y) > 0; - s->img_y = abs((int) s->img_y); - if (hsz == 12) { - if (bpp < 24) - psize = (offset - 14 - 24) / 3; - } else { - compress = stbi__get32le(s); - if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); - stbi__get32le(s); // discard sizeof - stbi__get32le(s); // discard hres - stbi__get32le(s); // discard vres - stbi__get32le(s); // discard colorsused - stbi__get32le(s); // discard max important - if (hsz == 40 || hsz == 56) { - if (hsz == 56) { - stbi__get32le(s); - stbi__get32le(s); - stbi__get32le(s); - stbi__get32le(s); - } - if (bpp == 16 || bpp == 32) { - mr = mg = mb = 0; - if (compress == 0) { - if (bpp == 32) { - mr = 0xffu << 16; - mg = 0xffu << 8; - mb = 0xffu << 0; - ma = 0xffu << 24; - all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 - } else { - mr = 31u << 10; - mg = 31u << 5; - mb = 31u << 0; - } - } else if (compress == 3) { - mr = stbi__get32le(s); - mg = stbi__get32le(s); - mb = stbi__get32le(s); - // not documented, but generated by photoshop and handled by mspaint - if (mr == mg && mg == mb) { - // ?!?!? - return stbi__errpuc("bad BMP", "bad BMP"); - } - } else - return stbi__errpuc("bad BMP", "bad BMP"); - } - } else { - STBI_ASSERT(hsz == 108 || hsz == 124); - mr = stbi__get32le(s); - mg = stbi__get32le(s); - mb = stbi__get32le(s); - ma = stbi__get32le(s); - stbi__get32le(s); // discard color space - for (i=0; i < 12; ++i) - stbi__get32le(s); // discard color space parameters - if (hsz == 124) { - stbi__get32le(s); // discard rendering intent - stbi__get32le(s); // discard offset of profile data - stbi__get32le(s); // discard size of profile data - stbi__get32le(s); // discard reserved - } - } - if (bpp < 16) - psize = (offset - 14 - hsz) >> 2; - } - s->img_n = ma ? 4 : 3; - if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 - target = req_comp; - else - target = s->img_n; // if they want monochrome, we'll post-convert - out = (stbi_uc *) stbi__malloc(target * s->img_x * s->img_y); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - if (bpp < 16) { - int z=0; - if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } - for (i=0; i < psize; ++i) { - pal[i][2] = stbi__get8(s); - pal[i][1] = stbi__get8(s); - pal[i][0] = stbi__get8(s); - if (hsz != 12) stbi__get8(s); - pal[i][3] = 255; - } - stbi__skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4)); - if (bpp == 4) width = (s->img_x + 1) >> 1; - else if (bpp == 8) width = s->img_x; - else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } - pad = (-width)&3; - for (j=0; j < (int) s->img_y; ++j) { - for (i=0; i < (int) s->img_x; i += 2) { - int v=stbi__get8(s),v2=0; - if (bpp == 4) { - v2 = v & 15; - v >>= 4; - } - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - if (i+1 == (int) s->img_x) break; - v = (bpp == 8) ? stbi__get8(s) : v2; - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - } - stbi__skip(s, pad); - } - } else { - int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; - int z = 0; - int easy=0; - stbi__skip(s, offset - 14 - hsz); - if (bpp == 24) width = 3 * s->img_x; - else if (bpp == 16) width = 2*s->img_x; - else /* bpp = 32 and pad = 0 */ width=0; - pad = (-width) & 3; - if (bpp == 24) { - easy = 1; - } else if (bpp == 32) { - if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) - easy = 2; - } - if (!easy) { - if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } - // right shift amt to put high bit in position #7 - rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); - gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); - bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); - ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); - } - for (j=0; j < (int) s->img_y; ++j) { - if (easy) { - for (i=0; i < (int) s->img_x; ++i) { - unsigned char a; - out[z+2] = stbi__get8(s); - out[z+1] = stbi__get8(s); - out[z+0] = stbi__get8(s); - z += 3; - a = (easy == 2 ? stbi__get8(s) : 255); - all_a |= a; - if (target == 4) out[z++] = a; - } - } else { - for (i=0; i < (int) s->img_x; ++i) { - stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); - int a; - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); - a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); - all_a |= a; - if (target == 4) out[z++] = STBI__BYTECAST(a); - } - } - stbi__skip(s, pad); - } - } - - // if alpha channel is all 0s, replace with all 255s - if (target == 4 && all_a == 0) - for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) - out[i] = 255; - - if (flip_vertically) { - stbi_uc t; - for (j=0; j < (int) s->img_y>>1; ++j) { - stbi_uc *p1 = out + j *s->img_x*target; - stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; - for (i=0; i < (int) s->img_x*target; ++i) { - t = p1[i], p1[i] = p2[i], p2[i] = t; - } - } - } - - if (req_comp && req_comp != target) { - out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } - - *x = s->img_x; - *y = s->img_y; - if (comp) *comp = s->img_n; - return out; -} -#endif - -// Targa Truevision - TGA -// by Jonathan Dummer -#ifndef STBI_NO_TGA -static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) -{ - int tga_w, tga_h, tga_comp; - int sz; - stbi__get8(s); // discard Offset - sz = stbi__get8(s); // color type - if( sz > 1 ) { - stbi__rewind(s); - return 0; // only RGB or indexed allowed - } - sz = stbi__get8(s); // image type - // only RGB or grey allowed, +/- RLE - if ((sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11)) return 0; - stbi__skip(s,9); - tga_w = stbi__get16le(s); - if( tga_w < 1 ) { - stbi__rewind(s); - return 0; // test width - } - tga_h = stbi__get16le(s); - if( tga_h < 1 ) { - stbi__rewind(s); - return 0; // test height - } - sz = stbi__get8(s); // bits per pixel - // only RGB or RGBA or grey allowed - if ((sz != 8) && (sz != 16) && (sz != 24) && (sz != 32)) { - stbi__rewind(s); - return 0; - } - tga_comp = sz; - if (x) *x = tga_w; - if (y) *y = tga_h; - if (comp) *comp = tga_comp / 8; - return 1; // seems to have passed everything -} - -static int stbi__tga_test(stbi__context *s) -{ - int res; - int sz; - stbi__get8(s); // discard Offset - sz = stbi__get8(s); // color type - if ( sz > 1 ) return 0; // only RGB or indexed allowed - sz = stbi__get8(s); // image type - if ( (sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11) ) return 0; // only RGB or grey allowed, +/- RLE - stbi__get16be(s); // discard palette start - stbi__get16be(s); // discard palette length - stbi__get8(s); // discard bits per palette color entry - stbi__get16be(s); // discard x origin - stbi__get16be(s); // discard y origin - if ( stbi__get16be(s) < 1 ) return 0; // test width - if ( stbi__get16be(s) < 1 ) return 0; // test height - sz = stbi__get8(s); // bits per pixel - if ( (sz != 8) && (sz != 16) && (sz != 24) && (sz != 32) ) - res = 0; - else - res = 1; - stbi__rewind(s); - return res; -} - -static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - // read in the TGA header stuff - int tga_offset = stbi__get8(s); - int tga_indexed = stbi__get8(s); - int tga_image_type = stbi__get8(s); - int tga_is_RLE = 0; - int tga_palette_start = stbi__get16le(s); - int tga_palette_len = stbi__get16le(s); - int tga_palette_bits = stbi__get8(s); - int tga_x_origin = stbi__get16le(s); - int tga_y_origin = stbi__get16le(s); - int tga_width = stbi__get16le(s); - int tga_height = stbi__get16le(s); - int tga_bits_per_pixel = stbi__get8(s); - int tga_comp = tga_bits_per_pixel / 8; - int tga_inverted = stbi__get8(s); - // image data - unsigned char *tga_data; - unsigned char *tga_palette = NULL; - int i, j; - unsigned char raw_data[4]; - int RLE_count = 0; - int RLE_repeating = 0; - int read_next_pixel = 1; - - // do a tiny bit of precessing - if ( tga_image_type >= 8 ) - { - tga_image_type -= 8; - tga_is_RLE = 1; - } - /* int tga_alpha_bits = tga_inverted & 15; */ - tga_inverted = 1 - ((tga_inverted >> 5) & 1); - - // error check - if ( //(tga_indexed) || - (tga_width < 1) || (tga_height < 1) || - (tga_image_type < 1) || (tga_image_type > 3) || - ((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16) && - (tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32)) - ) - { - return NULL; // we don't report this as a bad TGA because we don't even know if it's TGA - } - - // If I'm paletted, then I'll use the number of bits from the palette - if ( tga_indexed ) - { - tga_comp = tga_palette_bits / 8; - } - - // tga info - *x = tga_width; - *y = tga_height; - if (comp) *comp = tga_comp; - - tga_data = (unsigned char*)stbi__malloc( (size_t)tga_width * tga_height * tga_comp ); - if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); - - // skip to the data's starting position (offset usually = 0) - stbi__skip(s, tga_offset ); - - if ( !tga_indexed && !tga_is_RLE) { - for (i=0; i < tga_height; ++i) { - int row = tga_inverted ? tga_height -i - 1 : i; - stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; - stbi__getn(s, tga_row, tga_width * tga_comp); - } - } else { - // do I need to load a palette? - if ( tga_indexed) - { - // any data to skip? (offset usually = 0) - stbi__skip(s, tga_palette_start ); - // load the palette - tga_palette = (unsigned char*)stbi__malloc( tga_palette_len * tga_palette_bits / 8 ); - if (!tga_palette) { - STBI_FREE(tga_data); - return stbi__errpuc("outofmem", "Out of memory"); - } - if (!stbi__getn(s, tga_palette, tga_palette_len * tga_palette_bits / 8 )) { - STBI_FREE(tga_data); - STBI_FREE(tga_palette); - return stbi__errpuc("bad palette", "Corrupt TGA"); - } - } - // load the data - for (i=0; i < tga_width * tga_height; ++i) - { - // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? - if ( tga_is_RLE ) - { - if ( RLE_count == 0 ) - { - // yep, get the next byte as a RLE command - int RLE_cmd = stbi__get8(s); - RLE_count = 1 + (RLE_cmd & 127); - RLE_repeating = RLE_cmd >> 7; - read_next_pixel = 1; - } else if ( !RLE_repeating ) - { - read_next_pixel = 1; - } - } else - { - read_next_pixel = 1; - } - // OK, if I need to read a pixel, do it now - if ( read_next_pixel ) - { - // load however much data we did have - if ( tga_indexed ) - { - // read in 1 byte, then perform the lookup - int pal_idx = stbi__get8(s); - if ( pal_idx >= tga_palette_len ) - { - // invalid index - pal_idx = 0; - } - pal_idx *= tga_bits_per_pixel / 8; - for (j = 0; j*8 < tga_bits_per_pixel; ++j) - { - raw_data[j] = tga_palette[pal_idx+j]; - } - } else - { - // read in the data raw - for (j = 0; j*8 < tga_bits_per_pixel; ++j) - { - raw_data[j] = stbi__get8(s); - } - } - // clear the reading flag for the next pixel - read_next_pixel = 0; - } // end of reading a pixel - - // copy data - for (j = 0; j < tga_comp; ++j) - tga_data[i*tga_comp+j] = raw_data[j]; - - // in case we're in RLE mode, keep counting down - --RLE_count; - } - // do I need to invert the image? - if ( tga_inverted ) - { - for (j = 0; j*2 < tga_height; ++j) - { - int index1 = j * tga_width * tga_comp; - int index2 = (tga_height - 1 - j) * tga_width * tga_comp; - for (i = tga_width * tga_comp; i > 0; --i) - { - unsigned char temp = tga_data[index1]; - tga_data[index1] = tga_data[index2]; - tga_data[index2] = temp; - ++index1; - ++index2; - } - } - } - // clear my palette, if I had one - if ( tga_palette != NULL ) - { - STBI_FREE( tga_palette ); - } - } - - // swap RGB - if (tga_comp >= 3) - { - unsigned char* tga_pixel = tga_data; - for (i=0; i < tga_width * tga_height; ++i) - { - unsigned char temp = tga_pixel[0]; - tga_pixel[0] = tga_pixel[2]; - tga_pixel[2] = temp; - tga_pixel += tga_comp; - } - } - - // convert to target component count - if (req_comp && req_comp != tga_comp) - tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); - - // the things I do to get rid of an error message, and yet keep - // Microsoft's C compilers happy... [8^( - tga_palette_start = tga_palette_len = tga_palette_bits = - tga_x_origin = tga_y_origin = 0; - // OK, done - return tga_data; -} -#endif - -// ************************************************************************************************* -// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB - -#ifndef STBI_NO_PSD -static int stbi__psd_test(stbi__context *s) -{ - int r = (stbi__get32be(s) == 0x38425053); - stbi__rewind(s); - return r; -} - -static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - int pixelCount; - int channelCount, compression; - int channel, i, count, len; - int bitdepth; - int w,h; - stbi_uc *out; - - // Check identifier - if (stbi__get32be(s) != 0x38425053) // "8BPS" - return stbi__errpuc("not PSD", "Corrupt PSD image"); - - // Check file type version. - if (stbi__get16be(s) != 1) - return stbi__errpuc("wrong version", "Unsupported version of PSD image"); - - // Skip 6 reserved bytes. - stbi__skip(s, 6 ); - - // Read the number of channels (R, G, B, A, etc). - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) - return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); - - // Read the rows and columns of the image. - h = stbi__get32be(s); - w = stbi__get32be(s); - - // Make sure the depth is 8 bits. - bitdepth = stbi__get16be(s); - if (bitdepth != 8 && bitdepth != 16) - return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); - - // Make sure the color mode is RGB. - // Valid options are: - // 0: Bitmap - // 1: Grayscale - // 2: Indexed color - // 3: RGB color - // 4: CMYK color - // 7: Multichannel - // 8: Duotone - // 9: Lab color - if (stbi__get16be(s) != 3) - return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); - - // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) - stbi__skip(s,stbi__get32be(s) ); - - // Skip the image resources. (resolution, pen tool paths, etc) - stbi__skip(s, stbi__get32be(s) ); - - // Skip the reserved data. - stbi__skip(s, stbi__get32be(s) ); - - // Find out if the data is compressed. - // Known values: - // 0: no compression - // 1: RLE compressed - compression = stbi__get16be(s); - if (compression > 1) - return stbi__errpuc("bad compression", "PSD has an unknown compression format"); - - // Create the destination image. - out = (stbi_uc *) stbi__malloc(4 * w*h); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - pixelCount = w*h; - - // Initialize the data to zero. - //memset( out, 0, pixelCount * 4 ); - - // Finally, the image data. - if (compression) { - // RLE as used by .PSD and .TIFF - // Loop until you get the number of unpacked bytes you are expecting: - // Read the next source byte into n. - // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. - // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. - // Else if n is 128, noop. - // Endloop - - // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, - // which we're going to just skip. - stbi__skip(s, h * channelCount * 2 ); - - // Read the RLE data by channel. - for (channel = 0; channel < 4; channel++) { - stbi_uc *p; - - p = out+channel; - if (channel >= channelCount) { - // Fill this channel with default data. - for (i = 0; i < pixelCount; i++, p += 4) - *p = (channel == 3 ? 255 : 0); - } else { - // Read the RLE data. - count = 0; - while (count < pixelCount) { - len = stbi__get8(s); - if (len == 128) { - // No-op. - } else if (len < 128) { - // Copy next len+1 bytes literally. - len++; - count += len; - while (len) { - *p = stbi__get8(s); - p += 4; - len--; - } - } else if (len > 128) { - stbi_uc val; - // Next -len+1 bytes in the dest are replicated from next source byte. - // (Interpret len as a negative 8-bit int.) - len ^= 0x0FF; - len += 2; - val = stbi__get8(s); - count += len; - while (len) { - *p = val; - p += 4; - len--; - } - } - } - } - } - - } else { - // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) - // where each channel consists of an 8-bit value for each pixel in the image. - - // Read the data by channel. - for (channel = 0; channel < 4; channel++) { - stbi_uc *p; - - p = out + channel; - if (channel >= channelCount) { - // Fill this channel with default data. - stbi_uc val = channel == 3 ? 255 : 0; - for (i = 0; i < pixelCount; i++, p += 4) - *p = val; - } else { - // Read the data. - if (bitdepth == 16) { - for (i = 0; i < pixelCount; i++, p += 4) - *p = (stbi_uc) (stbi__get16be(s) >> 8); - } else { - for (i = 0; i < pixelCount; i++, p += 4) - *p = stbi__get8(s); - } - } - } - } - - if (req_comp && req_comp != 4) { - out = stbi__convert_format(out, 4, req_comp, w, h); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } - - if (comp) *comp = 4; - *y = h; - *x = w; - - return out; -} -#endif - -// ************************************************************************************************* -// Softimage PIC loader -// by Tom Seddon -// -// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format -// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ - -#ifndef STBI_NO_PIC -static int stbi__pic_is4(stbi__context *s,const char *str) -{ - int i; - for (i=0; i<4; ++i) - if (stbi__get8(s) != (stbi_uc)str[i]) - return 0; - - return 1; -} - -static int stbi__pic_test_core(stbi__context *s) -{ - int i; - - if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) - return 0; - - for(i=0;i<84;++i) - stbi__get8(s); - - if (!stbi__pic_is4(s,"PICT")) - return 0; - - return 1; -} - -typedef struct -{ - stbi_uc size,type,channel; -} stbi__pic_packet; - -static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) -{ - int mask=0x80, i; - - for (i=0; i<4; ++i, mask>>=1) { - if (channel & mask) { - if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); - dest[i]=stbi__get8(s); - } - } - - return dest; -} - -static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) -{ - int mask=0x80,i; - - for (i=0;i<4; ++i, mask>>=1) - if (channel&mask) - dest[i]=src[i]; -} - -static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) -{ - int act_comp=0,num_packets=0,y,chained; - stbi__pic_packet packets[10]; - - // this will (should...) cater for even some bizarre stuff like having data - // for the same channel in multiple packets. - do { - stbi__pic_packet *packet; - - if (num_packets==sizeof(packets)/sizeof(packets[0])) - return stbi__errpuc("bad format","too many packets"); - - packet = &packets[num_packets++]; - - chained = stbi__get8(s); - packet->size = stbi__get8(s); - packet->type = stbi__get8(s); - packet->channel = stbi__get8(s); - - act_comp |= packet->channel; - - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); - if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); - } while (chained); - - *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? - - for(y=0; ytype) { - default: - return stbi__errpuc("bad format","packet has bad compression type"); - - case 0: {//uncompressed - int x; - - for(x=0;xchannel,dest)) - return 0; - break; - } - - case 1://Pure RLE - { - int left=width, i; - - while (left>0) { - stbi_uc count,value[4]; - - count=stbi__get8(s); - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); - - if (count > left) - count = (stbi_uc) left; - - if (!stbi__readval(s,packet->channel,value)) return 0; - - for(i=0; ichannel,dest,value); - left -= count; - } - } - break; - - case 2: {//Mixed RLE - int left=width; - while (left>0) { - int count = stbi__get8(s), i; - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); - - if (count >= 128) { // Repeated - stbi_uc value[4]; - - if (count==128) - count = stbi__get16be(s); - else - count -= 127; - if (count > left) - return stbi__errpuc("bad file","scanline overrun"); - - if (!stbi__readval(s,packet->channel,value)) - return 0; - - for(i=0;ichannel,dest,value); - } else { // Raw - ++count; - if (count>left) return stbi__errpuc("bad file","scanline overrun"); - - for(i=0;ichannel,dest)) - return 0; - } - left-=count; - } - break; - } - } - } - } - - return result; -} - -static stbi_uc *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp) -{ - stbi_uc *result; - int i, x,y; - - for (i=0; i<92; ++i) - stbi__get8(s); - - x = stbi__get16be(s); - y = stbi__get16be(s); - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); - if ((1 << 28) / x < y) return stbi__errpuc("too large", "Image too large to decode"); - - stbi__get32be(s); //skip `ratio' - stbi__get16be(s); //skip `fields' - stbi__get16be(s); //skip `pad' - - // intermediate buffer is RGBA - result = (stbi_uc *) stbi__malloc(x*y*4); - memset(result, 0xff, x*y*4); - - if (!stbi__pic_load_core(s,x,y,comp, result)) { - STBI_FREE(result); - result=0; - } - *px = x; - *py = y; - if (req_comp == 0) req_comp = *comp; - result=stbi__convert_format(result,4,req_comp,x,y); - - return result; -} - -static int stbi__pic_test(stbi__context *s) -{ - int r = stbi__pic_test_core(s); - stbi__rewind(s); - return r; -} -#endif - -// ************************************************************************************************* -// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb - -#ifndef STBI_NO_GIF -typedef struct -{ - stbi__int16 prefix; - stbi_uc first; - stbi_uc suffix; -} stbi__gif_lzw; - -typedef struct -{ - int w,h; - stbi_uc *out, *old_out; // output buffer (always 4 components) - int flags, bgindex, ratio, transparent, eflags, delay; - stbi_uc pal[256][4]; - stbi_uc lpal[256][4]; - stbi__gif_lzw codes[4096]; - stbi_uc *color_table; - int parse, step; - int lflags; - int start_x, start_y; - int max_x, max_y; - int cur_x, cur_y; - int line_size; -} stbi__gif; - -static int stbi__gif_test_raw(stbi__context *s) -{ - int sz; - if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; - sz = stbi__get8(s); - if (sz != '9' && sz != '7') return 0; - if (stbi__get8(s) != 'a') return 0; - return 1; -} - -static int stbi__gif_test(stbi__context *s) -{ - int r = stbi__gif_test_raw(s); - stbi__rewind(s); - return r; -} - -static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) -{ - int i; - for (i=0; i < num_entries; ++i) { - pal[i][2] = stbi__get8(s); - pal[i][1] = stbi__get8(s); - pal[i][0] = stbi__get8(s); - pal[i][3] = transp == i ? 0 : 255; - } -} - -static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) -{ - stbi_uc version; - if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') - return stbi__err("not GIF", "Corrupt GIF"); - - version = stbi__get8(s); - if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); - if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); - - stbi__g_failure_reason = ""; - g->w = stbi__get16le(s); - g->h = stbi__get16le(s); - g->flags = stbi__get8(s); - g->bgindex = stbi__get8(s); - g->ratio = stbi__get8(s); - g->transparent = -1; - - if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments - - if (is_info) return 1; - - if (g->flags & 0x80) - stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); - - return 1; -} - -static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) -{ - stbi__gif g; - if (!stbi__gif_header(s, &g, comp, 1)) { - stbi__rewind( s ); - return 0; - } - if (x) *x = g.w; - if (y) *y = g.h; - return 1; -} - -static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) -{ - stbi_uc *p, *c; - - // recurse to decode the prefixes, since the linked-list is backwards, - // and working backwards through an interleaved image would be nasty - if (g->codes[code].prefix >= 0) - stbi__out_gif_code(g, g->codes[code].prefix); - - if (g->cur_y >= g->max_y) return; - - p = &g->out[g->cur_x + g->cur_y]; - c = &g->color_table[g->codes[code].suffix * 4]; - - if (c[3] >= 128) { - p[0] = c[2]; - p[1] = c[1]; - p[2] = c[0]; - p[3] = c[3]; - } - g->cur_x += 4; - - if (g->cur_x >= g->max_x) { - g->cur_x = g->start_x; - g->cur_y += g->step; - - while (g->cur_y >= g->max_y && g->parse > 0) { - g->step = (1 << g->parse) * g->line_size; - g->cur_y = g->start_y + (g->step >> 1); - --g->parse; - } - } -} - -static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) -{ - stbi_uc lzw_cs; - stbi__int32 len, init_code; - stbi__uint32 first; - stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; - stbi__gif_lzw *p; - - lzw_cs = stbi__get8(s); - if (lzw_cs > 12) return NULL; - clear = 1 << lzw_cs; - first = 1; - codesize = lzw_cs + 1; - codemask = (1 << codesize) - 1; - bits = 0; - valid_bits = 0; - for (init_code = 0; init_code < clear; init_code++) { - g->codes[init_code].prefix = -1; - g->codes[init_code].first = (stbi_uc) init_code; - g->codes[init_code].suffix = (stbi_uc) init_code; - } - - // support no starting clear code - avail = clear+2; - oldcode = -1; - - len = 0; - for(;;) { - if (valid_bits < codesize) { - if (len == 0) { - len = stbi__get8(s); // start new block - if (len == 0) - return g->out; - } - --len; - bits |= (stbi__int32) stbi__get8(s) << valid_bits; - valid_bits += 8; - } else { - stbi__int32 code = bits & codemask; - bits >>= codesize; - valid_bits -= codesize; - // @OPTIMIZE: is there some way we can accelerate the non-clear path? - if (code == clear) { // clear code - codesize = lzw_cs + 1; - codemask = (1 << codesize) - 1; - avail = clear + 2; - oldcode = -1; - first = 0; - } else if (code == clear + 1) { // end of stream code - stbi__skip(s, len); - while ((len = stbi__get8(s)) > 0) - stbi__skip(s,len); - return g->out; - } else if (code <= avail) { - if (first) return stbi__errpuc("no clear code", "Corrupt GIF"); - - if (oldcode >= 0) { - p = &g->codes[avail++]; - if (avail > 4096) return stbi__errpuc("too many codes", "Corrupt GIF"); - p->prefix = (stbi__int16) oldcode; - p->first = g->codes[oldcode].first; - p->suffix = (code == avail) ? p->first : g->codes[code].first; - } else if (code == avail) - return stbi__errpuc("illegal code in raster", "Corrupt GIF"); - - stbi__out_gif_code(g, (stbi__uint16) code); - - if ((avail & codemask) == 0 && avail <= 0x0FFF) { - codesize++; - codemask = (1 << codesize) - 1; - } - - oldcode = code; - } else { - return stbi__errpuc("illegal code in raster", "Corrupt GIF"); - } - } - } -} - -static void stbi__fill_gif_background(stbi__gif *g, int x0, int y0, int x1, int y1) -{ - int x, y; - stbi_uc *c = g->pal[g->bgindex]; - for (y = y0; y < y1; y += 4 * g->w) { - for (x = x0; x < x1; x += 4) { - stbi_uc *p = &g->out[y + x]; - p[0] = c[2]; - p[1] = c[1]; - p[2] = c[0]; - p[3] = 0; - } - } -} - -// this function is designed to support animated gifs, although stb_image doesn't support it -static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp) -{ - int i; - stbi_uc *prev_out = 0; - - if (g->out == 0 && !stbi__gif_header(s, g, comp,0)) - return 0; // stbi__g_failure_reason set by stbi__gif_header - - prev_out = g->out; - g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); - if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); - - switch ((g->eflags & 0x1C) >> 2) { - case 0: // unspecified (also always used on 1st frame) - stbi__fill_gif_background(g, 0, 0, 4 * g->w, 4 * g->w * g->h); - break; - case 1: // do not dispose - if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h); - g->old_out = prev_out; - break; - case 2: // dispose to background - if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h); - stbi__fill_gif_background(g, g->start_x, g->start_y, g->max_x, g->max_y); - break; - case 3: // dispose to previous - if (g->old_out) { - for (i = g->start_y; i < g->max_y; i += 4 * g->w) - memcpy(&g->out[i + g->start_x], &g->old_out[i + g->start_x], g->max_x - g->start_x); - } - break; - } - - for (;;) { - switch (stbi__get8(s)) { - case 0x2C: /* Image Descriptor */ - { - int prev_trans = -1; - stbi__int32 x, y, w, h; - stbi_uc *o; - - x = stbi__get16le(s); - y = stbi__get16le(s); - w = stbi__get16le(s); - h = stbi__get16le(s); - if (((x + w) > (g->w)) || ((y + h) > (g->h))) - return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); - - g->line_size = g->w * 4; - g->start_x = x * 4; - g->start_y = y * g->line_size; - g->max_x = g->start_x + w * 4; - g->max_y = g->start_y + h * g->line_size; - g->cur_x = g->start_x; - g->cur_y = g->start_y; - - g->lflags = stbi__get8(s); - - if (g->lflags & 0x40) { - g->step = 8 * g->line_size; // first interlaced spacing - g->parse = 3; - } else { - g->step = g->line_size; - g->parse = 0; - } - - if (g->lflags & 0x80) { - stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); - g->color_table = (stbi_uc *) g->lpal; - } else if (g->flags & 0x80) { - if (g->transparent >= 0 && (g->eflags & 0x01)) { - prev_trans = g->pal[g->transparent][3]; - g->pal[g->transparent][3] = 0; - } - g->color_table = (stbi_uc *) g->pal; - } else - return stbi__errpuc("missing color table", "Corrupt GIF"); - - o = stbi__process_gif_raster(s, g); - if (o == NULL) return NULL; - - if (prev_trans != -1) - g->pal[g->transparent][3] = (stbi_uc) prev_trans; - - return o; - } - - case 0x21: // Comment Extension. - { - int len; - if (stbi__get8(s) == 0xF9) { // Graphic Control Extension. - len = stbi__get8(s); - if (len == 4) { - g->eflags = stbi__get8(s); - g->delay = stbi__get16le(s); - g->transparent = stbi__get8(s); - } else { - stbi__skip(s, len); - break; - } - } - while ((len = stbi__get8(s)) != 0) - stbi__skip(s, len); - break; - } - - case 0x3B: // gif stream termination code - return (stbi_uc *) s; // using '1' causes warning on some compilers - - default: - return stbi__errpuc("unknown code", "Corrupt GIF"); - } - } - - STBI_NOTUSED(req_comp); -} - -static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi_uc *u = 0; - stbi__gif g; - memset(&g, 0, sizeof(g)); - - u = stbi__gif_load_next(s, &g, comp, req_comp); - if (u == (stbi_uc *) s) u = 0; // end of animated gif marker - if (u) { - *x = g.w; - *y = g.h; - if (req_comp && req_comp != 4) - u = stbi__convert_format(u, 4, req_comp, g.w, g.h); - } - else if (g.out) - STBI_FREE(g.out); - - return u; -} - -static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) -{ - return stbi__gif_info_raw(s,x,y,comp); -} -#endif - -// ************************************************************************************************* -// Radiance RGBE HDR loader -// originally by Nicolas Schulz -#ifndef STBI_NO_HDR -static int stbi__hdr_test_core(stbi__context *s) -{ - const char *signature = "#?RADIANCE\n"; - int i; - for (i=0; signature[i]; ++i) - if (stbi__get8(s) != signature[i]) - return 0; - return 1; -} - -static int stbi__hdr_test(stbi__context* s) -{ - int r = stbi__hdr_test_core(s); - stbi__rewind(s); - return r; -} - -#define STBI__HDR_BUFLEN 1024 -static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) -{ - int len=0; - char c = '\0'; - - c = (char) stbi__get8(z); - - while (!stbi__at_eof(z) && c != '\n') { - buffer[len++] = c; - if (len == STBI__HDR_BUFLEN-1) { - // flush to end of line - while (!stbi__at_eof(z) && stbi__get8(z) != '\n') - ; - break; - } - c = (char) stbi__get8(z); - } - - buffer[len] = 0; - return buffer; -} - -static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) -{ - if ( input[3] != 0 ) { - float f1; - // Exponent - f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); - if (req_comp <= 2) - output[0] = (input[0] + input[1] + input[2]) * f1 / 3; - else { - output[0] = input[0] * f1; - output[1] = input[1] * f1; - output[2] = input[2] * f1; - } - if (req_comp == 2) output[1] = 1; - if (req_comp == 4) output[3] = 1; - } else { - switch (req_comp) { - case 4: output[3] = 1; /* fallthrough */ - case 3: output[0] = output[1] = output[2] = 0; - break; - case 2: output[1] = 1; /* fallthrough */ - case 1: output[0] = 0; - break; - } - } -} - -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - char buffer[STBI__HDR_BUFLEN]; - char *token; - int valid = 0; - int width, height; - stbi_uc *scanline; - float *hdr_data; - int len; - unsigned char count, value; - int i, j, k, c1,c2, z; - - - // Check identifier - if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) - return stbi__errpf("not HDR", "Corrupt HDR image"); - - // Parse header - for(;;) { - token = stbi__hdr_gettoken(s,buffer); - if (token[0] == 0) break; - if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; - } - - if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); - - // Parse width and height - // can't use sscanf() if we're not using stdio! - token = stbi__hdr_gettoken(s,buffer); - if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); - token += 3; - height = (int) strtol(token, &token, 10); - while (*token == ' ') ++token; - if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); - token += 3; - width = (int) strtol(token, NULL, 10); - - *x = width; - *y = height; - - if (comp) *comp = 3; - if (req_comp == 0) req_comp = 3; - - // Read data - hdr_data = (float *) stbi__malloc(height * width * req_comp * sizeof(float)); - - // Load image data - // image data is stored as some number of sca - if ( width < 8 || width >= 32768) { - // Read flat data - for (j=0; j < height; ++j) { - for (i=0; i < width; ++i) { - stbi_uc rgbe[4]; - main_decode_loop: - stbi__getn(s, rgbe, 4); - stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); - } - } - } else { - // Read RLE-encoded data - scanline = NULL; - - for (j = 0; j < height; ++j) { - c1 = stbi__get8(s); - c2 = stbi__get8(s); - len = stbi__get8(s); - if (c1 != 2 || c2 != 2 || (len & 0x80)) { - // not run-length encoded, so we have to actually use THIS data as a decoded - // pixel (note this can't be a valid pixel--one of RGB must be >= 128) - stbi_uc rgbe[4]; - rgbe[0] = (stbi_uc) c1; - rgbe[1] = (stbi_uc) c2; - rgbe[2] = (stbi_uc) len; - rgbe[3] = (stbi_uc) stbi__get8(s); - stbi__hdr_convert(hdr_data, rgbe, req_comp); - i = 1; - j = 0; - STBI_FREE(scanline); - goto main_decode_loop; // yes, this makes no sense - } - len <<= 8; - len |= stbi__get8(s); - if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } - if (scanline == NULL) scanline = (stbi_uc *) stbi__malloc(width * 4); - - for (k = 0; k < 4; ++k) { - i = 0; - while (i < width) { - count = stbi__get8(s); - if (count > 128) { - // Run - value = stbi__get8(s); - count -= 128; - for (z = 0; z < count; ++z) - scanline[i++ * 4 + k] = value; - } else { - // Dump - for (z = 0; z < count; ++z) - scanline[i++ * 4 + k] = stbi__get8(s); - } - } - } - for (i=0; i < width; ++i) - stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); - } - STBI_FREE(scanline); - } - - return hdr_data; -} - -static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) -{ - char buffer[STBI__HDR_BUFLEN]; - char *token; - int valid = 0; - - if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) { - stbi__rewind( s ); - return 0; - } - - for(;;) { - token = stbi__hdr_gettoken(s,buffer); - if (token[0] == 0) break; - if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; - } - - if (!valid) { - stbi__rewind( s ); - return 0; - } - token = stbi__hdr_gettoken(s,buffer); - if (strncmp(token, "-Y ", 3)) { - stbi__rewind( s ); - return 0; - } - token += 3; - *y = (int) strtol(token, &token, 10); - while (*token == ' ') ++token; - if (strncmp(token, "+X ", 3)) { - stbi__rewind( s ); - return 0; - } - token += 3; - *x = (int) strtol(token, NULL, 10); - *comp = 3; - return 1; -} -#endif // STBI_NO_HDR - -#ifndef STBI_NO_BMP -static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) -{ - int hsz; - if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') { - stbi__rewind( s ); - return 0; - } - stbi__skip(s,12); - hsz = stbi__get32le(s); - if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) { - stbi__rewind( s ); - return 0; - } - if (hsz == 12) { - *x = stbi__get16le(s); - *y = stbi__get16le(s); - } else { - *x = stbi__get32le(s); - *y = stbi__get32le(s); - } - if (stbi__get16le(s) != 1) { - stbi__rewind( s ); - return 0; - } - *comp = stbi__get16le(s) / 8; - return 1; -} -#endif - -#ifndef STBI_NO_PSD -static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) -{ - int channelCount; - if (stbi__get32be(s) != 0x38425053) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 1) { - stbi__rewind( s ); - return 0; - } - stbi__skip(s, 6); - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) { - stbi__rewind( s ); - return 0; - } - *y = stbi__get32be(s); - *x = stbi__get32be(s); - if (stbi__get16be(s) != 8) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 3) { - stbi__rewind( s ); - return 0; - } - *comp = 4; - return 1; -} -#endif - -#ifndef STBI_NO_PIC -static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) -{ - int act_comp=0,num_packets=0,chained; - stbi__pic_packet packets[10]; - - if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { - stbi__rewind(s); - return 0; - } - - stbi__skip(s, 88); - - *x = stbi__get16be(s); - *y = stbi__get16be(s); - if (stbi__at_eof(s)) { - stbi__rewind( s); - return 0; - } - if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { - stbi__rewind( s ); - return 0; - } - - stbi__skip(s, 8); - - do { - stbi__pic_packet *packet; - - if (num_packets==sizeof(packets)/sizeof(packets[0])) - return 0; - - packet = &packets[num_packets++]; - chained = stbi__get8(s); - packet->size = stbi__get8(s); - packet->type = stbi__get8(s); - packet->channel = stbi__get8(s); - act_comp |= packet->channel; - - if (stbi__at_eof(s)) { - stbi__rewind( s ); - return 0; - } - if (packet->size != 8) { - stbi__rewind( s ); - return 0; - } - } while (chained); - - *comp = (act_comp & 0x10 ? 4 : 3); - - return 1; -} -#endif - -// ************************************************************************************************* -// Portable Gray Map and Portable Pixel Map loader -// by Ken Miller -// -// PGM: http://netpbm.sourceforge.net/doc/pgm.html -// PPM: http://netpbm.sourceforge.net/doc/ppm.html -// -// Known limitations: -// Does not support comments in the header section -// Does not support ASCII image data (formats P2 and P3) -// Does not support 16-bit-per-channel - -#ifndef STBI_NO_PNM - -static int stbi__pnm_test(stbi__context *s) -{ - char p, t; - p = (char) stbi__get8(s); - t = (char) stbi__get8(s); - if (p != 'P' || (t != '5' && t != '6')) { - stbi__rewind( s ); - return 0; - } - return 1; -} - -static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi_uc *out; - if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) - return 0; - *x = s->img_x; - *y = s->img_y; - *comp = s->img_n; - - out = (stbi_uc *) stbi__malloc(s->img_n * s->img_x * s->img_y); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - stbi__getn(s, out, s->img_n * s->img_x * s->img_y); - - if (req_comp && req_comp != s->img_n) { - out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } - return out; -} - -static int stbi__pnm_isspace(char c) -{ - return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; -} - -static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) -{ - while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) - *c = (char) stbi__get8(s); -} - -static int stbi__pnm_isdigit(char c) -{ - return c >= '0' && c <= '9'; -} - -static int stbi__pnm_getinteger(stbi__context *s, char *c) -{ - int value = 0; - - while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { - value = value*10 + (*c - '0'); - *c = (char) stbi__get8(s); - } - - return value; -} - -static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) -{ - int maxv; - char c, p, t; - - stbi__rewind( s ); - - // Get identifier - p = (char) stbi__get8(s); - t = (char) stbi__get8(s); - if (p != 'P' || (t != '5' && t != '6')) { - stbi__rewind( s ); - return 0; - } - - *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm - - c = (char) stbi__get8(s); - stbi__pnm_skip_whitespace(s, &c); - - *x = stbi__pnm_getinteger(s, &c); // read width - stbi__pnm_skip_whitespace(s, &c); - - *y = stbi__pnm_getinteger(s, &c); // read height - stbi__pnm_skip_whitespace(s, &c); - - maxv = stbi__pnm_getinteger(s, &c); // read max value - - if (maxv > 255) - return stbi__err("max value > 255", "PPM image not 8-bit"); - else - return 1; -} -#endif - -static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) -{ - #ifndef STBI_NO_JPEG - if (stbi__jpeg_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_PNG - if (stbi__png_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_GIF - if (stbi__gif_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_BMP - if (stbi__bmp_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_PSD - if (stbi__psd_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_PIC - if (stbi__pic_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_PNM - if (stbi__pnm_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_HDR - if (stbi__hdr_info(s, x, y, comp)) return 1; - #endif - - // test tga last because it's a crappy test! - #ifndef STBI_NO_TGA - if (stbi__tga_info(s, x, y, comp)) - return 1; - #endif - return stbi__err("unknown image type", "Image not of any known type, or corrupt"); -} - -#ifndef STBI_NO_STDIO -STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result; - if (!f) return stbi__err("can't fopen", "Unable to open file"); - result = stbi_info_from_file(f, x, y, comp); - fclose(f); - return result; -} - -STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) -{ - int r; - stbi__context s; - long pos = ftell(f); - stbi__start_file(&s, f); - r = stbi__info_main(&s,x,y,comp); - fseek(f,pos,SEEK_SET); - return r; -} -#endif // !STBI_NO_STDIO - -STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__info_main(&s,x,y,comp); -} - -STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); - return stbi__info_main(&s,x,y,comp); -} - -#endif // STB_IMAGE_IMPLEMENTATION - -/* - revision history: - 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA - 2.07 (2015-09-13) fix compiler warnings - partial animated GIF support - limited 16-bit PSD support - #ifdef unused functions - bug with < 92 byte PIC,PNM,HDR,TGA - 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value - 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning - 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit - 2.03 (2015-04-12) extra corruption checking (mmozeiko) - stbi_set_flip_vertically_on_load (nguillemot) - fix NEON support; fix mingw support - 2.02 (2015-01-19) fix incorrect assert, fix warning - 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 - 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG - 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) - progressive JPEG (stb) - PGM/PPM support (Ken Miller) - STBI_MALLOC,STBI_REALLOC,STBI_FREE - GIF bugfix -- seemingly never worked - STBI_NO_*, STBI_ONLY_* - 1.48 (2014-12-14) fix incorrectly-named assert() - 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) - optimize PNG (ryg) - fix bug in interlaced PNG with user-specified channel count (stb) - 1.46 (2014-08-26) - fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG - 1.45 (2014-08-16) - fix MSVC-ARM internal compiler error by wrapping malloc - 1.44 (2014-08-07) - various warning fixes from Ronny Chevalier - 1.43 (2014-07-15) - fix MSVC-only compiler problem in code changed in 1.42 - 1.42 (2014-07-09) - don't define _CRT_SECURE_NO_WARNINGS (affects user code) - fixes to stbi__cleanup_jpeg path - added STBI_ASSERT to avoid requiring assert.h - 1.41 (2014-06-25) - fix search&replace from 1.36 that messed up comments/error messages - 1.40 (2014-06-22) - fix gcc struct-initialization warning - 1.39 (2014-06-15) - fix to TGA optimization when req_comp != number of components in TGA; - fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) - add support for BMP version 5 (more ignored fields) - 1.38 (2014-06-06) - suppress MSVC warnings on integer casts truncating values - fix accidental rename of 'skip' field of I/O - 1.37 (2014-06-04) - remove duplicate typedef - 1.36 (2014-06-03) - convert to header file single-file library - if de-iphone isn't set, load iphone images color-swapped instead of returning NULL - 1.35 (2014-05-27) - various warnings - fix broken STBI_SIMD path - fix bug where stbi_load_from_file no longer left file pointer in correct place - fix broken non-easy path for 32-bit BMP (possibly never used) - TGA optimization by Arseny Kapoulkine - 1.34 (unknown) - use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case - 1.33 (2011-07-14) - make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements - 1.32 (2011-07-13) - support for "info" function for all supported filetypes (SpartanJ) - 1.31 (2011-06-20) - a few more leak fixes, bug in PNG handling (SpartanJ) - 1.30 (2011-06-11) - added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) - removed deprecated format-specific test/load functions - removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway - error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) - fix inefficiency in decoding 32-bit BMP (David Woo) - 1.29 (2010-08-16) - various warning fixes from Aurelien Pocheville - 1.28 (2010-08-01) - fix bug in GIF palette transparency (SpartanJ) - 1.27 (2010-08-01) - cast-to-stbi_uc to fix warnings - 1.26 (2010-07-24) - fix bug in file buffering for PNG reported by SpartanJ - 1.25 (2010-07-17) - refix trans_data warning (Won Chun) - 1.24 (2010-07-12) - perf improvements reading from files on platforms with lock-heavy fgetc() - minor perf improvements for jpeg - deprecated type-specific functions so we'll get feedback if they're needed - attempt to fix trans_data warning (Won Chun) - 1.23 fixed bug in iPhone support - 1.22 (2010-07-10) - removed image *writing* support - stbi_info support from Jetro Lauha - GIF support from Jean-Marc Lienher - iPhone PNG-extensions from James Brown - warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) - 1.21 fix use of 'stbi_uc' in header (reported by jon blow) - 1.20 added support for Softimage PIC, by Tom Seddon - 1.19 bug in interlaced PNG corruption check (found by ryg) - 1.18 (2008-08-02) - fix a threading bug (local mutable static) - 1.17 support interlaced PNG - 1.16 major bugfix - stbi__convert_format converted one too many pixels - 1.15 initialize some fields for thread safety - 1.14 fix threadsafe conversion bug - header-file-only version (#define STBI_HEADER_FILE_ONLY before including) - 1.13 threadsafe - 1.12 const qualifiers in the API - 1.11 Support installable IDCT, colorspace conversion routines - 1.10 Fixes for 64-bit (don't use "unsigned long") - optimized upsampling by Fabian "ryg" Giesen - 1.09 Fix format-conversion for PSD code (bad global variables!) - 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz - 1.07 attempt to fix C++ warning/errors again - 1.06 attempt to fix C++ warning/errors again - 1.05 fix TGA loading to return correct *comp and use good luminance calc - 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free - 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR - 1.02 support for (subset of) HDR files, float interface for preferred access to them - 1.01 fix bug: possible bug in handling right-side up bmps... not sure - fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all - 1.00 interface to zlib that skips zlib header - 0.99 correct handling of alpha in palette - 0.98 TGA loader by lonesock; dynamically add loaders (untested) - 0.97 jpeg errors on too large a file; also catch another malloc failure - 0.96 fix detection of invalid v value - particleman@mollyrocket forum - 0.95 during header scan, seek to markers in case of padding - 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same - 0.93 handle jpegtran output; verbose errors - 0.92 read 4,8,16,24,32-bit BMP files of several formats - 0.91 output 24-bit Windows 3.0 BMP files - 0.90 fix a few more warnings; bump version number to approach 1.0 - 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd - 0.60 fix compiling as c++ - 0.59 fix warnings: merge Dave Moore's -Wall fixes - 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian - 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available - 0.56 fix bug: zlib uncompressed mode len vs. nlen - 0.55 fix bug: restart_interval not initialized to 0 - 0.54 allow NULL for 'int *comp' - 0.53 fix bug in png 3->4; speedup png decoding - 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments - 0.51 obey req_comp requests, 1-component jpegs return as 1-component, - on 'test' only check type, not whether we support this variant - 0.50 (2006-11-19) - first released version -*/ diff --git a/subprojects/nk_pugl/nuklear/extra_font/Cousine-Regular.ttf b/subprojects/nk_pugl/nuklear/extra_font/Cousine-Regular.ttf deleted file mode 100644 index 70a0bf902e1482724d7706f7a0f40d94fe51f4c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43912 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 VEBwqml;Z2NCo|~pwK diff --git a/subprojects/nk_pugl/nuklear/extra_font/DroidSans.ttf b/subprojects/nk_pugl/nuklear/extra_font/DroidSans.ttf deleted file mode 100644 index 767c63ad000e3eea20f3cb7a43ba9f4154ed7a5d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 190044 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%0D=-PBu&{ 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 aWGe4uD(_?}?_?_PWGe4uD(~cOqW=eI(CQrk diff --git a/subprojects/nk_pugl/nuklear/extra_font/Raleway-Bold.ttf b/subprojects/nk_pugl/nuklear/extra_font/Raleway-Bold.ttf deleted file mode 100644 index 7aa37f014fec4c7b5a9abaecbbc5992e6507cdc2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 176280 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 diff --git a/subprojects/nk_pugl/nuklear/extra_font/Roboto-Bold.ttf b/subprojects/nk_pugl/nuklear/extra_font/Roboto-Bold.ttf deleted file mode 100644 index aaf374d2cc000c058f434f43c3b53bcaf315e2a0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 135820 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 TYqd&VnqJLHIX9iq_T+y7#;O#c diff --git a/subprojects/nk_pugl/nuklear/extra_font/Roboto-Light.ttf b/subprojects/nk_pugl/nuklear/extra_font/Roboto-Light.ttf deleted file mode 100644 index 664e1b2f9dbafbf6280305123d2df7fa0c66cee9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 140276 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 diff --git a/subprojects/nk_pugl/nuklear/extra_font/Roboto-Regular.ttf b/subprojects/nk_pugl/nuklear/extra_font/Roboto-Regular.ttf deleted file mode 100644 index 3e6e2e76134cd6040a49ccf9961d302f7d139fcd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 145348 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 PiOjzua{P-TkKXowY>-!K diff --git a/subprojects/nk_pugl/nuklear/extra_font/kenvector_future_thin.ttf b/subprojects/nk_pugl/nuklear/extra_font/kenvector_future_thin.ttf deleted file mode 100644 index 9f4b4fa59ac2211aabf9cb60c6f7caf441d087ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34100 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 KTY$`k7yb_mr&(bD diff --git a/subprojects/nk_pugl/nuklear/nuklear.h b/subprojects/nk_pugl/nuklear/nuklear.h deleted file mode 100644 index 29fcd6e..0000000 --- a/subprojects/nk_pugl/nuklear/nuklear.h +++ /dev/null @@ -1,25596 +0,0 @@ -/*/// # Nuklear -/// ![](https://cloud.githubusercontent.com/assets/8057201/11761525/ae06f0ca-a0c6-11e5-819d-5610b25f6ef4.gif) -/// -/// ## Contents -/// 1. About section -/// 2. Highlights section -/// 3. Features section -/// 4. Usage section -/// 1. Flags section -/// 2. Constants section -/// 3. Dependencies section -/// 5. Example section -/// 6. API section -/// 1. Context section -/// 2. Input section -/// 3. Drawing section -/// 4. Window section -/// 5. Layouting section -/// 6. Groups section -/// 7. Tree section -/// 8. Properties section -/// 7. License section -/// 8. Changelog section -/// 9. Gallery section -/// 10. Credits section -/// -/// ## About -/// This is a minimal state immediate mode graphical user interface toolkit -/// written in ANSI C and licensed under public domain. It was designed as a simple -/// embeddable user interface for application and does not have any dependencies, -/// a default renderbackend or OS window and input handling but instead provides a very modular -/// library approach by using simple input state for input and draw -/// commands describing primitive shapes as output. So instead of providing a -/// layered library that tries to abstract over a number of platform and -/// render backends it only focuses on the actual UI. -/// -/// ## Highlights -/// - Graphical user interface toolkit -/// - Single header library -/// - Written in C89 (a.k.a. ANSI C or ISO C90) -/// - Small codebase (~18kLOC) -/// - Focus on portability, efficiency and simplicity -/// - No dependencies (not even the standard library if not wanted) -/// - Fully skinnable and customizable -/// - Low memory footprint with total memory control if needed or wanted -/// - UTF-8 support -/// - No global or hidden state -/// - Customizable library modules (you can compile and use only what you need) -/// - Optional font baker and vertex buffer output -/// -/// ## Features -/// - Absolutely no platform dependent code -/// - Memory management control ranging from/to -/// - Ease of use by allocating everything from standard library -/// - Control every byte of memory inside the library -/// - Font handling control ranging from/to -/// - Use your own font implementation for everything -/// - Use this libraries internal font baking and handling API -/// - Drawing output control ranging from/to -/// - Simple shapes for more high level APIs which already have drawing capabilities -/// - Hardware accessible anti-aliased vertex buffer output -/// - Customizable colors and properties ranging from/to -/// - Simple changes to color by filling a simple color table -/// - Complete control with ability to use skinning to decorate widgets -/// - Bendable UI library with widget ranging from/to -/// - Basic widgets like buttons, checkboxes, slider, ... -/// - Advanced widget like abstract comboboxes, contextual menus,... -/// - Compile time configuration to only compile what you need -/// - Subset which can be used if you do not want to link or use the standard library -/// - Can be easily modified to only update on user input instead of frame updates -/// -/// ## Usage -/// This library is self contained in one single header file and can be used either -/// in header only mode or in implementation mode. The header only mode is used -/// by default when included and allows including this header in other headers -/// and does not contain the actual implementation.

-/// -/// The implementation mode requires to define the preprocessor macro -/// NK_IMPLEMENTATION in *one* .c/.cpp file before #includeing this file, e.g.: -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~C -/// #define NK_IMPLEMENTATION -/// #include "nuklear.h" -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Also optionally define the symbols listed in the section "OPTIONAL DEFINES" -/// below in header and implementation mode if you want to use additional functionality -/// or need more control over the library. -/// -/// !!! WARNING -/// Every time nuklear is included define the same compiler flags. This very important not doing so could lead to compiler errors or even worse stack corruptions. -/// -/// ### Flags -/// Flag | Description -/// --------------------------------|------------------------------------------ -/// NK_PRIVATE | If defined declares all functions as static, so they can only be accessed inside the file that contains the implementation -/// NK_INCLUDE_FIXED_TYPES | If defined it will include header `` for fixed sized types otherwise nuklear tries to select the correct type. If that fails it will throw a compiler error and you have to select the correct types yourself. -/// NK_INCLUDE_DEFAULT_ALLOCATOR | If defined it will include header `` and provide additional functions to use this library without caring for memory allocation control and therefore ease memory management. -/// NK_INCLUDE_STANDARD_IO | If defined it will include header `` and provide additional functions depending on file loading. -/// NK_INCLUDE_STANDARD_VARARGS | If defined it will include header and provide additional functions depending on file loading. -/// NK_INCLUDE_VERTEX_BUFFER_OUTPUT | Defining this adds a vertex draw command list backend to this library, which allows you to convert queue commands into vertex draw commands. This is mainly if you need a hardware accessible format for OpenGL, DirectX, Vulkan, Metal,... -/// NK_INCLUDE_FONT_BAKING | Defining this adds `stb_truetype` and `stb_rect_pack` implementation to this library and provides font baking and rendering. If you already have font handling or do not want to use this font handler you don't have to define it. -/// NK_INCLUDE_DEFAULT_FONT | Defining this adds the default font: ProggyClean.ttf into this library which can be loaded into a font atlas and allows using this library without having a truetype font -/// NK_INCLUDE_COMMAND_USERDATA | Defining this adds a userdata pointer into each command. Can be useful for example if you want to provide custom shaders depending on the used widget. Can be combined with the style structures. -/// NK_BUTTON_TRIGGER_ON_RELEASE | Different platforms require button clicks occurring either on buttons being pressed (up to down) or released (down to up). By default this library will react on buttons being pressed, but if you define this it will only trigger if a button is released. -/// NK_ZERO_COMMAND_MEMORY | Defining this will zero out memory for each drawing command added to a drawing queue (inside nk_command_buffer_push). Zeroing command memory is very useful for fast checking (using memcmp) if command buffers are equal and avoid drawing frames when nothing on screen has changed since previous frame. -/// -/// !!! WARNING -/// The following flags will pull in the standard C library: -/// - NK_INCLUDE_DEFAULT_ALLOCATOR -/// - NK_INCLUDE_STANDARD_IO -/// - NK_INCLUDE_STANDARD_VARARGS -/// -/// !!! WARNING -/// The following flags if defined need to be defined for both header and implementation: -/// - NK_INCLUDE_FIXED_TYPES -/// - NK_INCLUDE_DEFAULT_ALLOCATOR -/// - NK_INCLUDE_STANDARD_VARARGS -/// - NK_INCLUDE_VERTEX_BUFFER_OUTPUT -/// - NK_INCLUDE_FONT_BAKING -/// - NK_INCLUDE_DEFAULT_FONT -/// - NK_INCLUDE_STANDARD_VARARGS -/// - NK_INCLUDE_COMMAND_USERDATA -/// -/// ### Constants -/// Define | Description -/// --------------------------------|--------------------------------------- -/// NK_BUFFER_DEFAULT_INITIAL_SIZE | Initial buffer size allocated by all buffers while using the default allocator functions included by defining NK_INCLUDE_DEFAULT_ALLOCATOR. If you don't want to allocate the default 4k memory then redefine it. -/// NK_MAX_NUMBER_BUFFER | Maximum buffer size for the conversion buffer between float and string Under normal circumstances this should be more than sufficient. -/// NK_INPUT_MAX | Defines the max number of bytes which can be added as text input in one frame. Under normal circumstances this should be more than sufficient. -/// -/// !!! WARNING -/// The following constants if defined need to be defined for both header and implementation: -/// - NK_MAX_NUMBER_BUFFER -/// - NK_BUFFER_DEFAULT_INITIAL_SIZE -/// - NK_INPUT_MAX -/// -/// ### Dependencies -/// Function | Description -/// ------------|--------------------------------------------------------------- -/// NK_ASSERT | If you don't define this, nuklear will use with assert(). -/// NK_MEMSET | You can define this to 'memset' or your own memset implementation replacement. If not nuklear will use its own version. -/// NK_MEMCPY | You can define this to 'memcpy' or your own memcpy implementation replacement. If not nuklear will use its own version. -/// NK_SQRT | You can define this to 'sqrt' or your own sqrt implementation replacement. If not nuklear will use its own slow and not highly accurate version. -/// NK_SIN | You can define this to 'sinf' or your own sine implementation replacement. If not nuklear will use its own approximation implementation. -/// NK_COS | You can define this to 'cosf' or your own cosine implementation replacement. If not nuklear will use its own approximation implementation. -/// NK_STRTOD | You can define this to `strtod` or your own string to double conversion implementation replacement. If not defined nuklear will use its own imprecise and possibly unsafe version (does not handle nan or infinity!). -/// NK_DTOA | You can define this to `dtoa` or your own double to string conversion implementation replacement. If not defined nuklear will use its own imprecise and possibly unsafe version (does not handle nan or infinity!). -/// NK_VSNPRINTF| If you define `NK_INCLUDE_STANDARD_VARARGS` as well as `NK_INCLUDE_STANDARD_IO` and want to be safe define this to `vsnprintf` on compilers supporting later versions of C or C++. By default nuklear will check for your stdlib version in C as well as compiler version in C++. if `vsnprintf` is available it will define it to `vsnprintf` directly. If not defined and if you have older versions of C or C++ it will be defined to `vsprintf` which is unsafe. -/// -/// !!! WARNING -/// The following dependencies will pull in the standard C library if not redefined: -/// - NK_ASSERT -/// -/// !!! WARNING -/// The following dependencies if defined need to be defined for both header and implementation: -/// - NK_ASSERT -/// -/// !!! WARNING -/// The following dependencies if defined need to be defined only for the implementation part: -/// - NK_MEMSET -/// - NK_MEMCPY -/// - NK_SQRT -/// - NK_SIN -/// - NK_COS -/// - NK_STRTOD -/// - NK_DTOA -/// - NK_VSNPRINTF -/// -/// ## Example -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// // init gui state -/// enum {EASY, HARD}; -/// static int op = EASY; -/// static float value = 0.6f; -/// static int i = 20; -/// struct nk_context ctx; -/// -/// nk_init_fixed(&ctx, calloc(1, MAX_MEMORY), MAX_MEMORY, &font); -/// if (nk_begin(&ctx, "Show", nk_rect(50, 50, 220, 220), -/// NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE)) { -/// // fixed widget pixel width -/// nk_layout_row_static(&ctx, 30, 80, 1); -/// if (nk_button_label(&ctx, "button")) { -/// // event handling -/// } -/// -/// // fixed widget window ratio width -/// nk_layout_row_dynamic(&ctx, 30, 2); -/// if (nk_option_label(&ctx, "easy", op == EASY)) op = EASY; -/// if (nk_option_label(&ctx, "hard", op == HARD)) op = HARD; -/// -/// // custom widget pixel width -/// nk_layout_row_begin(&ctx, NK_STATIC, 30, 2); -/// { -/// nk_layout_row_push(&ctx, 50); -/// nk_label(&ctx, "Volume:", NK_TEXT_LEFT); -/// nk_layout_row_push(&ctx, 110); -/// nk_slider_float(&ctx, 0, &value, 1.0f, 0.1f); -/// } -/// nk_layout_row_end(&ctx); -/// } -/// nk_end(&ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// ![](https://cloud.githubusercontent.com/assets/8057201/10187981/584ecd68-675c-11e5-897c-822ef534a876.png) -/// -/// ## API -/// -*/ -#ifndef NK_NUKLEAR_H_ -#define NK_NUKLEAR_H_ - -#ifdef __cplusplus -extern "C" { -#endif -/* - * ============================================================== - * - * CONSTANTS - * - * =============================================================== - */ -#define NK_UNDEFINED (-1.0f) -#define NK_UTF_INVALID 0xFFFD /* internal invalid utf8 rune */ -#define NK_UTF_SIZE 4 /* describes the number of bytes a glyph consists of*/ -#ifndef NK_INPUT_MAX - #define NK_INPUT_MAX 16 -#endif -#ifndef NK_MAX_NUMBER_BUFFER - #define NK_MAX_NUMBER_BUFFER 64 -#endif -#ifndef NK_SCROLLBAR_HIDING_TIMEOUT - #define NK_SCROLLBAR_HIDING_TIMEOUT 4.0f -#endif -/* - * ============================================================== - * - * HELPER - * - * =============================================================== - */ -#ifndef NK_API - #ifdef NK_PRIVATE - #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199409L)) - #define NK_API static inline - #elif defined(__cplusplus) - #define NK_API static inline - #else - #define NK_API static - #endif - #else - #define NK_API extern - #endif -#endif - -#define NK_INTERN static -#define NK_STORAGE static -#define NK_GLOBAL static - -#define NK_FLAG(x) (1 << (x)) -#define NK_STRINGIFY(x) #x -#define NK_MACRO_STRINGIFY(x) NK_STRINGIFY(x) -#define NK_STRING_JOIN_IMMEDIATE(arg1, arg2) arg1 ## arg2 -#define NK_STRING_JOIN_DELAY(arg1, arg2) NK_STRING_JOIN_IMMEDIATE(arg1, arg2) -#define NK_STRING_JOIN(arg1, arg2) NK_STRING_JOIN_DELAY(arg1, arg2) - -#ifdef _MSC_VER - #define NK_UNIQUE_NAME(name) NK_STRING_JOIN(name,__COUNTER__) -#else - #define NK_UNIQUE_NAME(name) NK_STRING_JOIN(name,__LINE__) -#endif - -#ifndef NK_STATIC_ASSERT - #define NK_STATIC_ASSERT(exp) typedef char NK_UNIQUE_NAME(_dummy_array)[(exp)?1:-1] -#endif - -#ifndef NK_FILE_LINE -#ifdef _MSC_VER - #define NK_FILE_LINE __FILE__ ":" NK_MACRO_STRINGIFY(__COUNTER__) -#else - #define NK_FILE_LINE __FILE__ ":" NK_MACRO_STRINGIFY(__LINE__) -#endif -#endif - -#define NK_MIN(a,b) ((a) < (b) ? (a) : (b)) -#define NK_MAX(a,b) ((a) < (b) ? (b) : (a)) -#define NK_CLAMP(i,v,x) (NK_MAX(NK_MIN(v,x), i)) - -#ifdef NK_INCLUDE_STANDARD_VARARGS - #if defined(_MSC_VER) && (_MSC_VER >= 1600) /* VS 2010 and above */ - #include - #define NK_PRINTF_FORMAT_STRING _Printf_format_string_ - #else - #define NK_PRINTF_FORMAT_STRING - #endif - #if defined(__GNUC__) - #define NK_PRINTF_VARARG_FUNC(fmtargnumber) __attribute__((format(__printf__, fmtargnumber, fmtargnumber+1))) - #else - #define NK_PRINTF_VARARG_FUNC(fmtargnumber) - #endif -#endif - -/* - * =============================================================== - * - * BASIC - * - * =============================================================== - */ -#ifdef NK_INCLUDE_FIXED_TYPES - #include - #define NK_INT8 int8_t - #define NK_UINT8 uint8_t - #define NK_INT16 int16_t - #define NK_UINT16 uint16_t - #define NK_INT32 int32_t - #define NK_UINT32 uint32_t - #define NK_SIZE_TYPE uintptr_t - #define NK_POINTER_TYPE uintptr_t -#else - #ifndef NK_INT8 - #define NK_INT8 char - #endif - #ifndef NK_UINT8 - #define NK_UINT8 unsigned char - #endif - #ifndef NK_INT16 - #define NK_INT16 signed short - #endif - #ifndef NK_UINT16 - #define NK_UINT16 unsigned short - #endif - #ifndef NK_INT32 - #if defined(_MSC_VER) - #define NK_INT32 __int32 - #else - #define NK_INT32 signed int - #endif - #endif - #ifndef NK_UINT32 - #if defined(_MSC_VER) - #define NK_UINT32 unsigned __int32 - #else - #define NK_UINT32 unsigned int - #endif - #endif - #ifndef NK_SIZE_TYPE - #if defined(_WIN64) && defined(_MSC_VER) - #define NK_SIZE_TYPE unsigned __int64 - #elif (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER) - #define NK_SIZE_TYPE unsigned __int32 - #elif defined(__GNUC__) || defined(__clang__) - #if defined(__x86_64__) || defined(__ppc64__) - #define NK_SIZE_TYPE unsigned long - #else - #define NK_SIZE_TYPE unsigned int - #endif - #else - #define NK_SIZE_TYPE unsigned long - #endif - #endif - #ifndef NK_POINTER_TYPE - #if defined(_WIN64) && defined(_MSC_VER) - #define NK_POINTER_TYPE unsigned __int64 - #elif (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER) - #define NK_POINTER_TYPE unsigned __int32 - #elif defined(__GNUC__) || defined(__clang__) - #if defined(__x86_64__) || defined(__ppc64__) - #define NK_POINTER_TYPE unsigned long - #else - #define NK_POINTER_TYPE unsigned int - #endif - #else - #define NK_POINTER_TYPE unsigned long - #endif - #endif -#endif - -typedef NK_INT8 nk_char; -typedef NK_UINT8 nk_uchar; -typedef NK_UINT8 nk_byte; -typedef NK_INT16 nk_short; -typedef NK_UINT16 nk_ushort; -typedef NK_INT32 nk_int; -typedef NK_UINT32 nk_uint; -typedef NK_SIZE_TYPE nk_size; -typedef NK_POINTER_TYPE nk_ptr; - -typedef nk_uint nk_hash; -typedef nk_uint nk_flags; -typedef nk_uint nk_rune; - -/* Make sure correct type size: - * This will fire with a negative subscript error if the type sizes - * are set incorrectly by the compiler, and compile out if not */ -NK_STATIC_ASSERT(sizeof(nk_short) == 2); -NK_STATIC_ASSERT(sizeof(nk_ushort) == 2); -NK_STATIC_ASSERT(sizeof(nk_uint) == 4); -NK_STATIC_ASSERT(sizeof(nk_int) == 4); -NK_STATIC_ASSERT(sizeof(nk_byte) == 1); -NK_STATIC_ASSERT(sizeof(nk_flags) >= 4); -NK_STATIC_ASSERT(sizeof(nk_rune) >= 4); -NK_STATIC_ASSERT(sizeof(nk_size) >= sizeof(void*)); -NK_STATIC_ASSERT(sizeof(nk_ptr) >= sizeof(void*)); - -/* ============================================================================ - * - * API - * - * =========================================================================== */ -struct nk_buffer; -struct nk_allocator; -struct nk_command_buffer; -struct nk_draw_command; -struct nk_convert_config; -struct nk_style_item; -struct nk_text_edit; -struct nk_draw_list; -struct nk_user_font; -struct nk_panel; -struct nk_context; -struct nk_draw_vertex_layout_element; -struct nk_style_button; -struct nk_style_toggle; -struct nk_style_selectable; -struct nk_style_slide; -struct nk_style_progress; -struct nk_style_scrollbar; -struct nk_style_edit; -struct nk_style_property; -struct nk_style_chart; -struct nk_style_combo; -struct nk_style_tab; -struct nk_style_window_header; -struct nk_style_window; - -enum {nk_false, nk_true}; -struct nk_color {nk_byte r,g,b,a;}; -struct nk_colorf {float r,g,b,a;}; -struct nk_vec2 {float x,y;}; -struct nk_vec2i {short x, y;}; -struct nk_rect {float x,y,w,h;}; -struct nk_recti {short x,y,w,h;}; -typedef char nk_glyph[NK_UTF_SIZE]; -typedef union {void *ptr; int id;} nk_handle; -struct nk_image {nk_handle handle;unsigned short w,h;unsigned short region[4];}; -struct nk_cursor {struct nk_image img; struct nk_vec2 size, offset;}; -struct nk_scroll {nk_uint x, y;}; - -enum nk_heading {NK_UP, NK_RIGHT, NK_DOWN, NK_LEFT}; -enum nk_button_behavior {NK_BUTTON_DEFAULT, NK_BUTTON_REPEATER}; -enum nk_modify {NK_FIXED = nk_false, NK_MODIFIABLE = nk_true}; -enum nk_orientation {NK_VERTICAL, NK_HORIZONTAL}; -enum nk_collapse_states {NK_MINIMIZED = nk_false, NK_MAXIMIZED = nk_true}; -enum nk_show_states {NK_HIDDEN = nk_false, NK_SHOWN = nk_true}; -enum nk_chart_type {NK_CHART_LINES, NK_CHART_COLUMN, NK_CHART_MAX}; -enum nk_chart_event {NK_CHART_HOVERING = 0x01, NK_CHART_CLICKED = 0x02}; -enum nk_color_format {NK_RGB, NK_RGBA}; -enum nk_popup_type {NK_POPUP_STATIC, NK_POPUP_DYNAMIC}; -enum nk_layout_format {NK_DYNAMIC, NK_STATIC}; -enum nk_tree_type {NK_TREE_NODE, NK_TREE_TAB}; - -typedef void*(*nk_plugin_alloc)(nk_handle, void *old, nk_size); -typedef void (*nk_plugin_free)(nk_handle, void *old); -typedef int(*nk_plugin_filter)(const struct nk_text_edit*, nk_rune unicode); -typedef void(*nk_plugin_paste)(nk_handle, struct nk_text_edit*); -typedef void(*nk_plugin_copy)(nk_handle, const char*, int len); - -struct nk_allocator { - nk_handle userdata; - nk_plugin_alloc alloc; - nk_plugin_free free; -}; -enum nk_symbol_type { - NK_SYMBOL_NONE, - NK_SYMBOL_X, - NK_SYMBOL_UNDERSCORE, - NK_SYMBOL_CIRCLE_SOLID, - NK_SYMBOL_CIRCLE_OUTLINE, - NK_SYMBOL_RECT_SOLID, - NK_SYMBOL_RECT_OUTLINE, - NK_SYMBOL_TRIANGLE_UP, - NK_SYMBOL_TRIANGLE_DOWN, - NK_SYMBOL_TRIANGLE_LEFT, - NK_SYMBOL_TRIANGLE_RIGHT, - NK_SYMBOL_PLUS, - NK_SYMBOL_MINUS, - NK_SYMBOL_MAX -}; -/* ============================================================================= - * - * CONTEXT - * - * =============================================================================*/ -/*/// ### Context -/// Contexts are the main entry point and the majestro of nuklear and contain all required state. -/// They are used for window, memory, input, style, stack, commands and time management and need -/// to be passed into all nuklear GUI specific functions. -/// -/// #### Usage -/// To use a context it first has to be initialized which can be achieved by calling -/// one of either `nk_init_default`, `nk_init_fixed`, `nk_init`, `nk_init_custom`. -/// Each takes in a font handle and a specific way of handling memory. Memory control -/// hereby ranges from standard library to just specifying a fixed sized block of memory -/// which nuklear has to manage itself from. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_context ctx; -/// nk_init_xxx(&ctx, ...); -/// while (1) { -/// // [...] -/// nk_clear(&ctx); -/// } -/// nk_free(&ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// #### Reference -/// Function | Description -/// --------------------|------------------------------------------------------- -/// __nk_init_default__ | Initializes context with standard library memory allocation (malloc,free) -/// __nk_init_fixed__ | Initializes context from single fixed size memory block -/// __nk_init__ | Initializes context with memory allocator callbacks for alloc and free -/// __nk_init_custom__ | Initializes context from two buffers. One for draw commands the other for window/panel/table allocations -/// __nk_clear__ | Called at the end of the frame to reset and prepare the context for the next frame -/// __nk_free__ | Shutdown and free all memory allocated inside the context -/// __nk_set_user_data__| Utility function to pass user data to draw command - */ -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -/*/// #### nk_init_default -/// Initializes a `nk_context` struct with a default standard library allocator. -/// Should be used if you don't want to be bothered with memory management in nuklear. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_init_default(struct nk_context *ctx, const struct nk_user_font *font); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|--------------------------------------------------------------- -/// __ctx__ | Must point to an either stack or heap allocated `nk_context` struct -/// __font__ | Must point to a previously initialized font handle for more info look at font documentation -/// -/// Returns either `false(0)` on failure or `true(1)` on success. -/// -*/ -NK_API int nk_init_default(struct nk_context*, const struct nk_user_font*); -#endif -/*/// #### nk_init_fixed -/// Initializes a `nk_context` struct from single fixed size memory block -/// Should be used if you want complete control over nuklear's memory management. -/// Especially recommended for system with little memory or systems with virtual memory. -/// For the later case you can just allocate for example 16MB of virtual memory -/// and only the required amount of memory will actually be committed. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_init_fixed(struct nk_context *ctx, void *memory, nk_size size, const struct nk_user_font *font); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// !!! Warning -/// make sure the passed memory block is aligned correctly for `nk_draw_commands`. -/// -/// Parameter | Description -/// ------------|-------------------------------------------------------------- -/// __ctx__ | Must point to an either stack or heap allocated `nk_context` struct -/// __memory__ | Must point to a previously allocated memory block -/// __size__ | Must contain the total size of __memory__ -/// __font__ | Must point to a previously initialized font handle for more info look at font documentation -/// -/// Returns either `false(0)` on failure or `true(1)` on success. -*/ -NK_API int nk_init_fixed(struct nk_context*, void *memory, nk_size size, const struct nk_user_font*); -/*/// #### nk_init -/// Initializes a `nk_context` struct with memory allocation callbacks for nuklear to allocate -/// memory from. Used internally for `nk_init_default` and provides a kitchen sink allocation -/// interface to nuklear. Can be useful for cases like monitoring memory consumption. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_init(struct nk_context *ctx, struct nk_allocator *alloc, const struct nk_user_font *font); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|--------------------------------------------------------------- -/// __ctx__ | Must point to an either stack or heap allocated `nk_context` struct -/// __alloc__ | Must point to a previously allocated memory allocator -/// __font__ | Must point to a previously initialized font handle for more info look at font documentation -/// -/// Returns either `false(0)` on failure or `true(1)` on success. -*/ -NK_API int nk_init(struct nk_context*, struct nk_allocator*, const struct nk_user_font*); -/*/// #### nk_init_custom -/// Initializes a `nk_context` struct from two different either fixed or growing -/// buffers. The first buffer is for allocating draw commands while the second buffer is -/// used for allocating windows, panels and state tables. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_init_custom(struct nk_context *ctx, struct nk_buffer *cmds, struct nk_buffer *pool, const struct nk_user_font *font); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|--------------------------------------------------------------- -/// __ctx__ | Must point to an either stack or heap allocated `nk_context` struct -/// __cmds__ | Must point to a previously initialized memory buffer either fixed or dynamic to store draw commands into -/// __pool__ | Must point to a previously initialized memory buffer either fixed or dynamic to store windows, panels and tables -/// __font__ | Must point to a previously initialized font handle for more info look at font documentation -/// -/// Returns either `false(0)` on failure or `true(1)` on success. -*/ -NK_API int nk_init_custom(struct nk_context*, struct nk_buffer *cmds, struct nk_buffer *pool, const struct nk_user_font*); -/*/// #### nk_clear -/// Resets the context state at the end of the frame. This includes mostly -/// garbage collector tasks like removing windows or table not called and therefore -/// used anymore. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_clear(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -*/ -NK_API void nk_clear(struct nk_context*); -/*/// #### nk_free -/// Frees all memory allocated by nuklear. Not needed if context was -/// initialized with `nk_init_fixed`. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_free(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -*/ -NK_API void nk_free(struct nk_context*); -#ifdef NK_INCLUDE_COMMAND_USERDATA -/*/// #### nk_set_user_data -/// Sets the currently passed userdata passed down into each draw command. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_set_user_data(struct nk_context *ctx, nk_handle data); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|-------------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -/// __data__ | Handle with either pointer or index to be passed into every draw commands -*/ -NK_API void nk_set_user_data(struct nk_context*, nk_handle handle); -#endif -/* ============================================================================= - * - * INPUT - * - * =============================================================================*/ -/*/// ### Input -/// The input API is responsible for holding the current input state composed of -/// mouse, key and text input states. -/// It is worth noting that no direct os or window handling is done in nuklear. -/// Instead all input state has to be provided by platform specific code. This in one hand -/// expects more work from the user and complicates usage but on the other hand -/// provides simple abstraction over a big number of platforms, libraries and other -/// already provided functionality. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// nk_input_begin(&ctx); -/// while (GetEvent(&evt)) { -/// if (evt.type == MOUSE_MOVE) -/// nk_input_motion(&ctx, evt.motion.x, evt.motion.y); -/// else if (evt.type == [...]) { -/// // [...] -/// } -/// } nk_input_end(&ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// #### Usage -/// Input state needs to be provided to nuklear by first calling `nk_input_begin` -/// which resets internal state like delta mouse position and button transistions. -/// After `nk_input_begin` all current input state needs to be provided. This includes -/// mouse motion, button and key pressed and released, text input and scrolling. -/// Both event- or state-based input handling are supported by this API -/// and should work without problems. Finally after all input state has been -/// mirrored `nk_input_end` needs to be called to finish input process. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_context ctx; -/// nk_init_xxx(&ctx, ...); -/// while (1) { -/// Event evt; -/// nk_input_begin(&ctx); -/// while (GetEvent(&evt)) { -/// if (evt.type == MOUSE_MOVE) -/// nk_input_motion(&ctx, evt.motion.x, evt.motion.y); -/// else if (evt.type == [...]) { -/// // [...] -/// } -/// } -/// nk_input_end(&ctx); -/// // [...] -/// nk_clear(&ctx); -/// } nk_free(&ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// #### Reference -/// Function | Description -/// --------------------|------------------------------------------------------- -/// __nk_input_begin__ | Begins the input mirroring process. Needs to be called before all other `nk_input_xxx` calls -/// __nk_input_motion__ | Mirrors mouse cursor position -/// __nk_input_key__ | Mirrors key state with either pressed or released -/// __nk_input_button__ | Mirrors mouse button state with either pressed or released -/// __nk_input_scroll__ | Mirrors mouse scroll values -/// __nk_input_char__ | Adds a single ASCII text character into an internal text buffer -/// __nk_input_glyph__ | Adds a single multi-byte UTF-8 character into an internal text buffer -/// __nk_input_unicode__| Adds a single unicode rune into an internal text buffer -/// __nk_input_end__ | Ends the input mirroring process by calculating state changes. Don't call any `nk_input_xxx` function referenced above after this call -*/ -enum nk_keys { - NK_KEY_NONE, - NK_KEY_SHIFT, - NK_KEY_CTRL, - NK_KEY_DEL, - NK_KEY_ENTER, - NK_KEY_TAB, - NK_KEY_BACKSPACE, - NK_KEY_COPY, - NK_KEY_CUT, - NK_KEY_PASTE, - NK_KEY_UP, - NK_KEY_DOWN, - NK_KEY_LEFT, - NK_KEY_RIGHT, - /* Shortcuts: text field */ - NK_KEY_TEXT_INSERT_MODE, - NK_KEY_TEXT_REPLACE_MODE, - NK_KEY_TEXT_RESET_MODE, - NK_KEY_TEXT_LINE_START, - NK_KEY_TEXT_LINE_END, - NK_KEY_TEXT_START, - NK_KEY_TEXT_END, - NK_KEY_TEXT_UNDO, - NK_KEY_TEXT_REDO, - NK_KEY_TEXT_SELECT_ALL, - NK_KEY_TEXT_WORD_LEFT, - NK_KEY_TEXT_WORD_RIGHT, - /* Shortcuts: scrollbar */ - NK_KEY_SCROLL_START, - NK_KEY_SCROLL_END, - NK_KEY_SCROLL_DOWN, - NK_KEY_SCROLL_UP, - NK_KEY_MAX -}; -enum nk_buttons { - NK_BUTTON_LEFT, - NK_BUTTON_MIDDLE, - NK_BUTTON_RIGHT, - NK_BUTTON_DOUBLE, - NK_BUTTON_MAX -}; -/*/// #### nk_input_begin -/// Begins the input mirroring process by resetting text, scroll -/// mouse previous mouse position and movement as well as key state transitions, -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_input_begin(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -*/ -NK_API void nk_input_begin(struct nk_context*); -/*/// #### nk_input_motion -/// Mirrors current mouse position to nuklear -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_input_motion(struct nk_context *ctx, int x, int y); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -/// __x__ | Must hold an integer describing the current mouse cursor x-position -/// __y__ | Must hold an integer describing the current mouse cursor y-position -*/ -NK_API void nk_input_motion(struct nk_context*, int x, int y); -/*/// #### nk_input_key -/// Mirrors state of a specific key to nuklear -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_input_key(struct nk_context*, enum nk_keys key, int down); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -/// __key__ | Must be any value specified in enum `nk_keys` that needs to be mirrored -/// __down__ | Must be 0 for key is up and 1 for key is down -*/ -NK_API void nk_input_key(struct nk_context*, enum nk_keys, int down); -/*/// #### nk_input_button -/// Mirrors the state of a specific mouse button to nuklear -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_input_button(struct nk_context *ctx, enum nk_buttons btn, int x, int y, int down); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -/// __btn__ | Must be any value specified in enum `nk_buttons` that needs to be mirrored -/// __x__ | Must contain an integer describing mouse cursor x-position on click up/down -/// __y__ | Must contain an integer describing mouse cursor y-position on click up/down -/// __down__ | Must be 0 for key is up and 1 for key is down -*/ -NK_API void nk_input_button(struct nk_context*, enum nk_buttons, int x, int y, int down); -/*/// #### nk_input_scroll -/// Copies the last mouse scroll value to nuklear. Is generally -/// a scroll value. So does not have to come from mouse and could also originate -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_input_scroll(struct nk_context *ctx, struct nk_vec2 val); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -/// __val__ | vector with both X- as well as Y-scroll value -*/ -NK_API void nk_input_scroll(struct nk_context*, struct nk_vec2 val); -/*/// #### nk_input_char -/// Copies a single ASCII character into an internal text buffer -/// This is basically a helper function to quickly push ASCII characters into -/// nuklear. -/// -/// !!! Note -/// Stores up to NK_INPUT_MAX bytes between `nk_input_begin` and `nk_input_end`. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_input_char(struct nk_context *ctx, char c); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -/// __c__ | Must be a single ASCII character preferable one that can be printed -*/ -NK_API void nk_input_char(struct nk_context*, char); -/*/// #### nk_input_glyph -/// Converts an encoded unicode rune into UTF-8 and copies the result into an -/// internal text buffer. -/// -/// !!! Note -/// Stores up to NK_INPUT_MAX bytes between `nk_input_begin` and `nk_input_end`. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_input_glyph(struct nk_context *ctx, const nk_glyph g); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -/// __g__ | UTF-32 unicode codepoint -*/ -NK_API void nk_input_glyph(struct nk_context*, const nk_glyph); -/*/// #### nk_input_unicode -/// Converts a unicode rune into UTF-8 and copies the result -/// into an internal text buffer. -/// !!! Note -/// Stores up to NK_INPUT_MAX bytes between `nk_input_begin` and `nk_input_end`. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_input_unicode(struct nk_context*, nk_rune rune); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -/// __rune__ | UTF-32 unicode codepoint -*/ -NK_API void nk_input_unicode(struct nk_context*, nk_rune); -/*/// #### nk_input_end -/// End the input mirroring process by resetting mouse grabbing -/// state to ensure the mouse cursor is not grabbed indefinitely./// -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_input_end(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to a previously initialized `nk_context` struct -*/ -NK_API void nk_input_end(struct nk_context*); -/* ============================================================================= - * - * DRAWING - * - * =============================================================================*/ -/*/// ### Drawing -/// This library was designed to be render backend agnostic so it does -/// not draw anything to screen directly. Instead all drawn shapes, widgets -/// are made of, are buffered into memory and make up a command queue. -/// Each frame therefore fills the command buffer with draw commands -/// that then need to be executed by the user and his own render backend. -/// After that the command buffer needs to be cleared and a new frame can be -/// started. It is probably important to note that the command buffer is the main -/// drawing API and the optional vertex buffer API only takes this format and -/// converts it into a hardware accessible format. -/// -/// #### Usage -/// To draw all draw commands accumulated over a frame you need your own render -/// backend able to draw a number of 2D primitives. This includes at least -/// filled and stroked rectangles, circles, text, lines, triangles and scissors. -/// As soon as this criterion is met you can iterate over each draw command -/// and execute each draw command in a interpreter like fashion: -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// const struct nk_command *cmd = 0; -/// nk_foreach(cmd, &ctx) { -/// switch (cmd->type) { -/// case NK_COMMAND_LINE: -/// your_draw_line_function(...) -/// break; -/// case NK_COMMAND_RECT -/// your_draw_rect_function(...) -/// break; -/// case //...: -/// //[...] -/// } -/// } -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// In program flow context draw commands need to be executed after input has been -/// gathered and the complete UI with windows and their contained widgets have -/// been executed and before calling `nk_clear` which frees all previously -/// allocated draw commands. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_context ctx; -/// nk_init_xxx(&ctx, ...); -/// while (1) { -/// Event evt; -/// nk_input_begin(&ctx); -/// while (GetEvent(&evt)) { -/// if (evt.type == MOUSE_MOVE) -/// nk_input_motion(&ctx, evt.motion.x, evt.motion.y); -/// else if (evt.type == [...]) { -/// [...] -/// } -/// } -/// nk_input_end(&ctx); -/// // -/// // [...] -/// // -/// const struct nk_command *cmd = 0; -/// nk_foreach(cmd, &ctx) { -/// switch (cmd->type) { -/// case NK_COMMAND_LINE: -/// your_draw_line_function(...) -/// break; -/// case NK_COMMAND_RECT -/// your_draw_rect_function(...) -/// break; -/// case ...: -/// // [...] -/// } -/// nk_clear(&ctx); -/// } -/// nk_free(&ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// You probably noticed that you have to draw all of the UI each frame which is -/// quite wasteful. While the actual UI updating loop is quite fast rendering -/// without actually needing it is not. So there are multiple things you could do. -/// -/// First is only update on input. This of course is only an option if your -/// application only depends on the UI and does not require any outside calculations. -/// If you actually only update on input make sure to update the UI two times each -/// frame and call `nk_clear` directly after the first pass and only draw in -/// the second pass. In addition it is recommended to also add additional timers -/// to make sure the UI is not drawn more than a fixed number of frames per second. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_context ctx; -/// nk_init_xxx(&ctx, ...); -/// while (1) { -/// // [...wait for input ] -/// // [...do two UI passes ...] -/// do_ui(...) -/// nk_clear(&ctx); -/// do_ui(...) -/// // -/// // draw -/// const struct nk_command *cmd = 0; -/// nk_foreach(cmd, &ctx) { -/// switch (cmd->type) { -/// case NK_COMMAND_LINE: -/// your_draw_line_function(...) -/// break; -/// case NK_COMMAND_RECT -/// your_draw_rect_function(...) -/// break; -/// case ...: -/// //[...] -/// } -/// nk_clear(&ctx); -/// } -/// nk_free(&ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// The second probably more applicable trick is to only draw if anything changed. -/// It is not really useful for applications with continuous draw loop but -/// quite useful for desktop applications. To actually get nuklear to only -/// draw on changes you first have to define `NK_ZERO_COMMAND_MEMORY` and -/// allocate a memory buffer that will store each unique drawing output. -/// After each frame you compare the draw command memory inside the library -/// with your allocated buffer by memcmp. If memcmp detects differences -/// you have to copy the command buffer into the allocated buffer -/// and then draw like usual (this example uses fixed memory but you could -/// use dynamically allocated memory). -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// //[... other defines ...] -/// #define NK_ZERO_COMMAND_MEMORY -/// #include "nuklear.h" -/// // -/// // setup context -/// struct nk_context ctx; -/// void *last = calloc(1,64*1024); -/// void *buf = calloc(1,64*1024); -/// nk_init_fixed(&ctx, buf, 64*1024); -/// // -/// // loop -/// while (1) { -/// // [...input...] -/// // [...ui...] -/// void *cmds = nk_buffer_memory(&ctx.memory); -/// if (memcmp(cmds, last, ctx.memory.allocated)) { -/// memcpy(last,cmds,ctx.memory.allocated); -/// const struct nk_command *cmd = 0; -/// nk_foreach(cmd, &ctx) { -/// switch (cmd->type) { -/// case NK_COMMAND_LINE: -/// your_draw_line_function(...) -/// break; -/// case NK_COMMAND_RECT -/// your_draw_rect_function(...) -/// break; -/// case ...: -/// // [...] -/// } -/// } -/// } -/// nk_clear(&ctx); -/// } -/// nk_free(&ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Finally while using draw commands makes sense for higher abstracted platforms like -/// X11 and Win32 or drawing libraries it is often desirable to use graphics -/// hardware directly. Therefore it is possible to just define -/// `NK_INCLUDE_VERTEX_BUFFER_OUTPUT` which includes optional vertex output. -/// To access the vertex output you first have to convert all draw commands into -/// vertexes by calling `nk_convert` which takes in your preferred vertex format. -/// After successfully converting all draw commands just iterate over and execute all -/// vertex draw commands: -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// // fill configuration -/// struct nk_convert_config cfg = {}; -/// static const struct nk_draw_vertex_layout_element vertex_layout[] = { -/// {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct your_vertex, pos)}, -/// {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct your_vertex, uv)}, -/// {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct your_vertex, col)}, -/// {NK_VERTEX_LAYOUT_END} -/// }; -/// cfg.shape_AA = NK_ANTI_ALIASING_ON; -/// cfg.line_AA = NK_ANTI_ALIASING_ON; -/// cfg.vertex_layout = vertex_layout; -/// cfg.vertex_size = sizeof(struct your_vertex); -/// cfg.vertex_alignment = NK_ALIGNOF(struct your_vertex); -/// cfg.circle_segment_count = 22; -/// cfg.curve_segment_count = 22; -/// cfg.arc_segment_count = 22; -/// cfg.global_alpha = 1.0f; -/// cfg.null = dev->null; -/// // -/// // setup buffers and convert -/// struct nk_buffer cmds, verts, idx; -/// nk_buffer_init_default(&cmds); -/// nk_buffer_init_default(&verts); -/// nk_buffer_init_default(&idx); -/// nk_convert(&ctx, &cmds, &verts, &idx, &cfg); -/// // -/// // draw -/// nk_draw_foreach(cmd, &ctx, &cmds) { -/// if (!cmd->elem_count) continue; -/// //[...] -/// } -/// nk_buffer_free(&cms); -/// nk_buffer_free(&verts); -/// nk_buffer_free(&idx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// #### Reference -/// Function | Description -/// --------------------|------------------------------------------------------- -/// __nk__begin__ | Returns the first draw command in the context draw command list to be drawn -/// __nk__next__ | Increments the draw command iterator to the next command inside the context draw command list -/// __nk_foreach__ | Iterates over each draw command inside the context draw command list -/// __nk_convert__ | Converts from the abstract draw commands list into a hardware accessible vertex format -/// __nk_draw_begin__ | Returns the first vertex command in the context vertex draw list to be executed -/// __nk__draw_next__ | Increments the vertex command iterator to the next command inside the context vertex command list -/// __nk__draw_end__ | Returns the end of the vertex draw list -/// __nk_draw_foreach__ | Iterates over each vertex draw command inside the vertex draw list -*/ -enum nk_anti_aliasing {NK_ANTI_ALIASING_OFF, NK_ANTI_ALIASING_ON}; -enum nk_convert_result { - NK_CONVERT_SUCCESS = 0, - NK_CONVERT_INVALID_PARAM = 1, - NK_CONVERT_COMMAND_BUFFER_FULL = NK_FLAG(1), - NK_CONVERT_VERTEX_BUFFER_FULL = NK_FLAG(2), - NK_CONVERT_ELEMENT_BUFFER_FULL = NK_FLAG(3) -}; -struct nk_draw_null_texture { - nk_handle texture; /* texture handle to a texture with a white pixel */ - struct nk_vec2 uv; /* coordinates to a white pixel in the texture */ -}; -struct nk_convert_config { - float global_alpha; /* global alpha value */ - enum nk_anti_aliasing line_AA; /* line anti-aliasing flag can be turned off if you are tight on memory */ - enum nk_anti_aliasing shape_AA; /* shape anti-aliasing flag can be turned off if you are tight on memory */ - unsigned circle_segment_count; /* number of segments used for circles: default to 22 */ - unsigned arc_segment_count; /* number of segments used for arcs: default to 22 */ - unsigned curve_segment_count; /* number of segments used for curves: default to 22 */ - struct nk_draw_null_texture null; /* handle to texture with a white pixel for shape drawing */ - const struct nk_draw_vertex_layout_element *vertex_layout; /* describes the vertex output format and packing */ - nk_size vertex_size; /* sizeof one vertex for vertex packing */ - nk_size vertex_alignment; /* vertex alignment: Can be obtained by NK_ALIGNOF */ -}; -/*/// #### nk__begin -/// Returns a draw command list iterator to iterate all draw -/// commands accumulated over one frame. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// const struct nk_command* nk__begin(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | must point to an previously initialized `nk_context` struct at the end of a frame -/// -/// Returns draw command pointer pointing to the first command inside the draw command list -*/ -NK_API const struct nk_command* nk__begin(struct nk_context*); -/*/// #### nk__next -/// Returns a draw command list iterator to iterate all draw -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// const struct nk_command* nk__next(struct nk_context*, const struct nk_command*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct at the end of a frame -/// __cmd__ | Must point to an previously a draw command either returned by `nk__begin` or `nk__next` -/// -/// Returns draw command pointer pointing to the next command inside the draw command list -*/ -NK_API const struct nk_command* nk__next(struct nk_context*, const struct nk_command*); -/*/// #### nk_foreach -/// Iterates over each draw command inside the context draw command list -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// #define nk_foreach(c, ctx) -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct at the end of a frame -/// __cmd__ | Command pointer initialized to NULL -/// -/// Returns draw command pointer pointing to the next command inside the draw command list -*/ -#define nk_foreach(c, ctx) for((c) = nk__begin(ctx); (c) != 0; (c) = nk__next(ctx,c)) -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT -/*/// #### nk_convert -/// Converts all internal draw commands into vertex draw commands and fills -/// three buffers with vertexes, vertex draw commands and vertex indices. The vertex format -/// as well as some other configuration values have to be configured by filling out a -/// `nk_convert_config` struct. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// nk_flags nk_convert(struct nk_context *ctx, struct nk_buffer *cmds, -// struct nk_buffer *vertices, struct nk_buffer *elements, const struct nk_convert_config*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct at the end of a frame -/// __cmds__ | Must point to a previously initialized buffer to hold converted vertex draw commands -/// __vertices__| Must point to a previously initialized buffer to hold all produced vertices -/// __elements__| Must point to a previously initialized buffer to hold all produced vertex indices -/// __config__ | Must point to a filled out `nk_config` struct to configure the conversion process -/// -/// Returns one of enum nk_convert_result error codes -/// -/// Parameter | Description -/// --------------------------------|----------------------------------------------------------- -/// NK_CONVERT_SUCCESS | Signals a successful draw command to vertex buffer conversion -/// NK_CONVERT_INVALID_PARAM | An invalid argument was passed in the function call -/// NK_CONVERT_COMMAND_BUFFER_FULL | The provided buffer for storing draw commands is full or failed to allocate more memory -/// NK_CONVERT_VERTEX_BUFFER_FULL | The provided buffer for storing vertices is full or failed to allocate more memory -/// NK_CONVERT_ELEMENT_BUFFER_FULL | The provided buffer for storing indicies is full or failed to allocate more memory -*/ -NK_API nk_flags nk_convert(struct nk_context*, struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, const struct nk_convert_config*); -/*/// #### nk__draw_begin -/// Returns a draw vertex command buffer iterator to iterate each the vertex draw command buffer -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// const struct nk_draw_command* nk__draw_begin(const struct nk_context*, const struct nk_buffer*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct at the end of a frame -/// __buf__ | Must point to an previously by `nk_convert` filled out vertex draw command buffer -/// -/// Returns vertex draw command pointer pointing to the first command inside the vertex draw command buffer -*/ -NK_API const struct nk_draw_command* nk__draw_begin(const struct nk_context*, const struct nk_buffer*); -/*/// #### nk__draw_end -/// Returns the vertex draw command at the end of the vertex draw command buffer -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// const struct nk_draw_command* nk__draw_end(const struct nk_context *ctx, const struct nk_buffer *buf); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct at the end of a frame -/// __buf__ | Must point to an previously by `nk_convert` filled out vertex draw command buffer -/// -/// Returns vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer -*/ -NK_API const struct nk_draw_command* nk__draw_end(const struct nk_context*, const struct nk_buffer*); -/*/// #### nk__draw_next -/// Increments the vertex draw command buffer iterator -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// const struct nk_draw_command* nk__draw_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __cmd__ | Must point to an previously either by `nk__draw_begin` or `nk__draw_next` returned vertex draw command -/// __buf__ | Must point to an previously by `nk_convert` filled out vertex draw command buffer -/// __ctx__ | Must point to an previously initialized `nk_context` struct at the end of a frame -/// -/// Returns vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer -*/ -NK_API const struct nk_draw_command* nk__draw_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_context*); -/*/// #### nk_draw_foreach -/// Iterates over each vertex draw command inside a vertex draw command buffer -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// #define nk_draw_foreach(cmd,ctx, b) -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __cmd__ | `nk_draw_command`iterator set to NULL -/// __buf__ | Must point to an previously by `nk_convert` filled out vertex draw command buffer -/// __ctx__ | Must point to an previously initialized `nk_context` struct at the end of a frame -*/ -#define nk_draw_foreach(cmd,ctx, b) for((cmd)=nk__draw_begin(ctx, b); (cmd)!=0; (cmd)=nk__draw_next(cmd, b, ctx)) -#endif -/* ============================================================================= - * - * WINDOW - * - * ============================================================================= -/// ### Window -/// Windows are the main persistent state used inside nuklear and are life time -/// controlled by simply "retouching" (i.e. calling) each window each frame. -/// All widgets inside nuklear can only be added inside function pair `nk_begin_xxx` -/// and `nk_end`. Calling any widgets outside these two functions will result in an -/// assert in debug or no state change in release mode.

-/// -/// Each window holds frame persistent state like position, size, flags, state tables, -/// and some garbage collected internal persistent widget state. Each window -/// is linked into a window stack list which determines the drawing and overlapping -/// order. The topmost window thereby is the currently active window.

-/// -/// To change window position inside the stack occurs either automatically by -/// user input by being clicked on or programmatically by calling `nk_window_focus`. -/// Windows by default are visible unless explicitly being defined with flag -/// `NK_WINDOW_HIDDEN`, the user clicked the close button on windows with flag -/// `NK_WINDOW_CLOSABLE` or if a window was explicitly hidden by calling -/// `nk_window_show`. To explicitly close and destroy a window call `nk_window_close`.

-/// -/// #### Usage -/// To create and keep a window you have to call one of the two `nk_begin_xxx` -/// functions to start window declarations and `nk_end` at the end. Furthermore it -/// is recommended to check the return value of `nk_begin_xxx` and only process -/// widgets inside the window if the value is not 0. Either way you have to call -/// `nk_end` at the end of window declarations. Furthermore, do not attempt to -/// nest `nk_begin_xxx` calls which will hopefully result in an assert or if not -/// in a segmentation fault. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// if (nk_begin_xxx(...) { -/// // [... widgets ...] -/// } -/// nk_end(ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// In the grand concept window and widget declarations need to occur after input -/// handling and before drawing to screen. Not doing so can result in higher -/// latency or at worst invalid behavior. Furthermore make sure that `nk_clear` -/// is called at the end of the frame. While nuklear's default platform backends -/// already call `nk_clear` for you if you write your own backend not calling -/// `nk_clear` can cause asserts or even worse undefined behavior. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_context ctx; -/// nk_init_xxx(&ctx, ...); -/// while (1) { -/// Event evt; -/// nk_input_begin(&ctx); -/// while (GetEvent(&evt)) { -/// if (evt.type == MOUSE_MOVE) -/// nk_input_motion(&ctx, evt.motion.x, evt.motion.y); -/// else if (evt.type == [...]) { -/// nk_input_xxx(...); -/// } -/// } -/// nk_input_end(&ctx); -/// -/// if (nk_begin_xxx(...) { -/// //[...] -/// } -/// nk_end(ctx); -/// -/// const struct nk_command *cmd = 0; -/// nk_foreach(cmd, &ctx) { -/// case NK_COMMAND_LINE: -/// your_draw_line_function(...) -/// break; -/// case NK_COMMAND_RECT -/// your_draw_rect_function(...) -/// break; -/// case //...: -/// //[...] -/// } -/// nk_clear(&ctx); -/// } -/// nk_free(&ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// #### Reference -/// Function | Description -/// ------------------------------------|---------------------------------------- -/// nk_begin | Starts a new window; needs to be called every frame for every window (unless hidden) or otherwise the window gets removed -/// nk_begin_titled | Extended window start with separated title and identifier to allow multiple windows with same name but not title -/// nk_end | Needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup -// -/// nk_window_find | Finds and returns the window with give name -/// nk_window_get_bounds | Returns a rectangle with screen position and size of the currently processed window. -/// nk_window_get_position | Returns the position of the currently processed window -/// nk_window_get_size | Returns the size with width and height of the currently processed window -/// nk_window_get_width | Returns the width of the currently processed window -/// nk_window_get_height | Returns the height of the currently processed window -/// nk_window_get_panel | Returns the underlying panel which contains all processing state of the current window -/// nk_window_get_content_region | Returns the position and size of the currently visible and non-clipped space inside the currently processed window -/// nk_window_get_content_region_min | Returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window -/// nk_window_get_content_region_max | Returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window -/// nk_window_get_content_region_size | Returns the size of the currently visible and non-clipped space inside the currently processed window -/// nk_window_get_canvas | Returns the draw command buffer. Can be used to draw custom widgets -/// nk_window_has_focus | Returns if the currently processed window is currently active -/// nk_window_is_collapsed | Returns if the window with given name is currently minimized/collapsed -/// nk_window_is_closed | Returns if the currently processed window was closed -/// nk_window_is_hidden | Returns if the currently processed window was hidden -/// nk_window_is_active | Same as nk_window_has_focus for some reason -/// nk_window_is_hovered | Returns if the currently processed window is currently being hovered by mouse -/// nk_window_is_any_hovered | Return if any window currently hovered -/// nk_item_is_any_active | Returns if any window or widgets is currently hovered or active -// -/// nk_window_set_bounds | Updates position and size of the currently processed window -/// nk_window_set_position | Updates position of the currently process window -/// nk_window_set_size | Updates the size of the currently processed window -/// nk_window_set_focus | Set the currently processed window as active window -// -/// nk_window_close | Closes the window with given window name which deletes the window at the end of the frame -/// nk_window_collapse | Collapses the window with given window name -/// nk_window_collapse_if | Collapses the window with given window name if the given condition was met -/// nk_window_show | Hides a visible or reshows a hidden window -/// nk_window_show_if | Hides/shows a window depending on condition -*/ -/* -/// #### nk_panel_flags -/// Flag | Description -/// ----------------------------|---------------------------------------- -/// NK_WINDOW_BORDER | Draws a border around the window to visually separate window from the background -/// NK_WINDOW_MOVABLE | The movable flag indicates that a window can be moved by user input or by dragging the window header -/// NK_WINDOW_SCALABLE | The scalable flag indicates that a window can be scaled by user input by dragging a scaler icon at the button of the window -/// NK_WINDOW_CLOSABLE | Adds a closable icon into the header -/// NK_WINDOW_MINIMIZABLE | Adds a minimize icon into the header -/// NK_WINDOW_NO_SCROLLBAR | Removes the scrollbar from the window -/// NK_WINDOW_TITLE | Forces a header at the top at the window showing the title -/// NK_WINDOW_SCROLL_AUTO_HIDE | Automatically hides the window scrollbar if no user interaction: also requires delta time in `nk_context` to be set each frame -/// NK_WINDOW_BACKGROUND | Always keep window in the background -/// NK_WINDOW_SCALE_LEFT | Puts window scaler in the left-ottom corner instead right-bottom -/// NK_WINDOW_NO_INPUT | Prevents window of scaling, moving or getting focus -/// -/// #### nk_collapse_states -/// State | Description -/// ----------------|----------------------------------------------------------- -/// __NK_MINIMIZED__| UI section is collased and not visibile until maximized -/// __NK_MAXIMIZED__| UI section is extended and visibile until minimized -///

-*/ -enum nk_panel_flags { - NK_WINDOW_BORDER = NK_FLAG(0), - NK_WINDOW_MOVABLE = NK_FLAG(1), - NK_WINDOW_SCALABLE = NK_FLAG(2), - NK_WINDOW_CLOSABLE = NK_FLAG(3), - NK_WINDOW_MINIMIZABLE = NK_FLAG(4), - NK_WINDOW_NO_SCROLLBAR = NK_FLAG(5), - NK_WINDOW_TITLE = NK_FLAG(6), - NK_WINDOW_SCROLL_AUTO_HIDE = NK_FLAG(7), - NK_WINDOW_BACKGROUND = NK_FLAG(8), - NK_WINDOW_SCALE_LEFT = NK_FLAG(9), - NK_WINDOW_NO_INPUT = NK_FLAG(10) -}; -/*/// #### nk_begin -/// Starts a new window; needs to be called every frame for every -/// window (unless hidden) or otherwise the window gets removed -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_begin(struct nk_context *ctx, const char *title, struct nk_rect bounds, nk_flags flags); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __title__ | Window title and identifier. Needs to be persistent over frames to identify the window -/// __bounds__ | Initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame -/// __flags__ | Window flags defined in the nk_panel_flags section with a number of different window behaviors -/// -/// Returns `true(1)` if the window can be filled up with widgets from this point -/// until `nk_end` or `false(0)` otherwise for example if minimized -*/ -NK_API int nk_begin(struct nk_context *ctx, const char *title, struct nk_rect bounds, nk_flags flags); -/*/// #### nk_begin_titled -/// Extended window start with separated title and identifier to allow multiple -/// windows with same name but not title -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, struct nk_rect bounds, nk_flags flags); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Window identifier. Needs to be persistent over frames to identify the window -/// __title__ | Window title displayed inside header if flag `NK_WINDOW_TITLE` or either `NK_WINDOW_CLOSABLE` or `NK_WINDOW_MINIMIZED` was set -/// __bounds__ | Initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame -/// __flags__ | Window flags defined in the nk_panel_flags section with a number of different window behaviors -/// -/// Returns `true(1)` if the window can be filled up with widgets from this point -/// until `nk_end` or `false(0)` otherwise for example if minimized -*/ -NK_API int nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, struct nk_rect bounds, nk_flags flags); -/*/// #### nk_end -/// Needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup. -/// All widget calls after this functions will result in asserts or no state changes -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_end(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -*/ -NK_API void nk_end(struct nk_context *ctx); -/*/// #### nk_window_find -/// Finds and returns a window from passed name -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_end(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Window identifier -/// -/// Returns a `nk_window` struct pointing to the identified window or NULL if -/// no window with given name was found -*/ -NK_API struct nk_window *nk_window_find(struct nk_context *ctx, const char *name); -/*/// #### nk_window_get_bounds -/// -/// Returns a rectangle with screen position and size of the currently processed window -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_rect nk_window_get_bounds(const struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns a `nk_rect` struct with window upper left window position and size -*/ -NK_API struct nk_rect nk_window_get_bounds(const struct nk_context *ctx); -/*/// #### nk_window_get_bounds -/// -/// Returns the position of the currently processed window. -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_vec2 nk_window_get_position(const struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns a `nk_vec2` struct with window upper left position -*/ -NK_API struct nk_vec2 nk_window_get_position(const struct nk_context *ctx); -/*/// #### nk_window_get_size -/// -/// Returns the size with width and height of the currently processed window. -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_vec2 nk_window_get_size(const struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns a `nk_vec2` struct with window width and height -*/ -NK_API struct nk_vec2 nk_window_get_size(const struct nk_context*); -/*/// #### nk_window_get_width -/// -/// Returns the width of the currently processed window. -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// float nk_window_get_width(const struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns the current window width -*/ -NK_API float nk_window_get_width(const struct nk_context*); -/*/// #### nk_window_get_height -/// -/// Returns the height of the currently processed window. -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// float nk_window_get_height(const struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns the current window height -*/ -NK_API float nk_window_get_height(const struct nk_context*); -/*/// #### nk_window_get_panel -/// -/// Returns the underlying panel which contains all processing state of the current window. -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// !!! WARNING -/// Do not keep the returned panel pointer around it is only valid until `nk_end` -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_panel* nk_window_get_panel(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns a pointer to window internal `nk_panel` state. -*/ -NK_API struct nk_panel* nk_window_get_panel(struct nk_context*); -/*/// #### nk_window_get_content_region -/// -/// Returns the position and size of the currently visible and non-clipped space -/// inside the currently processed window. -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_rect nk_window_get_content_region(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns `nk_rect` struct with screen position and size (no scrollbar offset) -/// of the visible space inside the current window -*/ -NK_API struct nk_rect nk_window_get_content_region(struct nk_context*); -/*/// #### nk_window_get_content_region_min -/// -/// Returns the upper left position of the currently visible and non-clipped -/// space inside the currently processed window. -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_vec2 nk_window_get_content_region_min(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// returns `nk_vec2` struct with upper left screen position (no scrollbar offset) -/// of the visible space inside the current window -*/ -NK_API struct nk_vec2 nk_window_get_content_region_min(struct nk_context*); -/*/// #### nk_window_get_content_region_max -/// -/// Returns the lower right screen position of the currently visible and -/// non-clipped space inside the currently processed window. -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_vec2 nk_window_get_content_region_max(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns `nk_vec2` struct with lower right screen position (no scrollbar offset) -/// of the visible space inside the current window -*/ -NK_API struct nk_vec2 nk_window_get_content_region_max(struct nk_context*); -/*/// #### nk_window_get_content_region_size -/// -/// Returns the size of the currently visible and non-clipped space inside the -/// currently processed window -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_vec2 nk_window_get_content_region_size(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns `nk_vec2` struct with size the visible space inside the current window -*/ -NK_API struct nk_vec2 nk_window_get_content_region_size(struct nk_context*); -/*/// #### nk_window_get_canvas -/// Returns the draw command buffer. Can be used to draw custom widgets -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// !!! WARNING -/// Do not keep the returned command buffer pointer around it is only valid until `nk_end` -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_command_buffer* nk_window_get_canvas(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns a pointer to window internal `nk_command_buffer` struct used as -/// drawing canvas. Can be used to do custom drawing. -*/ -NK_API struct nk_command_buffer* nk_window_get_canvas(struct nk_context*); -/*/// #### nk_window_has_focus -/// Returns if the currently processed window is currently active -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_window_has_focus(const struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns `false(0)` if current window is not active or `true(1)` if it is -*/ -NK_API int nk_window_has_focus(const struct nk_context*); -/*/// #### nk_window_is_hovered -/// Return if the current window is being hovered -/// !!! WARNING -/// Only call this function between calls `nk_begin_xxx` and `nk_end` -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_window_is_hovered(struct nk_context *ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns `true(1)` if current window is hovered or `false(0)` otherwise -*/ -NK_API int nk_window_is_hovered(struct nk_context*); -/*/// #### nk_window_is_collapsed -/// Returns if the window with given name is currently minimized/collapsed -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_window_is_collapsed(struct nk_context *ctx, const char *name); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of window you want to check if it is collapsed -/// -/// Returns `true(1)` if current window is minimized and `false(0)` if window not -/// found or is not minimized -*/ -NK_API int nk_window_is_collapsed(struct nk_context *ctx, const char *name); -/*/// #### nk_window_is_closed -/// Returns if the window with given name was closed by calling `nk_close` -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_window_is_closed(struct nk_context *ctx, const char *name); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of window you want to check if it is closed -/// -/// Returns `true(1)` if current window was closed or `false(0)` window not found or not closed -*/ -NK_API int nk_window_is_closed(struct nk_context*, const char*); -/*/// #### nk_window_is_hidden -/// Returns if the window with given name is hidden -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_window_is_hidden(struct nk_context *ctx, const char *name); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of window you want to check if it is hidden -/// -/// Returns `true(1)` if current window is hidden or `false(0)` window not found or visible -*/ -NK_API int nk_window_is_hidden(struct nk_context*, const char*); -/*/// #### nk_window_is_active -/// Same as nk_window_has_focus for some reason -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_window_is_active(struct nk_context *ctx, const char *name); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of window you want to check if it is active -/// -/// Returns `true(1)` if current window is active or `false(0)` window not found or not active -*/ -NK_API int nk_window_is_active(struct nk_context*, const char*); -/*/// #### nk_window_is_any_hovered -/// Returns if the any window is being hovered -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_window_is_any_hovered(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns `true(1)` if any window is hovered or `false(0)` otherwise -*/ -NK_API int nk_window_is_any_hovered(struct nk_context*); -/*/// #### nk_item_is_any_active -/// Returns if the any window is being hovered or any widget is currently active. -/// Can be used to decide if input should be processed by UI or your specific input handling. -/// Example could be UI and 3D camera to move inside a 3D space. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_item_is_any_active(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// -/// Returns `true(1)` if any window is hovered or any item is active or `false(0)` otherwise -*/ -NK_API int nk_item_is_any_active(struct nk_context*); -/*/// #### nk_window_set_bounds -/// Updates position and size of window with passed in name -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_window_set_bounds(struct nk_context*, const char *name, struct nk_rect bounds); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of the window to modify both position and size -/// __bounds__ | Must point to a `nk_rect` struct with the new position and size -*/ -NK_API void nk_window_set_bounds(struct nk_context*, const char *name, struct nk_rect bounds); -/*/// #### nk_window_set_position -/// Updates position of window with passed name -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_window_set_position(struct nk_context*, const char *name, struct nk_vec2 pos); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of the window to modify both position -/// __pos__ | Must point to a `nk_vec2` struct with the new position -*/ -NK_API void nk_window_set_position(struct nk_context*, const char *name, struct nk_vec2 pos); -/*/// #### nk_window_set_size -/// Updates size of window with passed in name -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_window_set_size(struct nk_context*, const char *name, struct nk_vec2); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of the window to modify both window size -/// __size__ | Must point to a `nk_vec2` struct with new window size -*/ -NK_API void nk_window_set_size(struct nk_context*, const char *name, struct nk_vec2); -/*/// #### nk_window_set_focus -/// Sets the window with given name as active -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_window_set_focus(struct nk_context*, const char *name); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of the window to set focus on -*/ -NK_API void nk_window_set_focus(struct nk_context*, const char *name); -/*/// #### nk_window_close -/// Closes a window and marks it for being freed at the end of the frame -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_window_close(struct nk_context *ctx, const char *name); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of the window to close -*/ -NK_API void nk_window_close(struct nk_context *ctx, const char *name); -/*/// #### nk_window_collapse -/// Updates collapse state of a window with given name -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_window_collapse(struct nk_context*, const char *name, enum nk_collapse_states state); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of the window to close -/// __state__ | value out of nk_collapse_states section -*/ -NK_API void nk_window_collapse(struct nk_context*, const char *name, enum nk_collapse_states state); -/*/// #### nk_window_collapse_if -/// Updates collapse state of a window with given name if given condition is met -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_window_collapse_if(struct nk_context*, const char *name, enum nk_collapse_states, int cond); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of the window to either collapse or maximize -/// __state__ | value out of nk_collapse_states section the window should be put into -/// __cond__ | condition that has to be met to actually commit the collapse state change -*/ -NK_API void nk_window_collapse_if(struct nk_context*, const char *name, enum nk_collapse_states, int cond); -/*/// #### nk_window_show -/// updates visibility state of a window with given name -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_window_show(struct nk_context*, const char *name, enum nk_show_states); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of the window to either collapse or maximize -/// __state__ | state with either visible or hidden to modify the window with -*/ -NK_API void nk_window_show(struct nk_context*, const char *name, enum nk_show_states); -/*/// #### nk_window_show_if -/// Updates visibility state of a window with given name if a given condition is met -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_window_show_if(struct nk_context*, const char *name, enum nk_show_states, int cond); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __name__ | Identifier of the window to either hide or show -/// __state__ | state with either visible or hidden to modify the window with -/// __cond__ | condition that has to be met to actually commit the visbility state change -*/ -NK_API void nk_window_show_if(struct nk_context*, const char *name, enum nk_show_states, int cond); -/* ============================================================================= - * - * LAYOUT - * - * ============================================================================= -/// ### Layouting -/// Layouting in general describes placing widget inside a window with position and size. -/// While in this particular implementation there are five different APIs for layouting -/// each with different trade offs between control and ease of use.

-/// -/// All layouting methods in this library are based around the concept of a row. -/// A row has a height the window content grows by and a number of columns and each -/// layouting method specifies how each widget is placed inside the row. -/// After a row has been allocated by calling a layouting functions and then -/// filled with widgets will advance an internal pointer over the allocated row.

-/// -/// To actually define a layout you just call the appropriate layouting function -/// and each subsequent widget call will place the widget as specified. Important -/// here is that if you define more widgets then columns defined inside the layout -/// functions it will allocate the next row without you having to make another layouting

-/// call. -/// -/// Biggest limitation with using all these APIs outside the `nk_layout_space_xxx` API -/// is that you have to define the row height for each. However the row height -/// often depends on the height of the font.

-/// -/// To fix that internally nuklear uses a minimum row height that is set to the -/// height plus padding of currently active font and overwrites the row height -/// value if zero.

-/// -/// If you manually want to change the minimum row height then -/// use nk_layout_set_min_row_height, and use nk_layout_reset_min_row_height to -/// reset it back to be derived from font height.

-/// -/// Also if you change the font in nuklear it will automatically change the minimum -/// row height for you and. This means if you change the font but still want -/// a minimum row height smaller than the font you have to repush your value.

-/// -/// For actually more advanced UI I would even recommend using the `nk_layout_space_xxx` -/// layouting method in combination with a cassowary constraint solver (there are -/// some versions on github with permissive license model) to take over all control over widget -/// layouting yourself. However for quick and dirty layouting using all the other layouting -/// functions should be fine. -/// -/// #### Usage -/// 1. __nk_layout_row_dynamic__

-/// The easiest layouting function is `nk_layout_row_dynamic`. It provides each -/// widgets with same horizontal space inside the row and dynamically grows -/// if the owning window grows in width. So the number of columns dictates -/// the size of each widget dynamically by formula: -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// widget_width = (window_width - padding - spacing) * (1/colum_count) -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Just like all other layouting APIs if you define more widget than columns this -/// library will allocate a new row and keep all layouting parameters previously -/// defined. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// if (nk_begin_xxx(...) { -/// // first row with height: 30 composed of two widgets -/// nk_layout_row_dynamic(&ctx, 30, 2); -/// nk_widget(...); -/// nk_widget(...); -/// // -/// // second row with same parameter as defined above -/// nk_widget(...); -/// nk_widget(...); -/// // -/// // third row uses 0 for height which will use auto layouting -/// nk_layout_row_dynamic(&ctx, 0, 2); -/// nk_widget(...); -/// nk_widget(...); -/// } -/// nk_end(...); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// 2. __nk_layout_row_static__

-/// Another easy layouting function is `nk_layout_row_static`. It provides each -/// widget with same horizontal pixel width inside the row and does not grow -/// if the owning window scales smaller or bigger. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// if (nk_begin_xxx(...) { -/// // first row with height: 30 composed of two widgets with width: 80 -/// nk_layout_row_static(&ctx, 30, 80, 2); -/// nk_widget(...); -/// nk_widget(...); -/// // -/// // second row with same parameter as defined above -/// nk_widget(...); -/// nk_widget(...); -/// // -/// // third row uses 0 for height which will use auto layouting -/// nk_layout_row_static(&ctx, 0, 80, 2); -/// nk_widget(...); -/// nk_widget(...); -/// } -/// nk_end(...); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// 3. __nk_layout_row_xxx__

-/// A little bit more advanced layouting API are functions `nk_layout_row_begin`, -/// `nk_layout_row_push` and `nk_layout_row_end`. They allow to directly -/// specify each column pixel or window ratio in a row. It supports either -/// directly setting per column pixel width or widget window ratio but not -/// both. Furthermore it is a immediate mode API so each value is directly -/// pushed before calling a widget. Therefore the layout is not automatically -/// repeating like the last two layouting functions. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// if (nk_begin_xxx(...) { -/// // first row with height: 25 composed of two widgets with width 60 and 40 -/// nk_layout_row_begin(ctx, NK_STATIC, 25, 2); -/// nk_layout_row_push(ctx, 60); -/// nk_widget(...); -/// nk_layout_row_push(ctx, 40); -/// nk_widget(...); -/// nk_layout_row_end(ctx); -/// // -/// // second row with height: 25 composed of two widgets with window ratio 0.25 and 0.75 -/// nk_layout_row_begin(ctx, NK_DYNAMIC, 25, 2); -/// nk_layout_row_push(ctx, 0.25f); -/// nk_widget(...); -/// nk_layout_row_push(ctx, 0.75f); -/// nk_widget(...); -/// nk_layout_row_end(ctx); -/// // -/// // third row with auto generated height: composed of two widgets with window ratio 0.25 and 0.75 -/// nk_layout_row_begin(ctx, NK_DYNAMIC, 0, 2); -/// nk_layout_row_push(ctx, 0.25f); -/// nk_widget(...); -/// nk_layout_row_push(ctx, 0.75f); -/// nk_widget(...); -/// nk_layout_row_end(ctx); -/// } -/// nk_end(...); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// 4. __nk_layout_row__

-/// The array counterpart to API nk_layout_row_xxx is the single nk_layout_row -/// functions. Instead of pushing either pixel or window ratio for every widget -/// it allows to define it by array. The trade of for less control is that -/// `nk_layout_row` is automatically repeating. Otherwise the behavior is the -/// same. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// if (nk_begin_xxx(...) { -/// // two rows with height: 30 composed of two widgets with width 60 and 40 -/// const float size[] = {60,40}; -/// nk_layout_row(ctx, NK_STATIC, 30, 2, ratio); -/// nk_widget(...); -/// nk_widget(...); -/// nk_widget(...); -/// nk_widget(...); -/// // -/// // two rows with height: 30 composed of two widgets with window ratio 0.25 and 0.75 -/// const float ratio[] = {0.25, 0.75}; -/// nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratio); -/// nk_widget(...); -/// nk_widget(...); -/// nk_widget(...); -/// nk_widget(...); -/// // -/// // two rows with auto generated height composed of two widgets with window ratio 0.25 and 0.75 -/// const float ratio[] = {0.25, 0.75}; -/// nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratio); -/// nk_widget(...); -/// nk_widget(...); -/// nk_widget(...); -/// nk_widget(...); -/// } -/// nk_end(...); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// 5. __nk_layout_row_template_xxx__

-/// The most complex and second most flexible API is a simplified flexbox version without -/// line wrapping and weights for dynamic widgets. It is an immediate mode API but -/// unlike `nk_layout_row_xxx` it has auto repeat behavior and needs to be called -/// before calling the templated widgets. -/// The row template layout has three different per widget size specifier. The first -/// one is the `nk_layout_row_template_push_static` with fixed widget pixel width. -/// They do not grow if the row grows and will always stay the same. -/// The second size specifier is `nk_layout_row_template_push_variable` -/// which defines a minimum widget size but it also can grow if more space is available -/// not taken by other widgets. -/// Finally there are dynamic widgets with `nk_layout_row_template_push_dynamic` -/// which are completely flexible and unlike variable widgets can even shrink -/// to zero if not enough space is provided. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// if (nk_begin_xxx(...) { -/// // two rows with height: 30 composed of three widgets -/// nk_layout_row_template_begin(ctx, 30); -/// nk_layout_row_template_push_dynamic(ctx); -/// nk_layout_row_template_push_variable(ctx, 80); -/// nk_layout_row_template_push_static(ctx, 80); -/// nk_layout_row_template_end(ctx); -/// // -/// // first row -/// nk_widget(...); // dynamic widget can go to zero if not enough space -/// nk_widget(...); // variable widget with min 80 pixel but can grow bigger if enough space -/// nk_widget(...); // static widget with fixed 80 pixel width -/// // -/// // second row same layout -/// nk_widget(...); -/// nk_widget(...); -/// nk_widget(...); -/// } -/// nk_end(...); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// 6. __nk_layout_space_xxx__

-/// Finally the most flexible API directly allows you to place widgets inside the -/// window. The space layout API is an immediate mode API which does not support -/// row auto repeat and directly sets position and size of a widget. Position -/// and size hereby can be either specified as ratio of allocated space or -/// allocated space local position and pixel size. Since this API is quite -/// powerful there are a number of utility functions to get the available space -/// and convert between local allocated space and screen space. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// if (nk_begin_xxx(...) { -/// // static row with height: 500 (you can set column count to INT_MAX if you don't want to be bothered) -/// nk_layout_space_begin(ctx, NK_STATIC, 500, INT_MAX); -/// nk_layout_space_push(ctx, nk_rect(0,0,150,200)); -/// nk_widget(...); -/// nk_layout_space_push(ctx, nk_rect(200,200,100,200)); -/// nk_widget(...); -/// nk_layout_space_end(ctx); -/// // -/// // dynamic row with height: 500 (you can set column count to INT_MAX if you don't want to be bothered) -/// nk_layout_space_begin(ctx, NK_DYNAMIC, 500, INT_MAX); -/// nk_layout_space_push(ctx, nk_rect(0.5,0.5,0.1,0.1)); -/// nk_widget(...); -/// nk_layout_space_push(ctx, nk_rect(0.7,0.6,0.1,0.1)); -/// nk_widget(...); -/// } -/// nk_end(...); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// #### Reference -/// Function | Description -/// ----------------------------------------|------------------------------------ -/// nk_layout_set_min_row_height | Set the currently used minimum row height to a specified value -/// nk_layout_reset_min_row_height | Resets the currently used minimum row height to font height -/// nk_layout_widget_bounds | Calculates current width a static layout row can fit inside a window -/// nk_layout_ratio_from_pixel | Utility functions to calculate window ratio from pixel size -// -/// nk_layout_row_dynamic | Current layout is divided into n same sized growing columns -/// nk_layout_row_static | Current layout is divided into n same fixed sized columns -/// nk_layout_row_begin | Starts a new row with given height and number of columns -/// nk_layout_row_push | Pushes another column with given size or window ratio -/// nk_layout_row_end | Finished previously started row -/// nk_layout_row | Specifies row columns in array as either window ratio or size -// -/// nk_layout_row_template_begin | Begins the row template declaration -/// nk_layout_row_template_push_dynamic | Adds a dynamic column that dynamically grows and can go to zero if not enough space -/// nk_layout_row_template_push_variable | Adds a variable column that dynamically grows but does not shrink below specified pixel width -/// nk_layout_row_template_push_static | Adds a static column that does not grow and will always have the same size -/// nk_layout_row_template_end | Marks the end of the row template -// -/// nk_layout_space_begin | Begins a new layouting space that allows to specify each widgets position and size -/// nk_layout_space_push | Pushes position and size of the next widget in own coordinate space either as pixel or ratio -/// nk_layout_space_end | Marks the end of the layouting space -// -/// nk_layout_space_bounds | Callable after nk_layout_space_begin and returns total space allocated -/// nk_layout_space_to_screen | Converts vector from nk_layout_space coordinate space into screen space -/// nk_layout_space_to_local | Converts vector from screen space into nk_layout_space coordinates -/// nk_layout_space_rect_to_screen | Converts rectangle from nk_layout_space coordinate space into screen space -/// nk_layout_space_rect_to_local | Converts rectangle from screen space into nk_layout_space coordinates -*/ -/*/// #### nk_layout_set_min_row_height -/// Sets the currently used minimum row height. -/// !!! WARNING -/// The passed height needs to include both your preferred row height -/// as well as padding. No internal padding is added. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_set_min_row_height(struct nk_context*, float height); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __height__ | New minimum row height to be used for auto generating the row height -*/ -NK_API void nk_layout_set_min_row_height(struct nk_context*, float height); -/*/// #### nk_layout_reset_min_row_height -/// Reset the currently used minimum row height back to `font_height + text_padding + padding` -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_reset_min_row_height(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -*/ -NK_API void nk_layout_reset_min_row_height(struct nk_context*); -/*/// #### nk_layout_widget_bounds -/// Returns the width of the next row allocate by one of the layouting functions -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_rect nk_layout_widget_bounds(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// -/// Return `nk_rect` with both position and size of the next row -*/ -NK_API struct nk_rect nk_layout_widget_bounds(struct nk_context*); -/*/// #### nk_layout_ratio_from_pixel -/// Utility functions to calculate window ratio from pixel size -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// float nk_layout_ratio_from_pixel(struct nk_context*, float pixel_width); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __pixel__ | Pixel_width to convert to window ratio -/// -/// Returns `nk_rect` with both position and size of the next row -*/ -NK_API float nk_layout_ratio_from_pixel(struct nk_context*, float pixel_width); -/*/// #### nk_layout_row_dynamic -/// Sets current row layout to share horizontal space -/// between @cols number of widgets evenly. Once called all subsequent widget -/// calls greater than @cols will allocate a new row with same layout. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __height__ | Holds height of each widget in row or zero for auto layouting -/// __columns__ | Number of widget inside row -*/ -NK_API void nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols); -/*/// #### nk_layout_row_dynamic -/// Sets current row layout to fill @cols number of widgets -/// in row with same @item_width horizontal size. Once called all subsequent widget -/// calls greater than @cols will allocate a new row with same layout. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __height__ | Holds height of each widget in row or zero for auto layouting -/// __width__ | Holds pixel width of each widget in the row -/// __columns__ | Number of widget inside row -*/ -NK_API void nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols); -/*/// #### nk_layout_row_begin -/// Starts a new dynamic or fixed row with given height and columns. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt, float row_height, int cols); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __fmt__ | either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns -/// __height__ | holds height of each widget in row or zero for auto layouting -/// __columns__ | Number of widget inside row -*/ -NK_API void nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt, float row_height, int cols); -/*/// #### nk_layout_row_push -/// Specifies either window ratio or width of a single column -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_row_push(struct nk_context*, float value); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __value__ | either a window ratio or fixed width depending on @fmt in previous `nk_layout_row_begin` call -*/ -NK_API void nk_layout_row_push(struct nk_context*, float value); -/*/// #### nk_layout_row_end -/// Finished previously started row -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_row_end(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -*/ -NK_API void nk_layout_row_end(struct nk_context*); -/*/// #### nk_layout_row -/// Specifies row columns in array as either window ratio or size -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_row(struct nk_context*, enum nk_layout_format, float height, int cols, const float *ratio); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __fmt__ | Either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns -/// __height__ | Holds height of each widget in row or zero for auto layouting -/// __columns__ | Number of widget inside row -*/ -NK_API void nk_layout_row(struct nk_context*, enum nk_layout_format, float height, int cols, const float *ratio); -/*/// #### nk_layout_row_template_begin -/// Begins the row template declaration -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_row_template_begin(struct nk_context*, float row_height); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __height__ | Holds height of each widget in row or zero for auto layouting -*/ -NK_API void nk_layout_row_template_begin(struct nk_context*, float row_height); -/*/// #### nk_layout_row_template_push_dynamic -/// Adds a dynamic column that dynamically grows and can go to zero if not enough space -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_row_template_push_dynamic(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __height__ | Holds height of each widget in row or zero for auto layouting -*/ -NK_API void nk_layout_row_template_push_dynamic(struct nk_context*); -/*/// #### nk_layout_row_template_push_variable -/// Adds a variable column that dynamically grows but does not shrink below specified pixel width -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_row_template_push_variable(struct nk_context*, float min_width); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __width__ | Holds the minimum pixel width the next column must always be -*/ -NK_API void nk_layout_row_template_push_variable(struct nk_context*, float min_width); -/*/// #### nk_layout_row_template_push_static -/// Adds a static column that does not grow and will always have the same size -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_row_template_push_static(struct nk_context*, float width); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __width__ | Holds the absolute pixel width value the next column must be -*/ -NK_API void nk_layout_row_template_push_static(struct nk_context*, float width); -/*/// #### nk_layout_row_template_end -/// Marks the end of the row template -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_row_template_end(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -*/ -NK_API void nk_layout_row_template_end(struct nk_context*); -/*/// #### nk_layout_space_begin -/// Begins a new layouting space that allows to specify each widgets position and size. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_space_begin(struct nk_context*, enum nk_layout_format, float height, int widget_count); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` -/// __fmt__ | Either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns -/// __height__ | Holds height of each widget in row or zero for auto layouting -/// __columns__ | Number of widgets inside row -*/ -NK_API void nk_layout_space_begin(struct nk_context*, enum nk_layout_format, float height, int widget_count); -/*/// #### nk_layout_space_push -/// Pushes position and size of the next widget in own coordinate space either as pixel or ratio -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_space_push(struct nk_context *ctx, struct nk_rect bounds); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` -/// __bounds__ | Position and size in laoyut space local coordinates -*/ -NK_API void nk_layout_space_push(struct nk_context*, struct nk_rect bounds); -/*/// #### nk_layout_space_end -/// Marks the end of the layout space -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_layout_space_end(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` -*/ -NK_API void nk_layout_space_end(struct nk_context*); -/*/// #### nk_layout_space_bounds -/// Utility function to calculate total space allocated for `nk_layout_space` -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_rect nk_layout_space_bounds(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` -/// -/// Returns `nk_rect` holding the total space allocated -*/ -NK_API struct nk_rect nk_layout_space_bounds(struct nk_context*); -/*/// #### nk_layout_space_to_screen -/// Converts vector from nk_layout_space coordinate space into screen space -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_vec2 nk_layout_space_to_screen(struct nk_context*, struct nk_vec2); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` -/// __vec__ | Position to convert from layout space into screen coordinate space -/// -/// Returns transformed `nk_vec2` in screen space coordinates -*/ -NK_API struct nk_vec2 nk_layout_space_to_screen(struct nk_context*, struct nk_vec2); -/*/// #### nk_layout_space_to_screen -/// Converts vector from layout space into screen space -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_vec2 nk_layout_space_to_local(struct nk_context*, struct nk_vec2); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` -/// __vec__ | Position to convert from screen space into layout coordinate space -/// -/// Returns transformed `nk_vec2` in layout space coordinates -*/ -NK_API struct nk_vec2 nk_layout_space_to_local(struct nk_context*, struct nk_vec2); -/*/// #### nk_layout_space_rect_to_screen -/// Converts rectangle from screen space into layout space -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_rect nk_layout_space_rect_to_screen(struct nk_context*, struct nk_rect); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` -/// __bounds__ | Rectangle to convert from layout space into screen space -/// -/// Returns transformed `nk_rect` in screen space coordinates -*/ -NK_API struct nk_rect nk_layout_space_rect_to_screen(struct nk_context*, struct nk_rect); -/*/// #### nk_layout_space_rect_to_local -/// Converts rectangle from layout space into screen space -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_rect nk_layout_space_rect_to_local(struct nk_context*, struct nk_rect); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` -/// __bounds__ | Rectangle to convert from layout space into screen space -/// -/// Returns transformed `nk_rect` in layout space coordinates -*/ -NK_API struct nk_rect nk_layout_space_rect_to_local(struct nk_context*, struct nk_rect); -/* ============================================================================= - * - * GROUP - * - * ============================================================================= -/// ### Groups -/// Groups are basically windows inside windows. They allow to subdivide space -/// in a window to layout widgets as a group. Almost all more complex widget -/// layouting requirements can be solved using groups and basic layouting -/// fuctionality. Groups just like windows are identified by an unique name and -/// internally keep track of scrollbar offsets by default. However additional -/// versions are provided to directly manage the scrollbar. -/// -/// #### Usage -/// To create a group you have to call one of the three `nk_group_begin_xxx` -/// functions to start group declarations and `nk_group_end` at the end. Furthermore it -/// is required to check the return value of `nk_group_begin_xxx` and only process -/// widgets inside the window if the value is not 0. -/// Nesting groups is possible and even encouraged since many layouting schemes -/// can only be achieved by nesting. Groups, unlike windows, need `nk_group_end` -/// to be only called if the corosponding `nk_group_begin_xxx` call does not return 0: -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// if (nk_group_begin_xxx(ctx, ...) { -/// // [... widgets ...] -/// nk_group_end(ctx); -/// } -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// In the grand concept groups can be called after starting a window -/// with `nk_begin_xxx` and before calling `nk_end`: -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// struct nk_context ctx; -/// nk_init_xxx(&ctx, ...); -/// while (1) { -/// // Input -/// Event evt; -/// nk_input_begin(&ctx); -/// while (GetEvent(&evt)) { -/// if (evt.type == MOUSE_MOVE) -/// nk_input_motion(&ctx, evt.motion.x, evt.motion.y); -/// else if (evt.type == [...]) { -/// nk_input_xxx(...); -/// } -/// } -/// nk_input_end(&ctx); -/// // -/// // Window -/// if (nk_begin_xxx(...) { -/// // [...widgets...] -/// nk_layout_row_dynamic(...); -/// if (nk_group_begin_xxx(ctx, ...) { -/// //[... widgets ...] -/// nk_group_end(ctx); -/// } -/// } -/// nk_end(ctx); -/// // -/// // Draw -/// const struct nk_command *cmd = 0; -/// nk_foreach(cmd, &ctx) { -/// switch (cmd->type) { -/// case NK_COMMAND_LINE: -/// your_draw_line_function(...) -/// break; -/// case NK_COMMAND_RECT -/// your_draw_rect_function(...) -/// break; -/// case ...: -/// // [...] -/// } -// nk_clear(&ctx); -/// } -/// nk_free(&ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// #### Reference -/// Function | Description -/// --------------------------------|------------------------------------------- -/// nk_group_begin | Start a new group with internal scrollbar handling -/// nk_group_begin_titled | Start a new group with separeted name and title and internal scrollbar handling -/// nk_group_end | Ends a group. Should only be called if nk_group_begin returned non-zero -/// nk_group_scrolled_offset_begin | Start a new group with manual separated handling of scrollbar x- and y-offset -/// nk_group_scrolled_begin | Start a new group with manual scrollbar handling -/// nk_group_scrolled_end | Ends a group with manual scrollbar handling. Should only be called if nk_group_begin returned non-zero -*/ -/*/// #### nk_group_begin -/// Starts a new widget group. Requires a previous layouting function to specify a pos/size. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_group_begin(struct nk_context*, const char *title, nk_flags); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __title__ | Must be an unique identifier for this group that is also used for the group header -/// __flags__ | Window flags defined in the nk_panel_flags section with a number of different group behaviors -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -NK_API int nk_group_begin(struct nk_context*, const char *title, nk_flags); -/*/// #### nk_group_begin_titled -/// Starts a new widget group. Requires a previous layouting function to specify a pos/size. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_group_begin_titled(struct nk_context*, const char *name, const char *title, nk_flags); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __id__ | Must be an unique identifier for this group -/// __title__ | Group header title -/// __flags__ | Window flags defined in the nk_panel_flags section with a number of different group behaviors -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -NK_API int nk_group_begin_titled(struct nk_context*, const char *name, const char *title, nk_flags); -/*/// #### nk_group_end -/// Ends a widget group -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_group_end(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -*/ -NK_API void nk_group_end(struct nk_context*); -/*/// #### nk_group_scrolled_offset_begin -/// starts a new widget group. requires a previous layouting function to specify -/// a size. Does not keep track of scrollbar. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_group_scrolled_offset_begin(struct nk_context*, nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __x_offset__| Scrollbar x-offset to offset all widgets inside the group horizontally. -/// __y_offset__| Scrollbar y-offset to offset all widgets inside the group vertically -/// __title__ | Window unique group title used to both identify and display in the group header -/// __flags__ | Window flags from the nk_panel_flags section -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -NK_API int nk_group_scrolled_offset_begin(struct nk_context*, nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags); -/*/// #### nk_group_scrolled_begin -/// Starts a new widget group. requires a previous -/// layouting function to specify a size. Does not keep track of scrollbar. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_group_scrolled_begin(struct nk_context*, struct nk_scroll *off, const char *title, nk_flags); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __off__ | Both x- and y- scroll offset. Allows for manual scrollbar control -/// __title__ | Window unique group title used to both identify and display in the group header -/// __flags__ | Window flags from nk_panel_flags section -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -NK_API int nk_group_scrolled_begin(struct nk_context*, struct nk_scroll *off, const char *title, nk_flags); -/*/// #### nk_group_scrolled_end -/// Ends a widget group after calling nk_group_scrolled_offset_begin or nk_group_scrolled_begin. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_group_scrolled_end(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -*/ -NK_API void nk_group_scrolled_end(struct nk_context*); -/* ============================================================================= - * - * TREE - * - * ============================================================================= -/// ### Tree -/// Trees represent two different concept. First the concept of a collapsable -/// UI section that can be either in a hidden or visibile state. They allow the UI -/// user to selectively minimize the current set of visible UI to comprehend. -/// The second concept are tree widgets for visual UI representation of trees.

-/// -/// Trees thereby can be nested for tree representations and multiple nested -/// collapsable UI sections. All trees are started by calling of the -/// `nk_tree_xxx_push_tree` functions and ended by calling one of the -/// `nk_tree_xxx_pop_xxx()` functions. Each starting functions takes a title label -/// and optionally an image to be displayed and the initial collapse state from -/// the nk_collapse_states section.

-/// -/// The runtime state of the tree is either stored outside the library by the caller -/// or inside which requires a unique ID. The unique ID can either be generated -/// automatically from `__FILE__` and `__LINE__` with function `nk_tree_push`, -/// by `__FILE__` and a user provided ID generated for example by loop index with -/// function `nk_tree_push_id` or completely provided from outside by user with -/// function `nk_tree_push_hashed`. -/// -/// #### Usage -/// To create a tree you have to call one of the seven `nk_tree_xxx_push_xxx` -/// functions to start a collapsable UI section and `nk_tree_xxx_pop` to mark the -/// end. -/// Each starting function will either return `false(0)` if the tree is collapsed -/// or hidden and therefore does not need to be filled with content or `true(1)` -/// if visible and required to be filled. -/// -/// !!! Note -/// The tree header does not require and layouting function and instead -/// calculates a auto height based on the currently used font size -/// -/// The tree ending functions only need to be called if the tree content is -/// actually visible. So make sure the tree push function is guarded by `if` -/// and the pop call is only taken if the tree is visible. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// if (nk_tree_push(ctx, NK_TREE_TAB, "Tree", NK_MINIMIZED)) { -/// nk_layout_row_dynamic(...); -/// nk_widget(...); -/// nk_tree_pop(ctx); -/// } -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// #### Reference -/// Function | Description -/// ----------------------------|------------------------------------------- -/// nk_tree_push | Start a collapsable UI section with internal state management -/// nk_tree_push_id | Start a collapsable UI section with internal state management callable in a look -/// nk_tree_push_hashed | Start a collapsable UI section with internal state management with full control over internal unique ID use to store state -/// nk_tree_image_push | Start a collapsable UI section with image and label header -/// nk_tree_image_push_id | Start a collapsable UI section with image and label header and internal state management callable in a look -/// nk_tree_image_push_hashed | Start a collapsable UI section with image and label header and internal state management with full control over internal unique ID use to store state -/// nk_tree_pop | Ends a collapsable UI section -// -/// nk_tree_state_push | Start a collapsable UI section with external state management -/// nk_tree_state_image_push | Start a collapsable UI section with image and label header and external state management -/// nk_tree_state_pop | Ends a collapsabale UI section -/// -/// #### nk_tree_type -/// Flag | Description -/// ----------------|---------------------------------------- -/// NK_TREE_NODE | Highlighted tree header to mark a collapsable UI section -/// NK_TREE_TAB | Non-highighted tree header closer to tree representations -*/ -/*/// #### nk_tree_push -/// Starts a collapsable UI section with internal state management -/// !!! WARNING -/// To keep track of the runtime tree collapsable state this function uses -/// defines `__FILE__` and `__LINE__` to generate a unique ID. If you want -/// to call this function in a loop please use `nk_tree_push_id` or -/// `nk_tree_push_hashed` instead. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// #define nk_tree_push(ctx, type, title, state) -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -/// __title__ | Label printed in the tree header -/// __state__ | Initial tree state value out of nk_collapse_states -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -#define nk_tree_push(ctx, type, title, state) nk_tree_push_hashed(ctx, type, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__) -/*/// #### nk_tree_push_id -/// Starts a collapsable UI section with internal state management callable in a look -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// #define nk_tree_push_id(ctx, type, title, state, id) -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -/// __title__ | Label printed in the tree header -/// __state__ | Initial tree state value out of nk_collapse_states -/// __id__ | Loop counter index if this function is called in a loop -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -#define nk_tree_push_id(ctx, type, title, state, id) nk_tree_push_hashed(ctx, type, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id) -/*/// #### nk_tree_push_hashed -/// Start a collapsable UI section with internal state management with full -/// control over internal unique ID used to store state -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_tree_push_hashed(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -/// __title__ | Label printed in the tree header -/// __state__ | Initial tree state value out of nk_collapse_states -/// __hash__ | Memory block or string to generate the ID from -/// __len__ | Size of passed memory block or string in __hash__ -/// __seed__ | Seeding value if this function is called in a loop or default to `0` -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -NK_API int nk_tree_push_hashed(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed); -/*/// #### nk_tree_image_push -/// Start a collapsable UI section with image and label header -/// !!! WARNING -/// To keep track of the runtime tree collapsable state this function uses -/// defines `__FILE__` and `__LINE__` to generate a unique ID. If you want -/// to call this function in a loop please use `nk_tree_image_push_id` or -/// `nk_tree_image_push_hashed` instead. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// #define nk_tree_image_push(ctx, type, img, title, state) -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -/// __img__ | Image to display inside the header on the left of the label -/// __title__ | Label printed in the tree header -/// __state__ | Initial tree state value out of nk_collapse_states -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -#define nk_tree_image_push(ctx, type, img, title, state) nk_tree_image_push_hashed(ctx, type, img, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__) -/*/// #### nk_tree_image_push_id -/// Start a collapsable UI section with image and label header and internal state -/// management callable in a look -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// #define nk_tree_image_push_id(ctx, type, img, title, state, id) -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -/// __img__ | Image to display inside the header on the left of the label -/// __title__ | Label printed in the tree header -/// __state__ | Initial tree state value out of nk_collapse_states -/// __id__ | Loop counter index if this function is called in a loop -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -#define nk_tree_image_push_id(ctx, type, img, title, state, id) nk_tree_image_push_hashed(ctx, type, img, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id) -/*/// #### nk_tree_image_push_hashed -/// Start a collapsable UI section with internal state management with full -/// control over internal unique ID used to store state -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_tree_image_push_hashed(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct -/// __type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -/// __img__ | Image to display inside the header on the left of the label -/// __title__ | Label printed in the tree header -/// __state__ | Initial tree state value out of nk_collapse_states -/// __hash__ | Memory block or string to generate the ID from -/// __len__ | Size of passed memory block or string in __hash__ -/// __seed__ | Seeding value if this function is called in a loop or default to `0` -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -NK_API int nk_tree_image_push_hashed(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed); -/*/// #### nk_tree_pop -/// Ends a collapsabale UI section -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_tree_pop(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx` -*/ -NK_API void nk_tree_pop(struct nk_context*); -/*/// #### nk_tree_state_push -/// Start a collapsable UI section with external state management -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_tree_state_push(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states *state); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx` -/// __type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -/// __title__ | Label printed in the tree header -/// __state__ | Persistent state to update -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -NK_API int nk_tree_state_push(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states *state); -/*/// #### nk_tree_state_image_push -/// Start a collapsable UI section with image and label header and external state management -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_tree_state_image_push(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states *state); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx` -/// __img__ | Image to display inside the header on the left of the label -/// __type__ | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node -/// __title__ | Label printed in the tree header -/// __state__ | Persistent state to update -/// -/// Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise -*/ -NK_API int nk_tree_state_image_push(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states *state); -/*/// #### nk_tree_state_pop -/// Ends a collapsabale UI section -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_tree_state_pop(struct nk_context*); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// ------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx` -*/ -NK_API void nk_tree_state_pop(struct nk_context*); -/* ============================================================================= - * - * LIST VIEW - * - * ============================================================================= */ -struct nk_list_view { -/* public: */ - int begin, end, count; -/* private: */ - int total_height; - struct nk_context *ctx; - nk_uint *scroll_pointer; - nk_uint scroll_value; -}; -NK_API int nk_list_view_begin(struct nk_context*, struct nk_list_view *out, const char *id, nk_flags, int row_height, int row_count); -NK_API void nk_list_view_end(struct nk_list_view*); -/* ============================================================================= - * - * WIDGET - * - * ============================================================================= */ -enum nk_widget_layout_states { - NK_WIDGET_INVALID, /* The widget cannot be seen and is completely out of view */ - NK_WIDGET_VALID, /* The widget is completely inside the window and can be updated and drawn */ - NK_WIDGET_ROM /* The widget is partially visible and cannot be updated */ -}; -enum nk_widget_states { - NK_WIDGET_STATE_MODIFIED = NK_FLAG(1), - NK_WIDGET_STATE_INACTIVE = NK_FLAG(2), /* widget is neither active nor hovered */ - NK_WIDGET_STATE_ENTERED = NK_FLAG(3), /* widget has been hovered on the current frame */ - NK_WIDGET_STATE_HOVER = NK_FLAG(4), /* widget is being hovered */ - NK_WIDGET_STATE_ACTIVED = NK_FLAG(5),/* widget is currently activated */ - NK_WIDGET_STATE_LEFT = NK_FLAG(6), /* widget is from this frame on not hovered anymore */ - NK_WIDGET_STATE_HOVERED = NK_WIDGET_STATE_HOVER|NK_WIDGET_STATE_MODIFIED, /* widget is being hovered */ - NK_WIDGET_STATE_ACTIVE = NK_WIDGET_STATE_ACTIVED|NK_WIDGET_STATE_MODIFIED /* widget is currently activated */ -}; -NK_API enum nk_widget_layout_states nk_widget(struct nk_rect*, const struct nk_context*); -NK_API enum nk_widget_layout_states nk_widget_fitting(struct nk_rect*, struct nk_context*, struct nk_vec2); -NK_API struct nk_rect nk_widget_bounds(struct nk_context*); -NK_API struct nk_vec2 nk_widget_position(struct nk_context*); -NK_API struct nk_vec2 nk_widget_size(struct nk_context*); -NK_API float nk_widget_width(struct nk_context*); -NK_API float nk_widget_height(struct nk_context*); -NK_API int nk_widget_is_hovered(struct nk_context*); -NK_API int nk_widget_is_mouse_clicked(struct nk_context*, enum nk_buttons); -NK_API int nk_widget_has_mouse_click_down(struct nk_context*, enum nk_buttons, int down); -NK_API void nk_spacing(struct nk_context*, int cols); -/* ============================================================================= - * - * TEXT - * - * ============================================================================= */ -enum nk_text_align { - NK_TEXT_ALIGN_LEFT = 0x01, - NK_TEXT_ALIGN_CENTERED = 0x02, - NK_TEXT_ALIGN_RIGHT = 0x04, - NK_TEXT_ALIGN_TOP = 0x08, - NK_TEXT_ALIGN_MIDDLE = 0x10, - NK_TEXT_ALIGN_BOTTOM = 0x20 -}; -enum nk_text_alignment { - NK_TEXT_LEFT = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_LEFT, - NK_TEXT_CENTERED = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_CENTERED, - NK_TEXT_RIGHT = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_RIGHT -}; -NK_API void nk_text(struct nk_context*, const char*, int, nk_flags); -NK_API void nk_text_colored(struct nk_context*, const char*, int, nk_flags, struct nk_color); -NK_API void nk_text_wrap(struct nk_context*, const char*, int); -NK_API void nk_text_wrap_colored(struct nk_context*, const char*, int, struct nk_color); -NK_API void nk_label(struct nk_context*, const char*, nk_flags align); -NK_API void nk_label_colored(struct nk_context*, const char*, nk_flags align, struct nk_color); -NK_API void nk_label_wrap(struct nk_context*, const char*); -NK_API void nk_label_colored_wrap(struct nk_context*, const char*, struct nk_color); -NK_API void nk_image(struct nk_context*, struct nk_image); -NK_API void nk_image_color(struct nk_context*, struct nk_image, struct nk_color); -#ifdef NK_INCLUDE_STANDARD_VARARGS -NK_API void nk_labelf(struct nk_context*, nk_flags, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(3); -NK_API void nk_labelf_colored(struct nk_context*, nk_flags, struct nk_color, NK_PRINTF_FORMAT_STRING const char*,...) NK_PRINTF_VARARG_FUNC(4); -NK_API void nk_labelf_wrap(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*,...) NK_PRINTF_VARARG_FUNC(2); -NK_API void nk_labelf_colored_wrap(struct nk_context*, struct nk_color, NK_PRINTF_FORMAT_STRING const char*,...) NK_PRINTF_VARARG_FUNC(3); -NK_API void nk_value_bool(struct nk_context*, const char *prefix, int); -NK_API void nk_value_int(struct nk_context*, const char *prefix, int); -NK_API void nk_value_uint(struct nk_context*, const char *prefix, unsigned int); -NK_API void nk_value_float(struct nk_context*, const char *prefix, float); -NK_API void nk_value_color_byte(struct nk_context*, const char *prefix, struct nk_color); -NK_API void nk_value_color_float(struct nk_context*, const char *prefix, struct nk_color); -NK_API void nk_value_color_hex(struct nk_context*, const char *prefix, struct nk_color); -#endif -/* ============================================================================= - * - * BUTTON - * - * ============================================================================= */ -NK_API int nk_button_text(struct nk_context*, const char *title, int len); -NK_API int nk_button_label(struct nk_context*, const char *title); -NK_API int nk_button_color(struct nk_context*, struct nk_color); -NK_API int nk_button_symbol(struct nk_context*, enum nk_symbol_type); -NK_API int nk_button_image(struct nk_context*, struct nk_image img); -NK_API int nk_button_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags text_alignment); -NK_API int nk_button_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); -NK_API int nk_button_image_label(struct nk_context*, struct nk_image img, const char*, nk_flags text_alignment); -NK_API int nk_button_image_text(struct nk_context*, struct nk_image img, const char*, int, nk_flags alignment); -NK_API int nk_button_text_styled(struct nk_context*, const struct nk_style_button*, const char *title, int len); -NK_API int nk_button_label_styled(struct nk_context*, const struct nk_style_button*, const char *title); -NK_API int nk_button_symbol_styled(struct nk_context*, const struct nk_style_button*, enum nk_symbol_type); -NK_API int nk_button_image_styled(struct nk_context*, const struct nk_style_button*, struct nk_image img); -NK_API int nk_button_symbol_text_styled(struct nk_context*,const struct nk_style_button*, enum nk_symbol_type, const char*, int, nk_flags alignment); -NK_API int nk_button_symbol_label_styled(struct nk_context *ctx, const struct nk_style_button *style, enum nk_symbol_type symbol, const char *title, nk_flags align); -NK_API int nk_button_image_label_styled(struct nk_context*,const struct nk_style_button*, struct nk_image img, const char*, nk_flags text_alignment); -NK_API int nk_button_image_text_styled(struct nk_context*,const struct nk_style_button*, struct nk_image img, const char*, int, nk_flags alignment); -NK_API void nk_button_set_behavior(struct nk_context*, enum nk_button_behavior); -NK_API int nk_button_push_behavior(struct nk_context*, enum nk_button_behavior); -NK_API int nk_button_pop_behavior(struct nk_context*); -/* ============================================================================= - * - * CHECKBOX - * - * ============================================================================= */ -NK_API int nk_check_label(struct nk_context*, const char*, int active); -NK_API int nk_check_text(struct nk_context*, const char*, int,int active); -NK_API unsigned nk_check_flags_label(struct nk_context*, const char*, unsigned int flags, unsigned int value); -NK_API unsigned nk_check_flags_text(struct nk_context*, const char*, int, unsigned int flags, unsigned int value); -NK_API int nk_checkbox_label(struct nk_context*, const char*, int *active); -NK_API int nk_checkbox_text(struct nk_context*, const char*, int, int *active); -NK_API int nk_checkbox_flags_label(struct nk_context*, const char*, unsigned int *flags, unsigned int value); -NK_API int nk_checkbox_flags_text(struct nk_context*, const char*, int, unsigned int *flags, unsigned int value); -/* ============================================================================= - * - * RADIO BUTTON - * - * ============================================================================= */ -NK_API int nk_radio_label(struct nk_context*, const char*, int *active); -NK_API int nk_radio_text(struct nk_context*, const char*, int, int *active); -NK_API int nk_option_label(struct nk_context*, const char*, int active); -NK_API int nk_option_text(struct nk_context*, const char*, int, int active); -/* ============================================================================= - * - * SELECTABLE - * - * ============================================================================= */ -NK_API int nk_selectable_label(struct nk_context*, const char*, nk_flags align, int *value); -NK_API int nk_selectable_text(struct nk_context*, const char*, int, nk_flags align, int *value); -NK_API int nk_selectable_image_label(struct nk_context*,struct nk_image, const char*, nk_flags align, int *value); -NK_API int nk_selectable_image_text(struct nk_context*,struct nk_image, const char*, int, nk_flags align, int *value); -NK_API int nk_select_label(struct nk_context*, const char*, nk_flags align, int value); -NK_API int nk_select_text(struct nk_context*, const char*, int, nk_flags align, int value); -NK_API int nk_select_image_label(struct nk_context*, struct nk_image,const char*, nk_flags align, int value); -NK_API int nk_select_image_text(struct nk_context*, struct nk_image,const char*, int, nk_flags align, int value); -/* ============================================================================= - * - * SLIDER - * - * ============================================================================= */ -NK_API float nk_slide_float(struct nk_context*, float min, float val, float max, float step); -NK_API int nk_slide_int(struct nk_context*, int min, int val, int max, int step); -NK_API int nk_slider_float(struct nk_context*, float min, float *val, float max, float step); -NK_API int nk_slider_int(struct nk_context*, int min, int *val, int max, int step); -/* ============================================================================= - * - * PROGRESSBAR - * - * ============================================================================= */ -NK_API int nk_progress(struct nk_context*, nk_size *cur, nk_size max, int modifyable); -NK_API nk_size nk_prog(struct nk_context*, nk_size cur, nk_size max, int modifyable); - -/* ============================================================================= - * - * COLOR PICKER - * - * ============================================================================= */ -NK_API struct nk_colorf nk_color_picker(struct nk_context*, struct nk_colorf, enum nk_color_format); -NK_API int nk_color_pick(struct nk_context*, struct nk_colorf*, enum nk_color_format); -/* ============================================================================= - * - * PROPERTIES - * - * ============================================================================= -/// ### Properties -/// Properties are the main value modification widgets in Nuklear. Changing a value -/// can be achieved by dragging, adding/removing incremental steps on button click -/// or by directly typing a number. -/// -/// #### Usage -/// Each property requires a unique name for identifaction that is also used for -/// displaying a label. If you want to use the same name multiple times make sure -/// add a '#' before your name. The '#' will not be shown but will generate a -/// unique ID. Each propery also takes in a minimum and maximum value. If you want -/// to make use of the complete number range of a type just use the provided -/// type limits from `limits.h`. For example `INT_MIN` and `INT_MAX` for -/// `nk_property_int` and `nk_propertyi`. In additional each property takes in -/// a increment value that will be added or subtracted if either the increment -/// decrement button is clicked. Finally there is a value for increment per pixel -/// dragged that is added or subtracted from the value. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int value = 0; -/// struct nk_context ctx; -/// nk_init_xxx(&ctx, ...); -/// while (1) { -/// // Input -/// Event evt; -/// nk_input_begin(&ctx); -/// while (GetEvent(&evt)) { -/// if (evt.type == MOUSE_MOVE) -/// nk_input_motion(&ctx, evt.motion.x, evt.motion.y); -/// else if (evt.type == [...]) { -/// nk_input_xxx(...); -/// } -/// } -/// nk_input_end(&ctx); -/// // -/// // Window -/// if (nk_begin_xxx(...) { -/// // Property -/// nk_layout_row_dynamic(...); -/// nk_property_int(ctx, "ID", INT_MIN, &value, INT_MAX, 1, 1); -/// } -/// nk_end(ctx); -/// // -/// // Draw -/// const struct nk_command *cmd = 0; -/// nk_foreach(cmd, &ctx) { -/// switch (cmd->type) { -/// case NK_COMMAND_LINE: -/// your_draw_line_function(...) -/// break; -/// case NK_COMMAND_RECT -/// your_draw_rect_function(...) -/// break; -/// case ...: -/// // [...] -/// } -// nk_clear(&ctx); -/// } -/// nk_free(&ctx); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// #### Reference -/// Function | Description -/// --------------------|------------------------------------------- -/// nk_property_int | Integer property directly modifing a passed in value -/// nk_property_float | Float property directly modifing a passed in value -/// nk_property_double | Double property directly modifing a passed in value -/// nk_propertyi | Integer property returning the modified int value -/// nk_propertyf | Float property returning the modified float value -/// nk_propertyd | Double property returning the modified double value -/// -*/ -/*/// #### nk_property_int -/// Integer property directly modifing a passed in value -/// !!! WARNING -/// To generate a unique property ID using the same label make sure to insert -/// a `#` at the beginning. It will not be shown but guarantees correct behavior. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_property_int(struct nk_context *ctx, const char *name, int min, int *val, int max, int step, float inc_per_pixel); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// --------------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after calling a layouting function -/// __name__ | String used both as a label as well as a unique identifier -/// __min__ | Minimum value not allowed to be underflown -/// __val__ | Integer pointer to be modified -/// __max__ | Maximum value not allowed to be overflown -/// __step__ | Increment added and subtracted on increment and decrement button -/// __inc_per_pixel__ | Value per pixel added or subtracted on dragging -*/ -NK_API void nk_property_int(struct nk_context*, const char *name, int min, int *val, int max, int step, float inc_per_pixel); -/*/// #### nk_property_float -/// Float property directly modifing a passed in value -/// !!! WARNING -/// To generate a unique property ID using the same label make sure to insert -/// a `#` at the beginning. It will not be shown but guarantees correct behavior. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_property_float(struct nk_context *ctx, const char *name, float min, float *val, float max, float step, float inc_per_pixel); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// --------------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after calling a layouting function -/// __name__ | String used both as a label as well as a unique identifier -/// __min__ | Minimum value not allowed to be underflown -/// __val__ | Float pointer to be modified -/// __max__ | Maximum value not allowed to be overflown -/// __step__ | Increment added and subtracted on increment and decrement button -/// __inc_per_pixel__ | Value per pixel added or subtracted on dragging -*/ -NK_API void nk_property_float(struct nk_context*, const char *name, float min, float *val, float max, float step, float inc_per_pixel); -/*/// #### nk_property_double -/// Double property directly modifing a passed in value -/// !!! WARNING -/// To generate a unique property ID using the same label make sure to insert -/// a `#` at the beginning. It will not be shown but guarantees correct behavior. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// void nk_property_double(struct nk_context *ctx, const char *name, double min, double *val, double max, double step, double inc_per_pixel); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// --------------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after calling a layouting function -/// __name__ | String used both as a label as well as a unique identifier -/// __min__ | Minimum value not allowed to be underflown -/// __val__ | Double pointer to be modified -/// __max__ | Maximum value not allowed to be overflown -/// __step__ | Increment added and subtracted on increment and decrement button -/// __inc_per_pixel__ | Value per pixel added or subtracted on dragging -*/ -NK_API void nk_property_double(struct nk_context*, const char *name, double min, double *val, double max, double step, float inc_per_pixel); -/*/// #### nk_propertyi -/// Integer property modifing a passed in value and returning the new value -/// !!! WARNING -/// To generate a unique property ID using the same label make sure to insert -/// a `#` at the beginning. It will not be shown but guarantees correct behavior. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// int nk_propertyi(struct nk_context *ctx, const char *name, int min, int val, int max, int step, float inc_per_pixel); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// --------------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after calling a layouting function -/// __name__ | String used both as a label as well as a unique identifier -/// __min__ | Minimum value not allowed to be underflown -/// __val__ | Current integer value to be modified and returned -/// __max__ | Maximum value not allowed to be overflown -/// __step__ | Increment added and subtracted on increment and decrement button -/// __inc_per_pixel__ | Value per pixel added or subtracted on dragging -/// -/// Returns the new modified integer value -*/ -NK_API int nk_propertyi(struct nk_context*, const char *name, int min, int val, int max, int step, float inc_per_pixel); -/*/// #### nk_propertyf -/// Float property modifing a passed in value and returning the new value -/// !!! WARNING -/// To generate a unique property ID using the same label make sure to insert -/// a `#` at the beginning. It will not be shown but guarantees correct behavior. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// float nk_propertyf(struct nk_context *ctx, const char *name, float min, float val, float max, float step, float inc_per_pixel); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// --------------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after calling a layouting function -/// __name__ | String used both as a label as well as a unique identifier -/// __min__ | Minimum value not allowed to be underflown -/// __val__ | Current float value to be modified and returned -/// __max__ | Maximum value not allowed to be overflown -/// __step__ | Increment added and subtracted on increment and decrement button -/// __inc_per_pixel__ | Value per pixel added or subtracted on dragging -/// -/// Returns the new modified float value -*/ -NK_API float nk_propertyf(struct nk_context*, const char *name, float min, float val, float max, float step, float inc_per_pixel); -/*/// #### nk_propertyd -/// Float property modifing a passed in value and returning the new value -/// !!! WARNING -/// To generate a unique property ID using the same label make sure to insert -/// a `#` at the beginning. It will not be shown but guarantees correct behavior. -/// -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c -/// float nk_propertyd(struct nk_context *ctx, const char *name, double min, double val, double max, double step, double inc_per_pixel); -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// Parameter | Description -/// --------------------|----------------------------------------------------------- -/// __ctx__ | Must point to an previously initialized `nk_context` struct after calling a layouting function -/// __name__ | String used both as a label as well as a unique identifier -/// __min__ | Minimum value not allowed to be underflown -/// __val__ | Current double value to be modified and returned -/// __max__ | Maximum value not allowed to be overflown -/// __step__ | Increment added and subtracted on increment and decrement button -/// __inc_per_pixel__ | Value per pixel added or subtracted on dragging -/// -/// Returns the new modified double value -*/ -NK_API double nk_propertyd(struct nk_context*, const char *name, double min, double val, double max, double step, float inc_per_pixel); -/* ============================================================================= - * - * TEXT EDIT - * - * ============================================================================= */ -enum nk_edit_flags { - NK_EDIT_DEFAULT = 0, - NK_EDIT_READ_ONLY = NK_FLAG(0), - NK_EDIT_AUTO_SELECT = NK_FLAG(1), - NK_EDIT_SIG_ENTER = NK_FLAG(2), - NK_EDIT_ALLOW_TAB = NK_FLAG(3), - NK_EDIT_NO_CURSOR = NK_FLAG(4), - NK_EDIT_SELECTABLE = NK_FLAG(5), - NK_EDIT_CLIPBOARD = NK_FLAG(6), - NK_EDIT_CTRL_ENTER_NEWLINE = NK_FLAG(7), - NK_EDIT_NO_HORIZONTAL_SCROLL = NK_FLAG(8), - NK_EDIT_ALWAYS_INSERT_MODE = NK_FLAG(9), - NK_EDIT_MULTILINE = NK_FLAG(10), - NK_EDIT_GOTO_END_ON_ACTIVATE = NK_FLAG(11) -}; -enum nk_edit_types { - NK_EDIT_SIMPLE = NK_EDIT_ALWAYS_INSERT_MODE, - NK_EDIT_FIELD = NK_EDIT_SIMPLE|NK_EDIT_SELECTABLE|NK_EDIT_CLIPBOARD, - NK_EDIT_BOX = NK_EDIT_ALWAYS_INSERT_MODE| NK_EDIT_SELECTABLE| NK_EDIT_MULTILINE|NK_EDIT_ALLOW_TAB|NK_EDIT_CLIPBOARD, - NK_EDIT_EDITOR = NK_EDIT_SELECTABLE|NK_EDIT_MULTILINE|NK_EDIT_ALLOW_TAB| NK_EDIT_CLIPBOARD -}; -enum nk_edit_events { - NK_EDIT_ACTIVE = NK_FLAG(0), /* edit widget is currently being modified */ - NK_EDIT_INACTIVE = NK_FLAG(1), /* edit widget is not active and is not being modified */ - NK_EDIT_ACTIVATED = NK_FLAG(2), /* edit widget went from state inactive to state active */ - NK_EDIT_DEACTIVATED = NK_FLAG(3), /* edit widget went from state active to state inactive */ - NK_EDIT_COMMITED = NK_FLAG(4) /* edit widget has received an enter and lost focus */ -}; -NK_API nk_flags nk_edit_string(struct nk_context*, nk_flags, char *buffer, int *len, int max, nk_plugin_filter); -NK_API nk_flags nk_edit_string_zero_terminated(struct nk_context*, nk_flags, char *buffer, int max, nk_plugin_filter); -NK_API nk_flags nk_edit_buffer(struct nk_context*, nk_flags, struct nk_text_edit*, nk_plugin_filter); -NK_API void nk_edit_focus(struct nk_context*, nk_flags flags); -NK_API void nk_edit_unfocus(struct nk_context*); -/* ============================================================================= - * - * CHART - * - * ============================================================================= */ -NK_API int nk_chart_begin(struct nk_context*, enum nk_chart_type, int num, float min, float max); -NK_API int nk_chart_begin_colored(struct nk_context*, enum nk_chart_type, struct nk_color, struct nk_color active, int num, float min, float max); -NK_API void nk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type, int count, float min_value, float max_value); -NK_API void nk_chart_add_slot_colored(struct nk_context *ctx, const enum nk_chart_type, struct nk_color, struct nk_color active, int count, float min_value, float max_value); -NK_API nk_flags nk_chart_push(struct nk_context*, float); -NK_API nk_flags nk_chart_push_slot(struct nk_context*, float, int); -NK_API void nk_chart_end(struct nk_context*); -NK_API void nk_plot(struct nk_context*, enum nk_chart_type, const float *values, int count, int offset); -NK_API void nk_plot_function(struct nk_context*, enum nk_chart_type, void *userdata, float(*value_getter)(void* user, int index), int count, int offset); -/* ============================================================================= - * - * POPUP - * - * ============================================================================= */ -NK_API int nk_popup_begin(struct nk_context*, enum nk_popup_type, const char*, nk_flags, struct nk_rect bounds); -NK_API void nk_popup_close(struct nk_context*); -NK_API void nk_popup_end(struct nk_context*); -/* ============================================================================= - * - * COMBOBOX - * - * ============================================================================= */ -NK_API int nk_combo(struct nk_context*, const char **items, int count, int selected, int item_height, struct nk_vec2 size); -NK_API int nk_combo_separator(struct nk_context*, const char *items_separated_by_separator, int separator, int selected, int count, int item_height, struct nk_vec2 size); -NK_API int nk_combo_string(struct nk_context*, const char *items_separated_by_zeros, int selected, int count, int item_height, struct nk_vec2 size); -NK_API int nk_combo_callback(struct nk_context*, void(*item_getter)(void*, int, const char**), void *userdata, int selected, int count, int item_height, struct nk_vec2 size); -NK_API void nk_combobox(struct nk_context*, const char **items, int count, int *selected, int item_height, struct nk_vec2 size); -NK_API void nk_combobox_string(struct nk_context*, const char *items_separated_by_zeros, int *selected, int count, int item_height, struct nk_vec2 size); -NK_API void nk_combobox_separator(struct nk_context*, const char *items_separated_by_separator, int separator,int *selected, int count, int item_height, struct nk_vec2 size); -NK_API void nk_combobox_callback(struct nk_context*, void(*item_getter)(void*, int, const char**), void*, int *selected, int count, int item_height, struct nk_vec2 size); -/* ============================================================================= - * - * ABSTRACT COMBOBOX - * - * ============================================================================= */ -NK_API int nk_combo_begin_text(struct nk_context*, const char *selected, int, struct nk_vec2 size); -NK_API int nk_combo_begin_label(struct nk_context*, const char *selected, struct nk_vec2 size); -NK_API int nk_combo_begin_color(struct nk_context*, struct nk_color color, struct nk_vec2 size); -NK_API int nk_combo_begin_symbol(struct nk_context*, enum nk_symbol_type, struct nk_vec2 size); -NK_API int nk_combo_begin_symbol_label(struct nk_context*, const char *selected, enum nk_symbol_type, struct nk_vec2 size); -NK_API int nk_combo_begin_symbol_text(struct nk_context*, const char *selected, int, enum nk_symbol_type, struct nk_vec2 size); -NK_API int nk_combo_begin_image(struct nk_context*, struct nk_image img, struct nk_vec2 size); -NK_API int nk_combo_begin_image_label(struct nk_context*, const char *selected, struct nk_image, struct nk_vec2 size); -NK_API int nk_combo_begin_image_text(struct nk_context*, const char *selected, int, struct nk_image, struct nk_vec2 size); -NK_API int nk_combo_item_label(struct nk_context*, const char*, nk_flags alignment); -NK_API int nk_combo_item_text(struct nk_context*, const char*,int, nk_flags alignment); -NK_API int nk_combo_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment); -NK_API int nk_combo_item_image_text(struct nk_context*, struct nk_image, const char*, int,nk_flags alignment); -NK_API int nk_combo_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment); -NK_API int nk_combo_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); -NK_API void nk_combo_close(struct nk_context*); -NK_API void nk_combo_end(struct nk_context*); -/* ============================================================================= - * - * CONTEXTUAL - * - * ============================================================================= */ -NK_API int nk_contextual_begin(struct nk_context*, nk_flags, struct nk_vec2, struct nk_rect trigger_bounds); -NK_API int nk_contextual_item_text(struct nk_context*, const char*, int,nk_flags align); -NK_API int nk_contextual_item_label(struct nk_context*, const char*, nk_flags align); -NK_API int nk_contextual_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment); -NK_API int nk_contextual_item_image_text(struct nk_context*, struct nk_image, const char*, int len, nk_flags alignment); -NK_API int nk_contextual_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment); -NK_API int nk_contextual_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); -NK_API void nk_contextual_close(struct nk_context*); -NK_API void nk_contextual_end(struct nk_context*); -/* ============================================================================= - * - * TOOLTIP - * - * ============================================================================= */ -NK_API void nk_tooltip(struct nk_context*, const char*); -#ifdef NK_INCLUDE_STANDARD_VARARGS -NK_API void nk_tooltipf(struct nk_context*, const char*, ...); -#endif -NK_API int nk_tooltip_begin(struct nk_context*, float width); -NK_API void nk_tooltip_end(struct nk_context*); -/* ============================================================================= - * - * MENU - * - * ============================================================================= */ -NK_API void nk_menubar_begin(struct nk_context*); -NK_API void nk_menubar_end(struct nk_context*); -NK_API int nk_menu_begin_text(struct nk_context*, const char* title, int title_len, nk_flags align, struct nk_vec2 size); -NK_API int nk_menu_begin_label(struct nk_context*, const char*, nk_flags align, struct nk_vec2 size); -NK_API int nk_menu_begin_image(struct nk_context*, const char*, struct nk_image, struct nk_vec2 size); -NK_API int nk_menu_begin_image_text(struct nk_context*, const char*, int,nk_flags align,struct nk_image, struct nk_vec2 size); -NK_API int nk_menu_begin_image_label(struct nk_context*, const char*, nk_flags align,struct nk_image, struct nk_vec2 size); -NK_API int nk_menu_begin_symbol(struct nk_context*, const char*, enum nk_symbol_type, struct nk_vec2 size); -NK_API int nk_menu_begin_symbol_text(struct nk_context*, const char*, int,nk_flags align,enum nk_symbol_type, struct nk_vec2 size); -NK_API int nk_menu_begin_symbol_label(struct nk_context*, const char*, nk_flags align,enum nk_symbol_type, struct nk_vec2 size); -NK_API int nk_menu_item_text(struct nk_context*, const char*, int,nk_flags align); -NK_API int nk_menu_item_label(struct nk_context*, const char*, nk_flags alignment); -NK_API int nk_menu_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment); -NK_API int nk_menu_item_image_text(struct nk_context*, struct nk_image, const char*, int len, nk_flags alignment); -NK_API int nk_menu_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment); -NK_API int nk_menu_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment); -NK_API void nk_menu_close(struct nk_context*); -NK_API void nk_menu_end(struct nk_context*); -/* ============================================================================= - * - * STYLE - * - * ============================================================================= */ -enum nk_style_colors { - NK_COLOR_TEXT, - NK_COLOR_WINDOW, - NK_COLOR_HEADER, - NK_COLOR_BORDER, - NK_COLOR_BUTTON, - NK_COLOR_BUTTON_HOVER, - NK_COLOR_BUTTON_ACTIVE, - NK_COLOR_TOGGLE, - NK_COLOR_TOGGLE_HOVER, - NK_COLOR_TOGGLE_CURSOR, - NK_COLOR_SELECT, - NK_COLOR_SELECT_ACTIVE, - NK_COLOR_SLIDER, - NK_COLOR_SLIDER_CURSOR, - NK_COLOR_SLIDER_CURSOR_HOVER, - NK_COLOR_SLIDER_CURSOR_ACTIVE, - NK_COLOR_PROPERTY, - NK_COLOR_EDIT, - NK_COLOR_EDIT_CURSOR, - NK_COLOR_COMBO, - NK_COLOR_CHART, - NK_COLOR_CHART_COLOR, - NK_COLOR_CHART_COLOR_HIGHLIGHT, - NK_COLOR_SCROLLBAR, - NK_COLOR_SCROLLBAR_CURSOR, - NK_COLOR_SCROLLBAR_CURSOR_HOVER, - NK_COLOR_SCROLLBAR_CURSOR_ACTIVE, - NK_COLOR_TAB_HEADER, - NK_COLOR_COUNT -}; -enum nk_style_cursor { - NK_CURSOR_ARROW, - NK_CURSOR_TEXT, - NK_CURSOR_MOVE, - NK_CURSOR_RESIZE_VERTICAL, - NK_CURSOR_RESIZE_HORIZONTAL, - NK_CURSOR_RESIZE_TOP_LEFT_DOWN_RIGHT, - NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT, - NK_CURSOR_COUNT -}; -NK_API void nk_style_default(struct nk_context*); -NK_API void nk_style_from_table(struct nk_context*, const struct nk_color*); -NK_API void nk_style_load_cursor(struct nk_context*, enum nk_style_cursor, const struct nk_cursor*); -NK_API void nk_style_load_all_cursors(struct nk_context*, struct nk_cursor*); -NK_API const char* nk_style_get_color_by_name(enum nk_style_colors); -NK_API void nk_style_set_font(struct nk_context*, const struct nk_user_font*); -NK_API int nk_style_set_cursor(struct nk_context*, enum nk_style_cursor); -NK_API void nk_style_show_cursor(struct nk_context*); -NK_API void nk_style_hide_cursor(struct nk_context*); - -NK_API int nk_style_push_font(struct nk_context*, const struct nk_user_font*); -NK_API int nk_style_push_float(struct nk_context*, float*, float); -NK_API int nk_style_push_vec2(struct nk_context*, struct nk_vec2*, struct nk_vec2); -NK_API int nk_style_push_style_item(struct nk_context*, struct nk_style_item*, struct nk_style_item); -NK_API int nk_style_push_flags(struct nk_context*, nk_flags*, nk_flags); -NK_API int nk_style_push_color(struct nk_context*, struct nk_color*, struct nk_color); - -NK_API int nk_style_pop_font(struct nk_context*); -NK_API int nk_style_pop_float(struct nk_context*); -NK_API int nk_style_pop_vec2(struct nk_context*); -NK_API int nk_style_pop_style_item(struct nk_context*); -NK_API int nk_style_pop_flags(struct nk_context*); -NK_API int nk_style_pop_color(struct nk_context*); -/* ============================================================================= - * - * COLOR - * - * ============================================================================= */ -NK_API struct nk_color nk_rgb(int r, int g, int b); -NK_API struct nk_color nk_rgb_iv(const int *rgb); -NK_API struct nk_color nk_rgb_bv(const nk_byte* rgb); -NK_API struct nk_color nk_rgb_f(float r, float g, float b); -NK_API struct nk_color nk_rgb_fv(const float *rgb); -NK_API struct nk_color nk_rgb_cf(struct nk_colorf c); -NK_API struct nk_color nk_rgb_hex(const char *rgb); - -NK_API struct nk_color nk_rgba(int r, int g, int b, int a); -NK_API struct nk_color nk_rgba_u32(nk_uint); -NK_API struct nk_color nk_rgba_iv(const int *rgba); -NK_API struct nk_color nk_rgba_bv(const nk_byte *rgba); -NK_API struct nk_color nk_rgba_f(float r, float g, float b, float a); -NK_API struct nk_color nk_rgba_fv(const float *rgba); -NK_API struct nk_color nk_rgba_cf(struct nk_colorf c); -NK_API struct nk_color nk_rgba_hex(const char *rgb); - -NK_API struct nk_colorf nk_hsva_colorf(float h, float s, float v, float a); -NK_API struct nk_colorf nk_hsva_colorfv(float *c); -NK_API void nk_colorf_hsva_f(float *out_h, float *out_s, float *out_v, float *out_a, struct nk_colorf in); -NK_API void nk_colorf_hsva_fv(float *hsva, struct nk_colorf in); - -NK_API struct nk_color nk_hsv(int h, int s, int v); -NK_API struct nk_color nk_hsv_iv(const int *hsv); -NK_API struct nk_color nk_hsv_bv(const nk_byte *hsv); -NK_API struct nk_color nk_hsv_f(float h, float s, float v); -NK_API struct nk_color nk_hsv_fv(const float *hsv); - -NK_API struct nk_color nk_hsva(int h, int s, int v, int a); -NK_API struct nk_color nk_hsva_iv(const int *hsva); -NK_API struct nk_color nk_hsva_bv(const nk_byte *hsva); -NK_API struct nk_color nk_hsva_f(float h, float s, float v, float a); -NK_API struct nk_color nk_hsva_fv(const float *hsva); - -/* color (conversion nuklear --> user) */ -NK_API void nk_color_f(float *r, float *g, float *b, float *a, struct nk_color); -NK_API void nk_color_fv(float *rgba_out, struct nk_color); -NK_API struct nk_colorf nk_color_cf(struct nk_color); -NK_API void nk_color_d(double *r, double *g, double *b, double *a, struct nk_color); -NK_API void nk_color_dv(double *rgba_out, struct nk_color); - -NK_API nk_uint nk_color_u32(struct nk_color); -NK_API void nk_color_hex_rgba(char *output, struct nk_color); -NK_API void nk_color_hex_rgb(char *output, struct nk_color); - -NK_API void nk_color_hsv_i(int *out_h, int *out_s, int *out_v, struct nk_color); -NK_API void nk_color_hsv_b(nk_byte *out_h, nk_byte *out_s, nk_byte *out_v, struct nk_color); -NK_API void nk_color_hsv_iv(int *hsv_out, struct nk_color); -NK_API void nk_color_hsv_bv(nk_byte *hsv_out, struct nk_color); -NK_API void nk_color_hsv_f(float *out_h, float *out_s, float *out_v, struct nk_color); -NK_API void nk_color_hsv_fv(float *hsv_out, struct nk_color); - -NK_API void nk_color_hsva_i(int *h, int *s, int *v, int *a, struct nk_color); -NK_API void nk_color_hsva_b(nk_byte *h, nk_byte *s, nk_byte *v, nk_byte *a, struct nk_color); -NK_API void nk_color_hsva_iv(int *hsva_out, struct nk_color); -NK_API void nk_color_hsva_bv(nk_byte *hsva_out, struct nk_color); -NK_API void nk_color_hsva_f(float *out_h, float *out_s, float *out_v, float *out_a, struct nk_color); -NK_API void nk_color_hsva_fv(float *hsva_out, struct nk_color); -/* ============================================================================= - * - * IMAGE - * - * ============================================================================= */ -NK_API nk_handle nk_handle_ptr(void*); -NK_API nk_handle nk_handle_id(int); -NK_API struct nk_image nk_image_handle(nk_handle); -NK_API struct nk_image nk_image_ptr(void*); -NK_API struct nk_image nk_image_id(int); -NK_API int nk_image_is_subimage(const struct nk_image* img); -NK_API struct nk_image nk_subimage_ptr(void*, unsigned short w, unsigned short h, struct nk_rect sub_region); -NK_API struct nk_image nk_subimage_id(int, unsigned short w, unsigned short h, struct nk_rect sub_region); -NK_API struct nk_image nk_subimage_handle(nk_handle, unsigned short w, unsigned short h, struct nk_rect sub_region); -/* ============================================================================= - * - * MATH - * - * ============================================================================= */ -NK_API nk_hash nk_murmur_hash(const void *key, int len, nk_hash seed); -NK_API void nk_triangle_from_direction(struct nk_vec2 *result, struct nk_rect r, float pad_x, float pad_y, enum nk_heading); - -NK_API struct nk_vec2 nk_vec2(float x, float y); -NK_API struct nk_vec2 nk_vec2i(int x, int y); -NK_API struct nk_vec2 nk_vec2v(const float *xy); -NK_API struct nk_vec2 nk_vec2iv(const int *xy); - -NK_API struct nk_rect nk_get_null_rect(void); -NK_API struct nk_rect nk_rect(float x, float y, float w, float h); -NK_API struct nk_rect nk_recti(int x, int y, int w, int h); -NK_API struct nk_rect nk_recta(struct nk_vec2 pos, struct nk_vec2 size); -NK_API struct nk_rect nk_rectv(const float *xywh); -NK_API struct nk_rect nk_rectiv(const int *xywh); -NK_API struct nk_vec2 nk_rect_pos(struct nk_rect); -NK_API struct nk_vec2 nk_rect_size(struct nk_rect); -/* ============================================================================= - * - * STRING - * - * ============================================================================= */ -NK_API int nk_strlen(const char *str); -NK_API int nk_stricmp(const char *s1, const char *s2); -NK_API int nk_stricmpn(const char *s1, const char *s2, int n); -NK_API int nk_strtoi(const char *str, const char **endptr); -NK_API float nk_strtof(const char *str, const char **endptr); -NK_API double nk_strtod(const char *str, const char **endptr); -NK_API int nk_strfilter(const char *text, const char *regexp); -NK_API int nk_strmatch_fuzzy_string(char const *str, char const *pattern, int *out_score); -NK_API int nk_strmatch_fuzzy_text(const char *txt, int txt_len, const char *pattern, int *out_score); -/* ============================================================================= - * - * UTF-8 - * - * ============================================================================= */ -NK_API int nk_utf_decode(const char*, nk_rune*, int); -NK_API int nk_utf_encode(nk_rune, char*, int); -NK_API int nk_utf_len(const char*, int byte_len); -NK_API const char* nk_utf_at(const char *buffer, int length, int index, nk_rune *unicode, int *len); -/* =============================================================== - * - * FONT - * - * ===============================================================*/ -/* Font handling in this library was designed to be quite customizable and lets - you decide what you want to use and what you want to provide. There are three - different ways to use the font atlas. The first two will use your font - handling scheme and only requires essential data to run nuklear. The next - slightly more advanced features is font handling with vertex buffer output. - Finally the most complex API wise is using nuklear's font baking API. - - 1.) Using your own implementation without vertex buffer output - -------------------------------------------------------------- - So first up the easiest way to do font handling is by just providing a - `nk_user_font` struct which only requires the height in pixel of the used - font and a callback to calculate the width of a string. This way of handling - fonts is best fitted for using the normal draw shape command API where you - do all the text drawing yourself and the library does not require any kind - of deeper knowledge about which font handling mechanism you use. - IMPORTANT: the `nk_user_font` pointer provided to nuklear has to persist - over the complete life time! I know this sucks but it is currently the only - way to switch between fonts. - - float your_text_width_calculation(nk_handle handle, float height, const char *text, int len) - { - your_font_type *type = handle.ptr; - float text_width = ...; - return text_width; - } - - struct nk_user_font font; - font.userdata.ptr = &your_font_class_or_struct; - font.height = your_font_height; - font.width = your_text_width_calculation; - - struct nk_context ctx; - nk_init_default(&ctx, &font); - - 2.) Using your own implementation with vertex buffer output - -------------------------------------------------------------- - While the first approach works fine if you don't want to use the optional - vertex buffer output it is not enough if you do. To get font handling working - for these cases you have to provide two additional parameters inside the - `nk_user_font`. First a texture atlas handle used to draw text as subimages - of a bigger font atlas texture and a callback to query a character's glyph - information (offset, size, ...). So it is still possible to provide your own - font and use the vertex buffer output. - - float your_text_width_calculation(nk_handle handle, float height, const char *text, int len) - { - your_font_type *type = handle.ptr; - float text_width = ...; - return text_width; - } - void query_your_font_glyph(nk_handle handle, float font_height, struct nk_user_font_glyph *glyph, nk_rune codepoint, nk_rune next_codepoint) - { - your_font_type *type = handle.ptr; - glyph.width = ...; - glyph.height = ...; - glyph.xadvance = ...; - glyph.uv[0].x = ...; - glyph.uv[0].y = ...; - glyph.uv[1].x = ...; - glyph.uv[1].y = ...; - glyph.offset.x = ...; - glyph.offset.y = ...; - } - - struct nk_user_font font; - font.userdata.ptr = &your_font_class_or_struct; - font.height = your_font_height; - font.width = your_text_width_calculation; - font.query = query_your_font_glyph; - font.texture.id = your_font_texture; - - struct nk_context ctx; - nk_init_default(&ctx, &font); - - 3.) Nuklear font baker - ------------------------------------ - The final approach if you do not have a font handling functionality or don't - want to use it in this library is by using the optional font baker. - The font baker APIs can be used to create a font plus font atlas texture - and can be used with or without the vertex buffer output. - - It still uses the `nk_user_font` struct and the two different approaches - previously stated still work. The font baker is not located inside - `nk_context` like all other systems since it can be understood as more of - an extension to nuklear and does not really depend on any `nk_context` state. - - Font baker need to be initialized first by one of the nk_font_atlas_init_xxx - functions. If you don't care about memory just call the default version - `nk_font_atlas_init_default` which will allocate all memory from the standard library. - If you want to control memory allocation but you don't care if the allocated - memory is temporary and therefore can be freed directly after the baking process - is over or permanent you can call `nk_font_atlas_init`. - - After successfully initializing the font baker you can add Truetype(.ttf) fonts from - different sources like memory or from file by calling one of the `nk_font_atlas_add_xxx`. - functions. Adding font will permanently store each font, font config and ttf memory block(!) - inside the font atlas and allows to reuse the font atlas. If you don't want to reuse - the font baker by for example adding additional fonts you can call - `nk_font_atlas_cleanup` after the baking process is over (after calling nk_font_atlas_end). - - As soon as you added all fonts you wanted you can now start the baking process - for every selected glyph to image by calling `nk_font_atlas_bake`. - The baking process returns image memory, width and height which can be used to - either create your own image object or upload it to any graphics library. - No matter which case you finally have to call `nk_font_atlas_end` which - will free all temporary memory including the font atlas image so make sure - you created our texture beforehand. `nk_font_atlas_end` requires a handle - to your font texture or object and optionally fills a `struct nk_draw_null_texture` - which can be used for the optional vertex output. If you don't want it just - set the argument to `NULL`. - - At this point you are done and if you don't want to reuse the font atlas you - can call `nk_font_atlas_cleanup` to free all truetype blobs and configuration - memory. Finally if you don't use the font atlas and any of it's fonts anymore - you need to call `nk_font_atlas_clear` to free all memory still being used. - - struct nk_font_atlas atlas; - nk_font_atlas_init_default(&atlas); - nk_font_atlas_begin(&atlas); - nk_font *font = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font.ttf", 13, 0); - nk_font *font2 = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font2.ttf", 16, 0); - const void* img = nk_font_atlas_bake(&atlas, &img_width, &img_height, NK_FONT_ATLAS_RGBA32); - nk_font_atlas_end(&atlas, nk_handle_id(texture), 0); - - struct nk_context ctx; - nk_init_default(&ctx, &font->handle); - while (1) { - - } - nk_font_atlas_clear(&atlas); - - The font baker API is probably the most complex API inside this library and - I would suggest reading some of my examples `example/` to get a grip on how - to use the font atlas. There are a number of details I left out. For example - how to merge fonts, configure a font with `nk_font_config` to use other languages, - use another texture coordinate format and a lot more: - - struct nk_font_config cfg = nk_font_config(font_pixel_height); - cfg.merge_mode = nk_false or nk_true; - cfg.range = nk_font_korean_glyph_ranges(); - cfg.coord_type = NK_COORD_PIXEL; - nk_font *font = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font.ttf", 13, &cfg); - -*/ -struct nk_user_font_glyph; -typedef float(*nk_text_width_f)(nk_handle, float h, const char*, int len); -typedef void(*nk_query_font_glyph_f)(nk_handle handle, float font_height, - struct nk_user_font_glyph *glyph, - nk_rune codepoint, nk_rune next_codepoint); - -#if defined(NK_INCLUDE_VERTEX_BUFFER_OUTPUT) || defined(NK_INCLUDE_SOFTWARE_FONT) -struct nk_user_font_glyph { - struct nk_vec2 uv[2]; - /* texture coordinates */ - struct nk_vec2 offset; - /* offset between top left and glyph */ - float width, height; - /* size of the glyph */ - float xadvance; - /* offset to the next glyph */ -}; -#endif - -struct nk_user_font { - nk_handle userdata; - /* user provided font handle */ - float height; - /* max height of the font */ - nk_text_width_f width; - /* font string width in pixel callback */ -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT - nk_query_font_glyph_f query; - /* font glyph callback to query drawing info */ - nk_handle texture; - /* texture handle to the used font atlas or texture */ -#endif -}; - -#ifdef NK_INCLUDE_FONT_BAKING -enum nk_font_coord_type { - NK_COORD_UV, /* texture coordinates inside font glyphs are clamped between 0-1 */ - NK_COORD_PIXEL /* texture coordinates inside font glyphs are in absolute pixel */ -}; - -struct nk_font; -struct nk_baked_font { - float height; - /* height of the font */ - float ascent, descent; - /* font glyphs ascent and descent */ - nk_rune glyph_offset; - /* glyph array offset inside the font glyph baking output array */ - nk_rune glyph_count; - /* number of glyphs of this font inside the glyph baking array output */ - const nk_rune *ranges; - /* font codepoint ranges as pairs of (from/to) and 0 as last element */ -}; - -struct nk_font_config { - struct nk_font_config *next; - /* NOTE: only used internally */ - void *ttf_blob; - /* pointer to loaded TTF file memory block. - * NOTE: not needed for nk_font_atlas_add_from_memory and nk_font_atlas_add_from_file. */ - nk_size ttf_size; - /* size of the loaded TTF file memory block - * NOTE: not needed for nk_font_atlas_add_from_memory and nk_font_atlas_add_from_file. */ - - unsigned char ttf_data_owned_by_atlas; - /* used inside font atlas: default to: 0*/ - unsigned char merge_mode; - /* merges this font into the last font */ - unsigned char pixel_snap; - /* align every character to pixel boundary (if true set oversample (1,1)) */ - unsigned char oversample_v, oversample_h; - /* rasterize at hight quality for sub-pixel position */ - unsigned char padding[3]; - - float size; - /* baked pixel height of the font */ - enum nk_font_coord_type coord_type; - /* texture coordinate format with either pixel or UV coordinates */ - struct nk_vec2 spacing; - /* extra pixel spacing between glyphs */ - const nk_rune *range; - /* list of unicode ranges (2 values per range, zero terminated) */ - struct nk_baked_font *font; - /* font to setup in the baking process: NOTE: not needed for font atlas */ - nk_rune fallback_glyph; - /* fallback glyph to use if a given rune is not found */ - struct nk_font_config *n; - struct nk_font_config *p; -}; - -struct nk_font_glyph { - nk_rune codepoint; - float xadvance; - float x0, y0, x1, y1, w, h; - float u0, v0, u1, v1; -}; - -struct nk_font { - struct nk_font *next; - struct nk_user_font handle; - struct nk_baked_font info; - float scale; - struct nk_font_glyph *glyphs; - const struct nk_font_glyph *fallback; - nk_rune fallback_codepoint; - nk_handle texture; - struct nk_font_config *config; -}; - -enum nk_font_atlas_format { - NK_FONT_ATLAS_ALPHA8, - NK_FONT_ATLAS_RGBA32 -}; - -struct nk_font_atlas { - void *pixel; - int tex_width; - int tex_height; - - struct nk_allocator permanent; - struct nk_allocator temporary; - - struct nk_recti custom; - struct nk_cursor cursors[NK_CURSOR_COUNT]; - - int glyph_count; - struct nk_font_glyph *glyphs; - struct nk_font *default_font; - struct nk_font *fonts; - struct nk_font_config *config; - int font_num; -}; - -/* some language glyph codepoint ranges */ -NK_API const nk_rune *nk_font_default_glyph_ranges(void); -NK_API const nk_rune *nk_font_chinese_glyph_ranges(void); -NK_API const nk_rune *nk_font_cyrillic_glyph_ranges(void); -NK_API const nk_rune *nk_font_korean_glyph_ranges(void); - -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API void nk_font_atlas_init_default(struct nk_font_atlas*); -#endif -NK_API void nk_font_atlas_init(struct nk_font_atlas*, struct nk_allocator*); -NK_API void nk_font_atlas_init_custom(struct nk_font_atlas*, struct nk_allocator *persistent, struct nk_allocator *transient); -NK_API void nk_font_atlas_begin(struct nk_font_atlas*); -NK_API struct nk_font_config nk_font_config(float pixel_height); -NK_API struct nk_font *nk_font_atlas_add(struct nk_font_atlas*, const struct nk_font_config*); -#ifdef NK_INCLUDE_DEFAULT_FONT -NK_API struct nk_font* nk_font_atlas_add_default(struct nk_font_atlas*, float height, const struct nk_font_config*); -#endif -NK_API struct nk_font* nk_font_atlas_add_from_memory(struct nk_font_atlas *atlas, void *memory, nk_size size, float height, const struct nk_font_config *config); -#ifdef NK_INCLUDE_STANDARD_IO -NK_API struct nk_font* nk_font_atlas_add_from_file(struct nk_font_atlas *atlas, const char *file_path, float height, const struct nk_font_config*); -#endif -NK_API struct nk_font *nk_font_atlas_add_compressed(struct nk_font_atlas*, void *memory, nk_size size, float height, const struct nk_font_config*); -NK_API struct nk_font* nk_font_atlas_add_compressed_base85(struct nk_font_atlas*, const char *data, float height, const struct nk_font_config *config); -NK_API const void* nk_font_atlas_bake(struct nk_font_atlas*, int *width, int *height, enum nk_font_atlas_format); -NK_API void nk_font_atlas_end(struct nk_font_atlas*, nk_handle tex, struct nk_draw_null_texture*); -NK_API const struct nk_font_glyph* nk_font_find_glyph(struct nk_font*, nk_rune unicode); -NK_API void nk_font_atlas_cleanup(struct nk_font_atlas *atlas); -NK_API void nk_font_atlas_clear(struct nk_font_atlas*); - -#endif - -/* ============================================================== - * - * MEMORY BUFFER - * - * ===============================================================*/ -/* A basic (double)-buffer with linear allocation and resetting as only - freeing policy. The buffer's main purpose is to control all memory management - inside the GUI toolkit and still leave memory control as much as possible in - the hand of the user while also making sure the library is easy to use if - not as much control is needed. - In general all memory inside this library can be provided from the user in - three different ways. - - The first way and the one providing most control is by just passing a fixed - size memory block. In this case all control lies in the hand of the user - since he can exactly control where the memory comes from and how much memory - the library should consume. Of course using the fixed size API removes the - ability to automatically resize a buffer if not enough memory is provided so - you have to take over the resizing. While being a fixed sized buffer sounds - quite limiting, it is very effective in this library since the actual memory - consumption is quite stable and has a fixed upper bound for a lot of cases. - - If you don't want to think about how much memory the library should allocate - at all time or have a very dynamic UI with unpredictable memory consumption - habits but still want control over memory allocation you can use the dynamic - allocator based API. The allocator consists of two callbacks for allocating - and freeing memory and optional userdata so you can plugin your own allocator. - - The final and easiest way can be used by defining - NK_INCLUDE_DEFAULT_ALLOCATOR which uses the standard library memory - allocation functions malloc and free and takes over complete control over - memory in this library. -*/ -struct nk_memory_status { - void *memory; - unsigned int type; - nk_size size; - nk_size allocated; - nk_size needed; - nk_size calls; -}; - -enum nk_allocation_type { - NK_BUFFER_FIXED, - NK_BUFFER_DYNAMIC -}; - -enum nk_buffer_allocation_type { - NK_BUFFER_FRONT, - NK_BUFFER_BACK, - NK_BUFFER_MAX -}; - -struct nk_buffer_marker { - int active; - nk_size offset; -}; - -struct nk_memory {void *ptr;nk_size size;}; -struct nk_buffer { - struct nk_buffer_marker marker[NK_BUFFER_MAX]; - /* buffer marker to free a buffer to a certain offset */ - struct nk_allocator pool; - /* allocator callback for dynamic buffers */ - enum nk_allocation_type type; - /* memory management type */ - struct nk_memory memory; - /* memory and size of the current memory block */ - float grow_factor; - /* growing factor for dynamic memory management */ - nk_size allocated; - /* total amount of memory allocated */ - nk_size needed; - /* totally consumed memory given that enough memory is present */ - nk_size calls; - /* number of allocation calls */ - nk_size size; - /* current size of the buffer */ -}; - -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API void nk_buffer_init_default(struct nk_buffer*); -#endif -NK_API void nk_buffer_init(struct nk_buffer*, const struct nk_allocator*, nk_size size); -NK_API void nk_buffer_init_fixed(struct nk_buffer*, void *memory, nk_size size); -NK_API void nk_buffer_info(struct nk_memory_status*, struct nk_buffer*); -NK_API void nk_buffer_push(struct nk_buffer*, enum nk_buffer_allocation_type type, const void *memory, nk_size size, nk_size align); -NK_API void nk_buffer_mark(struct nk_buffer*, enum nk_buffer_allocation_type type); -NK_API void nk_buffer_reset(struct nk_buffer*, enum nk_buffer_allocation_type type); -NK_API void nk_buffer_clear(struct nk_buffer*); -NK_API void nk_buffer_free(struct nk_buffer*); -NK_API void *nk_buffer_memory(struct nk_buffer*); -NK_API const void *nk_buffer_memory_const(const struct nk_buffer*); -NK_API nk_size nk_buffer_total(struct nk_buffer*); - -/* ============================================================== - * - * STRING - * - * ===============================================================*/ -/* Basic string buffer which is only used in context with the text editor - * to manage and manipulate dynamic or fixed size string content. This is _NOT_ - * the default string handling method. The only instance you should have any contact - * with this API is if you interact with an `nk_text_edit` object inside one of the - * copy and paste functions and even there only for more advanced cases. */ -struct nk_str { - struct nk_buffer buffer; - int len; /* in codepoints/runes/glyphs */ -}; - -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API void nk_str_init_default(struct nk_str*); -#endif -NK_API void nk_str_init(struct nk_str*, const struct nk_allocator*, nk_size size); -NK_API void nk_str_init_fixed(struct nk_str*, void *memory, nk_size size); -NK_API void nk_str_clear(struct nk_str*); -NK_API void nk_str_free(struct nk_str*); - -NK_API int nk_str_append_text_char(struct nk_str*, const char*, int); -NK_API int nk_str_append_str_char(struct nk_str*, const char*); -NK_API int nk_str_append_text_utf8(struct nk_str*, const char*, int); -NK_API int nk_str_append_str_utf8(struct nk_str*, const char*); -NK_API int nk_str_append_text_runes(struct nk_str*, const nk_rune*, int); -NK_API int nk_str_append_str_runes(struct nk_str*, const nk_rune*); - -NK_API int nk_str_insert_at_char(struct nk_str*, int pos, const char*, int); -NK_API int nk_str_insert_at_rune(struct nk_str*, int pos, const char*, int); - -NK_API int nk_str_insert_text_char(struct nk_str*, int pos, const char*, int); -NK_API int nk_str_insert_str_char(struct nk_str*, int pos, const char*); -NK_API int nk_str_insert_text_utf8(struct nk_str*, int pos, const char*, int); -NK_API int nk_str_insert_str_utf8(struct nk_str*, int pos, const char*); -NK_API int nk_str_insert_text_runes(struct nk_str*, int pos, const nk_rune*, int); -NK_API int nk_str_insert_str_runes(struct nk_str*, int pos, const nk_rune*); - -NK_API void nk_str_remove_chars(struct nk_str*, int len); -NK_API void nk_str_remove_runes(struct nk_str *str, int len); -NK_API void nk_str_delete_chars(struct nk_str*, int pos, int len); -NK_API void nk_str_delete_runes(struct nk_str*, int pos, int len); - -NK_API char *nk_str_at_char(struct nk_str*, int pos); -NK_API char *nk_str_at_rune(struct nk_str*, int pos, nk_rune *unicode, int *len); -NK_API nk_rune nk_str_rune_at(const struct nk_str*, int pos); -NK_API const char *nk_str_at_char_const(const struct nk_str*, int pos); -NK_API const char *nk_str_at_const(const struct nk_str*, int pos, nk_rune *unicode, int *len); - -NK_API char *nk_str_get(struct nk_str*); -NK_API const char *nk_str_get_const(const struct nk_str*); -NK_API int nk_str_len(struct nk_str*); -NK_API int nk_str_len_char(struct nk_str*); - -/*=============================================================== - * - * TEXT EDITOR - * - * ===============================================================*/ -/* Editing text in this library is handled by either `nk_edit_string` or - * `nk_edit_buffer`. But like almost everything in this library there are multiple - * ways of doing it and a balance between control and ease of use with memory - * as well as functionality controlled by flags. - * - * This library generally allows three different levels of memory control: - * First of is the most basic way of just providing a simple char array with - * string length. This method is probably the easiest way of handling simple - * user text input. Main upside is complete control over memory while the biggest - * downside in comparison with the other two approaches is missing undo/redo. - * - * For UIs that require undo/redo the second way was created. It is based on - * a fixed size nk_text_edit struct, which has an internal undo/redo stack. - * This is mainly useful if you want something more like a text editor but don't want - * to have a dynamically growing buffer. - * - * The final way is using a dynamically growing nk_text_edit struct, which - * has both a default version if you don't care where memory comes from and an - * allocator version if you do. While the text editor is quite powerful for its - * complexity I would not recommend editing gigabytes of data with it. - * It is rather designed for uses cases which make sense for a GUI library not for - * an full blown text editor. - */ -#ifndef NK_TEXTEDIT_UNDOSTATECOUNT -#define NK_TEXTEDIT_UNDOSTATECOUNT 99 -#endif - -#ifndef NK_TEXTEDIT_UNDOCHARCOUNT -#define NK_TEXTEDIT_UNDOCHARCOUNT 999 -#endif - -struct nk_text_edit; -struct nk_clipboard { - nk_handle userdata; - nk_plugin_paste paste; - nk_plugin_copy copy; -}; - -struct nk_text_undo_record { - int where; - short insert_length; - short delete_length; - short char_storage; -}; - -struct nk_text_undo_state { - struct nk_text_undo_record undo_rec[NK_TEXTEDIT_UNDOSTATECOUNT]; - nk_rune undo_char[NK_TEXTEDIT_UNDOCHARCOUNT]; - short undo_point; - short redo_point; - short undo_char_point; - short redo_char_point; -}; - -enum nk_text_edit_type { - NK_TEXT_EDIT_SINGLE_LINE, - NK_TEXT_EDIT_MULTI_LINE -}; - -enum nk_text_edit_mode { - NK_TEXT_EDIT_MODE_VIEW, - NK_TEXT_EDIT_MODE_INSERT, - NK_TEXT_EDIT_MODE_REPLACE -}; - -struct nk_token { - struct nk_color color; - int offset; -}; - -struct nk_lexer { - struct nk_token *tokens; - struct nk_token *(*lex)(void *data, const char *buf, int size); - void *data; - int needs_refresh; -}; - -struct nk_text_edit { - struct nk_clipboard clip; - struct nk_str string; - nk_plugin_filter filter; - struct nk_vec2 scrollbar; - - int cursor; - int select_start; - int select_end; - unsigned char mode; - unsigned char cursor_at_end_of_line; - unsigned char initialized; - unsigned char has_preferred_x; - unsigned char single_line; - unsigned char active; - unsigned char padding1; - float preferred_x; - struct nk_text_undo_state undo; - struct nk_lexer lexer; -}; - -/* filter function */ -NK_API int nk_filter_default(const struct nk_text_edit*, nk_rune unicode); -NK_API int nk_filter_ascii(const struct nk_text_edit*, nk_rune unicode); -NK_API int nk_filter_float(const struct nk_text_edit*, nk_rune unicode); -NK_API int nk_filter_decimal(const struct nk_text_edit*, nk_rune unicode); -NK_API int nk_filter_hex(const struct nk_text_edit*, nk_rune unicode); -NK_API int nk_filter_oct(const struct nk_text_edit*, nk_rune unicode); -NK_API int nk_filter_binary(const struct nk_text_edit*, nk_rune unicode); - -/* text editor */ -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API void nk_textedit_init_default(struct nk_text_edit*); -#endif -NK_API void nk_textedit_init(struct nk_text_edit*, struct nk_allocator*, nk_size size); -NK_API void nk_textedit_init_fixed(struct nk_text_edit*, void *memory, nk_size size); -NK_API void nk_textedit_free(struct nk_text_edit*); -NK_API void nk_textedit_text(struct nk_text_edit*, const char*, int total_len); -NK_API void nk_textedit_delete(struct nk_text_edit*, int where, int len); -NK_API void nk_textedit_delete_selection(struct nk_text_edit*); -NK_API void nk_textedit_select_all(struct nk_text_edit*); -NK_API int nk_textedit_cut(struct nk_text_edit*); -NK_API int nk_textedit_paste(struct nk_text_edit*, char const*, int len); -NK_API void nk_textedit_undo(struct nk_text_edit*); -NK_API void nk_textedit_redo(struct nk_text_edit*); - -/* =============================================================== - * - * DRAWING - * - * ===============================================================*/ -/* This library was designed to be render backend agnostic so it does - not draw anything to screen. Instead all drawn shapes, widgets - are made of, are buffered into memory and make up a command queue. - Each frame therefore fills the command buffer with draw commands - that then need to be executed by the user and his own render backend. - After that the command buffer needs to be cleared and a new frame can be - started. It is probably important to note that the command buffer is the main - drawing API and the optional vertex buffer API only takes this format and - converts it into a hardware accessible format. - - To use the command queue to draw your own widgets you can access the - command buffer of each window by calling `nk_window_get_canvas` after - previously having called `nk_begin`: - - void draw_red_rectangle_widget(struct nk_context *ctx) - { - struct nk_command_buffer *canvas; - struct nk_input *input = &ctx->input; - canvas = nk_window_get_canvas(ctx); - - struct nk_rect space; - enum nk_widget_layout_states state; - state = nk_widget(&space, ctx); - if (!state) return; - - if (state != NK_WIDGET_ROM) - update_your_widget_by_user_input(...); - nk_fill_rect(canvas, space, 0, nk_rgb(255,0,0)); - } - - if (nk_begin(...)) { - nk_layout_row_dynamic(ctx, 25, 1); - draw_red_rectangle_widget(ctx); - } - nk_end(..) - - Important to know if you want to create your own widgets is the `nk_widget` - call. It allocates space on the panel reserved for this widget to be used, - but also returns the state of the widget space. If your widget is not seen and does - not have to be updated it is '0' and you can just return. If it only has - to be drawn the state will be `NK_WIDGET_ROM` otherwise you can do both - update and draw your widget. The reason for separating is to only draw and - update what is actually necessary which is crucial for performance. -*/ -enum nk_command_type { - NK_COMMAND_NOP, - NK_COMMAND_SCISSOR, - NK_COMMAND_LINE, - NK_COMMAND_CURVE, - NK_COMMAND_RECT, - NK_COMMAND_RECT_FILLED, - NK_COMMAND_RECT_MULTI_COLOR, - NK_COMMAND_CIRCLE, - NK_COMMAND_CIRCLE_FILLED, - NK_COMMAND_ARC, - NK_COMMAND_ARC_FILLED, - NK_COMMAND_TRIANGLE, - NK_COMMAND_TRIANGLE_FILLED, - NK_COMMAND_POLYGON, - NK_COMMAND_POLYGON_FILLED, - NK_COMMAND_POLYLINE, - NK_COMMAND_TEXT, - NK_COMMAND_IMAGE, - NK_COMMAND_CUSTOM -}; - -/* command base and header of every command inside the buffer */ -struct nk_command { - enum nk_command_type type; - nk_size next; -#ifdef NK_INCLUDE_COMMAND_USERDATA - nk_handle userdata; -#endif -}; - -struct nk_command_scissor { - struct nk_command header; - short x, y; - unsigned short w, h; -}; - -struct nk_command_line { - struct nk_command header; - unsigned short line_thickness; - struct nk_vec2i begin; - struct nk_vec2i end; - struct nk_color color; -}; - -struct nk_command_curve { - struct nk_command header; - unsigned short line_thickness; - struct nk_vec2i begin; - struct nk_vec2i end; - struct nk_vec2i ctrl[2]; - struct nk_color color; -}; - -struct nk_command_rect { - struct nk_command header; - unsigned short rounding; - unsigned short line_thickness; - short x, y; - unsigned short w, h; - struct nk_color color; -}; - -struct nk_command_rect_filled { - struct nk_command header; - unsigned short rounding; - short x, y; - unsigned short w, h; - struct nk_color color; -}; - -struct nk_command_rect_multi_color { - struct nk_command header; - short x, y; - unsigned short w, h; - struct nk_color left; - struct nk_color top; - struct nk_color bottom; - struct nk_color right; -}; - -struct nk_command_triangle { - struct nk_command header; - unsigned short line_thickness; - struct nk_vec2i a; - struct nk_vec2i b; - struct nk_vec2i c; - struct nk_color color; -}; - -struct nk_command_triangle_filled { - struct nk_command header; - struct nk_vec2i a; - struct nk_vec2i b; - struct nk_vec2i c; - struct nk_color color; -}; - -struct nk_command_circle { - struct nk_command header; - short x, y; - unsigned short line_thickness; - unsigned short w, h; - struct nk_color color; -}; - -struct nk_command_circle_filled { - struct nk_command header; - short x, y; - unsigned short w, h; - struct nk_color color; -}; - -struct nk_command_arc { - struct nk_command header; - short cx, cy; - unsigned short r; - unsigned short line_thickness; - float a[2]; - struct nk_color color; -}; - -struct nk_command_arc_filled { - struct nk_command header; - short cx, cy; - unsigned short r; - float a[2]; - struct nk_color color; -}; - -struct nk_command_polygon { - struct nk_command header; - struct nk_color color; - unsigned short line_thickness; - unsigned short point_count; - struct nk_vec2i points[1]; -}; - -struct nk_command_polygon_filled { - struct nk_command header; - struct nk_color color; - unsigned short point_count; - struct nk_vec2i points[1]; -}; - -struct nk_command_polyline { - struct nk_command header; - struct nk_color color; - unsigned short line_thickness; - unsigned short point_count; - struct nk_vec2i points[1]; -}; - -struct nk_command_image { - struct nk_command header; - short x, y; - unsigned short w, h; - struct nk_image img; - struct nk_color col; -}; - -typedef void (*nk_command_custom_callback)(void *canvas, short x,short y, - unsigned short w, unsigned short h, nk_handle callback_data); -struct nk_command_custom { - struct nk_command header; - short x, y; - unsigned short w, h; - nk_handle callback_data; - nk_command_custom_callback callback; -}; - -struct nk_command_text { - struct nk_command header; - const struct nk_user_font *font; - struct nk_color background; - struct nk_color foreground; - short x, y; - unsigned short w, h; - float height; - int length; - char string[1]; -}; - -enum nk_command_clipping { - NK_CLIPPING_OFF = nk_false, - NK_CLIPPING_ON = nk_true -}; - -struct nk_command_buffer { - struct nk_buffer *base; - struct nk_rect clip; - int use_clipping; - nk_handle userdata; - nk_size begin, end, last; -}; - -/* shape outlines */ -NK_API void nk_stroke_line(struct nk_command_buffer *b, float x0, float y0, float x1, float y1, float line_thickness, struct nk_color); -NK_API void nk_stroke_curve(struct nk_command_buffer*, float, float, float, float, float, float, float, float, float line_thickness, struct nk_color); -NK_API void nk_stroke_rect(struct nk_command_buffer*, struct nk_rect, float rounding, float line_thickness, struct nk_color); -NK_API void nk_stroke_circle(struct nk_command_buffer*, struct nk_rect, float line_thickness, struct nk_color); -NK_API void nk_stroke_arc(struct nk_command_buffer*, float cx, float cy, float radius, float a_min, float a_max, float line_thickness, struct nk_color); -NK_API void nk_stroke_triangle(struct nk_command_buffer*, float, float, float, float, float, float, float line_thichness, struct nk_color); -NK_API void nk_stroke_polyline(struct nk_command_buffer*, float *points, int point_count, float line_thickness, struct nk_color col); -NK_API void nk_stroke_polygon(struct nk_command_buffer*, float*, int point_count, float line_thickness, struct nk_color); - -/* filled shades */ -NK_API void nk_fill_rect(struct nk_command_buffer*, struct nk_rect, float rounding, struct nk_color); -NK_API void nk_fill_rect_multi_color(struct nk_command_buffer*, struct nk_rect, struct nk_color left, struct nk_color top, struct nk_color right, struct nk_color bottom); -NK_API void nk_fill_circle(struct nk_command_buffer*, struct nk_rect, struct nk_color); -NK_API void nk_fill_arc(struct nk_command_buffer*, float cx, float cy, float radius, float a_min, float a_max, struct nk_color); -NK_API void nk_fill_triangle(struct nk_command_buffer*, float x0, float y0, float x1, float y1, float x2, float y2, struct nk_color); -NK_API void nk_fill_polygon(struct nk_command_buffer*, float*, int point_count, struct nk_color); - -/* misc */ -NK_API void nk_draw_image(struct nk_command_buffer*, struct nk_rect, const struct nk_image*, struct nk_color); -NK_API void nk_draw_text(struct nk_command_buffer*, struct nk_rect, const char *text, int len, const struct nk_user_font*, struct nk_color, struct nk_color); -NK_API void nk_push_scissor(struct nk_command_buffer*, struct nk_rect); -NK_API void nk_push_custom(struct nk_command_buffer*, struct nk_rect, nk_command_custom_callback, nk_handle usr); - -/* =============================================================== - * - * INPUT - * - * ===============================================================*/ -struct nk_mouse_button { - int down; - unsigned int clicked; - struct nk_vec2 clicked_pos; -}; -struct nk_mouse { - struct nk_mouse_button buttons[NK_BUTTON_MAX]; - struct nk_vec2 pos; - struct nk_vec2 prev; - struct nk_vec2 delta; - struct nk_vec2 scroll_delta; - unsigned char grab; - unsigned char grabbed; - unsigned char ungrab; -}; - -struct nk_key { - int down; - unsigned int clicked; -}; -struct nk_keyboard { - struct nk_key keys[NK_KEY_MAX]; - char text[NK_INPUT_MAX]; - int text_len; -}; - -struct nk_input { - struct nk_keyboard keyboard; - struct nk_mouse mouse; -}; - -NK_API int nk_input_has_mouse_click(const struct nk_input*, enum nk_buttons); -NK_API int nk_input_has_mouse_click_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect); -NK_API int nk_input_has_mouse_click_down_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect, int down); -NK_API int nk_input_is_mouse_click_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect); -NK_API int nk_input_is_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id, struct nk_rect b, int down); -NK_API int nk_input_any_mouse_click_in_rect(const struct nk_input*, struct nk_rect); -NK_API int nk_input_is_mouse_prev_hovering_rect(const struct nk_input*, struct nk_rect); -NK_API int nk_input_is_mouse_hovering_rect(const struct nk_input*, struct nk_rect); -NK_API int nk_input_mouse_clicked(const struct nk_input*, enum nk_buttons, struct nk_rect); -NK_API int nk_input_is_mouse_down(const struct nk_input*, enum nk_buttons); -NK_API int nk_input_is_mouse_pressed(const struct nk_input*, enum nk_buttons); -NK_API int nk_input_is_mouse_released(const struct nk_input*, enum nk_buttons); -NK_API int nk_input_is_key_pressed(const struct nk_input*, enum nk_keys); -NK_API int nk_input_is_key_released(const struct nk_input*, enum nk_keys); -NK_API int nk_input_is_key_down(const struct nk_input*, enum nk_keys); - -/* =============================================================== - * - * DRAW LIST - * - * ===============================================================*/ -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT -/* The optional vertex buffer draw list provides a 2D drawing context - with antialiasing functionality which takes basic filled or outlined shapes - or a path and outputs vertexes, elements and draw commands. - The actual draw list API is not required to be used directly while using this - library since converting the default library draw command output is done by - just calling `nk_convert` but I decided to still make this library accessible - since it can be useful. - - The draw list is based on a path buffering and polygon and polyline - rendering API which allows a lot of ways to draw 2D content to screen. - In fact it is probably more powerful than needed but allows even more crazy - things than this library provides by default. -*/ -typedef nk_ushort nk_draw_index; -enum nk_draw_list_stroke { - NK_STROKE_OPEN = nk_false, - /* build up path has no connection back to the beginning */ - NK_STROKE_CLOSED = nk_true - /* build up path has a connection back to the beginning */ -}; - -enum nk_draw_vertex_layout_attribute { - NK_VERTEX_POSITION, - NK_VERTEX_COLOR, - NK_VERTEX_TEXCOORD, - NK_VERTEX_ATTRIBUTE_COUNT -}; - -enum nk_draw_vertex_layout_format { - NK_FORMAT_SCHAR, - NK_FORMAT_SSHORT, - NK_FORMAT_SINT, - NK_FORMAT_UCHAR, - NK_FORMAT_USHORT, - NK_FORMAT_UINT, - NK_FORMAT_FLOAT, - NK_FORMAT_DOUBLE, - -NK_FORMAT_COLOR_BEGIN, - NK_FORMAT_R8G8B8 = NK_FORMAT_COLOR_BEGIN, - NK_FORMAT_R16G15B16, - NK_FORMAT_R32G32B32, - - NK_FORMAT_R8G8B8A8, - NK_FORMAT_B8G8R8A8, - NK_FORMAT_R16G15B16A16, - NK_FORMAT_R32G32B32A32, - NK_FORMAT_R32G32B32A32_FLOAT, - NK_FORMAT_R32G32B32A32_DOUBLE, - - NK_FORMAT_RGB32, - NK_FORMAT_RGBA32, -NK_FORMAT_COLOR_END = NK_FORMAT_RGBA32, - NK_FORMAT_COUNT -}; - -#define NK_VERTEX_LAYOUT_END NK_VERTEX_ATTRIBUTE_COUNT,NK_FORMAT_COUNT,0 -struct nk_draw_vertex_layout_element { - enum nk_draw_vertex_layout_attribute attribute; - enum nk_draw_vertex_layout_format format; - nk_size offset; -}; - -struct nk_draw_command { - unsigned int elem_count; - /* number of elements in the current draw batch */ - struct nk_rect clip_rect; - /* current screen clipping rectangle */ - nk_handle texture; - /* current texture to set */ -#ifdef NK_INCLUDE_COMMAND_USERDATA - nk_handle userdata; -#endif -}; - -struct nk_draw_list { - struct nk_rect clip_rect; - struct nk_vec2 circle_vtx[12]; - struct nk_convert_config config; - - struct nk_buffer *buffer; - struct nk_buffer *vertices; - struct nk_buffer *elements; - - unsigned int element_count; - unsigned int vertex_count; - unsigned int cmd_count; - nk_size cmd_offset; - - unsigned int path_count; - unsigned int path_offset; - - enum nk_anti_aliasing line_AA; - enum nk_anti_aliasing shape_AA; - -#ifdef NK_INCLUDE_COMMAND_USERDATA - nk_handle userdata; -#endif -}; - -/* draw list */ -NK_API void nk_draw_list_init(struct nk_draw_list*); -NK_API void nk_draw_list_setup(struct nk_draw_list*, const struct nk_convert_config*, struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, enum nk_anti_aliasing line_aa,enum nk_anti_aliasing shape_aa); -NK_API void nk_draw_list_clear(struct nk_draw_list*); - -/* drawing */ -#define nk_draw_list_foreach(cmd, can, b) for((cmd)=nk__draw_list_begin(can, b); (cmd)!=0; (cmd)=nk__draw_list_next(cmd, b, can)) -NK_API const struct nk_draw_command* nk__draw_list_begin(const struct nk_draw_list*, const struct nk_buffer*); -NK_API const struct nk_draw_command* nk__draw_list_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_draw_list*); -NK_API const struct nk_draw_command* nk__draw_list_end(const struct nk_draw_list*, const struct nk_buffer*); - -/* path */ -NK_API void nk_draw_list_path_clear(struct nk_draw_list*); -NK_API void nk_draw_list_path_line_to(struct nk_draw_list*, struct nk_vec2 pos); -NK_API void nk_draw_list_path_arc_to_fast(struct nk_draw_list*, struct nk_vec2 center, float radius, int a_min, int a_max); -NK_API void nk_draw_list_path_arc_to(struct nk_draw_list*, struct nk_vec2 center, float radius, float a_min, float a_max, unsigned int segments); -NK_API void nk_draw_list_path_rect_to(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, float rounding); -NK_API void nk_draw_list_path_curve_to(struct nk_draw_list*, struct nk_vec2 p2, struct nk_vec2 p3, struct nk_vec2 p4, unsigned int num_segments); -NK_API void nk_draw_list_path_fill(struct nk_draw_list*, struct nk_color); -NK_API void nk_draw_list_path_stroke(struct nk_draw_list*, struct nk_color, enum nk_draw_list_stroke closed, float thickness); - -/* stroke */ -NK_API void nk_draw_list_stroke_line(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_color, float thickness); -NK_API void nk_draw_list_stroke_rect(struct nk_draw_list*, struct nk_rect rect, struct nk_color, float rounding, float thickness); -NK_API void nk_draw_list_stroke_triangle(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_vec2 c, struct nk_color, float thickness); -NK_API void nk_draw_list_stroke_circle(struct nk_draw_list*, struct nk_vec2 center, float radius, struct nk_color, unsigned int segs, float thickness); -NK_API void nk_draw_list_stroke_curve(struct nk_draw_list*, struct nk_vec2 p0, struct nk_vec2 cp0, struct nk_vec2 cp1, struct nk_vec2 p1, struct nk_color, unsigned int segments, float thickness); -NK_API void nk_draw_list_stroke_poly_line(struct nk_draw_list*, const struct nk_vec2 *pnts, const unsigned int cnt, struct nk_color, enum nk_draw_list_stroke, float thickness, enum nk_anti_aliasing); - -/* fill */ -NK_API void nk_draw_list_fill_rect(struct nk_draw_list*, struct nk_rect rect, struct nk_color, float rounding); -NK_API void nk_draw_list_fill_rect_multi_color(struct nk_draw_list*, struct nk_rect rect, struct nk_color left, struct nk_color top, struct nk_color right, struct nk_color bottom); -NK_API void nk_draw_list_fill_triangle(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_vec2 c, struct nk_color); -NK_API void nk_draw_list_fill_circle(struct nk_draw_list*, struct nk_vec2 center, float radius, struct nk_color col, unsigned int segs); -NK_API void nk_draw_list_fill_poly_convex(struct nk_draw_list*, const struct nk_vec2 *points, const unsigned int count, struct nk_color, enum nk_anti_aliasing); - -/* misc */ -NK_API void nk_draw_list_add_image(struct nk_draw_list*, struct nk_image texture, struct nk_rect rect, struct nk_color); -NK_API void nk_draw_list_add_text(struct nk_draw_list*, const struct nk_user_font*, struct nk_rect, const char *text, int len, float font_height, struct nk_color); -#ifdef NK_INCLUDE_COMMAND_USERDATA -NK_API void nk_draw_list_push_userdata(struct nk_draw_list*, nk_handle userdata); -#endif - -#endif - -/* =============================================================== - * - * GUI - * - * ===============================================================*/ -enum nk_style_item_type { - NK_STYLE_ITEM_COLOR, - NK_STYLE_ITEM_IMAGE -}; - -union nk_style_item_data { - struct nk_image image; - struct nk_color color; -}; - -struct nk_style_item { - enum nk_style_item_type type; - union nk_style_item_data data; -}; - -struct nk_style_text { - struct nk_color color; - struct nk_vec2 padding; -}; - -struct nk_style_button { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - - /* text */ - struct nk_color text_background; - struct nk_color text_normal; - struct nk_color text_hover; - struct nk_color text_active; - nk_flags text_alignment; - - /* properties */ - float border; - float rounding; - struct nk_vec2 padding; - struct nk_vec2 image_padding; - struct nk_vec2 touch_padding; - - /* optional user callbacks */ - nk_handle userdata; - void(*draw_begin)(struct nk_command_buffer*, nk_handle userdata); - void(*draw_end)(struct nk_command_buffer*, nk_handle userdata); -}; - -struct nk_style_toggle { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - - /* cursor */ - struct nk_style_item cursor_normal; - struct nk_style_item cursor_hover; - - /* text */ - struct nk_color text_normal; - struct nk_color text_hover; - struct nk_color text_active; - struct nk_color text_background; - nk_flags text_alignment; - - /* properties */ - struct nk_vec2 padding; - struct nk_vec2 touch_padding; - float spacing; - float border; - - /* optional user callbacks */ - nk_handle userdata; - void(*draw_begin)(struct nk_command_buffer*, nk_handle); - void(*draw_end)(struct nk_command_buffer*, nk_handle); -}; - -struct nk_style_selectable { - /* background (inactive) */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item pressed; - - /* background (active) */ - struct nk_style_item normal_active; - struct nk_style_item hover_active; - struct nk_style_item pressed_active; - - /* text color (inactive) */ - struct nk_color text_normal; - struct nk_color text_hover; - struct nk_color text_pressed; - - /* text color (active) */ - struct nk_color text_normal_active; - struct nk_color text_hover_active; - struct nk_color text_pressed_active; - struct nk_color text_background; - nk_flags text_alignment; - - /* properties */ - float rounding; - struct nk_vec2 padding; - struct nk_vec2 touch_padding; - struct nk_vec2 image_padding; - - /* optional user callbacks */ - nk_handle userdata; - void(*draw_begin)(struct nk_command_buffer*, nk_handle); - void(*draw_end)(struct nk_command_buffer*, nk_handle); -}; - -struct nk_style_slider { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - - /* background bar */ - struct nk_color bar_normal; - struct nk_color bar_hover; - struct nk_color bar_active; - struct nk_color bar_filled; - - /* cursor */ - struct nk_style_item cursor_normal; - struct nk_style_item cursor_hover; - struct nk_style_item cursor_active; - - /* properties */ - float border; - float rounding; - float bar_height; - struct nk_vec2 padding; - struct nk_vec2 spacing; - struct nk_vec2 cursor_size; - - /* optional buttons */ - int show_buttons; - struct nk_style_button inc_button; - struct nk_style_button dec_button; - enum nk_symbol_type inc_symbol; - enum nk_symbol_type dec_symbol; - - /* optional user callbacks */ - nk_handle userdata; - void(*draw_begin)(struct nk_command_buffer*, nk_handle); - void(*draw_end)(struct nk_command_buffer*, nk_handle); -}; - -struct nk_style_progress { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - - /* cursor */ - struct nk_style_item cursor_normal; - struct nk_style_item cursor_hover; - struct nk_style_item cursor_active; - struct nk_color cursor_border_color; - - /* properties */ - float rounding; - float border; - float cursor_border; - float cursor_rounding; - struct nk_vec2 padding; - - /* optional user callbacks */ - nk_handle userdata; - void(*draw_begin)(struct nk_command_buffer*, nk_handle); - void(*draw_end)(struct nk_command_buffer*, nk_handle); -}; - -struct nk_style_scrollbar { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - - /* cursor */ - struct nk_style_item cursor_normal; - struct nk_style_item cursor_hover; - struct nk_style_item cursor_active; - struct nk_color cursor_border_color; - - /* properties */ - float border; - float rounding; - float border_cursor; - float rounding_cursor; - struct nk_vec2 padding; - - /* optional buttons */ - int show_buttons; - struct nk_style_button inc_button; - struct nk_style_button dec_button; - enum nk_symbol_type inc_symbol; - enum nk_symbol_type dec_symbol; - - /* optional user callbacks */ - nk_handle userdata; - void(*draw_begin)(struct nk_command_buffer*, nk_handle); - void(*draw_end)(struct nk_command_buffer*, nk_handle); -}; - -struct nk_style_edit { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - struct nk_style_scrollbar scrollbar; - - /* cursor */ - struct nk_color cursor_normal; - struct nk_color cursor_hover; - struct nk_color cursor_text_normal; - struct nk_color cursor_text_hover; - - /* text (unselected) */ - struct nk_color text_normal; - struct nk_color text_hover; - struct nk_color text_active; - - /* text (selected) */ - struct nk_color selected_normal; - struct nk_color selected_hover; - struct nk_color selected_text_normal; - struct nk_color selected_text_hover; - - /* properties */ - float border; - float rounding; - float cursor_size; - struct nk_vec2 scrollbar_size; - struct nk_vec2 padding; - float row_padding; -}; - -struct nk_style_property { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - - /* text */ - struct nk_color label_normal; - struct nk_color label_hover; - struct nk_color label_active; - - /* symbols */ - enum nk_symbol_type sym_left; - enum nk_symbol_type sym_right; - - /* properties */ - float border; - float rounding; - struct nk_vec2 padding; - - struct nk_style_edit edit; - struct nk_style_button inc_button; - struct nk_style_button dec_button; - - /* optional user callbacks */ - nk_handle userdata; - void(*draw_begin)(struct nk_command_buffer*, nk_handle); - void(*draw_end)(struct nk_command_buffer*, nk_handle); -}; - -struct nk_style_chart { - /* colors */ - struct nk_style_item background; - struct nk_color border_color; - struct nk_color selected_color; - struct nk_color color; - - /* properties */ - float border; - float rounding; - struct nk_vec2 padding; -}; - -struct nk_style_combo { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - struct nk_color border_color; - - /* label */ - struct nk_color label_normal; - struct nk_color label_hover; - struct nk_color label_active; - - /* symbol */ - struct nk_color symbol_normal; - struct nk_color symbol_hover; - struct nk_color symbol_active; - - /* button */ - struct nk_style_button button; - enum nk_symbol_type sym_normal; - enum nk_symbol_type sym_hover; - enum nk_symbol_type sym_active; - - /* properties */ - float border; - float rounding; - struct nk_vec2 content_padding; - struct nk_vec2 button_padding; - struct nk_vec2 spacing; -}; - -struct nk_style_tab { - /* background */ - struct nk_style_item background; - struct nk_color border_color; - struct nk_color text; - - /* button */ - struct nk_style_button tab_maximize_button; - struct nk_style_button tab_minimize_button; - struct nk_style_button node_maximize_button; - struct nk_style_button node_minimize_button; - enum nk_symbol_type sym_minimize; - enum nk_symbol_type sym_maximize; - - /* properties */ - float border; - float rounding; - float indent; - struct nk_vec2 padding; - struct nk_vec2 spacing; -}; - -enum nk_style_header_align { - NK_HEADER_LEFT, - NK_HEADER_RIGHT -}; -struct nk_style_window_header { - /* background */ - struct nk_style_item normal; - struct nk_style_item hover; - struct nk_style_item active; - - /* button */ - struct nk_style_button close_button; - struct nk_style_button minimize_button; - enum nk_symbol_type close_symbol; - enum nk_symbol_type minimize_symbol; - enum nk_symbol_type maximize_symbol; - - /* title */ - struct nk_color label_normal; - struct nk_color label_hover; - struct nk_color label_active; - - /* properties */ - enum nk_style_header_align align; - struct nk_vec2 padding; - struct nk_vec2 label_padding; - struct nk_vec2 spacing; -}; - -struct nk_style_window { - struct nk_style_window_header header; - struct nk_style_item fixed_background; - struct nk_color background; - - struct nk_color border_color; - struct nk_color popup_border_color; - struct nk_color combo_border_color; - struct nk_color contextual_border_color; - struct nk_color menu_border_color; - struct nk_color group_border_color; - struct nk_color tooltip_border_color; - struct nk_style_item scaler; - - float border; - float combo_border; - float contextual_border; - float menu_border; - float group_border; - float tooltip_border; - float popup_border; - float min_row_height_padding; - - float rounding; - struct nk_vec2 spacing; - struct nk_vec2 scrollbar_size; - struct nk_vec2 min_size; - - struct nk_vec2 padding; - struct nk_vec2 group_padding; - struct nk_vec2 popup_padding; - struct nk_vec2 combo_padding; - struct nk_vec2 contextual_padding; - struct nk_vec2 menu_padding; - struct nk_vec2 tooltip_padding; -}; - -struct nk_style { - const struct nk_user_font *font; - const struct nk_cursor *cursors[NK_CURSOR_COUNT]; - const struct nk_cursor *cursor_active; - struct nk_cursor *cursor_last; - int cursor_visible; - - struct nk_style_text text; - struct nk_style_button button; - struct nk_style_button contextual_button; - struct nk_style_button menu_button; - struct nk_style_toggle option; - struct nk_style_toggle checkbox; - struct nk_style_selectable selectable; - struct nk_style_slider slider; - struct nk_style_progress progress; - struct nk_style_property property; - struct nk_style_edit edit; - struct nk_style_chart chart; - struct nk_style_scrollbar scrollh; - struct nk_style_scrollbar scrollv; - struct nk_style_tab tab; - struct nk_style_combo combo; - struct nk_style_window window; -}; - -NK_API struct nk_style_item nk_style_item_image(struct nk_image img); -NK_API struct nk_style_item nk_style_item_color(struct nk_color); -NK_API struct nk_style_item nk_style_item_hide(void); - -/*============================================================== - * PANEL - * =============================================================*/ -#ifndef NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS -#define NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS 16 -#endif -#ifndef NK_CHART_MAX_SLOT -#define NK_CHART_MAX_SLOT 4 -#endif - -enum nk_panel_type { - NK_PANEL_WINDOW = NK_FLAG(0), - NK_PANEL_GROUP = NK_FLAG(1), - NK_PANEL_POPUP = NK_FLAG(2), - NK_PANEL_CONTEXTUAL = NK_FLAG(4), - NK_PANEL_COMBO = NK_FLAG(5), - NK_PANEL_MENU = NK_FLAG(6), - NK_PANEL_TOOLTIP = NK_FLAG(7) -}; -enum nk_panel_set { - NK_PANEL_SET_NONBLOCK = NK_PANEL_CONTEXTUAL|NK_PANEL_COMBO|NK_PANEL_MENU|NK_PANEL_TOOLTIP, - NK_PANEL_SET_POPUP = NK_PANEL_SET_NONBLOCK|NK_PANEL_POPUP, - NK_PANEL_SET_SUB = NK_PANEL_SET_POPUP|NK_PANEL_GROUP -}; - -struct nk_chart_slot { - enum nk_chart_type type; - struct nk_color color; - struct nk_color highlight; - float min, max, range; - int count; - struct nk_vec2 last; - int index; -}; - -struct nk_chart { - int slot; - float x, y, w, h; - struct nk_chart_slot slots[NK_CHART_MAX_SLOT]; -}; - -enum nk_panel_row_layout_type { - NK_LAYOUT_DYNAMIC_FIXED = 0, - NK_LAYOUT_DYNAMIC_ROW, - NK_LAYOUT_DYNAMIC_FREE, - NK_LAYOUT_DYNAMIC, - NK_LAYOUT_STATIC_FIXED, - NK_LAYOUT_STATIC_ROW, - NK_LAYOUT_STATIC_FREE, - NK_LAYOUT_STATIC, - NK_LAYOUT_TEMPLATE, - NK_LAYOUT_COUNT -}; -struct nk_row_layout { - enum nk_panel_row_layout_type type; - int index; - float height; - float min_height; - int columns; - const float *ratio; - float item_width; - float item_height; - float item_offset; - float filled; - struct nk_rect item; - int tree_depth; - float templates[NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS]; -}; - -struct nk_popup_buffer { - nk_size begin; - nk_size parent; - nk_size last; - nk_size end; - int active; -}; - -struct nk_menu_state { - float x, y, w, h; - struct nk_scroll offset; -}; - -struct nk_panel { - enum nk_panel_type type; - nk_flags flags; - struct nk_rect bounds; - nk_uint *offset_x; - nk_uint *offset_y; - float at_x, at_y, max_x; - float footer_height; - float header_height; - float border; - unsigned int has_scrolling; - struct nk_rect clip; - struct nk_menu_state menu; - struct nk_row_layout row; - struct nk_chart chart; - struct nk_command_buffer *buffer; - struct nk_panel *parent; -}; - -/*============================================================== - * WINDOW - * =============================================================*/ -#ifndef NK_WINDOW_MAX_NAME -#define NK_WINDOW_MAX_NAME 64 -#endif - -struct nk_table; -enum nk_window_flags { - NK_WINDOW_PRIVATE = NK_FLAG(11), - NK_WINDOW_DYNAMIC = NK_WINDOW_PRIVATE, - /* special window type growing up in height while being filled to a certain maximum height */ - NK_WINDOW_ROM = NK_FLAG(12), - /* sets window widgets into a read only mode and does not allow input changes */ - NK_WINDOW_NOT_INTERACTIVE = NK_WINDOW_ROM|NK_WINDOW_NO_INPUT, - /* prevents all interaction caused by input to either window or widgets inside */ - NK_WINDOW_HIDDEN = NK_FLAG(13), - /* Hides window and stops any window interaction and drawing */ - NK_WINDOW_CLOSED = NK_FLAG(14), - /* Directly closes and frees the window at the end of the frame */ - NK_WINDOW_MINIMIZED = NK_FLAG(15), - /* marks the window as minimized */ - NK_WINDOW_REMOVE_ROM = NK_FLAG(16) - /* Removes read only mode at the end of the window */ -}; - -struct nk_popup_state { - struct nk_window *win; - enum nk_panel_type type; - struct nk_popup_buffer buf; - nk_hash name; - int active; - unsigned combo_count; - unsigned con_count, con_old; - unsigned active_con; - struct nk_rect header; -}; - -struct nk_edit_state { - nk_hash name; - unsigned int seq; - unsigned int old; - int active, prev; - int cursor; - int sel_start; - int sel_end; - struct nk_scroll scrollbar; - unsigned char mode; - unsigned char single_line; -}; - -struct nk_property_state { - int active, prev; - char buffer[NK_MAX_NUMBER_BUFFER]; - int length; - int cursor; - int select_start; - int select_end; - nk_hash name; - unsigned int seq; - unsigned int old; - int state; -}; - -struct nk_window { - unsigned int seq; - nk_hash name; - char name_string[NK_WINDOW_MAX_NAME]; - nk_flags flags; - - struct nk_rect bounds; - struct nk_scroll scrollbar; - struct nk_command_buffer buffer; - struct nk_panel *layout; - float scrollbar_hiding_timer; - - /* persistent widget state */ - struct nk_property_state property; - struct nk_popup_state popup; - struct nk_edit_state edit; - unsigned int scrolled; - - struct nk_table *tables; - unsigned int table_count; - - /* window list hooks */ - struct nk_window *next; - struct nk_window *prev; - struct nk_window *parent; -}; - -/*============================================================== - * STACK - * =============================================================*/ -/* The style modifier stack can be used to temporarily change a - * property inside `nk_style`. For example if you want a special - * red button you can temporarily push the old button color onto a stack - * draw the button with a red color and then you just pop the old color - * back from the stack: - * - * nk_style_push_style_item(ctx, &ctx->style.button.normal, nk_style_item_color(nk_rgb(255,0,0))); - * nk_style_push_style_item(ctx, &ctx->style.button.hover, nk_style_item_color(nk_rgb(255,0,0))); - * nk_style_push_style_item(ctx, &ctx->style.button.active, nk_style_item_color(nk_rgb(255,0,0))); - * nk_style_push_vec2(ctx, &cx->style.button.padding, nk_vec2(2,2)); - * - * nk_button(...); - * - * nk_style_pop_style_item(ctx); - * nk_style_pop_style_item(ctx); - * nk_style_pop_style_item(ctx); - * nk_style_pop_vec2(ctx); - * - * Nuklear has a stack for style_items, float properties, vector properties, - * flags, colors, fonts and for button_behavior. Each has it's own fixed size stack - * which can be changed at compile time. - */ -#ifndef NK_BUTTON_BEHAVIOR_STACK_SIZE -#define NK_BUTTON_BEHAVIOR_STACK_SIZE 8 -#endif - -#ifndef NK_FONT_STACK_SIZE -#define NK_FONT_STACK_SIZE 8 -#endif - -#ifndef NK_STYLE_ITEM_STACK_SIZE -#define NK_STYLE_ITEM_STACK_SIZE 16 -#endif - -#ifndef NK_FLOAT_STACK_SIZE -#define NK_FLOAT_STACK_SIZE 32 -#endif - -#ifndef NK_VECTOR_STACK_SIZE -#define NK_VECTOR_STACK_SIZE 16 -#endif - -#ifndef NK_FLAGS_STACK_SIZE -#define NK_FLAGS_STACK_SIZE 32 -#endif - -#ifndef NK_COLOR_STACK_SIZE -#define NK_COLOR_STACK_SIZE 32 -#endif - -#define NK_CONFIGURATION_STACK_TYPE(prefix, name, type)\ - struct nk_config_stack_##name##_element {\ - prefix##_##type *address;\ - prefix##_##type old_value;\ - } -#define NK_CONFIG_STACK(type,size)\ - struct nk_config_stack_##type {\ - int head;\ - struct nk_config_stack_##type##_element elements[size];\ - } - -#define nk_float float -NK_CONFIGURATION_STACK_TYPE(struct nk, style_item, style_item); -NK_CONFIGURATION_STACK_TYPE(nk ,float, float); -NK_CONFIGURATION_STACK_TYPE(struct nk, vec2, vec2); -NK_CONFIGURATION_STACK_TYPE(nk ,flags, flags); -NK_CONFIGURATION_STACK_TYPE(struct nk, color, color); -NK_CONFIGURATION_STACK_TYPE(const struct nk, user_font, user_font*); -NK_CONFIGURATION_STACK_TYPE(enum nk, button_behavior, button_behavior); - -NK_CONFIG_STACK(style_item, NK_STYLE_ITEM_STACK_SIZE); -NK_CONFIG_STACK(float, NK_FLOAT_STACK_SIZE); -NK_CONFIG_STACK(vec2, NK_VECTOR_STACK_SIZE); -NK_CONFIG_STACK(flags, NK_FLAGS_STACK_SIZE); -NK_CONFIG_STACK(color, NK_COLOR_STACK_SIZE); -NK_CONFIG_STACK(user_font, NK_FONT_STACK_SIZE); -NK_CONFIG_STACK(button_behavior, NK_BUTTON_BEHAVIOR_STACK_SIZE); - -struct nk_configuration_stacks { - struct nk_config_stack_style_item style_items; - struct nk_config_stack_float floats; - struct nk_config_stack_vec2 vectors; - struct nk_config_stack_flags flags; - struct nk_config_stack_color colors; - struct nk_config_stack_user_font fonts; - struct nk_config_stack_button_behavior button_behaviors; -}; - -/*============================================================== - * CONTEXT - * =============================================================*/ -#define NK_VALUE_PAGE_CAPACITY \ - (((NK_MAX(sizeof(struct nk_window),sizeof(struct nk_panel)) / sizeof(nk_uint))) / 2) - -struct nk_table { - unsigned int seq; - unsigned int size; - nk_hash keys[NK_VALUE_PAGE_CAPACITY]; - nk_uint values[NK_VALUE_PAGE_CAPACITY]; - struct nk_table *next, *prev; -}; - -union nk_page_data { - struct nk_table tbl; - struct nk_panel pan; - struct nk_window win; -}; - -struct nk_page_element { - union nk_page_data data; - struct nk_page_element *next; - struct nk_page_element *prev; -}; - -struct nk_page { - unsigned int size; - struct nk_page *next; - struct nk_page_element win[1]; -}; - -struct nk_pool { - struct nk_allocator alloc; - enum nk_allocation_type type; - unsigned int page_count; - struct nk_page *pages; - struct nk_page_element *freelist; - unsigned capacity; - nk_size size; - nk_size cap; -}; - -struct nk_context { -/* public: can be accessed freely */ - struct nk_input input; - struct nk_style style; - struct nk_buffer memory; - struct nk_clipboard clip; - nk_flags last_widget_state; - enum nk_button_behavior button_behavior; - struct nk_configuration_stacks stacks; - float delta_time_seconds; - -/* private: - should only be accessed if you - know what you are doing */ -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT - struct nk_draw_list draw_list; -#endif -#ifdef NK_INCLUDE_COMMAND_USERDATA - nk_handle userdata; -#endif - /* text editor objects are quite big because of an internal - * undo/redo stack. Therefore it does not make sense to have one for - * each window for temporary use cases, so I only provide *one* instance - * for all windows. This works because the content is cleared anyway */ - struct nk_text_edit text_edit; - /* draw buffer used for overlay drawing operation like cursor */ - struct nk_command_buffer overlay; - - /* windows */ - int build; - int use_pool; - struct nk_pool pool; - struct nk_window *begin; - struct nk_window *end; - struct nk_window *active; - struct nk_window *current; - struct nk_page_element *freelist; - unsigned int count; - unsigned int seq; -}; - -/* ============================================================== - * MATH - * =============================================================== */ -#define NK_PI 3.141592654f -#define NK_UTF_INVALID 0xFFFD -#define NK_MAX_FLOAT_PRECISION 2 - -#define NK_UNUSED(x) ((void)(x)) -#define NK_SATURATE(x) (NK_MAX(0, NK_MIN(1.0f, x))) -#define NK_LEN(a) (sizeof(a)/sizeof(a)[0]) -#define NK_ABS(a) (((a) < 0) ? -(a) : (a)) -#define NK_BETWEEN(x, a, b) ((a) <= (x) && (x) < (b)) -#define NK_INBOX(px, py, x, y, w, h)\ - (NK_BETWEEN(px,x,x+w) && NK_BETWEEN(py,y,y+h)) -#define NK_INTERSECT(x0, y0, w0, h0, x1, y1, w1, h1) \ - (!(((x1 > (x0 + w0)) || ((x1 + w1) < x0) || (y1 > (y0 + h0)) || (y1 + h1) < y0))) -#define NK_CONTAINS(x, y, w, h, bx, by, bw, bh)\ - (NK_INBOX(x,y, bx, by, bw, bh) && NK_INBOX(x+w,y+h, bx, by, bw, bh)) - -#define nk_vec2_sub(a, b) nk_vec2((a).x - (b).x, (a).y - (b).y) -#define nk_vec2_add(a, b) nk_vec2((a).x + (b).x, (a).y + (b).y) -#define nk_vec2_len_sqr(a) ((a).x*(a).x+(a).y*(a).y) -#define nk_vec2_muls(a, t) nk_vec2((a).x * (t), (a).y * (t)) - -#define nk_ptr_add(t, p, i) ((t*)((void*)((nk_byte*)(p) + (i)))) -#define nk_ptr_add_const(t, p, i) ((const t*)((const void*)((const nk_byte*)(p) + (i)))) -#define nk_zero_struct(s) nk_zero(&s, sizeof(s)) - -/* ============================================================== - * ALIGNMENT - * =============================================================== */ -/* Pointer to Integer type conversion for pointer alignment */ -#if defined(__PTRDIFF_TYPE__) /* This case should work for GCC*/ -# define NK_UINT_TO_PTR(x) ((void*)(__PTRDIFF_TYPE__)(x)) -# define NK_PTR_TO_UINT(x) ((nk_size)(__PTRDIFF_TYPE__)(x)) -#elif !defined(__GNUC__) /* works for compilers other than LLVM */ -# define NK_UINT_TO_PTR(x) ((void*)&((char*)0)[x]) -# define NK_PTR_TO_UINT(x) ((nk_size)(((char*)x)-(char*)0)) -#elif defined(NK_USE_FIXED_TYPES) /* used if we have */ -# define NK_UINT_TO_PTR(x) ((void*)(uintptr_t)(x)) -# define NK_PTR_TO_UINT(x) ((uintptr_t)(x)) -#else /* generates warning but works */ -# define NK_UINT_TO_PTR(x) ((void*)(x)) -# define NK_PTR_TO_UINT(x) ((nk_size)(x)) -#endif - -#define NK_ALIGN_PTR(x, mask)\ - (NK_UINT_TO_PTR((NK_PTR_TO_UINT((nk_byte*)(x) + (mask-1)) & ~(mask-1)))) -#define NK_ALIGN_PTR_BACK(x, mask)\ - (NK_UINT_TO_PTR((NK_PTR_TO_UINT((nk_byte*)(x)) & ~(mask-1)))) - -#define NK_OFFSETOF(st,m) ((nk_ptr)&(((st*)0)->m)) -#define NK_CONTAINER_OF(ptr,type,member)\ - (type*)((void*)((char*)(1 ? (ptr): &((type*)0)->member) - NK_OFFSETOF(type, member))) - -#ifdef __cplusplus -} -#endif - -#ifdef __cplusplus -template struct nk_alignof; -template struct nk_helper{enum {value = size_diff};}; -template struct nk_helper{enum {value = nk_alignof::value};}; -template struct nk_alignof{struct Big {T x; char c;}; enum { - diff = sizeof(Big) - sizeof(T), value = nk_helper::value};}; -#define NK_ALIGNOF(t) (nk_alignof::value) -#elif defined(_MSC_VER) -#define NK_ALIGNOF(t) (__alignof(t)) -#else -#define NK_ALIGNOF(t) ((char*)(&((struct {char c; t _h;}*)0)->_h) - (char*)0) -#endif - -#endif /* NK_NUKLEAR_H_ */ -/* - * ============================================================== - * - * IMPLEMENTATION - * - * =============================================================== - */ -#ifdef NK_IMPLEMENTATION - -#ifndef NK_POOL_DEFAULT_CAPACITY -#define NK_POOL_DEFAULT_CAPACITY 16 -#endif - -#ifndef NK_DEFAULT_COMMAND_BUFFER_SIZE -#define NK_DEFAULT_COMMAND_BUFFER_SIZE (4*1024) -#endif - -#ifndef NK_BUFFER_DEFAULT_INITIAL_SIZE -#define NK_BUFFER_DEFAULT_INITIAL_SIZE (4*1024) -#endif - -/* standard library headers */ -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -#include /* malloc, free */ -#endif -#ifdef NK_INCLUDE_STANDARD_IO -#include /* fopen, fclose,... */ -#endif -#ifdef NK_INCLUDE_STANDARD_VARARGS -#include /* valist, va_start, va_end, ... */ -#endif -#ifndef NK_ASSERT -#include -#define NK_ASSERT(expr) assert(expr) -#endif - -#ifndef NK_MEMSET -#define NK_MEMSET nk_memset -#endif -#ifndef NK_MEMCPY -#define NK_MEMCPY nk_memcopy -#endif -#ifndef NK_SQRT -#define NK_SQRT nk_sqrt -#endif -#ifndef NK_SIN -#define NK_SIN nk_sin -#endif -#ifndef NK_COS -#define NK_COS nk_cos -#endif -#ifndef NK_STRTOD -#define NK_STRTOD nk_strtod -#endif -#ifndef NK_DTOA -#define NK_DTOA nk_dtoa -#endif - -#define NK_DEFAULT (-1) - -#ifndef NK_VSNPRINTF -/* If your compiler does support `vsnprintf` I would highly recommend - * defining this to vsnprintf instead since `vsprintf` is basically - * unbelievable unsafe and should *NEVER* be used. But I have to support - * it since C89 only provides this unsafe version. */ - #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) ||\ - (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ - (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) ||\ - (defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) ||\ - defined(_ISOC99_SOURCE) || defined(_BSD_SOURCE) - #define NK_VSNPRINTF(s,n,f,a) vsnprintf(s,n,f,a) - #else - #define NK_VSNPRINTF(s,n,f,a) vsprintf(s,f,a) - #endif -#endif - -#define NK_SCHAR_MIN (-127) -#define NK_SCHAR_MAX 127 -#define NK_UCHAR_MIN 0 -#define NK_UCHAR_MAX 256 -#define NK_SSHORT_MIN (-32767) -#define NK_SSHORT_MAX 32767 -#define NK_USHORT_MIN 0 -#define NK_USHORT_MAX 65535 -#define NK_SINT_MIN (-2147483647) -#define NK_SINT_MAX 2147483647 -#define NK_UINT_MIN 0 -#define NK_UINT_MAX 4294967295u - -/* Make sure correct type size: - * This will fire with a negative subscript error if the type sizes - * are set incorrectly by the compiler, and compile out if not */ -NK_STATIC_ASSERT(sizeof(nk_size) >= sizeof(void*)); -NK_STATIC_ASSERT(sizeof(nk_ptr) == sizeof(void*)); -NK_STATIC_ASSERT(sizeof(nk_flags) >= 4); -NK_STATIC_ASSERT(sizeof(nk_rune) >= 4); -NK_STATIC_ASSERT(sizeof(nk_ushort) == 2); -NK_STATIC_ASSERT(sizeof(nk_short) == 2); -NK_STATIC_ASSERT(sizeof(nk_uint) == 4); -NK_STATIC_ASSERT(sizeof(nk_int) == 4); -NK_STATIC_ASSERT(sizeof(nk_byte) == 1); - -NK_GLOBAL const struct nk_rect nk_null_rect = {-8192.0f, -8192.0f, 16384, 16384}; -#define NK_FLOAT_PRECISION 0.00000000000001 - -NK_GLOBAL const struct nk_color nk_red = {255,0,0,255}; -NK_GLOBAL const struct nk_color nk_green = {0,255,0,255}; -NK_GLOBAL const struct nk_color nk_blue = {0,0,255,255}; -NK_GLOBAL const struct nk_color nk_white = {255,255,255,255}; -NK_GLOBAL const struct nk_color nk_black = {0,0,0,255}; -NK_GLOBAL const struct nk_color nk_yellow = {255,255,0,255}; - -/* - * ============================================================== - * - * MATH - * - * =============================================================== - */ -/* Since nuklear is supposed to work on all systems providing floating point - math without any dependencies I also had to implement my own math functions - for sqrt, sin and cos. Since the actual highly accurate implementations for - the standard library functions are quite complex and I do not need high - precision for my use cases I use approximations. - - Sqrt - ---- - For square root nuklear uses the famous fast inverse square root: - https://en.wikipedia.org/wiki/Fast_inverse_square_root with - slightly tweaked magic constant. While on today's hardware it is - probably not faster it is still fast and accurate enough for - nuklear's use cases. IMPORTANT: this requires float format IEEE 754 - - Sine/Cosine - ----------- - All constants inside both function are generated Remez's minimax - approximations for value range 0...2*PI. The reason why I decided to - approximate exactly that range is that nuklear only needs sine and - cosine to generate circles which only requires that exact range. - In addition I used Remez instead of Taylor for additional precision: - www.lolengine.net/blog/2011/12/21/better-function-approximations. - - The tool I used to generate constants for both sine and cosine - (it can actually approximate a lot more functions) can be - found here: www.lolengine.net/wiki/oss/lolremez -*/ -NK_INTERN float -nk_inv_sqrt(float number) -{ - float x2; - const float threehalfs = 1.5f; - union {nk_uint i; float f;} conv = {0}; - conv.f = number; - x2 = number * 0.5f; - conv.i = 0x5f375A84 - (conv.i >> 1); - conv.f = conv.f * (threehalfs - (x2 * conv.f * conv.f)); - return conv.f; -} - -NK_INTERN float -nk_sqrt(float x) -{ - return x * nk_inv_sqrt(x); -} - -NK_INTERN float -nk_sin(float x) -{ - NK_STORAGE const float a0 = +1.91059300966915117e-31f; - NK_STORAGE const float a1 = +1.00086760103908896f; - NK_STORAGE const float a2 = -1.21276126894734565e-2f; - NK_STORAGE const float a3 = -1.38078780785773762e-1f; - NK_STORAGE const float a4 = -2.67353392911981221e-2f; - NK_STORAGE const float a5 = +2.08026600266304389e-2f; - NK_STORAGE const float a6 = -3.03996055049204407e-3f; - NK_STORAGE const float a7 = +1.38235642404333740e-4f; - return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*a7)))))); -} - -NK_INTERN float -nk_cos(float x) -{ - NK_STORAGE const float a0 = +1.00238601909309722f; - NK_STORAGE const float a1 = -3.81919947353040024e-2f; - NK_STORAGE const float a2 = -3.94382342128062756e-1f; - NK_STORAGE const float a3 = -1.18134036025221444e-1f; - NK_STORAGE const float a4 = +1.07123798512170878e-1f; - NK_STORAGE const float a5 = -1.86637164165180873e-2f; - NK_STORAGE const float a6 = +9.90140908664079833e-4f; - NK_STORAGE const float a7 = -5.23022132118824778e-14f; - return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*a7)))))); -} - -NK_INTERN nk_uint -nk_round_up_pow2(nk_uint v) -{ - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - return v; -} - -NK_API struct nk_rect -nk_get_null_rect(void) -{ - return nk_null_rect; -} - -NK_API struct nk_rect -nk_rect(float x, float y, float w, float h) -{ - struct nk_rect r; - r.x = x; r.y = y; - r.w = w; r.h = h; - return r; -} - -NK_API struct nk_rect -nk_recti(int x, int y, int w, int h) -{ - struct nk_rect r; - r.x = (float)x; - r.y = (float)y; - r.w = (float)w; - r.h = (float)h; - return r; -} - -NK_API struct nk_rect -nk_recta(struct nk_vec2 pos, struct nk_vec2 size) -{ - return nk_rect(pos.x, pos.y, size.x, size.y); -} - -NK_API struct nk_rect -nk_rectv(const float *r) -{ - return nk_rect(r[0], r[1], r[2], r[3]); -} - -NK_API struct nk_rect -nk_rectiv(const int *r) -{ - return nk_recti(r[0], r[1], r[2], r[3]); -} - -NK_API struct nk_vec2 -nk_rect_pos(struct nk_rect r) -{ - struct nk_vec2 ret; - ret.x = r.x; ret.y = r.y; - return ret; -} - -NK_API struct nk_vec2 -nk_rect_size(struct nk_rect r) -{ - struct nk_vec2 ret; - ret.x = r.w; ret.y = r.h; - return ret; -} - -NK_INTERN struct nk_rect -nk_shrink_rect(struct nk_rect r, float amount) -{ - struct nk_rect res; - r.w = NK_MAX(r.w, 2 * amount); - r.h = NK_MAX(r.h, 2 * amount); - res.x = r.x + amount; - res.y = r.y + amount; - res.w = r.w - 2 * amount; - res.h = r.h - 2 * amount; - return res; -} - -NK_INTERN struct nk_rect -nk_pad_rect(struct nk_rect r, struct nk_vec2 pad) -{ - r.w = NK_MAX(r.w, 2 * pad.x); - r.h = NK_MAX(r.h, 2 * pad.y); - r.x += pad.x; r.y += pad.y; - r.w -= 2 * pad.x; - r.h -= 2 * pad.y; - return r; -} - -NK_API struct nk_vec2 -nk_vec2(float x, float y) -{ - struct nk_vec2 ret; - ret.x = x; ret.y = y; - return ret; -} - -NK_API struct nk_vec2 -nk_vec2i(int x, int y) -{ - struct nk_vec2 ret; - ret.x = (float)x; - ret.y = (float)y; - return ret; -} - -NK_API struct nk_vec2 -nk_vec2v(const float *v) -{ - return nk_vec2(v[0], v[1]); -} - -NK_API struct nk_vec2 -nk_vec2iv(const int *v) -{ - return nk_vec2i(v[0], v[1]); -} - -/* - * ============================================================== - * - * UTIL - * - * =============================================================== - */ -NK_INTERN int nk_str_match_here(const char *regexp, const char *text); -NK_INTERN int nk_str_match_star(int c, const char *regexp, const char *text); -NK_INTERN int nk_is_lower(int c) {return (c >= 'a' && c <= 'z') || (c >= 0xE0 && c <= 0xFF);} -NK_INTERN int nk_is_upper(int c){return (c >= 'A' && c <= 'Z') || (c >= 0xC0 && c <= 0xDF);} -NK_INTERN int nk_to_upper(int c) {return (c >= 'a' && c <= 'z') ? (c - ('a' - 'A')) : c;} -NK_INTERN int nk_to_lower(int c) {return (c >= 'A' && c <= 'Z') ? (c - ('a' + 'A')) : c;} - -NK_INTERN void* -nk_memcopy(void *dst0, const void *src0, nk_size length) -{ - nk_ptr t; - char *dst = (char*)dst0; - const char *src = (const char*)src0; - if (length == 0 || dst == src) - goto done; - - #define nk_word int - #define nk_wsize sizeof(nk_word) - #define nk_wmask (nk_wsize-1) - #define NK_TLOOP(s) if (t) NK_TLOOP1(s) - #define NK_TLOOP1(s) do { s; } while (--t) - - if (dst < src) { - t = (nk_ptr)src; /* only need low bits */ - if ((t | (nk_ptr)dst) & nk_wmask) { - if ((t ^ (nk_ptr)dst) & nk_wmask || length < nk_wsize) - t = length; - else - t = nk_wsize - (t & nk_wmask); - length -= t; - NK_TLOOP1(*dst++ = *src++); - } - t = length / nk_wsize; - NK_TLOOP(*(nk_word*)(void*)dst = *(const nk_word*)(const void*)src; - src += nk_wsize; dst += nk_wsize); - t = length & nk_wmask; - NK_TLOOP(*dst++ = *src++); - } else { - src += length; - dst += length; - t = (nk_ptr)src; - if ((t | (nk_ptr)dst) & nk_wmask) { - if ((t ^ (nk_ptr)dst) & nk_wmask || length <= nk_wsize) - t = length; - else - t &= nk_wmask; - length -= t; - NK_TLOOP1(*--dst = *--src); - } - t = length / nk_wsize; - NK_TLOOP(src -= nk_wsize; dst -= nk_wsize; - *(nk_word*)(void*)dst = *(const nk_word*)(const void*)src); - t = length & nk_wmask; - NK_TLOOP(*--dst = *--src); - } - #undef nk_word - #undef nk_wsize - #undef nk_wmask - #undef NK_TLOOP - #undef NK_TLOOP1 -done: - return (dst0); -} - -NK_INTERN void -nk_memset(void *ptr, int c0, nk_size size) -{ - #define nk_word unsigned - #define nk_wsize sizeof(nk_word) - #define nk_wmask (nk_wsize - 1) - nk_byte *dst = (nk_byte*)ptr; - unsigned c = 0; - nk_size t = 0; - - if ((c = (nk_byte)c0) != 0) { - c = (c << 8) | c; /* at least 16-bits */ - if (sizeof(unsigned int) > 2) - c = (c << 16) | c; /* at least 32-bits*/ - } - - /* too small of a word count */ - dst = (nk_byte*)ptr; - if (size < 3 * nk_wsize) { - while (size--) *dst++ = (nk_byte)c0; - return; - } - - /* align destination */ - if ((t = NK_PTR_TO_UINT(dst) & nk_wmask) != 0) { - t = nk_wsize -t; - size -= t; - do { - *dst++ = (nk_byte)c0; - } while (--t != 0); - } - - /* fill word */ - t = size / nk_wsize; - do { - *(nk_word*)((void*)dst) = c; - dst += nk_wsize; - } while (--t != 0); - - /* fill trailing bytes */ - t = (size & nk_wmask); - if (t != 0) { - do { - *dst++ = (nk_byte)c0; - } while (--t != 0); - } - - #undef nk_word - #undef nk_wsize - #undef nk_wmask -} - -NK_INTERN void -nk_zero(void *ptr, nk_size size) -{ - NK_ASSERT(ptr); - NK_MEMSET(ptr, 0, size); -} - -NK_API int -nk_strlen(const char *str) -{ - int siz = 0; - NK_ASSERT(str); - while (str && *str++ != '\0') siz++; - return siz; -} - -NK_API int -nk_strtoi(const char *str, const char **endptr) -{ - int neg = 1; - const char *p = str; - int value = 0; - - NK_ASSERT(str); - if (!str) return 0; - - /* skip whitespace */ - while (*p == ' ') p++; - if (*p == '-') { - neg = -1; - p++; - } - while (*p && *p >= '0' && *p <= '9') { - value = value * 10 + (int) (*p - '0'); - p++; - } - if (endptr) - *endptr = p; - return neg*value; -} - -NK_API double -nk_strtod(const char *str, const char **endptr) -{ - double m; - double neg = 1.0; - const char *p = str; - double value = 0; - double number = 0; - - NK_ASSERT(str); - if (!str) return 0; - - /* skip whitespace */ - while (*p == ' ') p++; - if (*p == '-') { - neg = -1.0; - p++; - } - - while (*p && *p != '.' && *p != 'e') { - value = value * 10.0 + (double) (*p - '0'); - p++; - } - - if (*p == '.') { - p++; - for(m = 0.1; *p && *p != 'e'; p++ ) { - value = value + (double) (*p - '0') * m; - m *= 0.1; - } - } - if (*p == 'e') { - int i, pow, div; - p++; - if (*p == '-') { - div = nk_true; - p++; - } else if (*p == '+') { - div = nk_false; - p++; - } else div = nk_false; - - for (pow = 0; *p; p++) - pow = pow * 10 + (int) (*p - '0'); - - for (m = 1.0, i = 0; i < pow; i++) - m *= 10.0; - - if (div) - value /= m; - else value *= m; - } - number = value * neg; - if (endptr) - *endptr = p; - return number; -} - -NK_API float -nk_strtof(const char *str, const char **endptr) -{ - float float_value; - double double_value; - double_value = NK_STRTOD(str, endptr); - float_value = (float)double_value; - return float_value; -} - -NK_API int -nk_stricmp(const char *s1, const char *s2) -{ - nk_int c1,c2,d; - do { - c1 = *s1++; - c2 = *s2++; - d = c1 - c2; - while (d) { - if (c1 <= 'Z' && c1 >= 'A') { - d += ('a' - 'A'); - if (!d) break; - } - if (c2 <= 'Z' && c2 >= 'A') { - d -= ('a' - 'A'); - if (!d) break; - } - return ((d >= 0) << 1) - 1; - } - } while (c1); - return 0; -} - -NK_API int -nk_stricmpn(const char *s1, const char *s2, int n) -{ - int c1,c2,d; - NK_ASSERT(n >= 0); - do { - c1 = *s1++; - c2 = *s2++; - if (!n--) return 0; - - d = c1 - c2; - while (d) { - if (c1 <= 'Z' && c1 >= 'A') { - d += ('a' - 'A'); - if (!d) break; - } - if (c2 <= 'Z' && c2 >= 'A') { - d -= ('a' - 'A'); - if (!d) break; - } - return ((d >= 0) << 1) - 1; - } - } while (c1); - return 0; -} - -NK_INTERN int -nk_str_match_here(const char *regexp, const char *text) -{ - if (regexp[0] == '\0') - return 1; - if (regexp[1] == '*') - return nk_str_match_star(regexp[0], regexp+2, text); - if (regexp[0] == '$' && regexp[1] == '\0') - return *text == '\0'; - if (*text!='\0' && (regexp[0]=='.' || regexp[0]==*text)) - return nk_str_match_here(regexp+1, text+1); - return 0; -} - -NK_INTERN int -nk_str_match_star(int c, const char *regexp, const char *text) -{ - do {/* a '* matches zero or more instances */ - if (nk_str_match_here(regexp, text)) - return 1; - } while (*text != '\0' && (*text++ == c || c == '.')); - return 0; -} - -NK_API int -nk_strfilter(const char *text, const char *regexp) -{ - /* - c matches any literal character c - . matches any single character - ^ matches the beginning of the input string - $ matches the end of the input string - * matches zero or more occurrences of the previous character*/ - if (regexp[0] == '^') - return nk_str_match_here(regexp+1, text); - do { /* must look even if string is empty */ - if (nk_str_match_here(regexp, text)) - return 1; - } while (*text++ != '\0'); - return 0; -} - -NK_API int -nk_strmatch_fuzzy_text(const char *str, int str_len, - const char *pattern, int *out_score) -{ - /* Returns true if each character in pattern is found sequentially within str - * if found then out_score is also set. Score value has no intrinsic meaning. - * Range varies with pattern. Can only compare scores with same search pattern. */ - - /* bonus for adjacent matches */ - #define NK_ADJACENCY_BONUS 5 - /* bonus if match occurs after a separator */ - #define NK_SEPARATOR_BONUS 10 - /* bonus if match is uppercase and prev is lower */ - #define NK_CAMEL_BONUS 10 - /* penalty applied for every letter in str before the first match */ - #define NK_LEADING_LETTER_PENALTY (-3) - /* maximum penalty for leading letters */ - #define NK_MAX_LEADING_LETTER_PENALTY (-9) - /* penalty for every letter that doesn't matter */ - #define NK_UNMATCHED_LETTER_PENALTY (-1) - - /* loop variables */ - int score = 0; - char const * pattern_iter = pattern; - int str_iter = 0; - int prev_matched = nk_false; - int prev_lower = nk_false; - /* true so if first letter match gets separator bonus*/ - int prev_separator = nk_true; - - /* use "best" matched letter if multiple string letters match the pattern */ - char const * best_letter = 0; - int best_letter_score = 0; - - /* loop over strings */ - NK_ASSERT(str); - NK_ASSERT(pattern); - if (!str || !str_len || !pattern) return 0; - while (str_iter < str_len) - { - const char pattern_letter = *pattern_iter; - const char str_letter = str[str_iter]; - - int next_match = *pattern_iter != '\0' && - nk_to_lower(pattern_letter) == nk_to_lower(str_letter); - int rematch = best_letter && nk_to_upper(*best_letter) == nk_to_upper(str_letter); - - int advanced = next_match && best_letter; - int pattern_repeat = best_letter && *pattern_iter != '\0'; - pattern_repeat = pattern_repeat && - nk_to_lower(*best_letter) == nk_to_lower(pattern_letter); - - if (advanced || pattern_repeat) { - score += best_letter_score; - best_letter = 0; - best_letter_score = 0; - } - - if (next_match || rematch) - { - int new_score = 0; - /* Apply penalty for each letter before the first pattern match */ - if (pattern_iter == pattern) { - int count = (int)(&str[str_iter] - str); - int penalty = NK_LEADING_LETTER_PENALTY * count; - if (penalty < NK_MAX_LEADING_LETTER_PENALTY) - penalty = NK_MAX_LEADING_LETTER_PENALTY; - - score += penalty; - } - - /* apply bonus for consecutive bonuses */ - if (prev_matched) - new_score += NK_ADJACENCY_BONUS; - - /* apply bonus for matches after a separator */ - if (prev_separator) - new_score += NK_SEPARATOR_BONUS; - - /* apply bonus across camel case boundaries */ - if (prev_lower && nk_is_upper(str_letter)) - new_score += NK_CAMEL_BONUS; - - /* update pattern iter IFF the next pattern letter was matched */ - if (next_match) - ++pattern_iter; - - /* update best letter in str which may be for a "next" letter or a rematch */ - if (new_score >= best_letter_score) { - /* apply penalty for now skipped letter */ - if (best_letter != 0) - score += NK_UNMATCHED_LETTER_PENALTY; - - best_letter = &str[str_iter]; - best_letter_score = new_score; - } - prev_matched = nk_true; - } else { - score += NK_UNMATCHED_LETTER_PENALTY; - prev_matched = nk_false; - } - - /* separators should be more easily defined */ - prev_lower = nk_is_lower(str_letter) != 0; - prev_separator = str_letter == '_' || str_letter == ' '; - - ++str_iter; - } - - /* apply score for last match */ - if (best_letter) - score += best_letter_score; - - /* did not match full pattern */ - if (*pattern_iter != '\0') - return nk_false; - - if (out_score) - *out_score = score; - return nk_true; -} - -NK_API int -nk_strmatch_fuzzy_string(char const *str, char const *pattern, int *out_score) -{return nk_strmatch_fuzzy_text(str, nk_strlen(str), pattern, out_score);} - -NK_INTERN int -nk_string_float_limit(char *string, int prec) -{ - int dot = 0; - char *c = string; - while (*c) { - if (*c == '.') { - dot = 1; - c++; - continue; - } - if (dot == (prec+1)) { - *c = 0; - break; - } - if (dot > 0) dot++; - c++; - } - return (int)(c - string); -} - -NK_INTERN double -nk_pow(double x, int n) -{ - /* check the sign of n */ - double r = 1; - int plus = n >= 0; - n = (plus) ? n : -n; - while (n > 0) { - if ((n & 1) == 1) - r *= x; - n /= 2; - x *= x; - } - return plus ? r : 1.0 / r; -} - -NK_INTERN int -nk_ifloord(double x) -{ - x = (double)((int)x - ((x < 0.0) ? 1 : 0)); - return (int)x; -} - -NK_INTERN int -nk_ifloorf(float x) -{ - x = (float)((int)x - ((x < 0.0f) ? 1 : 0)); - return (int)x; -} - -NK_INTERN int -nk_iceilf(float x) -{ - if (x >= 0) { - int i = (int)x; - return (x > i) ? i+1: i; - } else { - int t = (int)x; - float r = x - (float)t; - return (r > 0.0f) ? t+1: t; - } -} - -NK_INTERN int -nk_log10(double n) -{ - int neg; - int ret; - int exp = 0; - - neg = (n < 0) ? 1 : 0; - ret = (neg) ? (int)-n : (int)n; - while ((ret / 10) > 0) { - ret /= 10; - exp++; - } - if (neg) exp = -exp; - return exp; -} - -NK_INTERN void -nk_strrev_ascii(char *s) -{ - int len = nk_strlen(s); - int end = len / 2; - int i = 0; - char t; - for (; i < end; ++i) { - t = s[i]; - s[i] = s[len - 1 - i]; - s[len -1 - i] = t; - } -} - -NK_INTERN char* -nk_itoa(char *s, long n) -{ - long i = 0; - if (n == 0) { - s[i++] = '0'; - s[i] = 0; - return s; - } - if (n < 0) { - s[i++] = '-'; - n = -n; - } - while (n > 0) { - s[i++] = (char)('0' + (n % 10)); - n /= 10; - } - s[i] = 0; - if (s[0] == '-') - ++s; - - nk_strrev_ascii(s); - return s; -} - -NK_INTERN char* -nk_dtoa(char *s, double n) -{ - int useExp = 0; - int digit = 0, m = 0, m1 = 0; - char *c = s; - int neg = 0; - - NK_ASSERT(s); - if (!s) return 0; - - if (n == 0.0) { - s[0] = '0'; s[1] = '\0'; - return s; - } - - neg = (n < 0); - if (neg) n = -n; - - /* calculate magnitude */ - m = nk_log10(n); - useExp = (m >= 14 || (neg && m >= 9) || m <= -9); - if (neg) *(c++) = '-'; - - /* set up for scientific notation */ - if (useExp) { - if (m < 0) - m -= 1; - n = n / (double)nk_pow(10.0, m); - m1 = m; - m = 0; - } - if (m < 1.0) { - m = 0; - } - - /* convert the number */ - while (n > NK_FLOAT_PRECISION || m >= 0) { - double weight = nk_pow(10.0, m); - if (weight > 0) { - double t = (double)n / weight; - digit = nk_ifloord(t); - n -= ((double)digit * weight); - *(c++) = (char)('0' + (char)digit); - } - if (m == 0 && n > 0) - *(c++) = '.'; - m--; - } - - if (useExp) { - /* convert the exponent */ - int i, j; - *(c++) = 'e'; - if (m1 > 0) { - *(c++) = '+'; - } else { - *(c++) = '-'; - m1 = -m1; - } - m = 0; - while (m1 > 0) { - *(c++) = (char)('0' + (char)(m1 % 10)); - m1 /= 10; - m++; - } - c -= m; - for (i = 0, j = m-1; i= buf_size) break; - iter++; - - /* flag arguments */ - while (*iter) { - if (*iter == '-') flag |= NK_ARG_FLAG_LEFT; - else if (*iter == '+') flag |= NK_ARG_FLAG_PLUS; - else if (*iter == ' ') flag |= NK_ARG_FLAG_SPACE; - else if (*iter == '#') flag |= NK_ARG_FLAG_NUM; - else if (*iter == '0') flag |= NK_ARG_FLAG_ZERO; - else break; - iter++; - } - - /* width argument */ - width = NK_DEFAULT; - if (*iter >= '1' && *iter <= '9') { - const char *end; - width = nk_strtoi(iter, &end); - if (end == iter) - width = -1; - else iter = end; - } else if (*iter == '*') { - width = va_arg(args, int); - iter++; - } - - /* precision argument */ - precision = NK_DEFAULT; - if (*iter == '.') { - iter++; - if (*iter == '*') { - precision = va_arg(args, int); - iter++; - } else { - const char *end; - precision = nk_strtoi(iter, &end); - if (end == iter) - precision = -1; - else iter = end; - } - } - - /* length modifier */ - if (*iter == 'h') { - if (*(iter+1) == 'h') { - arg_type = NK_ARG_TYPE_CHAR; - iter++; - } else arg_type = NK_ARG_TYPE_SHORT; - iter++; - } else if (*iter == 'l') { - arg_type = NK_ARG_TYPE_LONG; - iter++; - } else arg_type = NK_ARG_TYPE_DEFAULT; - - /* specifier */ - if (*iter == '%') { - NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT); - NK_ASSERT(precision == NK_DEFAULT); - NK_ASSERT(width == NK_DEFAULT); - if (len < buf_size) - buf[len++] = '%'; - } else if (*iter == 's') { - /* string */ - const char *str = va_arg(args, const char*); - NK_ASSERT(str != buf && "buffer and argument are not allowed to overlap!"); - NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT); - NK_ASSERT(precision == NK_DEFAULT); - NK_ASSERT(width == NK_DEFAULT); - if (str == buf) return -1; - while (str && *str && len < buf_size) - buf[len++] = *str++; - } else if (*iter == 'n') { - /* current length callback */ - signed int *n = va_arg(args, int*); - NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT); - NK_ASSERT(precision == NK_DEFAULT); - NK_ASSERT(width == NK_DEFAULT); - if (n) *n = len; - } else if (*iter == 'c' || *iter == 'i' || *iter == 'd') { - /* signed integer */ - long value = 0; - const char *num_iter; - int num_len, num_print, padding; - int cur_precision = NK_MAX(precision, 1); - int cur_width = NK_MAX(width, 0); - - /* retrieve correct value type */ - if (arg_type == NK_ARG_TYPE_CHAR) - value = (signed char)va_arg(args, int); - else if (arg_type == NK_ARG_TYPE_SHORT) - value = (signed short)va_arg(args, int); - else if (arg_type == NK_ARG_TYPE_LONG) - value = va_arg(args, signed long); - else if (*iter == 'c') - value = (unsigned char)va_arg(args, int); - else value = va_arg(args, signed int); - - /* convert number to string */ - nk_itoa(number_buffer, value); - num_len = nk_strlen(number_buffer); - padding = NK_MAX(cur_width - NK_MAX(cur_precision, num_len), 0); - if ((flag & NK_ARG_FLAG_PLUS) || (flag & NK_ARG_FLAG_SPACE)) - padding = NK_MAX(padding-1, 0); - - /* fill left padding up to a total of `width` characters */ - if (!(flag & NK_ARG_FLAG_LEFT)) { - while (padding-- > 0 && (len < buf_size)) { - if ((flag & NK_ARG_FLAG_ZERO) && (precision == NK_DEFAULT)) - buf[len++] = '0'; - else buf[len++] = ' '; - } - } - - /* copy string value representation into buffer */ - if ((flag & NK_ARG_FLAG_PLUS) && value >= 0 && len < buf_size) - buf[len++] = '+'; - else if ((flag & NK_ARG_FLAG_SPACE) && value >= 0 && len < buf_size) - buf[len++] = ' '; - - /* fill up to precision number of digits with '0' */ - num_print = NK_MAX(cur_precision, num_len); - while (precision && (num_print > num_len) && (len < buf_size)) { - buf[len++] = '0'; - num_print--; - } - - /* copy string value representation into buffer */ - num_iter = number_buffer; - while (precision && *num_iter && len < buf_size) - buf[len++] = *num_iter++; - - /* fill right padding up to width characters */ - if (flag & NK_ARG_FLAG_LEFT) { - while ((padding-- > 0) && (len < buf_size)) - buf[len++] = ' '; - } - } else if (*iter == 'o' || *iter == 'x' || *iter == 'X' || *iter == 'u') { - /* unsigned integer */ - unsigned long value = 0; - int num_len = 0, num_print, padding = 0; - int cur_precision = NK_MAX(precision, 1); - int cur_width = NK_MAX(width, 0); - unsigned int base = (*iter == 'o') ? 8: (*iter == 'u')? 10: 16; - - /* print oct/hex/dec value */ - const char *upper_output_format = "0123456789ABCDEF"; - const char *lower_output_format = "0123456789abcdef"; - const char *output_format = (*iter == 'x') ? - lower_output_format: upper_output_format; - - /* retrieve correct value type */ - if (arg_type == NK_ARG_TYPE_CHAR) - value = (unsigned char)va_arg(args, int); - else if (arg_type == NK_ARG_TYPE_SHORT) - value = (unsigned short)va_arg(args, int); - else if (arg_type == NK_ARG_TYPE_LONG) - value = va_arg(args, unsigned long); - else value = va_arg(args, unsigned int); - - do { - /* convert decimal number into hex/oct number */ - int digit = output_format[value % base]; - if (num_len < NK_MAX_NUMBER_BUFFER) - number_buffer[num_len++] = (char)digit; - value /= base; - } while (value > 0); - - num_print = NK_MAX(cur_precision, num_len); - padding = NK_MAX(cur_width - NK_MAX(cur_precision, num_len), 0); - if (flag & NK_ARG_FLAG_NUM) - padding = NK_MAX(padding-1, 0); - - /* fill left padding up to a total of `width` characters */ - if (!(flag & NK_ARG_FLAG_LEFT)) { - while ((padding-- > 0) && (len < buf_size)) { - if ((flag & NK_ARG_FLAG_ZERO) && (precision == NK_DEFAULT)) - buf[len++] = '0'; - else buf[len++] = ' '; - } - } - - /* fill up to precision number of digits */ - if (num_print && (flag & NK_ARG_FLAG_NUM)) { - if ((*iter == 'o') && (len < buf_size)) { - buf[len++] = '0'; - } else if ((*iter == 'x') && ((len+1) < buf_size)) { - buf[len++] = '0'; - buf[len++] = 'x'; - } else if ((*iter == 'X') && ((len+1) < buf_size)) { - buf[len++] = '0'; - buf[len++] = 'X'; - } - } - while (precision && (num_print > num_len) && (len < buf_size)) { - buf[len++] = '0'; - num_print--; - } - - /* reverse number direction */ - while (num_len > 0) { - if (precision && (len < buf_size)) - buf[len++] = number_buffer[num_len-1]; - num_len--; - } - - /* fill right padding up to width characters */ - if (flag & NK_ARG_FLAG_LEFT) { - while ((padding-- > 0) && (len < buf_size)) - buf[len++] = ' '; - } - } else if (*iter == 'f') { - /* floating point */ - const char *num_iter; - int cur_precision = (precision < 0) ? 6: precision; - int prefix, cur_width = NK_MAX(width, 0); - double value = va_arg(args, double); - int num_len = 0, frac_len = 0, dot = 0; - int padding = 0; - - NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT); - NK_DTOA(number_buffer, value); - num_len = nk_strlen(number_buffer); - - /* calculate padding */ - num_iter = number_buffer; - while (*num_iter && *num_iter != '.') - num_iter++; - - prefix = (*num_iter == '.')?(int)(num_iter - number_buffer)+1:0; - padding = NK_MAX(cur_width - (prefix + NK_MIN(cur_precision, num_len - prefix)) , 0); - if ((flag & NK_ARG_FLAG_PLUS) || (flag & NK_ARG_FLAG_SPACE)) - padding = NK_MAX(padding-1, 0); - - /* fill left padding up to a total of `width` characters */ - if (!(flag & NK_ARG_FLAG_LEFT)) { - while (padding-- > 0 && (len < buf_size)) { - if (flag & NK_ARG_FLAG_ZERO) - buf[len++] = '0'; - else buf[len++] = ' '; - } - } - - /* copy string value representation into buffer */ - num_iter = number_buffer; - if ((flag & NK_ARG_FLAG_PLUS) && (value >= 0) && (len < buf_size)) - buf[len++] = '+'; - else if ((flag & NK_ARG_FLAG_SPACE) && (value >= 0) && (len < buf_size)) - buf[len++] = ' '; - while (*num_iter) { - if (dot) frac_len++; - if (len < buf_size) - buf[len++] = *num_iter; - if (*num_iter == '.') dot = 1; - if (frac_len >= cur_precision) break; - num_iter++; - } - - /* fill number up to precision */ - while (frac_len < cur_precision) { - if (!dot && len < buf_size) { - buf[len++] = '.'; - dot = 1; - } - if (len < buf_size) - buf[len++] = '0'; - frac_len++; - } - - /* fill right padding up to width characters */ - if (flag & NK_ARG_FLAG_LEFT) { - while ((padding-- > 0) && (len < buf_size)) - buf[len++] = ' '; - } - } else { - /* Specifier not supported: g,G,e,E,p,z */ - NK_ASSERT(0 && "specifier is not supported!"); - return result; - } - } - buf[(len >= buf_size)?(buf_size-1):len] = 0; - result = (len >= buf_size)?-1:len; - return result; -} -#endif - -NK_INTERN int -nk_strfmt(char *buf, int buf_size, const char *fmt, va_list args) -{ - int result = -1; - NK_ASSERT(buf); - NK_ASSERT(buf_size); - if (!buf || !buf_size || !fmt) return 0; -#ifdef NK_INCLUDE_STANDARD_IO - result = NK_VSNPRINTF(buf, (nk_size)buf_size, fmt, args); - result = (result >= buf_size) ? -1: result; - buf[buf_size-1] = 0; -#else - result = nk_vsnprintf(buf, buf_size, fmt, args); -#endif - return result; -} -#endif - -NK_API nk_hash -nk_murmur_hash(const void * key, int len, nk_hash seed) -{ - /* 32-Bit MurmurHash3: https://code.google.com/p/smhasher/wiki/MurmurHash3*/ - #define NK_ROTL(x,r) ((x) << (r) | ((x) >> (32 - r))) - union {const nk_uint *i; const nk_byte *b;} conv = {0}; - const nk_byte *data = (const nk_byte*)key; - const int nblocks = len/4; - nk_uint h1 = seed; - const nk_uint c1 = 0xcc9e2d51; - const nk_uint c2 = 0x1b873593; - const nk_byte *tail; - const nk_uint *blocks; - nk_uint k1; - int i; - - /* body */ - if (!key) return 0; - conv.b = (data + nblocks*4); - blocks = (const nk_uint*)conv.i; - for (i = -nblocks; i; ++i) { - k1 = blocks[i]; - k1 *= c1; - k1 = NK_ROTL(k1,15); - k1 *= c2; - - h1 ^= k1; - h1 = NK_ROTL(h1,13); - h1 = h1*5+0xe6546b64; - } - - /* tail */ - tail = (const nk_byte*)(data + nblocks*4); - k1 = 0; - switch (len & 3) { - case 3: k1 ^= (nk_uint)(tail[2] << 16); /* fallthrough */ - case 2: k1 ^= (nk_uint)(tail[1] << 8u); /* fallthrough */ - case 1: k1 ^= tail[0]; - k1 *= c1; - k1 = NK_ROTL(k1,15); - k1 *= c2; - h1 ^= k1; - break; - default: break; - } - - /* finalization */ - h1 ^= (nk_uint)len; - /* fmix32 */ - h1 ^= h1 >> 16; - h1 *= 0x85ebca6b; - h1 ^= h1 >> 13; - h1 *= 0xc2b2ae35; - h1 ^= h1 >> 16; - - #undef NK_ROTL - return h1; -} - -#ifdef NK_INCLUDE_STANDARD_IO -NK_INTERN char* -nk_file_load(const char* path, nk_size* siz, struct nk_allocator *alloc) -{ - char *buf; - FILE *fd; - long ret; - - NK_ASSERT(path); - NK_ASSERT(siz); - NK_ASSERT(alloc); - if (!path || !siz || !alloc) - return 0; - - fd = fopen(path, "rb"); - if (!fd) return 0; - fseek(fd, 0, SEEK_END); - ret = ftell(fd); - if (ret < 0) { - fclose(fd); - return 0; - } - *siz = (nk_size)ret; - fseek(fd, 0, SEEK_SET); - buf = (char*)alloc->alloc(alloc->userdata,0, *siz); - NK_ASSERT(buf); - if (!buf) { - fclose(fd); - return 0; - } - *siz = (nk_size)fread(buf, 1,*siz, fd); - fclose(fd); - return buf; -} -#endif - -/* - * ============================================================== - * - * COLOR - * - * =============================================================== - */ -NK_INTERN int -nk_parse_hex(const char *p, int length) -{ - int i = 0; - int len = 0; - while (len < length) { - i <<= 4; - if (p[len] >= 'a' && p[len] <= 'f') - i += ((p[len] - 'a') + 10); - else if (p[len] >= 'A' && p[len] <= 'F') - i += ((p[len] - 'A') + 10); - else i += (p[len] - '0'); - len++; - } - return i; -} - -NK_API struct nk_color -nk_rgba(int r, int g, int b, int a) -{ - struct nk_color ret; - ret.r = (nk_byte)NK_CLAMP(0, r, 255); - ret.g = (nk_byte)NK_CLAMP(0, g, 255); - ret.b = (nk_byte)NK_CLAMP(0, b, 255); - ret.a = (nk_byte)NK_CLAMP(0, a, 255); - return ret; -} - -NK_API struct nk_color -nk_rgb_hex(const char *rgb) -{ - struct nk_color col; - const char *c = rgb; - if (*c == '#') c++; - col.r = (nk_byte)nk_parse_hex(c, 2); - col.g = (nk_byte)nk_parse_hex(c+2, 2); - col.b = (nk_byte)nk_parse_hex(c+4, 2); - col.a = 255; - return col; -} - -NK_API struct nk_color -nk_rgba_hex(const char *rgb) -{ - struct nk_color col; - const char *c = rgb; - if (*c == '#') c++; - col.r = (nk_byte)nk_parse_hex(c, 2); - col.g = (nk_byte)nk_parse_hex(c+2, 2); - col.b = (nk_byte)nk_parse_hex(c+4, 2); - col.a = (nk_byte)nk_parse_hex(c+6, 2); - return col; -} - -NK_API void -nk_color_hex_rgba(char *output, struct nk_color col) -{ - #define NK_TO_HEX(i) ((i) <= 9 ? '0' + (i): 'A' - 10 + (i)) - output[0] = (char)NK_TO_HEX((col.r & 0xF0) >> 4); - output[1] = (char)NK_TO_HEX((col.r & 0x0F)); - output[2] = (char)NK_TO_HEX((col.g & 0xF0) >> 4); - output[3] = (char)NK_TO_HEX((col.g & 0x0F)); - output[4] = (char)NK_TO_HEX((col.b & 0xF0) >> 4); - output[5] = (char)NK_TO_HEX((col.b & 0x0F)); - output[6] = (char)NK_TO_HEX((col.a & 0xF0) >> 4); - output[7] = (char)NK_TO_HEX((col.a & 0x0F)); - output[8] = '\0'; - #undef NK_TO_HEX -} - -NK_API void -nk_color_hex_rgb(char *output, struct nk_color col) -{ - #define NK_TO_HEX(i) ((i) <= 9 ? '0' + (i): 'A' - 10 + (i)) - output[0] = (char)NK_TO_HEX((col.r & 0xF0) >> 4); - output[1] = (char)NK_TO_HEX((col.r & 0x0F)); - output[2] = (char)NK_TO_HEX((col.g & 0xF0) >> 4); - output[3] = (char)NK_TO_HEX((col.g & 0x0F)); - output[4] = (char)NK_TO_HEX((col.b & 0xF0) >> 4); - output[5] = (char)NK_TO_HEX((col.b & 0x0F)); - output[6] = '\0'; - #undef NK_TO_HEX -} - -NK_API struct nk_color -nk_rgba_iv(const int *c) -{ - return nk_rgba(c[0], c[1], c[2], c[3]); -} - -NK_API struct nk_color -nk_rgba_bv(const nk_byte *c) -{ - return nk_rgba(c[0], c[1], c[2], c[3]); -} - -NK_API struct nk_color -nk_rgb(int r, int g, int b) -{ - struct nk_color ret; - ret.r = (nk_byte)NK_CLAMP(0, r, 255); - ret.g = (nk_byte)NK_CLAMP(0, g, 255); - ret.b = (nk_byte)NK_CLAMP(0, b, 255); - ret.a = (nk_byte)255; - return ret; -} - -NK_API struct nk_color -nk_rgb_iv(const int *c) -{ - return nk_rgb(c[0], c[1], c[2]); -} - -NK_API struct nk_color -nk_rgb_bv(const nk_byte* c) -{ - return nk_rgb(c[0], c[1], c[2]); -} - -NK_API struct nk_color -nk_rgba_u32(nk_uint in) -{ - struct nk_color ret; - ret.r = (in & 0xFF); - ret.g = ((in >> 8) & 0xFF); - ret.b = ((in >> 16) & 0xFF); - ret.a = (nk_byte)((in >> 24) & 0xFF); - return ret; -} - -NK_API struct nk_color -nk_rgba_f(float r, float g, float b, float a) -{ - struct nk_color ret; - ret.r = (nk_byte)(NK_SATURATE(r) * 255.0f); - ret.g = (nk_byte)(NK_SATURATE(g) * 255.0f); - ret.b = (nk_byte)(NK_SATURATE(b) * 255.0f); - ret.a = (nk_byte)(NK_SATURATE(a) * 255.0f); - return ret; -} - -NK_API struct nk_color -nk_rgba_fv(const float *c) -{ - return nk_rgba_f(c[0], c[1], c[2], c[3]); -} - -NK_API struct nk_color -nk_rgba_cf(struct nk_colorf c) -{ - return nk_rgba_f(c.r, c.g, c.b, c.a); -} - -NK_API struct nk_color -nk_rgb_f(float r, float g, float b) -{ - struct nk_color ret; - ret.r = (nk_byte)(NK_SATURATE(r) * 255.0f); - ret.g = (nk_byte)(NK_SATURATE(g) * 255.0f); - ret.b = (nk_byte)(NK_SATURATE(b) * 255.0f); - ret.a = 255; - return ret; -} - -NK_API struct nk_color -nk_rgb_fv(const float *c) -{ - return nk_rgb_f(c[0], c[1], c[2]); -} - -NK_API struct nk_color -nk_rgb_cf(struct nk_colorf c) -{ - return nk_rgb_f(c.r, c.g, c.b); -} - -NK_API struct nk_color -nk_hsv(int h, int s, int v) -{ - return nk_hsva(h, s, v, 255); -} - -NK_API struct nk_color -nk_hsv_iv(const int *c) -{ - return nk_hsv(c[0], c[1], c[2]); -} - -NK_API struct nk_color -nk_hsv_bv(const nk_byte *c) -{ - return nk_hsv(c[0], c[1], c[2]); -} - -NK_API struct nk_color -nk_hsv_f(float h, float s, float v) -{ - return nk_hsva_f(h, s, v, 1.0f); -} - -NK_API struct nk_color -nk_hsv_fv(const float *c) -{ - return nk_hsv_f(c[0], c[1], c[2]); -} - -NK_API struct nk_color -nk_hsva(int h, int s, int v, int a) -{ - float hf = ((float)NK_CLAMP(0, h, 255)) / 255.0f; - float sf = ((float)NK_CLAMP(0, s, 255)) / 255.0f; - float vf = ((float)NK_CLAMP(0, v, 255)) / 255.0f; - float af = ((float)NK_CLAMP(0, a, 255)) / 255.0f; - return nk_hsva_f(hf, sf, vf, af); -} - -NK_API struct nk_color -nk_hsva_iv(const int *c) -{ - return nk_hsva(c[0], c[1], c[2], c[3]); -} - -NK_API struct nk_color -nk_hsva_bv(const nk_byte *c) -{ - return nk_hsva(c[0], c[1], c[2], c[3]); -} - -NK_API struct nk_colorf -nk_hsva_colorf(float h, float s, float v, float a) -{ - int i; - float p, q, t, f; - struct nk_colorf out = {0,0,0,0}; - if (s <= 0.0f) { - out.r = v; out.g = v; out.b = v; out.a = a; - return out; - } - h = h / (60.0f/360.0f); - i = (int)h; - f = h - (float)i; - p = v * (1.0f - s); - q = v * (1.0f - (s * f)); - t = v * (1.0f - s * (1.0f - f)); - - switch (i) { - case 0: default: out.r = v; out.g = t; out.b = p; break; - case 1: out.r = q; out.g = v; out.b = p; break; - case 2: out.r = p; out.g = v; out.b = t; break; - case 3: out.r = p; out.g = q; out.b = v; break; - case 4: out.r = t; out.g = p; out.b = v; break; - case 5: out.r = v; out.g = p; out.b = q; break;} - out.a = a; - return out; -} - -NK_API struct nk_colorf -nk_hsva_colorfv(float *c) -{ - return nk_hsva_colorf(c[0], c[1], c[2], c[3]); -} - -NK_API struct nk_color -nk_hsva_f(float h, float s, float v, float a) -{ - struct nk_colorf c = nk_hsva_colorf(h, s, v, a); - return nk_rgba_f(c.r, c.g, c.b, c.a); -} - -NK_API struct nk_color -nk_hsva_fv(const float *c) -{ - return nk_hsva_f(c[0], c[1], c[2], c[3]); -} - -NK_API nk_uint -nk_color_u32(struct nk_color in) -{ - nk_uint out = (nk_uint)in.r; - out |= ((nk_uint)in.g << 8); - out |= ((nk_uint)in.b << 16); - out |= ((nk_uint)in.a << 24); - return out; -} - -NK_API void -nk_color_f(float *r, float *g, float *b, float *a, struct nk_color in) -{ - NK_STORAGE const float s = 1.0f/255.0f; - *r = (float)in.r * s; - *g = (float)in.g * s; - *b = (float)in.b * s; - *a = (float)in.a * s; -} - -NK_API void -nk_color_fv(float *c, struct nk_color in) -{ - nk_color_f(&c[0], &c[1], &c[2], &c[3], in); -} - -NK_API struct nk_colorf -nk_color_cf(struct nk_color in) -{ - struct nk_colorf o; - nk_color_f(&o.r, &o.g, &o.b, &o.a, in); - return o; -} - -NK_API void -nk_color_d(double *r, double *g, double *b, double *a, struct nk_color in) -{ - NK_STORAGE const double s = 1.0/255.0; - *r = (double)in.r * s; - *g = (double)in.g * s; - *b = (double)in.b * s; - *a = (double)in.a * s; -} - -NK_API void -nk_color_dv(double *c, struct nk_color in) -{ - nk_color_d(&c[0], &c[1], &c[2], &c[3], in); -} - -NK_API void -nk_color_hsv_f(float *out_h, float *out_s, float *out_v, struct nk_color in) -{ - float a; - nk_color_hsva_f(out_h, out_s, out_v, &a, in); -} - -NK_API void -nk_color_hsv_fv(float *out, struct nk_color in) -{ - float a; - nk_color_hsva_f(&out[0], &out[1], &out[2], &a, in); -} - -NK_API void -nk_colorf_hsva_f(float *out_h, float *out_s, - float *out_v, float *out_a, struct nk_colorf in) -{ - float chroma; - float K = 0.0f; - if (in.g < in.b) { - const float t = in.g; in.g = in.b; in.b = t; - K = -1.f; - } - if (in.r < in.g) { - const float t = in.r; in.r = in.g; in.g = t; - K = -2.f/6.0f - K; - } - chroma = in.r - ((in.g < in.b) ? in.g: in.b); - *out_h = NK_ABS(K + (in.g - in.b)/(6.0f * chroma + 1e-20f)); - *out_s = chroma / (in.r + 1e-20f); - *out_v = in.r; - *out_a = in.a; - -} - -NK_API void -nk_colorf_hsva_fv(float *hsva, struct nk_colorf in) -{ - nk_colorf_hsva_f(&hsva[0], &hsva[1], &hsva[2], &hsva[3], in); -} -NK_API void -nk_color_hsva_f(float *out_h, float *out_s, - float *out_v, float *out_a, struct nk_color in) -{ - struct nk_colorf col; - nk_color_f(&col.r,&col.g,&col.b,&col.a, in); - nk_colorf_hsva_f(out_h, out_s, out_v, out_a, col); -} - -NK_API void -nk_color_hsva_fv(float *out, struct nk_color in) -{ - nk_color_hsva_f(&out[0], &out[1], &out[2], &out[3], in); -} - -NK_API void -nk_color_hsva_i(int *out_h, int *out_s, int *out_v, - int *out_a, struct nk_color in) -{ - float h,s,v,a; - nk_color_hsva_f(&h, &s, &v, &a, in); - *out_h = (nk_byte)(h * 255.0f); - *out_s = (nk_byte)(s * 255.0f); - *out_v = (nk_byte)(v * 255.0f); - *out_a = (nk_byte)(a * 255.0f); -} - -NK_API void -nk_color_hsva_iv(int *out, struct nk_color in) -{ - nk_color_hsva_i(&out[0], &out[1], &out[2], &out[3], in); -} - -NK_API void -nk_color_hsva_bv(nk_byte *out, struct nk_color in) -{ - int tmp[4]; - nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in); - out[0] = (nk_byte)tmp[0]; - out[1] = (nk_byte)tmp[1]; - out[2] = (nk_byte)tmp[2]; - out[3] = (nk_byte)tmp[3]; -} - -NK_API void -nk_color_hsva_b(nk_byte *h, nk_byte *s, nk_byte *v, nk_byte *a, struct nk_color in) -{ - int tmp[4]; - nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in); - *h = (nk_byte)tmp[0]; - *s = (nk_byte)tmp[1]; - *v = (nk_byte)tmp[2]; - *a = (nk_byte)tmp[3]; -} - -NK_API void -nk_color_hsv_i(int *out_h, int *out_s, int *out_v, struct nk_color in) -{ - int a; - nk_color_hsva_i(out_h, out_s, out_v, &a, in); -} - -NK_API void -nk_color_hsv_b(nk_byte *out_h, nk_byte *out_s, nk_byte *out_v, struct nk_color in) -{ - int tmp[4]; - nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in); - *out_h = (nk_byte)tmp[0]; - *out_s = (nk_byte)tmp[1]; - *out_v = (nk_byte)tmp[2]; -} - -NK_API void -nk_color_hsv_iv(int *out, struct nk_color in) -{ - nk_color_hsv_i(&out[0], &out[1], &out[2], in); -} - -NK_API void -nk_color_hsv_bv(nk_byte *out, struct nk_color in) -{ - int tmp[4]; - nk_color_hsv_i(&tmp[0], &tmp[1], &tmp[2], in); - out[0] = (nk_byte)tmp[0]; - out[1] = (nk_byte)tmp[1]; - out[2] = (nk_byte)tmp[2]; -} -/* - * ============================================================== - * - * IMAGE - * - * =============================================================== - */ -NK_API nk_handle -nk_handle_ptr(void *ptr) -{ - nk_handle handle = {0}; - handle.ptr = ptr; - return handle; -} - -NK_API nk_handle -nk_handle_id(int id) -{ - nk_handle handle; - nk_zero_struct(handle); - handle.id = id; - return handle; -} - -NK_API struct nk_image -nk_subimage_ptr(void *ptr, unsigned short w, unsigned short h, struct nk_rect r) -{ - struct nk_image s; - nk_zero(&s, sizeof(s)); - s.handle.ptr = ptr; - s.w = w; s.h = h; - s.region[0] = (unsigned short)r.x; - s.region[1] = (unsigned short)r.y; - s.region[2] = (unsigned short)r.w; - s.region[3] = (unsigned short)r.h; - return s; -} - -NK_API struct nk_image -nk_subimage_id(int id, unsigned short w, unsigned short h, struct nk_rect r) -{ - struct nk_image s; - nk_zero(&s, sizeof(s)); - s.handle.id = id; - s.w = w; s.h = h; - s.region[0] = (unsigned short)r.x; - s.region[1] = (unsigned short)r.y; - s.region[2] = (unsigned short)r.w; - s.region[3] = (unsigned short)r.h; - return s; -} - -NK_API struct nk_image -nk_subimage_handle(nk_handle handle, unsigned short w, unsigned short h, - struct nk_rect r) -{ - struct nk_image s; - nk_zero(&s, sizeof(s)); - s.handle = handle; - s.w = w; s.h = h; - s.region[0] = (unsigned short)r.x; - s.region[1] = (unsigned short)r.y; - s.region[2] = (unsigned short)r.w; - s.region[3] = (unsigned short)r.h; - return s; -} - -NK_API struct nk_image -nk_image_handle(nk_handle handle) -{ - struct nk_image s; - nk_zero(&s, sizeof(s)); - s.handle = handle; - s.w = 0; s.h = 0; - s.region[0] = 0; - s.region[1] = 0; - s.region[2] = 0; - s.region[3] = 0; - return s; -} - -NK_API struct nk_image -nk_image_ptr(void *ptr) -{ - struct nk_image s; - nk_zero(&s, sizeof(s)); - NK_ASSERT(ptr); - s.handle.ptr = ptr; - s.w = 0; s.h = 0; - s.region[0] = 0; - s.region[1] = 0; - s.region[2] = 0; - s.region[3] = 0; - return s; -} - -NK_API struct nk_image -nk_image_id(int id) -{ - struct nk_image s; - nk_zero(&s, sizeof(s)); - s.handle.id = id; - s.w = 0; s.h = 0; - s.region[0] = 0; - s.region[1] = 0; - s.region[2] = 0; - s.region[3] = 0; - return s; -} - -NK_API int -nk_image_is_subimage(const struct nk_image* img) -{ - NK_ASSERT(img); - return !(img->w == 0 && img->h == 0); -} - -NK_INTERN void -nk_unify(struct nk_rect *clip, const struct nk_rect *a, float x0, float y0, - float x1, float y1) -{ - NK_ASSERT(a); - NK_ASSERT(clip); - clip->x = NK_MAX(a->x, x0); - clip->y = NK_MAX(a->y, y0); - clip->w = NK_MIN(a->x + a->w, x1) - clip->x; - clip->h = NK_MIN(a->y + a->h, y1) - clip->y; - clip->w = NK_MAX(0, clip->w); - clip->h = NK_MAX(0, clip->h); -} - -NK_API void -nk_triangle_from_direction(struct nk_vec2 *result, struct nk_rect r, - float pad_x, float pad_y, enum nk_heading direction) -{ - float w_half, h_half; - NK_ASSERT(result); - - r.w = NK_MAX(2 * pad_x, r.w); - r.h = NK_MAX(2 * pad_y, r.h); - r.w = r.w - 2 * pad_x; - r.h = r.h - 2 * pad_y; - - r.x = r.x + pad_x; - r.y = r.y + pad_y; - - w_half = r.w / 2.0f; - h_half = r.h / 2.0f; - - if (direction == NK_UP) { - result[0] = nk_vec2(r.x + w_half, r.y); - result[1] = nk_vec2(r.x + r.w, r.y + r.h); - result[2] = nk_vec2(r.x, r.y + r.h); - } else if (direction == NK_RIGHT) { - result[0] = nk_vec2(r.x, r.y); - result[1] = nk_vec2(r.x + r.w, r.y + h_half); - result[2] = nk_vec2(r.x, r.y + r.h); - } else if (direction == NK_DOWN) { - result[0] = nk_vec2(r.x, r.y); - result[1] = nk_vec2(r.x + r.w, r.y); - result[2] = nk_vec2(r.x + w_half, r.y + r.h); - } else { - result[0] = nk_vec2(r.x, r.y + h_half); - result[1] = nk_vec2(r.x + r.w, r.y); - result[2] = nk_vec2(r.x + r.w, r.y + r.h); - } -} - -NK_INTERN int -nk_text_clamp(const struct nk_user_font *font, const char *text, - int text_len, float space, int *glyphs, float *text_width, - nk_rune *sep_list, int sep_count) -{ - int i = 0; - int glyph_len = 0; - float last_width = 0; - nk_rune unicode = 0; - float width = 0; - int len = 0; - int g = 0; - float s; - - int sep_len = 0; - int sep_g = 0; - float sep_width = 0; - sep_count = NK_MAX(sep_count,0); - - glyph_len = nk_utf_decode(text, &unicode, text_len); - while (glyph_len && (width < space) && (len < text_len)) { - len += glyph_len; - s = font->width(font->userdata, font->height, text, len); - for (i = 0; i < sep_count; ++i) { - if (unicode != sep_list[i]) continue; - sep_width = last_width = width; - sep_g = g+1; - sep_len = len; - break; - } - if (i == sep_count){ - last_width = sep_width = width; - sep_g = g+1; - } - width = s; - glyph_len = nk_utf_decode(&text[len], &unicode, text_len - len); - g++; - } - if (len >= text_len) { - *glyphs = g; - *text_width = last_width; - return len; - } else { - *glyphs = sep_g; - *text_width = sep_width; - return (!sep_len) ? len: sep_len; - } -} - -enum {NK_DO_NOT_STOP_ON_NEW_LINE, NK_STOP_ON_NEW_LINE}; -NK_INTERN struct nk_vec2 -nk_text_calculate_text_bounds(const struct nk_user_font *font, - const char *begin, int byte_len, float row_height, const char **remaining, - struct nk_vec2 *out_offset, int *glyphs, int op) -{ - float line_height = row_height; - struct nk_vec2 text_size = nk_vec2(0,0); - float line_width = 0.0f; - - float glyph_width; - int glyph_len = 0; - nk_rune unicode = 0; - int text_len = 0; - if (!begin || byte_len <= 0 || !font) - return nk_vec2(0,row_height); - - glyph_len = nk_utf_decode(begin, &unicode, byte_len); - if (!glyph_len) return text_size; - glyph_width = font->width(font->userdata, font->height, begin, glyph_len); - - *glyphs = 0; - while ((text_len < byte_len) && glyph_len) { - if (unicode == '\n') { - text_size.x = NK_MAX(text_size.x, line_width); - text_size.y += line_height; - line_width = 0; - *glyphs+=1; - if (op == NK_STOP_ON_NEW_LINE) - break; - - text_len++; - glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len); - continue; - } - - if (unicode == '\r') { - text_len++; - *glyphs+=1; - glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len); - continue; - } - - *glyphs = *glyphs + 1; - text_len += glyph_len; - line_width += (float)glyph_width; - glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len); - glyph_width = font->width(font->userdata, font->height, begin+text_len, glyph_len); - continue; - } - - if (text_size.x < line_width) - text_size.x = line_width; - if (out_offset) - *out_offset = nk_vec2(line_width, text_size.y + line_height); - if (line_width > 0 || text_size.y == 0.0f) - text_size.y += line_height; - if (remaining) - *remaining = begin+text_len; - return text_size; -} - -/* ============================================================== - * - * UTF-8 - * - * ===============================================================*/ -NK_GLOBAL const nk_byte nk_utfbyte[NK_UTF_SIZE+1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; -NK_GLOBAL const nk_byte nk_utfmask[NK_UTF_SIZE+1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; -NK_GLOBAL const nk_uint nk_utfmin[NK_UTF_SIZE+1] = {0, 0, 0x80, 0x800, 0x10000}; -NK_GLOBAL const nk_uint nk_utfmax[NK_UTF_SIZE+1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; - -NK_INTERN int -nk_utf_validate(nk_rune *u, int i) -{ - NK_ASSERT(u); - if (!u) return 0; - if (!NK_BETWEEN(*u, nk_utfmin[i], nk_utfmax[i]) || - NK_BETWEEN(*u, 0xD800, 0xDFFF)) - *u = NK_UTF_INVALID; - for (i = 1; *u > nk_utfmax[i]; ++i); - return i; -} - -NK_INTERN nk_rune -nk_utf_decode_byte(char c, int *i) -{ - NK_ASSERT(i); - if (!i) return 0; - for(*i = 0; *i < (int)NK_LEN(nk_utfmask); ++(*i)) { - if (((nk_byte)c & nk_utfmask[*i]) == nk_utfbyte[*i]) - return (nk_byte)(c & ~nk_utfmask[*i]); - } - return 0; -} - -NK_API int -nk_utf_decode(const char *c, nk_rune *u, int clen) -{ - int i, j, len, type=0; - nk_rune udecoded; - - NK_ASSERT(c); - NK_ASSERT(u); - - if (!c || !u) return 0; - if (!clen) return 0; - *u = NK_UTF_INVALID; - - udecoded = nk_utf_decode_byte(c[0], &len); - if (!NK_BETWEEN(len, 1, NK_UTF_SIZE)) - return 1; - - for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { - udecoded = (udecoded << 6) | nk_utf_decode_byte(c[i], &type); - if (type != 0) - return j; - } - if (j < len) - return 0; - *u = udecoded; - nk_utf_validate(u, len); - return len; -} - -NK_INTERN char -nk_utf_encode_byte(nk_rune u, int i) -{ - return (char)((nk_utfbyte[i]) | ((nk_byte)u & ~nk_utfmask[i])); -} - -NK_API int -nk_utf_encode(nk_rune u, char *c, int clen) -{ - int len, i; - len = nk_utf_validate(&u, 0); - if (clen < len || !len || len > NK_UTF_SIZE) - return 0; - - for (i = len - 1; i != 0; --i) { - c[i] = nk_utf_encode_byte(u, 0); - u >>= 6; - } - c[0] = nk_utf_encode_byte(u, len); - return len; -} - -NK_API int -nk_utf_len(const char *str, int len) -{ - const char *text; - int glyphs = 0; - int text_len; - int glyph_len; - int src_len = 0; - nk_rune unicode; - - NK_ASSERT(str); - if (!str || !len) return 0; - - text = str; - text_len = len; - glyph_len = nk_utf_decode(text, &unicode, text_len); - while (glyph_len && src_len < len) { - glyphs++; - src_len = src_len + glyph_len; - glyph_len = nk_utf_decode(text + src_len, &unicode, text_len - src_len); - } - return glyphs; -} - -NK_API const char* -nk_utf_at(const char *buffer, int length, int index, - nk_rune *unicode, int *len) -{ - int i = 0; - int src_len = 0; - int glyph_len = 0; - const char *text; - int text_len; - - NK_ASSERT(buffer); - NK_ASSERT(unicode); - NK_ASSERT(len); - - if (!buffer || !unicode || !len) return 0; - if (index < 0) { - *unicode = NK_UTF_INVALID; - *len = 0; - return 0; - } - - text = buffer; - text_len = length; - glyph_len = nk_utf_decode(text, unicode, text_len); - while (glyph_len) { - if (i == index) { - *len = glyph_len; - break; - } - - i++; - src_len = src_len + glyph_len; - glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len); - } - if (i != index) return 0; - return buffer + src_len; -} - -/* ============================================================== - * - * BUFFER - * - * ===============================================================*/ -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_INTERN void* nk_malloc(nk_handle unused, void *old,nk_size size) -{NK_UNUSED(unused); NK_UNUSED(old); return malloc(size);} -NK_INTERN void nk_mfree(nk_handle unused, void *ptr) -{NK_UNUSED(unused); free(ptr);} - -NK_API void -nk_buffer_init_default(struct nk_buffer *buffer) -{ - struct nk_allocator alloc; - alloc.userdata.ptr = 0; - alloc.alloc = nk_malloc; - alloc.free = nk_mfree; - nk_buffer_init(buffer, &alloc, NK_BUFFER_DEFAULT_INITIAL_SIZE); -} -#endif - -NK_API void -nk_buffer_init(struct nk_buffer *b, const struct nk_allocator *a, - nk_size initial_size) -{ - NK_ASSERT(b); - NK_ASSERT(a); - NK_ASSERT(initial_size); - if (!b || !a || !initial_size) return; - - nk_zero(b, sizeof(*b)); - b->type = NK_BUFFER_DYNAMIC; - b->memory.ptr = a->alloc(a->userdata,0, initial_size); - b->memory.size = initial_size; - b->size = initial_size; - b->grow_factor = 2.0f; - b->pool = *a; -} - -NK_API void -nk_buffer_init_fixed(struct nk_buffer *b, void *m, nk_size size) -{ - NK_ASSERT(b); - NK_ASSERT(m); - NK_ASSERT(size); - if (!b || !m || !size) return; - - nk_zero(b, sizeof(*b)); - b->type = NK_BUFFER_FIXED; - b->memory.ptr = m; - b->memory.size = size; - b->size = size; -} - -NK_INTERN void* -nk_buffer_align(void *unaligned, nk_size align, nk_size *alignment, - enum nk_buffer_allocation_type type) -{ - void *memory = 0; - switch (type) { - default: - case NK_BUFFER_MAX: - case NK_BUFFER_FRONT: - if (align) { - memory = NK_ALIGN_PTR(unaligned, align); - *alignment = (nk_size)((nk_byte*)memory - (nk_byte*)unaligned); - } else { - memory = unaligned; - *alignment = 0; - } - break; - case NK_BUFFER_BACK: - if (align) { - memory = NK_ALIGN_PTR_BACK(unaligned, align); - *alignment = (nk_size)((nk_byte*)unaligned - (nk_byte*)memory); - } else { - memory = unaligned; - *alignment = 0; - } - break; - } - return memory; -} - -NK_INTERN void* -nk_buffer_realloc(struct nk_buffer *b, nk_size capacity, nk_size *size) -{ - void *temp; - nk_size buffer_size; - - NK_ASSERT(b); - NK_ASSERT(size); - if (!b || !size || !b->pool.alloc || !b->pool.free) - return 0; - - buffer_size = b->memory.size; - temp = b->pool.alloc(b->pool.userdata, b->memory.ptr, capacity); - NK_ASSERT(temp); - if (!temp) return 0; - - *size = capacity; - if (temp != b->memory.ptr) { - NK_MEMCPY(temp, b->memory.ptr, buffer_size); - b->pool.free(b->pool.userdata, b->memory.ptr); - } - - if (b->size == buffer_size) { - /* no back buffer so just set correct size */ - b->size = capacity; - return temp; - } else { - /* copy back buffer to the end of the new buffer */ - void *dst, *src; - nk_size back_size; - back_size = buffer_size - b->size; - dst = nk_ptr_add(void, temp, capacity - back_size); - src = nk_ptr_add(void, temp, b->size); - NK_MEMCPY(dst, src, back_size); - b->size = capacity - back_size; - } - return temp; -} - -NK_INTERN void* -nk_buffer_alloc(struct nk_buffer *b, enum nk_buffer_allocation_type type, - nk_size size, nk_size align) -{ - int full; - nk_size alignment; - void *unaligned; - void *memory; - - NK_ASSERT(b); - NK_ASSERT(size); - if (!b || !size) return 0; - b->needed += size; - - /* calculate total size with needed alignment + size */ - if (type == NK_BUFFER_FRONT) - unaligned = nk_ptr_add(void, b->memory.ptr, b->allocated); - else unaligned = nk_ptr_add(void, b->memory.ptr, b->size - size); - memory = nk_buffer_align(unaligned, align, &alignment, type); - - /* check if buffer has enough memory*/ - if (type == NK_BUFFER_FRONT) - full = ((b->allocated + size + alignment) > b->size); - else full = ((b->size - NK_MIN(b->size,(size + alignment))) <= b->allocated); - - if (full) { - nk_size capacity; - if (b->type != NK_BUFFER_DYNAMIC) - return 0; - NK_ASSERT(b->pool.alloc && b->pool.free); - if (b->type != NK_BUFFER_DYNAMIC || !b->pool.alloc || !b->pool.free) - return 0; - - /* buffer is full so allocate bigger buffer if dynamic */ - capacity = (nk_size)((float)b->memory.size * b->grow_factor); - capacity = NK_MAX(capacity, nk_round_up_pow2((nk_uint)(b->allocated + size))); - b->memory.ptr = nk_buffer_realloc(b, capacity, &b->memory.size); - if (!b->memory.ptr) return 0; - - /* align newly allocated pointer */ - if (type == NK_BUFFER_FRONT) - unaligned = nk_ptr_add(void, b->memory.ptr, b->allocated); - else unaligned = nk_ptr_add(void, b->memory.ptr, b->size - size); - memory = nk_buffer_align(unaligned, align, &alignment, type); - } - if (type == NK_BUFFER_FRONT) - b->allocated += size + alignment; - else b->size -= (size + alignment); - b->needed += alignment; - b->calls++; - return memory; -} - -NK_API void -nk_buffer_push(struct nk_buffer *b, enum nk_buffer_allocation_type type, - const void *memory, nk_size size, nk_size align) -{ - void *mem = nk_buffer_alloc(b, type, size, align); - if (!mem) return; - NK_MEMCPY(mem, memory, size); -} - -NK_API void -nk_buffer_mark(struct nk_buffer *buffer, enum nk_buffer_allocation_type type) -{ - NK_ASSERT(buffer); - if (!buffer) return; - buffer->marker[type].active = nk_true; - if (type == NK_BUFFER_BACK) - buffer->marker[type].offset = buffer->size; - else buffer->marker[type].offset = buffer->allocated; -} - -NK_API void -nk_buffer_reset(struct nk_buffer *buffer, enum nk_buffer_allocation_type type) -{ - NK_ASSERT(buffer); - if (!buffer) return; - if (type == NK_BUFFER_BACK) { - /* reset back buffer either back to marker or empty */ - buffer->needed -= (buffer->memory.size - buffer->marker[type].offset); - if (buffer->marker[type].active) - buffer->size = buffer->marker[type].offset; - else buffer->size = buffer->memory.size; - buffer->marker[type].active = nk_false; - } else { - /* reset front buffer either back to back marker or empty */ - buffer->needed -= (buffer->allocated - buffer->marker[type].offset); - if (buffer->marker[type].active) - buffer->allocated = buffer->marker[type].offset; - else buffer->allocated = 0; - buffer->marker[type].active = nk_false; - } -} - -NK_API void -nk_buffer_clear(struct nk_buffer *b) -{ - NK_ASSERT(b); - if (!b) return; - b->allocated = 0; - b->size = b->memory.size; - b->calls = 0; - b->needed = 0; -} - -NK_API void -nk_buffer_free(struct nk_buffer *b) -{ - NK_ASSERT(b); - if (!b || !b->memory.ptr) return; - if (b->type == NK_BUFFER_FIXED) return; - if (!b->pool.free) return; - NK_ASSERT(b->pool.free); - b->pool.free(b->pool.userdata, b->memory.ptr); -} - -NK_API void -nk_buffer_info(struct nk_memory_status *s, struct nk_buffer *b) -{ - NK_ASSERT(b); - NK_ASSERT(s); - if (!s || !b) return; - s->allocated = b->allocated; - s->size = b->memory.size; - s->needed = b->needed; - s->memory = b->memory.ptr; - s->calls = b->calls; -} - -NK_API void* -nk_buffer_memory(struct nk_buffer *buffer) -{ - NK_ASSERT(buffer); - if (!buffer) return 0; - return buffer->memory.ptr; -} - -NK_API const void* -nk_buffer_memory_const(const struct nk_buffer *buffer) -{ - NK_ASSERT(buffer); - if (!buffer) return 0; - return buffer->memory.ptr; -} - -NK_API nk_size -nk_buffer_total(struct nk_buffer *buffer) -{ - NK_ASSERT(buffer); - if (!buffer) return 0; - return buffer->memory.size; -} - -/* - * ============================================================== - * - * STRING - * - * =============================================================== - */ -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API void -nk_str_init_default(struct nk_str *str) -{ - struct nk_allocator alloc; - alloc.userdata.ptr = 0; - alloc.alloc = nk_malloc; - alloc.free = nk_mfree; - nk_buffer_init(&str->buffer, &alloc, 32); - str->len = 0; -} -#endif - -NK_API void -nk_str_init(struct nk_str *str, const struct nk_allocator *alloc, nk_size size) -{ - nk_buffer_init(&str->buffer, alloc, size); - str->len = 0; -} - -NK_API void -nk_str_init_fixed(struct nk_str *str, void *memory, nk_size size) -{ - nk_buffer_init_fixed(&str->buffer, memory, size); - str->len = 0; -} - -NK_API int -nk_str_append_text_char(struct nk_str *s, const char *str, int len) -{ - char *mem; - NK_ASSERT(s); - NK_ASSERT(str); - if (!s || !str || !len) return 0; - mem = (char*)nk_buffer_alloc(&s->buffer, NK_BUFFER_FRONT, (nk_size)len * sizeof(char), 0); - if (!mem) return 0; - NK_MEMCPY(mem, str, (nk_size)len * sizeof(char)); - s->len += nk_utf_len(str, len); - return len; -} - -NK_API int -nk_str_append_str_char(struct nk_str *s, const char *str) -{ - return nk_str_append_text_char(s, str, nk_strlen(str)); -} - -NK_API int -nk_str_append_text_utf8(struct nk_str *str, const char *text, int len) -{ - int i = 0; - int byte_len = 0; - nk_rune unicode; - if (!str || !text || !len) return 0; - for (i = 0; i < len; ++i) - byte_len += nk_utf_decode(text+byte_len, &unicode, 4); - nk_str_append_text_char(str, text, byte_len); - return len; -} - -NK_API int -nk_str_append_str_utf8(struct nk_str *str, const char *text) -{ - int runes = 0; - int byte_len = 0; - int num_runes = 0; - int glyph_len = 0; - nk_rune unicode; - if (!str || !text) return 0; - - glyph_len = byte_len = nk_utf_decode(text+byte_len, &unicode, 4); - while (unicode != '\0' && glyph_len) { - glyph_len = nk_utf_decode(text+byte_len, &unicode, 4); - byte_len += glyph_len; - num_runes++; - } - nk_str_append_text_char(str, text, byte_len); - return runes; -} - -NK_API int -nk_str_append_text_runes(struct nk_str *str, const nk_rune *text, int len) -{ - int i = 0; - int byte_len = 0; - nk_glyph glyph; - - NK_ASSERT(str); - if (!str || !text || !len) return 0; - for (i = 0; i < len; ++i) { - byte_len = nk_utf_encode(text[i], glyph, NK_UTF_SIZE); - if (!byte_len) break; - nk_str_append_text_char(str, glyph, byte_len); - } - return len; -} - -NK_API int -nk_str_append_str_runes(struct nk_str *str, const nk_rune *runes) -{ - int i = 0; - nk_glyph glyph; - int byte_len; - NK_ASSERT(str); - if (!str || !runes) return 0; - while (runes[i] != '\0') { - byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE); - nk_str_append_text_char(str, glyph, byte_len); - i++; - } - return i; -} - -NK_API int -nk_str_insert_at_char(struct nk_str *s, int pos, const char *str, int len) -{ - int i; - void *mem; - char *src; - char *dst; - - int copylen; - NK_ASSERT(s); - NK_ASSERT(str); - NK_ASSERT(len >= 0); - if (!s || !str || !len || (nk_size)pos > s->buffer.allocated) return 0; - if ((s->buffer.allocated + (nk_size)len >= s->buffer.memory.size) && - (s->buffer.type == NK_BUFFER_FIXED)) return 0; - - copylen = (int)s->buffer.allocated - pos; - if (!copylen) { - nk_str_append_text_char(s, str, len); - return 1; - } - mem = nk_buffer_alloc(&s->buffer, NK_BUFFER_FRONT, (nk_size)len * sizeof(char), 0); - if (!mem) return 0; - - /* memmove */ - NK_ASSERT(((int)pos + (int)len + ((int)copylen - 1)) >= 0); - NK_ASSERT(((int)pos + ((int)copylen - 1)) >= 0); - dst = nk_ptr_add(char, s->buffer.memory.ptr, pos + len + (copylen - 1)); - src = nk_ptr_add(char, s->buffer.memory.ptr, pos + (copylen-1)); - for (i = 0; i < copylen; ++i) *dst-- = *src--; - mem = nk_ptr_add(void, s->buffer.memory.ptr, pos); - NK_MEMCPY(mem, str, (nk_size)len * sizeof(char)); - s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated); - return 1; -} - -NK_API int -nk_str_insert_at_rune(struct nk_str *str, int pos, const char *cstr, int len) -{ - int glyph_len; - nk_rune unicode; - const char *begin; - const char *buffer; - - NK_ASSERT(str); - NK_ASSERT(cstr); - NK_ASSERT(len); - if (!str || !cstr || !len) return 0; - begin = nk_str_at_rune(str, pos, &unicode, &glyph_len); - if (!str->len) - return nk_str_append_text_char(str, cstr, len); - buffer = nk_str_get_const(str); - if (!begin) return 0; - return nk_str_insert_at_char(str, (int)(begin - buffer), cstr, len); -} - -NK_API int -nk_str_insert_text_char(struct nk_str *str, int pos, const char *text, int len) -{ - return nk_str_insert_text_utf8(str, pos, text, len); -} - -NK_API int -nk_str_insert_str_char(struct nk_str *str, int pos, const char *text) -{ - return nk_str_insert_text_utf8(str, pos, text, nk_strlen(text)); -} - -NK_API int -nk_str_insert_text_utf8(struct nk_str *str, int pos, const char *text, int len) -{ - int i = 0; - int byte_len = 0; - nk_rune unicode; - - NK_ASSERT(str); - NK_ASSERT(text); - if (!str || !text || !len) return 0; - for (i = 0; i < len; ++i) - byte_len += nk_utf_decode(text+byte_len, &unicode, 4); - nk_str_insert_at_rune(str, pos, text, byte_len); - return len; -} - -NK_API int -nk_str_insert_str_utf8(struct nk_str *str, int pos, const char *text) -{ - int runes = 0; - int byte_len = 0; - int num_runes = 0; - int glyph_len = 0; - nk_rune unicode; - if (!str || !text) return 0; - - glyph_len = byte_len = nk_utf_decode(text+byte_len, &unicode, 4); - while (unicode != '\0' && glyph_len) { - glyph_len = nk_utf_decode(text+byte_len, &unicode, 4); - byte_len += glyph_len; - num_runes++; - } - nk_str_insert_at_rune(str, pos, text, byte_len); - return runes; -} - -NK_API int -nk_str_insert_text_runes(struct nk_str *str, int pos, const nk_rune *runes, int len) -{ - int i = 0; - int byte_len = 0; - nk_glyph glyph; - - NK_ASSERT(str); - if (!str || !runes || !len) return 0; - for (i = 0; i < len; ++i) { - byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE); - if (!byte_len) break; - nk_str_insert_at_rune(str, pos+i, glyph, byte_len); - } - return len; -} - -NK_API int -nk_str_insert_str_runes(struct nk_str *str, int pos, const nk_rune *runes) -{ - int i = 0; - nk_glyph glyph; - int byte_len; - NK_ASSERT(str); - if (!str || !runes) return 0; - while (runes[i] != '\0') { - byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE); - nk_str_insert_at_rune(str, pos+i, glyph, byte_len); - i++; - } - return i; -} - -NK_API void -nk_str_remove_chars(struct nk_str *s, int len) -{ - NK_ASSERT(s); - NK_ASSERT(len >= 0); - if (!s || len < 0 || (nk_size)len > s->buffer.allocated) return; - NK_ASSERT(((int)s->buffer.allocated - (int)len) >= 0); - s->buffer.allocated -= (nk_size)len; - s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated); -} - -NK_API void -nk_str_remove_runes(struct nk_str *str, int len) -{ - int index; - const char *begin; - const char *end; - nk_rune unicode; - - NK_ASSERT(str); - NK_ASSERT(len >= 0); - if (!str || len < 0) return; - if (len >= str->len) { - str->len = 0; - return; - } - - index = str->len - len; - begin = nk_str_at_rune(str, index, &unicode, &len); - end = (const char*)str->buffer.memory.ptr + str->buffer.allocated; - nk_str_remove_chars(str, (int)(end-begin)+1); -} - -NK_API void -nk_str_delete_chars(struct nk_str *s, int pos, int len) -{ - NK_ASSERT(s); - if (!s || !len || (nk_size)pos > s->buffer.allocated || - (nk_size)(pos + len) > s->buffer.allocated) return; - - if ((nk_size)(pos + len) < s->buffer.allocated) { - /* memmove */ - char *dst = nk_ptr_add(char, s->buffer.memory.ptr, pos); - char *src = nk_ptr_add(char, s->buffer.memory.ptr, pos + len); - NK_MEMCPY(dst, src, s->buffer.allocated - (nk_size)(pos + len)); - NK_ASSERT(((int)s->buffer.allocated - (int)len) >= 0); - s->buffer.allocated -= (nk_size)len; - } else nk_str_remove_chars(s, len); - s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated); -} - -NK_API void -nk_str_delete_runes(struct nk_str *s, int pos, int len) -{ - char *temp; - nk_rune unicode; - char *begin; - char *end; - int unused; - - NK_ASSERT(s); - NK_ASSERT(s->len >= pos + len); - if (s->len < pos + len) - len = NK_CLAMP(0, (s->len - pos), s->len); - if (!len) return; - - temp = (char *)s->buffer.memory.ptr; - begin = nk_str_at_rune(s, pos, &unicode, &unused); - if (!begin) return; - s->buffer.memory.ptr = begin; - end = nk_str_at_rune(s, len, &unicode, &unused); - s->buffer.memory.ptr = temp; - if (!end) return; - nk_str_delete_chars(s, (int)(begin - temp), (int)(end - begin)); -} - -NK_API char* -nk_str_at_char(struct nk_str *s, int pos) -{ - NK_ASSERT(s); - if (!s || pos > (int)s->buffer.allocated) return 0; - return nk_ptr_add(char, s->buffer.memory.ptr, pos); -} - -NK_API char* -nk_str_at_rune(struct nk_str *str, int pos, nk_rune *unicode, int *len) -{ - int i = 0; - int src_len = 0; - int glyph_len = 0; - char *text; - int text_len; - - NK_ASSERT(str); - NK_ASSERT(unicode); - NK_ASSERT(len); - - if (!str || !unicode || !len) return 0; - if (pos < 0) { - *unicode = 0; - *len = 0; - return 0; - } - - text = (char*)str->buffer.memory.ptr; - text_len = (int)str->buffer.allocated; - glyph_len = nk_utf_decode(text, unicode, text_len); - while (glyph_len) { - if (i == pos) { - *len = glyph_len; - break; - } - - i++; - src_len = src_len + glyph_len; - glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len); - } - if (i != pos) return 0; - return text + src_len; -} - -NK_API const char* -nk_str_at_char_const(const struct nk_str *s, int pos) -{ - NK_ASSERT(s); - if (!s || pos > (int)s->buffer.allocated) return 0; - return nk_ptr_add(char, s->buffer.memory.ptr, pos); -} - -NK_API const char* -nk_str_at_const(const struct nk_str *str, int pos, nk_rune *unicode, int *len) -{ - int i = 0; - int src_len = 0; - int glyph_len = 0; - char *text; - int text_len; - - NK_ASSERT(str); - NK_ASSERT(unicode); - NK_ASSERT(len); - - if (!str || !unicode || !len) return 0; - if (pos < 0) { - *unicode = 0; - *len = 0; - return 0; - } - - text = (char*)str->buffer.memory.ptr; - text_len = (int)str->buffer.allocated; - glyph_len = nk_utf_decode(text, unicode, text_len); - while (glyph_len) { - if (i == pos) { - *len = glyph_len; - break; - } - - i++; - src_len = src_len + glyph_len; - glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len); - } - if (i != pos) return 0; - return text + src_len; -} - -NK_API nk_rune -nk_str_rune_at(const struct nk_str *str, int pos) -{ - int len; - nk_rune unicode = 0; - nk_str_at_const(str, pos, &unicode, &len); - return unicode; -} - -NK_API char* -nk_str_get(struct nk_str *s) -{ - NK_ASSERT(s); - if (!s || !s->len || !s->buffer.allocated) return 0; - return (char*)s->buffer.memory.ptr; -} - -NK_API const char* -nk_str_get_const(const struct nk_str *s) -{ - NK_ASSERT(s); - if (!s || !s->len || !s->buffer.allocated) return 0; - return (const char*)s->buffer.memory.ptr; -} - -NK_API int -nk_str_len(struct nk_str *s) -{ - NK_ASSERT(s); - if (!s || !s->len || !s->buffer.allocated) return 0; - return s->len; -} - -NK_API int -nk_str_len_char(struct nk_str *s) -{ - NK_ASSERT(s); - if (!s || !s->len || !s->buffer.allocated) return 0; - return (int)s->buffer.allocated; -} - -NK_API void -nk_str_clear(struct nk_str *str) -{ - NK_ASSERT(str); - nk_buffer_clear(&str->buffer); - str->len = 0; -} - -NK_API void -nk_str_free(struct nk_str *str) -{ - NK_ASSERT(str); - nk_buffer_free(&str->buffer); - str->len = 0; -} - -/* - * ============================================================== - * - * Command buffer - * - * =============================================================== -*/ -NK_INTERN void -nk_command_buffer_init(struct nk_command_buffer *cmdbuf, - struct nk_buffer *buffer, enum nk_command_clipping clip) -{ - NK_ASSERT(cmdbuf); - NK_ASSERT(buffer); - if (!cmdbuf || !buffer) return; - cmdbuf->base = buffer; - cmdbuf->use_clipping = clip; - cmdbuf->begin = buffer->allocated; - cmdbuf->end = buffer->allocated; - cmdbuf->last = buffer->allocated; -} - -NK_INTERN void -nk_command_buffer_reset(struct nk_command_buffer *buffer) -{ - NK_ASSERT(buffer); - if (!buffer) return; - buffer->begin = 0; - buffer->end = 0; - buffer->last = 0; - buffer->clip = nk_null_rect; -#ifdef NK_INCLUDE_COMMAND_USERDATA - buffer->userdata.ptr = 0; -#endif -} - -NK_INTERN void* -nk_command_buffer_push(struct nk_command_buffer* b, - enum nk_command_type t, nk_size size) -{ - NK_STORAGE const nk_size align = NK_ALIGNOF(struct nk_command); - struct nk_command *cmd; - nk_size alignment; - void *unaligned; - void *memory; - - NK_ASSERT(b); - NK_ASSERT(b->base); - if (!b) return 0; - cmd = (struct nk_command*)nk_buffer_alloc(b->base,NK_BUFFER_FRONT,size,align); - if (!cmd) return 0; - - /* make sure the offset to the next command is aligned */ - b->last = (nk_size)((nk_byte*)cmd - (nk_byte*)b->base->memory.ptr); - unaligned = (nk_byte*)cmd + size; - memory = NK_ALIGN_PTR(unaligned, align); - alignment = (nk_size)((nk_byte*)memory - (nk_byte*)unaligned); -#ifdef NK_ZERO_COMMAND_MEMORY - NK_MEMSET(cmd, 0, size + alignment); -#endif - - cmd->type = t; - cmd->next = b->base->allocated + alignment; -#ifdef NK_INCLUDE_COMMAND_USERDATA - cmd->userdata = b->userdata; -#endif - b->end = cmd->next; - return cmd; -} - -NK_API void -nk_push_scissor(struct nk_command_buffer *b, struct nk_rect r) -{ - struct nk_command_scissor *cmd; - NK_ASSERT(b); - if (!b) return; - - b->clip.x = r.x; - b->clip.y = r.y; - b->clip.w = r.w; - b->clip.h = r.h; - cmd = (struct nk_command_scissor*) - nk_command_buffer_push(b, NK_COMMAND_SCISSOR, sizeof(*cmd)); - - if (!cmd) return; - cmd->x = (short)r.x; - cmd->y = (short)r.y; - cmd->w = (unsigned short)NK_MAX(0, r.w); - cmd->h = (unsigned short)NK_MAX(0, r.h); -} - -NK_API void -nk_stroke_line(struct nk_command_buffer *b, float x0, float y0, - float x1, float y1, float line_thickness, struct nk_color c) -{ - struct nk_command_line *cmd; - NK_ASSERT(b); - if (!b || line_thickness <= 0) return; - cmd = (struct nk_command_line*) - nk_command_buffer_push(b, NK_COMMAND_LINE, sizeof(*cmd)); - if (!cmd) return; - cmd->line_thickness = (unsigned short)line_thickness; - cmd->begin.x = (short)x0; - cmd->begin.y = (short)y0; - cmd->end.x = (short)x1; - cmd->end.y = (short)y1; - cmd->color = c; -} - -NK_API void -nk_stroke_curve(struct nk_command_buffer *b, float ax, float ay, - float ctrl0x, float ctrl0y, float ctrl1x, float ctrl1y, - float bx, float by, float line_thickness, struct nk_color col) -{ - struct nk_command_curve *cmd; - NK_ASSERT(b); - if (!b || col.a == 0 || line_thickness <= 0) return; - - cmd = (struct nk_command_curve*) - nk_command_buffer_push(b, NK_COMMAND_CURVE, sizeof(*cmd)); - if (!cmd) return; - cmd->line_thickness = (unsigned short)line_thickness; - cmd->begin.x = (short)ax; - cmd->begin.y = (short)ay; - cmd->ctrl[0].x = (short)ctrl0x; - cmd->ctrl[0].y = (short)ctrl0y; - cmd->ctrl[1].x = (short)ctrl1x; - cmd->ctrl[1].y = (short)ctrl1y; - cmd->end.x = (short)bx; - cmd->end.y = (short)by; - cmd->color = col; -} - -NK_API void -nk_stroke_rect(struct nk_command_buffer *b, struct nk_rect rect, - float rounding, float line_thickness, struct nk_color c) -{ - struct nk_command_rect *cmd; - NK_ASSERT(b); - if (!b || c.a == 0 || rect.w == 0 || rect.h == 0 || line_thickness <= 0) return; - if (b->use_clipping) { - const struct nk_rect *clip = &b->clip; - if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h, - clip->x, clip->y, clip->w, clip->h)) return; - } - cmd = (struct nk_command_rect*) - nk_command_buffer_push(b, NK_COMMAND_RECT, sizeof(*cmd)); - if (!cmd) return; - cmd->rounding = (unsigned short)rounding; - cmd->line_thickness = (unsigned short)line_thickness; - cmd->x = (short)rect.x; - cmd->y = (short)rect.y; - cmd->w = (unsigned short)NK_MAX(0, rect.w); - cmd->h = (unsigned short)NK_MAX(0, rect.h); - cmd->color = c; -} - -NK_API void -nk_fill_rect(struct nk_command_buffer *b, struct nk_rect rect, - float rounding, struct nk_color c) -{ - struct nk_command_rect_filled *cmd; - NK_ASSERT(b); - if (!b || c.a == 0 || rect.w == 0 || rect.h == 0) return; - if (b->use_clipping) { - const struct nk_rect *clip = &b->clip; - if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h, - clip->x, clip->y, clip->w, clip->h)) return; - } - - cmd = (struct nk_command_rect_filled*) - nk_command_buffer_push(b, NK_COMMAND_RECT_FILLED, sizeof(*cmd)); - if (!cmd) return; - cmd->rounding = (unsigned short)rounding; - cmd->x = (short)rect.x; - cmd->y = (short)rect.y; - cmd->w = (unsigned short)NK_MAX(0, rect.w); - cmd->h = (unsigned short)NK_MAX(0, rect.h); - cmd->color = c; -} - -NK_API void -nk_fill_rect_multi_color(struct nk_command_buffer *b, struct nk_rect rect, - struct nk_color left, struct nk_color top, struct nk_color right, - struct nk_color bottom) -{ - struct nk_command_rect_multi_color *cmd; - NK_ASSERT(b); - if (!b || rect.w == 0 || rect.h == 0) return; - if (b->use_clipping) { - const struct nk_rect *clip = &b->clip; - if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h, - clip->x, clip->y, clip->w, clip->h)) return; - } - - cmd = (struct nk_command_rect_multi_color*) - nk_command_buffer_push(b, NK_COMMAND_RECT_MULTI_COLOR, sizeof(*cmd)); - if (!cmd) return; - cmd->x = (short)rect.x; - cmd->y = (short)rect.y; - cmd->w = (unsigned short)NK_MAX(0, rect.w); - cmd->h = (unsigned short)NK_MAX(0, rect.h); - cmd->left = left; - cmd->top = top; - cmd->right = right; - cmd->bottom = bottom; -} - -NK_API void -nk_stroke_circle(struct nk_command_buffer *b, struct nk_rect r, - float line_thickness, struct nk_color c) -{ - struct nk_command_circle *cmd; - if (!b || r.w == 0 || r.h == 0 || line_thickness <= 0) return; - if (b->use_clipping) { - const struct nk_rect *clip = &b->clip; - if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h)) - return; - } - - cmd = (struct nk_command_circle*) - nk_command_buffer_push(b, NK_COMMAND_CIRCLE, sizeof(*cmd)); - if (!cmd) return; - cmd->line_thickness = (unsigned short)line_thickness; - cmd->x = (short)r.x; - cmd->y = (short)r.y; - cmd->w = (unsigned short)NK_MAX(r.w, 0); - cmd->h = (unsigned short)NK_MAX(r.h, 0); - cmd->color = c; -} - -NK_API void -nk_fill_circle(struct nk_command_buffer *b, struct nk_rect r, struct nk_color c) -{ - struct nk_command_circle_filled *cmd; - NK_ASSERT(b); - if (!b || c.a == 0 || r.w == 0 || r.h == 0) return; - if (b->use_clipping) { - const struct nk_rect *clip = &b->clip; - if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h)) - return; - } - - cmd = (struct nk_command_circle_filled*) - nk_command_buffer_push(b, NK_COMMAND_CIRCLE_FILLED, sizeof(*cmd)); - if (!cmd) return; - cmd->x = (short)r.x; - cmd->y = (short)r.y; - cmd->w = (unsigned short)NK_MAX(r.w, 0); - cmd->h = (unsigned short)NK_MAX(r.h, 0); - cmd->color = c; -} - -NK_API void -nk_stroke_arc(struct nk_command_buffer *b, float cx, float cy, float radius, - float a_min, float a_max, float line_thickness, struct nk_color c) -{ - struct nk_command_arc *cmd; - if (!b || c.a == 0 || line_thickness <= 0) return; - cmd = (struct nk_command_arc*) - nk_command_buffer_push(b, NK_COMMAND_ARC, sizeof(*cmd)); - if (!cmd) return; - cmd->line_thickness = (unsigned short)line_thickness; - cmd->cx = (short)cx; - cmd->cy = (short)cy; - cmd->r = (unsigned short)radius; - cmd->a[0] = a_min; - cmd->a[1] = a_max; - cmd->color = c; -} - -NK_API void -nk_fill_arc(struct nk_command_buffer *b, float cx, float cy, float radius, - float a_min, float a_max, struct nk_color c) -{ - struct nk_command_arc_filled *cmd; - NK_ASSERT(b); - if (!b || c.a == 0) return; - cmd = (struct nk_command_arc_filled*) - nk_command_buffer_push(b, NK_COMMAND_ARC_FILLED, sizeof(*cmd)); - if (!cmd) return; - cmd->cx = (short)cx; - cmd->cy = (short)cy; - cmd->r = (unsigned short)radius; - cmd->a[0] = a_min; - cmd->a[1] = a_max; - cmd->color = c; -} - -NK_API void -nk_stroke_triangle(struct nk_command_buffer *b, float x0, float y0, float x1, - float y1, float x2, float y2, float line_thickness, struct nk_color c) -{ - struct nk_command_triangle *cmd; - NK_ASSERT(b); - if (!b || c.a == 0 || line_thickness <= 0) return; - if (b->use_clipping) { - const struct nk_rect *clip = &b->clip; - if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) && - !NK_INBOX(x1, y1, clip->x, clip->y, clip->w, clip->h) && - !NK_INBOX(x2, y2, clip->x, clip->y, clip->w, clip->h)) - return; - } - - cmd = (struct nk_command_triangle*) - nk_command_buffer_push(b, NK_COMMAND_TRIANGLE, sizeof(*cmd)); - if (!cmd) return; - cmd->line_thickness = (unsigned short)line_thickness; - cmd->a.x = (short)x0; - cmd->a.y = (short)y0; - cmd->b.x = (short)x1; - cmd->b.y = (short)y1; - cmd->c.x = (short)x2; - cmd->c.y = (short)y2; - cmd->color = c; -} - -NK_API void -nk_fill_triangle(struct nk_command_buffer *b, float x0, float y0, float x1, - float y1, float x2, float y2, struct nk_color c) -{ - struct nk_command_triangle_filled *cmd; - NK_ASSERT(b); - if (!b || c.a == 0) return; - if (!b) return; - if (b->use_clipping) { - const struct nk_rect *clip = &b->clip; - if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) && - !NK_INBOX(x1, y1, clip->x, clip->y, clip->w, clip->h) && - !NK_INBOX(x2, y2, clip->x, clip->y, clip->w, clip->h)) - return; - } - - cmd = (struct nk_command_triangle_filled*) - nk_command_buffer_push(b, NK_COMMAND_TRIANGLE_FILLED, sizeof(*cmd)); - if (!cmd) return; - cmd->a.x = (short)x0; - cmd->a.y = (short)y0; - cmd->b.x = (short)x1; - cmd->b.y = (short)y1; - cmd->c.x = (short)x2; - cmd->c.y = (short)y2; - cmd->color = c; -} - -NK_API void -nk_stroke_polygon(struct nk_command_buffer *b, float *points, int point_count, - float line_thickness, struct nk_color col) -{ - int i; - nk_size size = 0; - struct nk_command_polygon *cmd; - - NK_ASSERT(b); - if (!b || col.a == 0 || line_thickness <= 0) return; - size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count; - cmd = (struct nk_command_polygon*) nk_command_buffer_push(b, NK_COMMAND_POLYGON, size); - if (!cmd) return; - cmd->color = col; - cmd->line_thickness = (unsigned short)line_thickness; - cmd->point_count = (unsigned short)point_count; - for (i = 0; i < point_count; ++i) { - cmd->points[i].x = (short)points[i*2]; - cmd->points[i].y = (short)points[i*2+1]; - } -} - -NK_API void -nk_fill_polygon(struct nk_command_buffer *b, float *points, int point_count, - struct nk_color col) -{ - int i; - nk_size size = 0; - struct nk_command_polygon_filled *cmd; - - NK_ASSERT(b); - if (!b || col.a == 0) return; - size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count; - cmd = (struct nk_command_polygon_filled*) - nk_command_buffer_push(b, NK_COMMAND_POLYGON_FILLED, size); - if (!cmd) return; - cmd->color = col; - cmd->point_count = (unsigned short)point_count; - for (i = 0; i < point_count; ++i) { - cmd->points[i].x = (short)points[i*2+0]; - cmd->points[i].y = (short)points[i*2+1]; - } -} - -NK_API void -nk_stroke_polyline(struct nk_command_buffer *b, float *points, int point_count, - float line_thickness, struct nk_color col) -{ - int i; - nk_size size = 0; - struct nk_command_polyline *cmd; - - NK_ASSERT(b); - if (!b || col.a == 0 || line_thickness <= 0) return; - size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count; - cmd = (struct nk_command_polyline*) nk_command_buffer_push(b, NK_COMMAND_POLYLINE, size); - if (!cmd) return; - cmd->color = col; - cmd->point_count = (unsigned short)point_count; - cmd->line_thickness = (unsigned short)line_thickness; - for (i = 0; i < point_count; ++i) { - cmd->points[i].x = (short)points[i*2]; - cmd->points[i].y = (short)points[i*2+1]; - } -} - -NK_API void -nk_draw_image(struct nk_command_buffer *b, struct nk_rect r, - const struct nk_image *img, struct nk_color col) -{ - struct nk_command_image *cmd; - NK_ASSERT(b); - if (!b) return; - if (b->use_clipping) { - const struct nk_rect *c = &b->clip; - if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h)) - return; - } - - cmd = (struct nk_command_image*) - nk_command_buffer_push(b, NK_COMMAND_IMAGE, sizeof(*cmd)); - if (!cmd) return; - cmd->x = (short)r.x; - cmd->y = (short)r.y; - cmd->w = (unsigned short)NK_MAX(0, r.w); - cmd->h = (unsigned short)NK_MAX(0, r.h); - cmd->img = *img; - cmd->col = col; -} - -NK_API void -nk_push_custom(struct nk_command_buffer *b, struct nk_rect r, - nk_command_custom_callback cb, nk_handle usr) -{ - struct nk_command_custom *cmd; - NK_ASSERT(b); - if (!b) return; - if (b->use_clipping) { - const struct nk_rect *c = &b->clip; - if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h)) - return; - } - - cmd = (struct nk_command_custom*) - nk_command_buffer_push(b, NK_COMMAND_CUSTOM, sizeof(*cmd)); - if (!cmd) return; - cmd->x = (short)r.x; - cmd->y = (short)r.y; - cmd->w = (unsigned short)NK_MAX(0, r.w); - cmd->h = (unsigned short)NK_MAX(0, r.h); - cmd->callback_data = usr; - cmd->callback = cb; -} - -NK_API void -nk_draw_text(struct nk_command_buffer *b, struct nk_rect r, - const char *string, int length, const struct nk_user_font *font, - struct nk_color bg, struct nk_color fg) -{ - float text_width = 0; - struct nk_command_text *cmd; - - NK_ASSERT(b); - NK_ASSERT(font); - if (!b || !string || !length || (bg.a == 0 && fg.a == 0)) return; - if (b->use_clipping) { - const struct nk_rect *c = &b->clip; - if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h)) - return; - } - - /* make sure text fits inside bounds */ - text_width = font->width(font->userdata, font->height, string, length); - if (text_width > r.w){ - int glyphs = 0; - float txt_width = (float)text_width; - length = nk_text_clamp(font, string, length, r.w, &glyphs, &txt_width, 0,0); - } - - if (!length) return; - cmd = (struct nk_command_text*) - nk_command_buffer_push(b, NK_COMMAND_TEXT, sizeof(*cmd) + (nk_size)(length + 1)); - if (!cmd) return; - cmd->x = (short)r.x; - cmd->y = (short)r.y; - cmd->w = (unsigned short)r.w; - cmd->h = (unsigned short)r.h; - cmd->background = bg; - cmd->foreground = fg; - cmd->font = font; - cmd->length = length; - cmd->height = font->height; - NK_MEMCPY(cmd->string, string, (nk_size)length); - cmd->string[length] = '\0'; -} - -/* ============================================================== - * - * DRAW LIST - * - * ===============================================================*/ -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT -NK_API void -nk_draw_list_init(struct nk_draw_list *list) -{ - nk_size i = 0; - NK_ASSERT(list); - if (!list) return; - nk_zero(list, sizeof(*list)); - for (i = 0; i < NK_LEN(list->circle_vtx); ++i) { - const float a = ((float)i / (float)NK_LEN(list->circle_vtx)) * 2 * NK_PI; - list->circle_vtx[i].x = (float)NK_COS(a); - list->circle_vtx[i].y = (float)NK_SIN(a); - } -} - -NK_API void -nk_draw_list_setup(struct nk_draw_list *canvas, const struct nk_convert_config *config, - struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, - enum nk_anti_aliasing line_aa, enum nk_anti_aliasing shape_aa) -{ - NK_ASSERT(canvas); - NK_ASSERT(config); - NK_ASSERT(cmds); - NK_ASSERT(vertices); - NK_ASSERT(elements); - if (!canvas || !config || !cmds || !vertices || !elements) - return; - - canvas->buffer = cmds; - canvas->config = *config; - canvas->elements = elements; - canvas->vertices = vertices; - canvas->line_AA = line_aa; - canvas->shape_AA = shape_aa; - canvas->clip_rect = nk_null_rect; -} - -NK_API const struct nk_draw_command* -nk__draw_list_begin(const struct nk_draw_list *canvas, const struct nk_buffer *buffer) -{ - nk_byte *memory; - nk_size offset; - const struct nk_draw_command *cmd; - - NK_ASSERT(buffer); - if (!buffer || !buffer->size || !canvas->cmd_count) - return 0; - - memory = (nk_byte*)buffer->memory.ptr; - offset = buffer->memory.size - canvas->cmd_offset; - cmd = nk_ptr_add(const struct nk_draw_command, memory, offset); - return cmd; -} - -NK_API const struct nk_draw_command* -nk__draw_list_end(const struct nk_draw_list *canvas, const struct nk_buffer *buffer) -{ - nk_size size; - nk_size offset; - nk_byte *memory; - const struct nk_draw_command *end; - - NK_ASSERT(buffer); - NK_ASSERT(canvas); - if (!buffer || !canvas) - return 0; - - memory = (nk_byte*)buffer->memory.ptr; - size = buffer->memory.size; - offset = size - canvas->cmd_offset; - end = nk_ptr_add(const struct nk_draw_command, memory, offset); - end -= (canvas->cmd_count-1); - return end; -} - -NK_API const struct nk_draw_command* -nk__draw_list_next(const struct nk_draw_command *cmd, - const struct nk_buffer *buffer, const struct nk_draw_list *canvas) -{ - const struct nk_draw_command *end; - NK_ASSERT(buffer); - NK_ASSERT(canvas); - if (!cmd || !buffer || !canvas) - return 0; - - end = nk__draw_list_end(canvas, buffer); - if (cmd <= end) return 0; - return (cmd-1); -} - -NK_API void -nk_draw_list_clear(struct nk_draw_list *list) -{ - NK_ASSERT(list); - if (!list) return; - if (list->buffer) - nk_buffer_clear(list->buffer); - if (list->vertices) - nk_buffer_clear(list->vertices); - if (list->elements) - nk_buffer_clear(list->elements); - - list->element_count = 0; - list->vertex_count = 0; - list->cmd_offset = 0; - list->cmd_count = 0; - list->path_count = 0; - list->vertices = 0; - list->elements = 0; - list->clip_rect = nk_null_rect; -} - -NK_INTERN struct nk_vec2* -nk_draw_list_alloc_path(struct nk_draw_list *list, int count) -{ - struct nk_vec2 *points; - NK_STORAGE const nk_size point_align = NK_ALIGNOF(struct nk_vec2); - NK_STORAGE const nk_size point_size = sizeof(struct nk_vec2); - points = (struct nk_vec2*) - nk_buffer_alloc(list->buffer, NK_BUFFER_FRONT, - point_size * (nk_size)count, point_align); - - if (!points) return 0; - if (!list->path_offset) { - void *memory = nk_buffer_memory(list->buffer); - list->path_offset = (unsigned int)((nk_byte*)points - (nk_byte*)memory); - } - list->path_count += (unsigned int)count; - return points; -} - -NK_INTERN struct nk_vec2 -nk_draw_list_path_last(struct nk_draw_list *list) -{ - void *memory; - struct nk_vec2 *point; - NK_ASSERT(list->path_count); - memory = nk_buffer_memory(list->buffer); - point = nk_ptr_add(struct nk_vec2, memory, list->path_offset); - point += (list->path_count-1); - return *point; -} - -NK_INTERN struct nk_draw_command* -nk_draw_list_push_command(struct nk_draw_list *list, struct nk_rect clip, - nk_handle texture) -{ - NK_STORAGE const nk_size cmd_align = NK_ALIGNOF(struct nk_draw_command); - NK_STORAGE const nk_size cmd_size = sizeof(struct nk_draw_command); - struct nk_draw_command *cmd; - - NK_ASSERT(list); - cmd = (struct nk_draw_command*) - nk_buffer_alloc(list->buffer, NK_BUFFER_BACK, cmd_size, cmd_align); - - if (!cmd) return 0; - if (!list->cmd_count) { - nk_byte *memory = (nk_byte*)nk_buffer_memory(list->buffer); - nk_size total = nk_buffer_total(list->buffer); - memory = nk_ptr_add(nk_byte, memory, total); - list->cmd_offset = (nk_size)(memory - (nk_byte*)cmd); - } - - cmd->elem_count = 0; - cmd->clip_rect = clip; - cmd->texture = texture; -#ifdef NK_INCLUDE_COMMAND_USERDATA - cmd->userdata = list->userdata; -#endif - - list->cmd_count++; - list->clip_rect = clip; - return cmd; -} - -NK_INTERN struct nk_draw_command* -nk_draw_list_command_last(struct nk_draw_list *list) -{ - void *memory; - nk_size size; - struct nk_draw_command *cmd; - NK_ASSERT(list->cmd_count); - - memory = nk_buffer_memory(list->buffer); - size = nk_buffer_total(list->buffer); - cmd = nk_ptr_add(struct nk_draw_command, memory, size - list->cmd_offset); - return (cmd - (list->cmd_count-1)); -} - -NK_INTERN void -nk_draw_list_add_clip(struct nk_draw_list *list, struct nk_rect rect) -{ - NK_ASSERT(list); - if (!list) return; - if (!list->cmd_count) { - nk_draw_list_push_command(list, rect, list->config.null.texture); - } else { - struct nk_draw_command *prev = nk_draw_list_command_last(list); - if (prev->elem_count == 0) - prev->clip_rect = rect; - nk_draw_list_push_command(list, rect, prev->texture); - } -} - -NK_INTERN void -nk_draw_list_push_image(struct nk_draw_list *list, nk_handle texture) -{ - NK_ASSERT(list); - if (!list) return; - if (!list->cmd_count) { - nk_draw_list_push_command(list, nk_null_rect, texture); - } else { - struct nk_draw_command *prev = nk_draw_list_command_last(list); - if (prev->elem_count == 0) { - prev->texture = texture; - #ifdef NK_INCLUDE_COMMAND_USERDATA - prev->userdata = list->userdata; - #endif - } else if (prev->texture.id != texture.id - #ifdef NK_INCLUDE_COMMAND_USERDATA - || prev->userdata.id != list->userdata.id - #endif - ) nk_draw_list_push_command(list, prev->clip_rect, texture); - } -} - -#ifdef NK_INCLUDE_COMMAND_USERDATA -NK_API void -nk_draw_list_push_userdata(struct nk_draw_list *list, nk_handle userdata) -{ - list->userdata = userdata; -} -#endif - -NK_INTERN void* -nk_draw_list_alloc_vertices(struct nk_draw_list *list, nk_size count) -{ - void *vtx; - NK_ASSERT(list); - if (!list) return 0; - vtx = nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT, - list->config.vertex_size*count, list->config.vertex_alignment); - if (!vtx) return 0; - list->vertex_count += (unsigned int)count; - return vtx; -} - -NK_INTERN nk_draw_index* -nk_draw_list_alloc_elements(struct nk_draw_list *list, nk_size count) -{ - nk_draw_index *ids; - struct nk_draw_command *cmd; - NK_STORAGE const nk_size elem_align = NK_ALIGNOF(nk_draw_index); - NK_STORAGE const nk_size elem_size = sizeof(nk_draw_index); - NK_ASSERT(list); - if (!list) return 0; - - ids = (nk_draw_index*) - nk_buffer_alloc(list->elements, NK_BUFFER_FRONT, elem_size*count, elem_align); - if (!ids) return 0; - cmd = nk_draw_list_command_last(list); - list->element_count += (unsigned int)count; - cmd->elem_count += (unsigned int)count; - return ids; -} - -NK_INTERN int -nk_draw_vertex_layout_element_is_end_of_layout( - const struct nk_draw_vertex_layout_element *element) -{ - return (element->attribute == NK_VERTEX_ATTRIBUTE_COUNT || - element->format == NK_FORMAT_COUNT); -} - -NK_INTERN void -nk_draw_vertex_color(void *attr, const float *vals, - enum nk_draw_vertex_layout_format format) -{ - /* if this triggers you tried to provide a value format for a color */ - float val[4]; - NK_ASSERT(format >= NK_FORMAT_COLOR_BEGIN); - NK_ASSERT(format <= NK_FORMAT_COLOR_END); - if (format < NK_FORMAT_COLOR_BEGIN || format > NK_FORMAT_COLOR_END) return; - - val[0] = NK_SATURATE(vals[0]); - val[1] = NK_SATURATE(vals[1]); - val[2] = NK_SATURATE(vals[2]); - val[3] = NK_SATURATE(vals[3]); - - switch (format) { - default: NK_ASSERT(0 && "Invalid vertex layout color format"); break; - case NK_FORMAT_R8G8B8A8: - case NK_FORMAT_R8G8B8: { - struct nk_color col = nk_rgba_fv(val); - NK_MEMCPY(attr, &col.r, sizeof(col)); - } break; - case NK_FORMAT_B8G8R8A8: { - struct nk_color col = nk_rgba_fv(val); - struct nk_color bgra = nk_rgba(col.b, col.g, col.r, col.a); - NK_MEMCPY(attr, &bgra, sizeof(bgra)); - } break; - case NK_FORMAT_R16G15B16: { - nk_ushort col[3]; - col[0] = (nk_ushort)(val[0]*(float)NK_USHORT_MAX); - col[1] = (nk_ushort)(val[1]*(float)NK_USHORT_MAX); - col[2] = (nk_ushort)(val[2]*(float)NK_USHORT_MAX); - NK_MEMCPY(attr, col, sizeof(col)); - } break; - case NK_FORMAT_R16G15B16A16: { - nk_ushort col[4]; - col[0] = (nk_ushort)(val[0]*(float)NK_USHORT_MAX); - col[1] = (nk_ushort)(val[1]*(float)NK_USHORT_MAX); - col[2] = (nk_ushort)(val[2]*(float)NK_USHORT_MAX); - col[3] = (nk_ushort)(val[3]*(float)NK_USHORT_MAX); - NK_MEMCPY(attr, col, sizeof(col)); - } break; - case NK_FORMAT_R32G32B32: { - nk_uint col[3]; - col[0] = (nk_uint)(val[0]*(float)NK_UINT_MAX); - col[1] = (nk_uint)(val[1]*(float)NK_UINT_MAX); - col[2] = (nk_uint)(val[2]*(float)NK_UINT_MAX); - NK_MEMCPY(attr, col, sizeof(col)); - } break; - case NK_FORMAT_R32G32B32A32: { - nk_uint col[4]; - col[0] = (nk_uint)(val[0]*(float)NK_UINT_MAX); - col[1] = (nk_uint)(val[1]*(float)NK_UINT_MAX); - col[2] = (nk_uint)(val[2]*(float)NK_UINT_MAX); - col[3] = (nk_uint)(val[3]*(float)NK_UINT_MAX); - NK_MEMCPY(attr, col, sizeof(col)); - } break; - case NK_FORMAT_R32G32B32A32_FLOAT: - NK_MEMCPY(attr, val, sizeof(float)*4); - break; - case NK_FORMAT_R32G32B32A32_DOUBLE: { - double col[4]; - col[0] = (double)val[0]; - col[1] = (double)val[1]; - col[2] = (double)val[2]; - col[3] = (double)val[3]; - NK_MEMCPY(attr, col, sizeof(col)); - } break; - case NK_FORMAT_RGB32: - case NK_FORMAT_RGBA32: { - struct nk_color col = nk_rgba_fv(val); - nk_uint color = nk_color_u32(col); - NK_MEMCPY(attr, &color, sizeof(color)); - } break; } -} - -NK_INTERN void -nk_draw_vertex_element(void *dst, const float *values, int value_count, - enum nk_draw_vertex_layout_format format) -{ - int value_index; - void *attribute = dst; - /* if this triggers you tried to provide a color format for a value */ - NK_ASSERT(format < NK_FORMAT_COLOR_BEGIN); - if (format >= NK_FORMAT_COLOR_BEGIN && format <= NK_FORMAT_COLOR_END) return; - for (value_index = 0; value_index < value_count; ++value_index) { - switch (format) { - default: NK_ASSERT(0 && "invalid vertex layout format"); break; - case NK_FORMAT_SCHAR: { - char value = (char)NK_CLAMP((float)NK_SCHAR_MIN, values[value_index], (float)NK_SCHAR_MAX); - NK_MEMCPY(attribute, &value, sizeof(value)); - attribute = (void*)((char*)attribute + sizeof(char)); - } break; - case NK_FORMAT_SSHORT: { - nk_short value = (nk_short)NK_CLAMP((float)NK_SSHORT_MIN, values[value_index], (float)NK_SSHORT_MAX); - NK_MEMCPY(attribute, &value, sizeof(value)); - attribute = (void*)((char*)attribute + sizeof(value)); - } break; - case NK_FORMAT_SINT: { - nk_int value = (nk_int)NK_CLAMP((float)NK_SINT_MIN, values[value_index], (float)NK_SINT_MAX); - NK_MEMCPY(attribute, &value, sizeof(value)); - attribute = (void*)((char*)attribute + sizeof(nk_int)); - } break; - case NK_FORMAT_UCHAR: { - unsigned char value = (unsigned char)NK_CLAMP((float)NK_UCHAR_MIN, values[value_index], (float)NK_UCHAR_MAX); - NK_MEMCPY(attribute, &value, sizeof(value)); - attribute = (void*)((char*)attribute + sizeof(unsigned char)); - } break; - case NK_FORMAT_USHORT: { - nk_ushort value = (nk_ushort)NK_CLAMP((float)NK_USHORT_MIN, values[value_index], (float)NK_USHORT_MAX); - NK_MEMCPY(attribute, &value, sizeof(value)); - attribute = (void*)((char*)attribute + sizeof(value)); - } break; - case NK_FORMAT_UINT: { - nk_uint value = (nk_uint)NK_CLAMP((float)NK_UINT_MIN, values[value_index], (float)NK_UINT_MAX); - NK_MEMCPY(attribute, &value, sizeof(value)); - attribute = (void*)((char*)attribute + sizeof(nk_uint)); - } break; - case NK_FORMAT_FLOAT: - NK_MEMCPY(attribute, &values[value_index], sizeof(values[value_index])); - attribute = (void*)((char*)attribute + sizeof(float)); - break; - case NK_FORMAT_DOUBLE: { - double value = (double)values[value_index]; - NK_MEMCPY(attribute, &value, sizeof(value)); - attribute = (void*)((char*)attribute + sizeof(double)); - } break; - } - } -} - -NK_INTERN void* -nk_draw_vertex(void *dst, const struct nk_convert_config *config, - struct nk_vec2 pos, struct nk_vec2 uv, struct nk_colorf color) -{ - void *result = (void*)((char*)dst + config->vertex_size); - const struct nk_draw_vertex_layout_element *elem_iter = config->vertex_layout; - while (!nk_draw_vertex_layout_element_is_end_of_layout(elem_iter)) { - void *address = (void*)((char*)dst + elem_iter->offset); - switch (elem_iter->attribute) { - case NK_VERTEX_ATTRIBUTE_COUNT: - default: NK_ASSERT(0 && "wrong element attribute"); break; - case NK_VERTEX_POSITION: nk_draw_vertex_element(address, &pos.x, 2, elem_iter->format); break; - case NK_VERTEX_TEXCOORD: nk_draw_vertex_element(address, &uv.x, 2, elem_iter->format); break; - case NK_VERTEX_COLOR: nk_draw_vertex_color(address, &color.r, elem_iter->format); break; - } - elem_iter++; - } - return result; -} - -NK_API void -nk_draw_list_stroke_poly_line(struct nk_draw_list *list, const struct nk_vec2 *points, - const unsigned int points_count, struct nk_color color, enum nk_draw_list_stroke closed, - float thickness, enum nk_anti_aliasing aliasing) -{ - nk_size count; - int thick_line; - struct nk_colorf col; - struct nk_colorf col_trans; - NK_ASSERT(list); - if (!list || points_count < 2) return; - - color.a = (nk_byte)((float)color.a * list->config.global_alpha); - count = points_count; - if (!closed) count = points_count-1; - thick_line = thickness > 1.0f; - -#ifdef NK_INCLUDE_COMMAND_USERDATA - nk_draw_list_push_userdata(list, list->userdata); -#endif - - color.a = (nk_byte)((float)color.a * list->config.global_alpha); - nk_color_fv(&col.r, color); - col_trans = col; - col_trans.a = 0; - - if (aliasing == NK_ANTI_ALIASING_ON) { - /* ANTI-ALIASED STROKE */ - const float AA_SIZE = 1.0f; - NK_STORAGE const nk_size pnt_align = NK_ALIGNOF(struct nk_vec2); - NK_STORAGE const nk_size pnt_size = sizeof(struct nk_vec2); - - /* allocate vertices and elements */ - nk_size i1 = 0; - nk_size vertex_offset; - nk_size index = list->vertex_count; - - const nk_size idx_count = (thick_line) ? (count * 18) : (count * 12); - const nk_size vtx_count = (thick_line) ? (points_count * 4): (points_count *3); - - void *vtx = nk_draw_list_alloc_vertices(list, vtx_count); - nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count); - - nk_size size; - struct nk_vec2 *normals, *temp; - if (!vtx || !ids) return; - - /* temporary allocate normals + points */ - vertex_offset = (nk_size)((nk_byte*)vtx - (nk_byte*)list->vertices->memory.ptr); - nk_buffer_mark(list->vertices, NK_BUFFER_FRONT); - size = pnt_size * ((thick_line) ? 5 : 3) * points_count; - normals = (struct nk_vec2*) nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT, size, pnt_align); - NK_ASSERT(normals); - if (!normals) return; - temp = normals + points_count; - - /* make sure vertex pointer is still correct */ - vtx = (void*)((nk_byte*)list->vertices->memory.ptr + vertex_offset); - - /* calculate normals */ - for (i1 = 0; i1 < count; ++i1) { - const nk_size i2 = ((i1 + 1) == points_count) ? 0 : (i1 + 1); - struct nk_vec2 diff = nk_vec2_sub(points[i2], points[i1]); - float len; - - /* vec2 inverted length */ - len = nk_vec2_len_sqr(diff); - if (len != 0.0f) - len = nk_inv_sqrt(len); - else len = 1.0f; - - diff = nk_vec2_muls(diff, len); - normals[i1].x = diff.y; - normals[i1].y = -diff.x; - } - - if (!closed) - normals[points_count-1] = normals[points_count-2]; - - if (!thick_line) { - nk_size idx1, i; - if (!closed) { - struct nk_vec2 d; - temp[0] = nk_vec2_add(points[0], nk_vec2_muls(normals[0], AA_SIZE)); - temp[1] = nk_vec2_sub(points[0], nk_vec2_muls(normals[0], AA_SIZE)); - d = nk_vec2_muls(normals[points_count-1], AA_SIZE); - temp[(points_count-1) * 2 + 0] = nk_vec2_add(points[points_count-1], d); - temp[(points_count-1) * 2 + 1] = nk_vec2_sub(points[points_count-1], d); - } - - /* fill elements */ - idx1 = index; - for (i1 = 0; i1 < count; i1++) { - struct nk_vec2 dm; - float dmr2; - nk_size i2 = ((i1 + 1) == points_count) ? 0 : (i1 + 1); - nk_size idx2 = ((i1+1) == points_count) ? index: (idx1 + 3); - - /* average normals */ - dm = nk_vec2_muls(nk_vec2_add(normals[i1], normals[i2]), 0.5f); - dmr2 = dm.x * dm.x + dm.y* dm.y; - if (dmr2 > 0.000001f) { - float scale = 1.0f/dmr2; - scale = NK_MIN(100.0f, scale); - dm = nk_vec2_muls(dm, scale); - } - - dm = nk_vec2_muls(dm, AA_SIZE); - temp[i2*2+0] = nk_vec2_add(points[i2], dm); - temp[i2*2+1] = nk_vec2_sub(points[i2], dm); - - ids[0] = (nk_draw_index)(idx2 + 0); ids[1] = (nk_draw_index)(idx1+0); - ids[2] = (nk_draw_index)(idx1 + 2); ids[3] = (nk_draw_index)(idx1+2); - ids[4] = (nk_draw_index)(idx2 + 2); ids[5] = (nk_draw_index)(idx2+0); - ids[6] = (nk_draw_index)(idx2 + 1); ids[7] = (nk_draw_index)(idx1+1); - ids[8] = (nk_draw_index)(idx1 + 0); ids[9] = (nk_draw_index)(idx1+0); - ids[10]= (nk_draw_index)(idx2 + 0); ids[11]= (nk_draw_index)(idx2+1); - ids += 12; - idx1 = idx2; - } - - /* fill vertices */ - for (i = 0; i < points_count; ++i) { - const struct nk_vec2 uv = list->config.null.uv; - vtx = nk_draw_vertex(vtx, &list->config, points[i], uv, col); - vtx = nk_draw_vertex(vtx, &list->config, temp[i*2+0], uv, col_trans); - vtx = nk_draw_vertex(vtx, &list->config, temp[i*2+1], uv, col_trans); - } - } else { - nk_size idx1, i; - const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f; - if (!closed) { - struct nk_vec2 d1 = nk_vec2_muls(normals[0], half_inner_thickness + AA_SIZE); - struct nk_vec2 d2 = nk_vec2_muls(normals[0], half_inner_thickness); - - temp[0] = nk_vec2_add(points[0], d1); - temp[1] = nk_vec2_add(points[0], d2); - temp[2] = nk_vec2_sub(points[0], d2); - temp[3] = nk_vec2_sub(points[0], d1); - - d1 = nk_vec2_muls(normals[points_count-1], half_inner_thickness + AA_SIZE); - d2 = nk_vec2_muls(normals[points_count-1], half_inner_thickness); - - temp[(points_count-1)*4+0] = nk_vec2_add(points[points_count-1], d1); - temp[(points_count-1)*4+1] = nk_vec2_add(points[points_count-1], d2); - temp[(points_count-1)*4+2] = nk_vec2_sub(points[points_count-1], d2); - temp[(points_count-1)*4+3] = nk_vec2_sub(points[points_count-1], d1); - } - - /* add all elements */ - idx1 = index; - for (i1 = 0; i1 < count; ++i1) { - struct nk_vec2 dm_out, dm_in; - const nk_size i2 = ((i1+1) == points_count) ? 0: (i1 + 1); - nk_size idx2 = ((i1+1) == points_count) ? index: (idx1 + 4); - - /* average normals */ - struct nk_vec2 dm = nk_vec2_muls(nk_vec2_add(normals[i1], normals[i2]), 0.5f); - float dmr2 = dm.x * dm.x + dm.y* dm.y; - if (dmr2 > 0.000001f) { - float scale = 1.0f/dmr2; - scale = NK_MIN(100.0f, scale); - dm = nk_vec2_muls(dm, scale); - } - - dm_out = nk_vec2_muls(dm, ((half_inner_thickness) + AA_SIZE)); - dm_in = nk_vec2_muls(dm, half_inner_thickness); - temp[i2*4+0] = nk_vec2_add(points[i2], dm_out); - temp[i2*4+1] = nk_vec2_add(points[i2], dm_in); - temp[i2*4+2] = nk_vec2_sub(points[i2], dm_in); - temp[i2*4+3] = nk_vec2_sub(points[i2], dm_out); - - /* add indexes */ - ids[0] = (nk_draw_index)(idx2 + 1); ids[1] = (nk_draw_index)(idx1+1); - ids[2] = (nk_draw_index)(idx1 + 2); ids[3] = (nk_draw_index)(idx1+2); - ids[4] = (nk_draw_index)(idx2 + 2); ids[5] = (nk_draw_index)(idx2+1); - ids[6] = (nk_draw_index)(idx2 + 1); ids[7] = (nk_draw_index)(idx1+1); - ids[8] = (nk_draw_index)(idx1 + 0); ids[9] = (nk_draw_index)(idx1+0); - ids[10]= (nk_draw_index)(idx2 + 0); ids[11] = (nk_draw_index)(idx2+1); - ids[12]= (nk_draw_index)(idx2 + 2); ids[13] = (nk_draw_index)(idx1+2); - ids[14]= (nk_draw_index)(idx1 + 3); ids[15] = (nk_draw_index)(idx1+3); - ids[16]= (nk_draw_index)(idx2 + 3); ids[17] = (nk_draw_index)(idx2+2); - ids += 18; - idx1 = idx2; - } - - /* add vertices */ - for (i = 0; i < points_count; ++i) { - const struct nk_vec2 uv = list->config.null.uv; - vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+0], uv, col_trans); - vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+1], uv, col); - vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+2], uv, col); - vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+3], uv, col_trans); - } - } - /* free temporary normals + points */ - nk_buffer_reset(list->vertices, NK_BUFFER_FRONT); - } else { - /* NON ANTI-ALIASED STROKE */ - nk_size i1 = 0; - nk_size idx = list->vertex_count; - const nk_size idx_count = count * 6; - const nk_size vtx_count = count * 4; - void *vtx = nk_draw_list_alloc_vertices(list, vtx_count); - nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count); - if (!vtx || !ids) return; - - for (i1 = 0; i1 < count; ++i1) { - float dx, dy; - const struct nk_vec2 uv = list->config.null.uv; - const nk_size i2 = ((i1+1) == points_count) ? 0 : i1 + 1; - const struct nk_vec2 p1 = points[i1]; - const struct nk_vec2 p2 = points[i2]; - struct nk_vec2 diff = nk_vec2_sub(p2, p1); - float len; - - /* vec2 inverted length */ - len = nk_vec2_len_sqr(diff); - if (len != 0.0f) - len = nk_inv_sqrt(len); - else len = 1.0f; - diff = nk_vec2_muls(diff, len); - - /* add vertices */ - dx = diff.x * (thickness * 0.5f); - dy = diff.y * (thickness * 0.5f); - - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p1.x + dy, p1.y - dx), uv, col); - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p2.x + dy, p2.y - dx), uv, col); - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p2.x - dy, p2.y + dx), uv, col); - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p1.x - dy, p1.y + dx), uv, col); - - ids[0] = (nk_draw_index)(idx+0); ids[1] = (nk_draw_index)(idx+1); - ids[2] = (nk_draw_index)(idx+2); ids[3] = (nk_draw_index)(idx+0); - ids[4] = (nk_draw_index)(idx+2); ids[5] = (nk_draw_index)(idx+3); - - ids += 6; - idx += 4; - } - } -} - -NK_API void -nk_draw_list_fill_poly_convex(struct nk_draw_list *list, - const struct nk_vec2 *points, const unsigned int points_count, - struct nk_color color, enum nk_anti_aliasing aliasing) -{ - struct nk_colorf col; - struct nk_colorf col_trans; - - NK_STORAGE const nk_size pnt_align = NK_ALIGNOF(struct nk_vec2); - NK_STORAGE const nk_size pnt_size = sizeof(struct nk_vec2); - NK_ASSERT(list); - if (!list || points_count < 3) return; - -#ifdef NK_INCLUDE_COMMAND_USERDATA - nk_draw_list_push_userdata(list, list->userdata); -#endif - - color.a = (nk_byte)((float)color.a * list->config.global_alpha); - nk_color_fv(&col.r, color); - col_trans = col; - col_trans.a = 0; - - if (aliasing == NK_ANTI_ALIASING_ON) { - nk_size i = 0; - nk_size i0 = 0; - nk_size i1 = 0; - - const float AA_SIZE = 1.0f; - nk_size vertex_offset = 0; - nk_size index = list->vertex_count; - - const nk_size idx_count = (points_count-2)*3 + points_count*6; - const nk_size vtx_count = (points_count*2); - - void *vtx = nk_draw_list_alloc_vertices(list, vtx_count); - nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count); - - nk_size size = 0; - struct nk_vec2 *normals = 0; - unsigned int vtx_inner_idx = (unsigned int)(index + 0); - unsigned int vtx_outer_idx = (unsigned int)(index + 1); - if (!vtx || !ids) return; - - /* temporary allocate normals */ - vertex_offset = (nk_size)((nk_byte*)vtx - (nk_byte*)list->vertices->memory.ptr); - nk_buffer_mark(list->vertices, NK_BUFFER_FRONT); - size = pnt_size * points_count; - normals = (struct nk_vec2*) nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT, size, pnt_align); - NK_ASSERT(normals); - if (!normals) return; - vtx = (void*)((nk_byte*)list->vertices->memory.ptr + vertex_offset); - - /* add elements */ - for (i = 2; i < points_count; i++) { - ids[0] = (nk_draw_index)(vtx_inner_idx); - ids[1] = (nk_draw_index)(vtx_inner_idx + ((i-1) << 1)); - ids[2] = (nk_draw_index)(vtx_inner_idx + (i << 1)); - ids += 3; - } - - /* compute normals */ - for (i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) { - struct nk_vec2 p0 = points[i0]; - struct nk_vec2 p1 = points[i1]; - struct nk_vec2 diff = nk_vec2_sub(p1, p0); - - /* vec2 inverted length */ - float len = nk_vec2_len_sqr(diff); - if (len != 0.0f) - len = nk_inv_sqrt(len); - else len = 1.0f; - diff = nk_vec2_muls(diff, len); - - normals[i0].x = diff.y; - normals[i0].y = -diff.x; - } - - /* add vertices + indexes */ - for (i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) { - const struct nk_vec2 uv = list->config.null.uv; - struct nk_vec2 n0 = normals[i0]; - struct nk_vec2 n1 = normals[i1]; - struct nk_vec2 dm = nk_vec2_muls(nk_vec2_add(n0, n1), 0.5f); - float dmr2 = dm.x*dm.x + dm.y*dm.y; - if (dmr2 > 0.000001f) { - float scale = 1.0f / dmr2; - scale = NK_MIN(scale, 100.0f); - dm = nk_vec2_muls(dm, scale); - } - dm = nk_vec2_muls(dm, AA_SIZE * 0.5f); - - /* add vertices */ - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2_sub(points[i1], dm), uv, col); - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2_add(points[i1], dm), uv, col_trans); - - /* add indexes */ - ids[0] = (nk_draw_index)(vtx_inner_idx+(i1<<1)); - ids[1] = (nk_draw_index)(vtx_inner_idx+(i0<<1)); - ids[2] = (nk_draw_index)(vtx_outer_idx+(i0<<1)); - ids[3] = (nk_draw_index)(vtx_outer_idx+(i0<<1)); - ids[4] = (nk_draw_index)(vtx_outer_idx+(i1<<1)); - ids[5] = (nk_draw_index)(vtx_inner_idx+(i1<<1)); - ids += 6; - } - /* free temporary normals + points */ - nk_buffer_reset(list->vertices, NK_BUFFER_FRONT); - } else { - nk_size i = 0; - nk_size index = list->vertex_count; - const nk_size idx_count = (points_count-2)*3; - const nk_size vtx_count = points_count; - void *vtx = nk_draw_list_alloc_vertices(list, vtx_count); - nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count); - - if (!vtx || !ids) return; - for (i = 0; i < vtx_count; ++i) - vtx = nk_draw_vertex(vtx, &list->config, points[i], list->config.null.uv, col); - for (i = 2; i < points_count; ++i) { - ids[0] = (nk_draw_index)index; - ids[1] = (nk_draw_index)(index+ i - 1); - ids[2] = (nk_draw_index)(index+i); - ids += 3; - } - } -} - -NK_API void -nk_draw_list_path_clear(struct nk_draw_list *list) -{ - NK_ASSERT(list); - if (!list) return; - nk_buffer_reset(list->buffer, NK_BUFFER_FRONT); - list->path_count = 0; - list->path_offset = 0; -} - -NK_API void -nk_draw_list_path_line_to(struct nk_draw_list *list, struct nk_vec2 pos) -{ - struct nk_vec2 *points = 0; - struct nk_draw_command *cmd = 0; - NK_ASSERT(list); - if (!list) return; - if (!list->cmd_count) - nk_draw_list_add_clip(list, nk_null_rect); - - cmd = nk_draw_list_command_last(list); - if (cmd && cmd->texture.ptr != list->config.null.texture.ptr) - nk_draw_list_push_image(list, list->config.null.texture); - - points = nk_draw_list_alloc_path(list, 1); - if (!points) return; - points[0] = pos; -} - -NK_API void -nk_draw_list_path_arc_to_fast(struct nk_draw_list *list, struct nk_vec2 center, - float radius, int a_min, int a_max) -{ - int a = 0; - NK_ASSERT(list); - if (!list) return; - if (a_min <= a_max) { - for (a = a_min; a <= a_max; a++) { - const struct nk_vec2 c = list->circle_vtx[(nk_size)a % NK_LEN(list->circle_vtx)]; - const float x = center.x + c.x * radius; - const float y = center.y + c.y * radius; - nk_draw_list_path_line_to(list, nk_vec2(x, y)); - } - } -} - -NK_API void -nk_draw_list_path_arc_to(struct nk_draw_list *list, struct nk_vec2 center, - float radius, float a_min, float a_max, unsigned int segments) -{ - unsigned int i = 0; - NK_ASSERT(list); - if (!list) return; - if (radius == 0.0f) return; - - /* This algorithm for arc drawing relies on these two trigonometric identities[1]: - sin(a + b) = sin(a) * cos(b) + cos(a) * sin(b) - cos(a + b) = cos(a) * cos(b) - sin(a) * sin(b) - - Two coordinates (x, y) of a point on a circle centered on - the origin can be written in polar form as: - x = r * cos(a) - y = r * sin(a) - where r is the radius of the circle, - a is the angle between (x, y) and the origin. - - This allows us to rotate the coordinates around the - origin by an angle b using the following transformation: - x' = r * cos(a + b) = x * cos(b) - y * sin(b) - y' = r * sin(a + b) = y * cos(b) + x * sin(b) - - [1] https://en.wikipedia.org/wiki/List_of_trigonometric_identities#Angle_sum_and_difference_identities - */ - {const float d_angle = (a_max - a_min) / (float)segments; - const float sin_d = (float)NK_SIN(d_angle); - const float cos_d = (float)NK_COS(d_angle); - - float cx = (float)NK_COS(a_min) * radius; - float cy = (float)NK_SIN(a_min) * radius; - for(i = 0; i <= segments; ++i) { - float new_cx, new_cy; - const float x = center.x + cx; - const float y = center.y + cy; - nk_draw_list_path_line_to(list, nk_vec2(x, y)); - - new_cx = cx * cos_d - cy * sin_d; - new_cy = cy * cos_d + cx * sin_d; - cx = new_cx; - cy = new_cy; - }} -} - -NK_API void -nk_draw_list_path_rect_to(struct nk_draw_list *list, struct nk_vec2 a, - struct nk_vec2 b, float rounding) -{ - float r; - NK_ASSERT(list); - if (!list) return; - r = rounding; - r = NK_MIN(r, ((b.x-a.x) < 0) ? -(b.x-a.x): (b.x-a.x)); - r = NK_MIN(r, ((b.y-a.y) < 0) ? -(b.y-a.y): (b.y-a.y)); - - if (r == 0.0f) { - nk_draw_list_path_line_to(list, a); - nk_draw_list_path_line_to(list, nk_vec2(b.x,a.y)); - nk_draw_list_path_line_to(list, b); - nk_draw_list_path_line_to(list, nk_vec2(a.x,b.y)); - } else { - nk_draw_list_path_arc_to_fast(list, nk_vec2(a.x + r, a.y + r), r, 6, 9); - nk_draw_list_path_arc_to_fast(list, nk_vec2(b.x - r, a.y + r), r, 9, 12); - nk_draw_list_path_arc_to_fast(list, nk_vec2(b.x - r, b.y - r), r, 0, 3); - nk_draw_list_path_arc_to_fast(list, nk_vec2(a.x + r, b.y - r), r, 3, 6); - } -} - -NK_API void -nk_draw_list_path_curve_to(struct nk_draw_list *list, struct nk_vec2 p2, - struct nk_vec2 p3, struct nk_vec2 p4, unsigned int num_segments) -{ - float t_step; - unsigned int i_step; - struct nk_vec2 p1; - - NK_ASSERT(list); - NK_ASSERT(list->path_count); - if (!list || !list->path_count) return; - num_segments = NK_MAX(num_segments, 1); - - p1 = nk_draw_list_path_last(list); - t_step = 1.0f/(float)num_segments; - for (i_step = 1; i_step <= num_segments; ++i_step) { - float t = t_step * (float)i_step; - float u = 1.0f - t; - float w1 = u*u*u; - float w2 = 3*u*u*t; - float w3 = 3*u*t*t; - float w4 = t * t *t; - float x = w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x; - float y = w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y; - nk_draw_list_path_line_to(list, nk_vec2(x,y)); - } -} - -NK_API void -nk_draw_list_path_fill(struct nk_draw_list *list, struct nk_color color) -{ - struct nk_vec2 *points; - NK_ASSERT(list); - if (!list) return; - points = (struct nk_vec2*)nk_buffer_memory(list->buffer); - nk_draw_list_fill_poly_convex(list, points, list->path_count, color, list->config.shape_AA); - nk_draw_list_path_clear(list); -} - -NK_API void -nk_draw_list_path_stroke(struct nk_draw_list *list, struct nk_color color, - enum nk_draw_list_stroke closed, float thickness) -{ - struct nk_vec2 *points; - NK_ASSERT(list); - if (!list) return; - points = (struct nk_vec2*)nk_buffer_memory(list->buffer); - nk_draw_list_stroke_poly_line(list, points, list->path_count, color, - closed, thickness, list->config.line_AA); - nk_draw_list_path_clear(list); -} - -NK_API void -nk_draw_list_stroke_line(struct nk_draw_list *list, struct nk_vec2 a, - struct nk_vec2 b, struct nk_color col, float thickness) -{ - NK_ASSERT(list); - if (!list || !col.a) return; - if (list->line_AA == NK_ANTI_ALIASING_ON) { - nk_draw_list_path_line_to(list, a); - nk_draw_list_path_line_to(list, b); - } else { - nk_draw_list_path_line_to(list, nk_vec2_sub(a,nk_vec2(0.5f,0.5f))); - nk_draw_list_path_line_to(list, nk_vec2_sub(b,nk_vec2(0.5f,0.5f))); - } - nk_draw_list_path_stroke(list, col, NK_STROKE_OPEN, thickness); -} - -NK_API void -nk_draw_list_fill_rect(struct nk_draw_list *list, struct nk_rect rect, - struct nk_color col, float rounding) -{ - NK_ASSERT(list); - if (!list || !col.a) return; - - if (list->line_AA == NK_ANTI_ALIASING_ON) { - nk_draw_list_path_rect_to(list, nk_vec2(rect.x, rect.y), - nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding); - } else { - nk_draw_list_path_rect_to(list, nk_vec2(rect.x-0.5f, rect.y-0.5f), - nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding); - } nk_draw_list_path_fill(list, col); -} - -NK_API void -nk_draw_list_stroke_rect(struct nk_draw_list *list, struct nk_rect rect, - struct nk_color col, float rounding, float thickness) -{ - NK_ASSERT(list); - if (!list || !col.a) return; - if (list->line_AA == NK_ANTI_ALIASING_ON) { - nk_draw_list_path_rect_to(list, nk_vec2(rect.x, rect.y), - nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding); - } else { - nk_draw_list_path_rect_to(list, nk_vec2(rect.x-0.5f, rect.y-0.5f), - nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding); - } nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness); -} - -NK_API void -nk_draw_list_fill_rect_multi_color(struct nk_draw_list *list, struct nk_rect rect, - struct nk_color left, struct nk_color top, struct nk_color right, - struct nk_color bottom) -{ - void *vtx; - struct nk_colorf col_left, col_top; - struct nk_colorf col_right, col_bottom; - nk_draw_index *idx; - nk_draw_index index; - - nk_color_fv(&col_left.r, left); - nk_color_fv(&col_right.r, right); - nk_color_fv(&col_top.r, top); - nk_color_fv(&col_bottom.r, bottom); - - NK_ASSERT(list); - if (!list) return; - - nk_draw_list_push_image(list, list->config.null.texture); - index = (nk_draw_index)list->vertex_count; - vtx = nk_draw_list_alloc_vertices(list, 4); - idx = nk_draw_list_alloc_elements(list, 6); - if (!vtx || !idx) return; - - idx[0] = (nk_draw_index)(index+0); idx[1] = (nk_draw_index)(index+1); - idx[2] = (nk_draw_index)(index+2); idx[3] = (nk_draw_index)(index+0); - idx[4] = (nk_draw_index)(index+2); idx[5] = (nk_draw_index)(index+3); - - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x, rect.y), list->config.null.uv, col_left); - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x + rect.w, rect.y), list->config.null.uv, col_top); - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x + rect.w, rect.y + rect.h), list->config.null.uv, col_right); - vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x, rect.y + rect.h), list->config.null.uv, col_bottom); -} - -NK_API void -nk_draw_list_fill_triangle(struct nk_draw_list *list, struct nk_vec2 a, - struct nk_vec2 b, struct nk_vec2 c, struct nk_color col) -{ - NK_ASSERT(list); - if (!list || !col.a) return; - nk_draw_list_path_line_to(list, a); - nk_draw_list_path_line_to(list, b); - nk_draw_list_path_line_to(list, c); - nk_draw_list_path_fill(list, col); -} - -NK_API void -nk_draw_list_stroke_triangle(struct nk_draw_list *list, struct nk_vec2 a, - struct nk_vec2 b, struct nk_vec2 c, struct nk_color col, float thickness) -{ - NK_ASSERT(list); - if (!list || !col.a) return; - nk_draw_list_path_line_to(list, a); - nk_draw_list_path_line_to(list, b); - nk_draw_list_path_line_to(list, c); - nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness); -} - -NK_API void -nk_draw_list_fill_circle(struct nk_draw_list *list, struct nk_vec2 center, - float radius, struct nk_color col, unsigned int segs) -{ - float a_max; - NK_ASSERT(list); - if (!list || !col.a) return; - a_max = NK_PI * 2.0f * ((float)segs - 1.0f) / (float)segs; - nk_draw_list_path_arc_to(list, center, radius, 0.0f, a_max, segs); - nk_draw_list_path_fill(list, col); -} - -NK_API void -nk_draw_list_stroke_circle(struct nk_draw_list *list, struct nk_vec2 center, - float radius, struct nk_color col, unsigned int segs, float thickness) -{ - float a_max; - NK_ASSERT(list); - if (!list || !col.a) return; - a_max = NK_PI * 2.0f * ((float)segs - 1.0f) / (float)segs; - nk_draw_list_path_arc_to(list, center, radius, 0.0f, a_max, segs); - nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness); -} - -NK_API void -nk_draw_list_stroke_curve(struct nk_draw_list *list, struct nk_vec2 p0, - struct nk_vec2 cp0, struct nk_vec2 cp1, struct nk_vec2 p1, - struct nk_color col, unsigned int segments, float thickness) -{ - NK_ASSERT(list); - if (!list || !col.a) return; - nk_draw_list_path_line_to(list, p0); - nk_draw_list_path_curve_to(list, cp0, cp1, p1, segments); - nk_draw_list_path_stroke(list, col, NK_STROKE_OPEN, thickness); -} - -NK_INTERN void -nk_draw_list_push_rect_uv(struct nk_draw_list *list, struct nk_vec2 a, - struct nk_vec2 c, struct nk_vec2 uva, struct nk_vec2 uvc, - struct nk_color color) -{ - void *vtx; - struct nk_vec2 uvb; - struct nk_vec2 uvd; - struct nk_vec2 b; - struct nk_vec2 d; - - struct nk_colorf col; - nk_draw_index *idx; - nk_draw_index index; - NK_ASSERT(list); - if (!list) return; - - nk_color_fv(&col.r, color); - uvb = nk_vec2(uvc.x, uva.y); - uvd = nk_vec2(uva.x, uvc.y); - b = nk_vec2(c.x, a.y); - d = nk_vec2(a.x, c.y); - - index = (nk_draw_index)list->vertex_count; - vtx = nk_draw_list_alloc_vertices(list, 4); - idx = nk_draw_list_alloc_elements(list, 6); - if (!vtx || !idx) return; - - idx[0] = (nk_draw_index)(index+0); idx[1] = (nk_draw_index)(index+1); - idx[2] = (nk_draw_index)(index+2); idx[3] = (nk_draw_index)(index+0); - idx[4] = (nk_draw_index)(index+2); idx[5] = (nk_draw_index)(index+3); - - vtx = nk_draw_vertex(vtx, &list->config, a, uva, col); - vtx = nk_draw_vertex(vtx, &list->config, b, uvb, col); - vtx = nk_draw_vertex(vtx, &list->config, c, uvc, col); - vtx = nk_draw_vertex(vtx, &list->config, d, uvd, col); -} - -NK_API void -nk_draw_list_add_image(struct nk_draw_list *list, struct nk_image texture, - struct nk_rect rect, struct nk_color color) -{ - NK_ASSERT(list); - if (!list) return; - /* push new command with given texture */ - nk_draw_list_push_image(list, texture.handle); - if (nk_image_is_subimage(&texture)) { - /* add region inside of the texture */ - struct nk_vec2 uv[2]; - uv[0].x = (float)texture.region[0]/(float)texture.w; - uv[0].y = (float)texture.region[1]/(float)texture.h; - uv[1].x = (float)(texture.region[0] + texture.region[2])/(float)texture.w; - uv[1].y = (float)(texture.region[1] + texture.region[3])/(float)texture.h; - nk_draw_list_push_rect_uv(list, nk_vec2(rect.x, rect.y), - nk_vec2(rect.x + rect.w, rect.y + rect.h), uv[0], uv[1], color); - } else nk_draw_list_push_rect_uv(list, nk_vec2(rect.x, rect.y), - nk_vec2(rect.x + rect.w, rect.y + rect.h), - nk_vec2(0.0f, 0.0f), nk_vec2(1.0f, 1.0f),color); -} - -NK_API void -nk_draw_list_add_text(struct nk_draw_list *list, const struct nk_user_font *font, - struct nk_rect rect, const char *text, int len, float font_height, - struct nk_color fg) -{ - float x = 0; - int text_len = 0; - nk_rune unicode = 0; - nk_rune next = 0; - int glyph_len = 0; - int next_glyph_len = 0; - struct nk_user_font_glyph g; - - NK_ASSERT(list); - if (!list || !len || !text) return; - if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h, - list->clip_rect.x, list->clip_rect.y, list->clip_rect.w, list->clip_rect.h)) return; - - nk_draw_list_push_image(list, font->texture); - x = rect.x; - glyph_len = nk_utf_decode(text, &unicode, len); - if (!glyph_len) return; - - /* draw every glyph image */ - fg.a = (nk_byte)((float)fg.a * list->config.global_alpha); - while (text_len < len && glyph_len) { - float gx, gy, gh, gw; - float char_width = 0; - if (unicode == NK_UTF_INVALID) break; - - /* query currently drawn glyph information */ - next_glyph_len = nk_utf_decode(text + text_len + glyph_len, &next, (int)len - text_len); - font->query(font->userdata, font_height, &g, unicode, - (next == NK_UTF_INVALID) ? '\0' : next); - - /* calculate and draw glyph drawing rectangle and image */ - gx = x + g.offset.x; - gy = rect.y + g.offset.y; - gw = g.width; gh = g.height; - char_width = g.xadvance; - nk_draw_list_push_rect_uv(list, nk_vec2(gx,gy), nk_vec2(gx + gw, gy+ gh), - g.uv[0], g.uv[1], fg); - - /* offset next glyph */ - text_len += glyph_len; - x += char_width; - glyph_len = next_glyph_len; - unicode = next; - } -} - -NK_API nk_flags -nk_convert(struct nk_context *ctx, struct nk_buffer *cmds, - struct nk_buffer *vertices, struct nk_buffer *elements, - const struct nk_convert_config *config) -{ - nk_flags res = NK_CONVERT_SUCCESS; - const struct nk_command *cmd; - NK_ASSERT(ctx); - NK_ASSERT(cmds); - NK_ASSERT(vertices); - NK_ASSERT(elements); - NK_ASSERT(config); - NK_ASSERT(config->vertex_layout); - NK_ASSERT(config->vertex_size); - if (!ctx || !cmds || !vertices || !elements || !config || !config->vertex_layout) - return NK_CONVERT_INVALID_PARAM; - - nk_draw_list_setup(&ctx->draw_list, config, cmds, vertices, elements, - config->line_AA, config->shape_AA); - nk_foreach(cmd, ctx) - { -#ifdef NK_INCLUDE_COMMAND_USERDATA - ctx->draw_list.userdata = cmd->userdata; -#endif - switch (cmd->type) { - case NK_COMMAND_NOP: break; - case NK_COMMAND_SCISSOR: { - const struct nk_command_scissor *s = (const struct nk_command_scissor*)cmd; - nk_draw_list_add_clip(&ctx->draw_list, nk_rect(s->x, s->y, s->w, s->h)); - } break; - case NK_COMMAND_LINE: { - const struct nk_command_line *l = (const struct nk_command_line*)cmd; - nk_draw_list_stroke_line(&ctx->draw_list, nk_vec2(l->begin.x, l->begin.y), - nk_vec2(l->end.x, l->end.y), l->color, l->line_thickness); - } break; - case NK_COMMAND_CURVE: { - const struct nk_command_curve *q = (const struct nk_command_curve*)cmd; - nk_draw_list_stroke_curve(&ctx->draw_list, nk_vec2(q->begin.x, q->begin.y), - nk_vec2(q->ctrl[0].x, q->ctrl[0].y), nk_vec2(q->ctrl[1].x, - q->ctrl[1].y), nk_vec2(q->end.x, q->end.y), q->color, - config->curve_segment_count, q->line_thickness); - } break; - case NK_COMMAND_RECT: { - const struct nk_command_rect *r = (const struct nk_command_rect*)cmd; - nk_draw_list_stroke_rect(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h), - r->color, (float)r->rounding, r->line_thickness); - } break; - case NK_COMMAND_RECT_FILLED: { - const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled*)cmd; - nk_draw_list_fill_rect(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h), - r->color, (float)r->rounding); - } break; - case NK_COMMAND_RECT_MULTI_COLOR: { - const struct nk_command_rect_multi_color *r = (const struct nk_command_rect_multi_color*)cmd; - nk_draw_list_fill_rect_multi_color(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h), - r->left, r->top, r->right, r->bottom); - } break; - case NK_COMMAND_CIRCLE: { - const struct nk_command_circle *c = (const struct nk_command_circle*)cmd; - nk_draw_list_stroke_circle(&ctx->draw_list, nk_vec2((float)c->x + (float)c->w/2, - (float)c->y + (float)c->h/2), (float)c->w/2, c->color, - config->circle_segment_count, c->line_thickness); - } break; - case NK_COMMAND_CIRCLE_FILLED: { - const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd; - nk_draw_list_fill_circle(&ctx->draw_list, nk_vec2((float)c->x + (float)c->w/2, - (float)c->y + (float)c->h/2), (float)c->w/2, c->color, - config->circle_segment_count); - } break; - case NK_COMMAND_ARC: { - const struct nk_command_arc *c = (const struct nk_command_arc*)cmd; - //nk_draw_list_path_line_to(&ctx->draw_list, nk_vec2(c->cx, c->cy)); - nk_draw_list_path_arc_to(&ctx->draw_list, nk_vec2(c->cx, c->cy), c->r, - c->a[0], c->a[1], config->arc_segment_count); - //nk_draw_list_path_stroke(&ctx->draw_list, c->color, NK_STROKE_CLOSED, c->line_thickness); - nk_draw_list_path_stroke(&ctx->draw_list, c->color, NK_STROKE_OPEN, c->line_thickness); - } break; - case NK_COMMAND_ARC_FILLED: { - const struct nk_command_arc_filled *c = (const struct nk_command_arc_filled*)cmd; - //nk_draw_list_path_line_to(&ctx->draw_list, nk_vec2(c->cx, c->cy)); - nk_draw_list_path_arc_to(&ctx->draw_list, nk_vec2(c->cx, c->cy), c->r, - c->a[0], c->a[1], config->arc_segment_count); - nk_draw_list_path_fill(&ctx->draw_list, c->color); - } break; - case NK_COMMAND_TRIANGLE: { - const struct nk_command_triangle *t = (const struct nk_command_triangle*)cmd; - nk_draw_list_stroke_triangle(&ctx->draw_list, nk_vec2(t->a.x, t->a.y), - nk_vec2(t->b.x, t->b.y), nk_vec2(t->c.x, t->c.y), t->color, - t->line_thickness); - } break; - case NK_COMMAND_TRIANGLE_FILLED: { - const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled*)cmd; - nk_draw_list_fill_triangle(&ctx->draw_list, nk_vec2(t->a.x, t->a.y), - nk_vec2(t->b.x, t->b.y), nk_vec2(t->c.x, t->c.y), t->color); - } break; - case NK_COMMAND_POLYGON: { - int i; - const struct nk_command_polygon*p = (const struct nk_command_polygon*)cmd; - for (i = 0; i < p->point_count; ++i) { - struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y); - nk_draw_list_path_line_to(&ctx->draw_list, pnt); - } - nk_draw_list_path_stroke(&ctx->draw_list, p->color, NK_STROKE_CLOSED, p->line_thickness); - } break; - case NK_COMMAND_POLYGON_FILLED: { - int i; - const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled*)cmd; - for (i = 0; i < p->point_count; ++i) { - struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y); - nk_draw_list_path_line_to(&ctx->draw_list, pnt); - } - nk_draw_list_path_fill(&ctx->draw_list, p->color); - } break; - case NK_COMMAND_POLYLINE: { - int i; - const struct nk_command_polyline *p = (const struct nk_command_polyline*)cmd; - for (i = 0; i < p->point_count; ++i) { - struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y); - nk_draw_list_path_line_to(&ctx->draw_list, pnt); - } - nk_draw_list_path_stroke(&ctx->draw_list, p->color, NK_STROKE_OPEN, p->line_thickness); - } break; - case NK_COMMAND_TEXT: { - const struct nk_command_text *t = (const struct nk_command_text*)cmd; - nk_draw_list_add_text(&ctx->draw_list, t->font, nk_rect(t->x, t->y, t->w, t->h), - t->string, t->length, t->height, t->foreground); - } break; - case NK_COMMAND_IMAGE: { - const struct nk_command_image *i = (const struct nk_command_image*)cmd; - nk_draw_list_add_image(&ctx->draw_list, i->img, nk_rect(i->x, i->y, i->w, i->h), i->col); - } break; - case NK_COMMAND_CUSTOM: { - const struct nk_command_custom *c = (const struct nk_command_custom*)cmd; - c->callback(&ctx->draw_list, c->x, c->y, c->w, c->h, c->callback_data); - } break; - default: break; - } - } - res |= (cmds->needed > cmds->allocated + (cmds->memory.size - cmds->size)) ? NK_CONVERT_COMMAND_BUFFER_FULL: 0; - res |= (vertices->needed > vertices->allocated) ? NK_CONVERT_VERTEX_BUFFER_FULL: 0; - res |= (elements->needed > elements->allocated) ? NK_CONVERT_ELEMENT_BUFFER_FULL: 0; - return res; -} -NK_API const struct nk_draw_command* -nk__draw_begin(const struct nk_context *ctx, - const struct nk_buffer *buffer) -{return nk__draw_list_begin(&ctx->draw_list, buffer);} - -NK_API const struct nk_draw_command* -nk__draw_end(const struct nk_context *ctx, const struct nk_buffer *buffer) -{return nk__draw_list_end(&ctx->draw_list, buffer);} - -NK_API const struct nk_draw_command* -nk__draw_next(const struct nk_draw_command *cmd, - const struct nk_buffer *buffer, const struct nk_context *ctx) -{return nk__draw_list_next(cmd, buffer, &ctx->draw_list);} - -#endif - -/* - * ============================================================== - * - * FONT HANDLING - * - * =============================================================== - */ -#ifdef NK_INCLUDE_FONT_BAKING -/* ------------------------------------------------------------- - * - * RECT PACK - * - * --------------------------------------------------------------*/ -/* stb_rect_pack.h - v0.05 - public domain - rectangle packing */ -/* Sean Barrett 2014 */ -#define NK_RP__MAXVAL 0xffff -typedef unsigned short nk_rp_coord; - -struct nk_rp_rect { - /* reserved for your use: */ - int id; - /* input: */ - nk_rp_coord w, h; - /* output: */ - nk_rp_coord x, y; - int was_packed; - /* non-zero if valid packing */ -}; /* 16 bytes, nominally */ - -struct nk_rp_node { - nk_rp_coord x,y; - struct nk_rp_node *next; -}; - -struct nk_rp_context { - int width; - int height; - int align; - int init_mode; - int heuristic; - int num_nodes; - struct nk_rp_node *active_head; - struct nk_rp_node *free_head; - struct nk_rp_node extra[2]; - /* we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' */ -}; - -struct nk_rp__findresult { - int x,y; - struct nk_rp_node **prev_link; -}; - -enum NK_RP_HEURISTIC { - NK_RP_HEURISTIC_Skyline_default=0, - NK_RP_HEURISTIC_Skyline_BL_sortHeight = NK_RP_HEURISTIC_Skyline_default, - NK_RP_HEURISTIC_Skyline_BF_sortHeight -}; -enum NK_RP_INIT_STATE{NK_RP__INIT_skyline = 1}; - -NK_INTERN void -nk_rp_setup_allow_out_of_mem(struct nk_rp_context *context, int allow_out_of_mem) -{ - if (allow_out_of_mem) - /* if it's ok to run out of memory, then don't bother aligning them; */ - /* this gives better packing, but may fail due to OOM (even though */ - /* the rectangles easily fit). @TODO a smarter approach would be to only */ - /* quantize once we've hit OOM, then we could get rid of this parameter. */ - context->align = 1; - else { - /* if it's not ok to run out of memory, then quantize the widths */ - /* so that num_nodes is always enough nodes. */ - /* */ - /* I.e. num_nodes * align >= width */ - /* align >= width / num_nodes */ - /* align = ceil(width/num_nodes) */ - context->align = (context->width + context->num_nodes-1) / context->num_nodes; - } -} - -NK_INTERN void -nk_rp_init_target(struct nk_rp_context *context, int width, int height, - struct nk_rp_node *nodes, int num_nodes) -{ - int i; -#ifndef STBRP_LARGE_RECTS - NK_ASSERT(width <= 0xffff && height <= 0xffff); -#endif - - for (i=0; i < num_nodes-1; ++i) - nodes[i].next = &nodes[i+1]; - nodes[i].next = 0; - context->init_mode = NK_RP__INIT_skyline; - context->heuristic = NK_RP_HEURISTIC_Skyline_default; - context->free_head = &nodes[0]; - context->active_head = &context->extra[0]; - context->width = width; - context->height = height; - context->num_nodes = num_nodes; - nk_rp_setup_allow_out_of_mem(context, 0); - - /* node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) */ - context->extra[0].x = 0; - context->extra[0].y = 0; - context->extra[0].next = &context->extra[1]; - context->extra[1].x = (nk_rp_coord) width; - context->extra[1].y = 65535; - context->extra[1].next = 0; -} - -/* find minimum y position if it starts at x1 */ -NK_INTERN int -nk_rp__skyline_find_min_y(struct nk_rp_context *c, struct nk_rp_node *first, - int x0, int width, int *pwaste) -{ - struct nk_rp_node *node = first; - int x1 = x0 + width; - int min_y, visited_width, waste_area; - NK_ASSERT(first->x <= x0); - NK_UNUSED(c); - - NK_ASSERT(node->next->x > x0); - /* we ended up handling this in the caller for efficiency */ - NK_ASSERT(node->x <= x0); - - min_y = 0; - waste_area = 0; - visited_width = 0; - while (node->x < x1) - { - if (node->y > min_y) { - /* raise min_y higher. */ - /* we've accounted for all waste up to min_y, */ - /* but we'll now add more waste for everything we've visited */ - waste_area += visited_width * (node->y - min_y); - min_y = node->y; - /* the first time through, visited_width might be reduced */ - if (node->x < x0) - visited_width += node->next->x - x0; - else - visited_width += node->next->x - node->x; - } else { - /* add waste area */ - int under_width = node->next->x - node->x; - if (under_width + visited_width > width) - under_width = width - visited_width; - waste_area += under_width * (min_y - node->y); - visited_width += under_width; - } - node = node->next; - } - *pwaste = waste_area; - return min_y; -} - -NK_INTERN struct nk_rp__findresult -nk_rp__skyline_find_best_pos(struct nk_rp_context *c, int width, int height) -{ - int best_waste = (1<<30), best_x, best_y = (1 << 30); - struct nk_rp__findresult fr; - struct nk_rp_node **prev, *node, *tail, **best = 0; - - /* align to multiple of c->align */ - width = (width + c->align - 1); - width -= width % c->align; - NK_ASSERT(width % c->align == 0); - - node = c->active_head; - prev = &c->active_head; - while (node->x + width <= c->width) { - int y,waste; - y = nk_rp__skyline_find_min_y(c, node, node->x, width, &waste); - /* actually just want to test BL */ - if (c->heuristic == NK_RP_HEURISTIC_Skyline_BL_sortHeight) { - /* bottom left */ - if (y < best_y) { - best_y = y; - best = prev; - } - } else { - /* best-fit */ - if (y + height <= c->height) { - /* can only use it if it first vertically */ - if (y < best_y || (y == best_y && waste < best_waste)) { - best_y = y; - best_waste = waste; - best = prev; - } - } - } - prev = &node->next; - node = node->next; - } - best_x = (best == 0) ? 0 : (*best)->x; - - /* if doing best-fit (BF), we also have to try aligning right edge to each node position */ - /* */ - /* e.g, if fitting */ - /* */ - /* ____________________ */ - /* |____________________| */ - /* */ - /* into */ - /* */ - /* | | */ - /* | ____________| */ - /* |____________| */ - /* */ - /* then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned */ - /* */ - /* This makes BF take about 2x the time */ - if (c->heuristic == NK_RP_HEURISTIC_Skyline_BF_sortHeight) - { - tail = c->active_head; - node = c->active_head; - prev = &c->active_head; - /* find first node that's admissible */ - while (tail->x < width) - tail = tail->next; - while (tail) - { - int xpos = tail->x - width; - int y,waste; - NK_ASSERT(xpos >= 0); - /* find the left position that matches this */ - while (node->next->x <= xpos) { - prev = &node->next; - node = node->next; - } - NK_ASSERT(node->next->x > xpos && node->x <= xpos); - y = nk_rp__skyline_find_min_y(c, node, xpos, width, &waste); - if (y + height < c->height) { - if (y <= best_y) { - if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { - best_x = xpos; - NK_ASSERT(y <= best_y); - best_y = y; - best_waste = waste; - best = prev; - } - } - } - tail = tail->next; - } - } - fr.prev_link = best; - fr.x = best_x; - fr.y = best_y; - return fr; -} - -NK_INTERN struct nk_rp__findresult -nk_rp__skyline_pack_rectangle(struct nk_rp_context *context, int width, int height) -{ - /* find best position according to heuristic */ - struct nk_rp__findresult res = nk_rp__skyline_find_best_pos(context, width, height); - struct nk_rp_node *node, *cur; - - /* bail if: */ - /* 1. it failed */ - /* 2. the best node doesn't fit (we don't always check this) */ - /* 3. we're out of memory */ - if (res.prev_link == 0 || res.y + height > context->height || context->free_head == 0) { - res.prev_link = 0; - return res; - } - - /* on success, create new node */ - node = context->free_head; - node->x = (nk_rp_coord) res.x; - node->y = (nk_rp_coord) (res.y + height); - - context->free_head = node->next; - - /* insert the new node into the right starting point, and */ - /* let 'cur' point to the remaining nodes needing to be */ - /* stitched back in */ - cur = *res.prev_link; - if (cur->x < res.x) { - /* preserve the existing one, so start testing with the next one */ - struct nk_rp_node *next = cur->next; - cur->next = node; - cur = next; - } else { - *res.prev_link = node; - } - - /* from here, traverse cur and free the nodes, until we get to one */ - /* that shouldn't be freed */ - while (cur->next && cur->next->x <= res.x + width) { - struct nk_rp_node *next = cur->next; - /* move the current node to the free list */ - cur->next = context->free_head; - context->free_head = cur; - cur = next; - } - /* stitch the list back in */ - node->next = cur; - - if (cur->x < res.x + width) - cur->x = (nk_rp_coord) (res.x + width); - return res; -} - -NK_INTERN int -nk_rect_height_compare(const void *a, const void *b) -{ - const struct nk_rp_rect *p = (const struct nk_rp_rect *) a; - const struct nk_rp_rect *q = (const struct nk_rp_rect *) b; - if (p->h > q->h) - return -1; - if (p->h < q->h) - return 1; - return (p->w > q->w) ? -1 : (p->w < q->w); -} - -NK_INTERN int -nk_rect_original_order(const void *a, const void *b) -{ - const struct nk_rp_rect *p = (const struct nk_rp_rect *) a; - const struct nk_rp_rect *q = (const struct nk_rp_rect *) b; - return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); -} - -NK_INTERN void -nk_rp_qsort(struct nk_rp_rect *array, unsigned int len, int(*cmp)(const void*,const void*)) -{ - /* iterative quick sort */ - #define NK_MAX_SORT_STACK 64 - unsigned right, left = 0, stack[NK_MAX_SORT_STACK], pos = 0; - unsigned seed = len/2 * 69069+1; - for (;;) { - for (; left+1 < len; len++) { - struct nk_rp_rect pivot, tmp; - if (pos == NK_MAX_SORT_STACK) len = stack[pos = 0]; - pivot = array[left+seed%(len-left)]; - seed = seed * 69069 + 1; - stack[pos++] = len; - for (right = left-1;;) { - while (cmp(&array[++right], &pivot) < 0); - while (cmp(&pivot, &array[--len]) < 0); - if (right >= len) break; - tmp = array[right]; - array[right] = array[len]; - array[len] = tmp; - } - } - if (pos == 0) break; - left = len; - len = stack[--pos]; - } - #undef NK_MAX_SORT_STACK -} - -NK_INTERN void -nk_rp_pack_rects(struct nk_rp_context *context, struct nk_rp_rect *rects, int num_rects) -{ - int i; - /* we use the 'was_packed' field internally to allow sorting/unsorting */ - for (i=0; i < num_rects; ++i) { - rects[i].was_packed = i; - } - - /* sort according to heuristic */ - nk_rp_qsort(rects, (unsigned)num_rects, nk_rect_height_compare); - - for (i=0; i < num_rects; ++i) { - struct nk_rp__findresult fr = nk_rp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); - if (fr.prev_link) { - rects[i].x = (nk_rp_coord) fr.x; - rects[i].y = (nk_rp_coord) fr.y; - } else { - rects[i].x = rects[i].y = NK_RP__MAXVAL; - } - } - - /* unsort */ - nk_rp_qsort(rects, (unsigned)num_rects, nk_rect_original_order); - - /* set was_packed flags */ - for (i=0; i < num_rects; ++i) - rects[i].was_packed = !(rects[i].x == NK_RP__MAXVAL && rects[i].y == NK_RP__MAXVAL); -} - -/* - * ============================================================== - * - * TRUETYPE - * - * =============================================================== - */ -/* stb_truetype.h - v1.07 - public domain */ -#define NK_TT_MAX_OVERSAMPLE 8 -#define NK_TT__OVER_MASK (NK_TT_MAX_OVERSAMPLE-1) - -struct nk_tt_bakedchar { - unsigned short x0,y0,x1,y1; - /* coordinates of bbox in bitmap */ - float xoff,yoff,xadvance; -}; - -struct nk_tt_aligned_quad{ - float x0,y0,s0,t0; /* top-left */ - float x1,y1,s1,t1; /* bottom-right */ -}; - -struct nk_tt_packedchar { - unsigned short x0,y0,x1,y1; - /* coordinates of bbox in bitmap */ - float xoff,yoff,xadvance; - float xoff2,yoff2; -}; - -struct nk_tt_pack_range { - float font_size; - int first_unicode_codepoint_in_range; - /* if non-zero, then the chars are continuous, and this is the first codepoint */ - int *array_of_unicode_codepoints; - /* if non-zero, then this is an array of unicode codepoints */ - int num_chars; - struct nk_tt_packedchar *chardata_for_range; /* output */ - unsigned char h_oversample, v_oversample; - /* don't set these, they're used internally */ -}; - -struct nk_tt_pack_context { - void *pack_info; - int width; - int height; - int stride_in_bytes; - int padding; - unsigned int h_oversample, v_oversample; - unsigned char *pixels; - void *nodes; -}; - -struct nk_tt_fontinfo { - const unsigned char* data; /* pointer to .ttf file */ - int fontstart;/* offset of start of font */ - int numGlyphs;/* number of glyphs, needed for range checking */ - int loca,head,glyf,hhea,hmtx,kern; /* table locations as offset from start of .ttf */ - int index_map; /* a cmap mapping for our chosen character encoding */ - int indexToLocFormat; /* format needed to map from glyph index to glyph */ -}; - -enum { - NK_TT_vmove=1, - NK_TT_vline, - NK_TT_vcurve -}; - -struct nk_tt_vertex { - short x,y,cx,cy; - unsigned char type,padding; -}; - -struct nk_tt__bitmap{ - int w,h,stride; - unsigned char *pixels; -}; - -struct nk_tt__hheap_chunk { - struct nk_tt__hheap_chunk *next; -}; -struct nk_tt__hheap { - struct nk_allocator alloc; - struct nk_tt__hheap_chunk *head; - void *first_free; - int num_remaining_in_head_chunk; -}; - -struct nk_tt__edge { - float x0,y0, x1,y1; - int invert; -}; - -struct nk_tt__active_edge { - struct nk_tt__active_edge *next; - float fx,fdx,fdy; - float direction; - float sy; - float ey; -}; -struct nk_tt__point {float x,y;}; - -#define NK_TT_MACSTYLE_DONTCARE 0 -#define NK_TT_MACSTYLE_BOLD 1 -#define NK_TT_MACSTYLE_ITALIC 2 -#define NK_TT_MACSTYLE_UNDERSCORE 4 -#define NK_TT_MACSTYLE_NONE 8 -/* <= not same as 0, this makes us check the bitfield is 0 */ - -enum { /* platformID */ - NK_TT_PLATFORM_ID_UNICODE =0, - NK_TT_PLATFORM_ID_MAC =1, - NK_TT_PLATFORM_ID_ISO =2, - NK_TT_PLATFORM_ID_MICROSOFT =3 -}; - -enum { /* encodingID for NK_TT_PLATFORM_ID_UNICODE */ - NK_TT_UNICODE_EID_UNICODE_1_0 =0, - NK_TT_UNICODE_EID_UNICODE_1_1 =1, - NK_TT_UNICODE_EID_ISO_10646 =2, - NK_TT_UNICODE_EID_UNICODE_2_0_BMP=3, - NK_TT_UNICODE_EID_UNICODE_2_0_FULL=4 -}; - -enum { /* encodingID for NK_TT_PLATFORM_ID_MICROSOFT */ - NK_TT_MS_EID_SYMBOL =0, - NK_TT_MS_EID_UNICODE_BMP =1, - NK_TT_MS_EID_SHIFTJIS =2, - NK_TT_MS_EID_UNICODE_FULL =10 -}; - -enum { /* encodingID for NK_TT_PLATFORM_ID_MAC; same as Script Manager codes */ - NK_TT_MAC_EID_ROMAN =0, NK_TT_MAC_EID_ARABIC =4, - NK_TT_MAC_EID_JAPANESE =1, NK_TT_MAC_EID_HEBREW =5, - NK_TT_MAC_EID_CHINESE_TRAD =2, NK_TT_MAC_EID_GREEK =6, - NK_TT_MAC_EID_KOREAN =3, NK_TT_MAC_EID_RUSSIAN =7 -}; - -enum { /* languageID for NK_TT_PLATFORM_ID_MICROSOFT; same as LCID... */ - /* problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs */ - NK_TT_MS_LANG_ENGLISH =0x0409, NK_TT_MS_LANG_ITALIAN =0x0410, - NK_TT_MS_LANG_CHINESE =0x0804, NK_TT_MS_LANG_JAPANESE =0x0411, - NK_TT_MS_LANG_DUTCH =0x0413, NK_TT_MS_LANG_KOREAN =0x0412, - NK_TT_MS_LANG_FRENCH =0x040c, NK_TT_MS_LANG_RUSSIAN =0x0419, - NK_TT_MS_LANG_GERMAN =0x0407, NK_TT_MS_LANG_SPANISH =0x0409, - NK_TT_MS_LANG_HEBREW =0x040d, NK_TT_MS_LANG_SWEDISH =0x041D -}; - -enum { /* languageID for NK_TT_PLATFORM_ID_MAC */ - NK_TT_MAC_LANG_ENGLISH =0 , NK_TT_MAC_LANG_JAPANESE =11, - NK_TT_MAC_LANG_ARABIC =12, NK_TT_MAC_LANG_KOREAN =23, - NK_TT_MAC_LANG_DUTCH =4 , NK_TT_MAC_LANG_RUSSIAN =32, - NK_TT_MAC_LANG_FRENCH =1 , NK_TT_MAC_LANG_SPANISH =6 , - NK_TT_MAC_LANG_GERMAN =2 , NK_TT_MAC_LANG_SWEDISH =5 , - NK_TT_MAC_LANG_HEBREW =10, NK_TT_MAC_LANG_CHINESE_SIMPLIFIED =33, - NK_TT_MAC_LANG_ITALIAN =3 , NK_TT_MAC_LANG_CHINESE_TRAD =19 -}; - -#define nk_ttBYTE(p) (* (const nk_byte *) (p)) -#define nk_ttCHAR(p) (* (const char *) (p)) - -#if defined(NK_BIGENDIAN) && !defined(NK_ALLOW_UNALIGNED_TRUETYPE) - #define nk_ttUSHORT(p) (* (nk_ushort *) (p)) - #define nk_ttSHORT(p) (* (nk_short *) (p)) - #define nk_ttULONG(p) (* (nk_uint *) (p)) - #define nk_ttLONG(p) (* (nk_int *) (p)) -#else - static nk_ushort nk_ttUSHORT(const nk_byte *p) { return (nk_ushort)(p[0]*256 + p[1]); } - static nk_short nk_ttSHORT(const nk_byte *p) { return (nk_short)(p[0]*256 + p[1]); } - static nk_uint nk_ttULONG(const nk_byte *p) { return (nk_uint)((p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]); } -#endif - -#define nk_tt_tag4(p,c0,c1,c2,c3)\ - ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) -#define nk_tt_tag(p,str) nk_tt_tag4(p,str[0],str[1],str[2],str[3]) - -NK_INTERN int nk_tt_GetGlyphShape(const struct nk_tt_fontinfo *info, struct nk_allocator *alloc, - int glyph_index, struct nk_tt_vertex **pvertices); - -NK_INTERN nk_uint -nk_tt__find_table(const nk_byte *data, nk_uint fontstart, const char *tag) -{ - /* @OPTIMIZE: binary search */ - nk_int num_tables = nk_ttUSHORT(data+fontstart+4); - nk_uint tabledir = fontstart + 12; - nk_int i; - for (i = 0; i < num_tables; ++i) { - nk_uint loc = tabledir + (nk_uint)(16*i); - if (nk_tt_tag(data+loc+0, tag)) - return nk_ttULONG(data+loc+8); - } - return 0; -} - -NK_INTERN int -nk_tt_InitFont(struct nk_tt_fontinfo *info, const unsigned char *data2, int fontstart) -{ - nk_uint cmap, t; - nk_int i,numTables; - const nk_byte *data = (const nk_byte *) data2; - - info->data = data; - info->fontstart = fontstart; - - cmap = nk_tt__find_table(data, (nk_uint)fontstart, "cmap"); /* required */ - info->loca = (int)nk_tt__find_table(data, (nk_uint)fontstart, "loca"); /* required */ - info->head = (int)nk_tt__find_table(data, (nk_uint)fontstart, "head"); /* required */ - info->glyf = (int)nk_tt__find_table(data, (nk_uint)fontstart, "glyf"); /* required */ - info->hhea = (int)nk_tt__find_table(data, (nk_uint)fontstart, "hhea"); /* required */ - info->hmtx = (int)nk_tt__find_table(data, (nk_uint)fontstart, "hmtx"); /* required */ - info->kern = (int)nk_tt__find_table(data, (nk_uint)fontstart, "kern"); /* not required */ - if (!cmap || !info->loca || !info->head || !info->glyf || !info->hhea || !info->hmtx) - return 0; - - t = nk_tt__find_table(data, (nk_uint)fontstart, "maxp"); - if (t) info->numGlyphs = nk_ttUSHORT(data+t+4); - else info->numGlyphs = 0xffff; - - /* find a cmap encoding table we understand *now* to avoid searching */ - /* later. (todo: could make this installable) */ - /* the same regardless of glyph. */ - numTables = nk_ttUSHORT(data + cmap + 2); - info->index_map = 0; - for (i=0; i < numTables; ++i) - { - nk_uint encoding_record = cmap + 4 + 8 * (nk_uint)i; - /* find an encoding we understand: */ - switch(nk_ttUSHORT(data+encoding_record)) { - case NK_TT_PLATFORM_ID_MICROSOFT: - switch (nk_ttUSHORT(data+encoding_record+2)) { - case NK_TT_MS_EID_UNICODE_BMP: - case NK_TT_MS_EID_UNICODE_FULL: - /* MS/Unicode */ - info->index_map = (int)(cmap + nk_ttULONG(data+encoding_record+4)); - break; - default: break; - } break; - case NK_TT_PLATFORM_ID_UNICODE: - /* Mac/iOS has these */ - /* all the encodingIDs are unicode, so we don't bother to check it */ - info->index_map = (int)(cmap + nk_ttULONG(data+encoding_record+4)); - break; - default: break; - } - } - if (info->index_map == 0) - return 0; - info->indexToLocFormat = nk_ttUSHORT(data+info->head + 50); - return 1; -} - -NK_INTERN int -nk_tt_FindGlyphIndex(const struct nk_tt_fontinfo *info, int unicode_codepoint) -{ - const nk_byte *data = info->data; - nk_uint index_map = (nk_uint)info->index_map; - - nk_ushort format = nk_ttUSHORT(data + index_map + 0); - if (format == 0) { /* apple byte encoding */ - nk_int bytes = nk_ttUSHORT(data + index_map + 2); - if (unicode_codepoint < bytes-6) - return nk_ttBYTE(data + index_map + 6 + unicode_codepoint); - return 0; - } else if (format == 6) { - nk_uint first = nk_ttUSHORT(data + index_map + 6); - nk_uint count = nk_ttUSHORT(data + index_map + 8); - if ((nk_uint) unicode_codepoint >= first && (nk_uint) unicode_codepoint < first+count) - return nk_ttUSHORT(data + index_map + 10 + (unicode_codepoint - (int)first)*2); - return 0; - } else if (format == 2) { - NK_ASSERT(0); /* @TODO: high-byte mapping for japanese/chinese/korean */ - return 0; - } else if (format == 4) { /* standard mapping for windows fonts: binary search collection of ranges */ - nk_ushort segcount = nk_ttUSHORT(data+index_map+6) >> 1; - nk_ushort searchRange = nk_ttUSHORT(data+index_map+8) >> 1; - nk_ushort entrySelector = nk_ttUSHORT(data+index_map+10); - nk_ushort rangeShift = nk_ttUSHORT(data+index_map+12) >> 1; - - /* do a binary search of the segments */ - nk_uint endCount = index_map + 14; - nk_uint search = endCount; - - if (unicode_codepoint > 0xffff) - return 0; - - /* they lie from endCount .. endCount + segCount */ - /* but searchRange is the nearest power of two, so... */ - if (unicode_codepoint >= nk_ttUSHORT(data + search + rangeShift*2)) - search += (nk_uint)(rangeShift*2); - - /* now decrement to bias correctly to find smallest */ - search -= 2; - while (entrySelector) { - nk_ushort end; - searchRange >>= 1; - end = nk_ttUSHORT(data + search + searchRange*2); - if (unicode_codepoint > end) - search += (nk_uint)(searchRange*2); - --entrySelector; - } - search += 2; - - { - nk_ushort offset, start; - nk_ushort item = (nk_ushort) ((search - endCount) >> 1); - - NK_ASSERT(unicode_codepoint <= nk_ttUSHORT(data + endCount + 2*item)); - start = nk_ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); - if (unicode_codepoint < start) - return 0; - - offset = nk_ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); - if (offset == 0) - return (nk_ushort) (unicode_codepoint + nk_ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); - - return nk_ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); - } - } else if (format == 12 || format == 13) { - nk_uint ngroups = nk_ttULONG(data+index_map+12); - nk_int low,high; - low = 0; high = (nk_int)ngroups; - /* Binary search the right group. */ - while (low < high) { - nk_int mid = low + ((high-low) >> 1); /* rounds down, so low <= mid < high */ - nk_uint start_char = nk_ttULONG(data+index_map+16+mid*12); - nk_uint end_char = nk_ttULONG(data+index_map+16+mid*12+4); - if ((nk_uint) unicode_codepoint < start_char) - high = mid; - else if ((nk_uint) unicode_codepoint > end_char) - low = mid+1; - else { - nk_uint start_glyph = nk_ttULONG(data+index_map+16+mid*12+8); - if (format == 12) - return (int)start_glyph + (int)unicode_codepoint - (int)start_char; - else /* format == 13 */ - return (int)start_glyph; - } - } - return 0; /* not found */ - } - /* @TODO */ - NK_ASSERT(0); - return 0; -} - -NK_INTERN void -nk_tt_setvertex(struct nk_tt_vertex *v, nk_byte type, nk_int x, nk_int y, nk_int cx, nk_int cy) -{ - v->type = type; - v->x = (nk_short) x; - v->y = (nk_short) y; - v->cx = (nk_short) cx; - v->cy = (nk_short) cy; -} - -NK_INTERN int -nk_tt__GetGlyfOffset(const struct nk_tt_fontinfo *info, int glyph_index) -{ - int g1,g2; - if (glyph_index >= info->numGlyphs) return -1; /* glyph index out of range */ - if (info->indexToLocFormat >= 2) return -1; /* unknown index->glyph map format */ - - if (info->indexToLocFormat == 0) { - g1 = info->glyf + nk_ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; - g2 = info->glyf + nk_ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; - } else { - g1 = info->glyf + (int)nk_ttULONG (info->data + info->loca + glyph_index * 4); - g2 = info->glyf + (int)nk_ttULONG (info->data + info->loca + glyph_index * 4 + 4); - } - return g1==g2 ? -1 : g1; /* if length is 0, return -1 */ -} - -NK_INTERN int -nk_tt_GetGlyphBox(const struct nk_tt_fontinfo *info, int glyph_index, - int *x0, int *y0, int *x1, int *y1) -{ - int g = nk_tt__GetGlyfOffset(info, glyph_index); - if (g < 0) return 0; - - if (x0) *x0 = nk_ttSHORT(info->data + g + 2); - if (y0) *y0 = nk_ttSHORT(info->data + g + 4); - if (x1) *x1 = nk_ttSHORT(info->data + g + 6); - if (y1) *y1 = nk_ttSHORT(info->data + g + 8); - return 1; -} - -NK_INTERN int -nk_tt__close_shape(struct nk_tt_vertex *vertices, int num_vertices, int was_off, - int start_off, nk_int sx, nk_int sy, nk_int scx, nk_int scy, nk_int cx, nk_int cy) -{ - if (start_off) { - if (was_off) - nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy); - nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve, sx,sy,scx,scy); - } else { - if (was_off) - nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve,sx,sy,cx,cy); - else - nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vline,sx,sy,0,0); - } - return num_vertices; -} - -NK_INTERN int -nk_tt_GetGlyphShape(const struct nk_tt_fontinfo *info, struct nk_allocator *alloc, - int glyph_index, struct nk_tt_vertex **pvertices) -{ - nk_short numberOfContours; - const nk_byte *endPtsOfContours; - const nk_byte *data = info->data; - struct nk_tt_vertex *vertices=0; - int num_vertices=0; - int g = nk_tt__GetGlyfOffset(info, glyph_index); - *pvertices = 0; - - if (g < 0) return 0; - numberOfContours = nk_ttSHORT(data + g); - if (numberOfContours > 0) { - nk_byte flags=0,flagcount; - nk_int ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0; - nk_int x,y,cx,cy,sx,sy, scx,scy; - const nk_byte *points; - endPtsOfContours = (data + g + 10); - ins = nk_ttUSHORT(data + g + 10 + numberOfContours * 2); - points = data + g + 10 + numberOfContours * 2 + 2 + ins; - - n = 1+nk_ttUSHORT(endPtsOfContours + numberOfContours*2-2); - m = n + 2*numberOfContours; /* a loose bound on how many vertices we might need */ - vertices = (struct nk_tt_vertex *)alloc->alloc(alloc->userdata, 0, (nk_size)m * sizeof(vertices[0])); - if (vertices == 0) - return 0; - - next_move = 0; - flagcount=0; - - /* in first pass, we load uninterpreted data into the allocated array */ - /* above, shifted to the end of the array so we won't overwrite it when */ - /* we create our final data starting from the front */ - off = m - n; /* starting offset for uninterpreted data, regardless of how m ends up being calculated */ - - /* first load flags */ - for (i=0; i < n; ++i) { - if (flagcount == 0) { - flags = *points++; - if (flags & 8) - flagcount = *points++; - } else --flagcount; - vertices[off+i].type = flags; - } - - /* now load x coordinates */ - x=0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - if (flags & 2) { - nk_short dx = *points++; - x += (flags & 16) ? dx : -dx; /* ??? */ - } else { - if (!(flags & 16)) { - x = x + (nk_short) (points[0]*256 + points[1]); - points += 2; - } - } - vertices[off+i].x = (nk_short) x; - } - - /* now load y coordinates */ - y=0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - if (flags & 4) { - nk_short dy = *points++; - y += (flags & 32) ? dy : -dy; /* ??? */ - } else { - if (!(flags & 32)) { - y = y + (nk_short) (points[0]*256 + points[1]); - points += 2; - } - } - vertices[off+i].y = (nk_short) y; - } - - /* now convert them to our format */ - num_vertices=0; - sx = sy = cx = cy = scx = scy = 0; - for (i=0; i < n; ++i) - { - flags = vertices[off+i].type; - x = (nk_short) vertices[off+i].x; - y = (nk_short) vertices[off+i].y; - - if (next_move == i) { - if (i != 0) - num_vertices = nk_tt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); - - /* now start the new one */ - start_off = !(flags & 1); - if (start_off) { - /* if we start off with an off-curve point, then when we need to find a point on the curve */ - /* where we can start, and we need to save some state for when we wraparound. */ - scx = x; - scy = y; - if (!(vertices[off+i+1].type & 1)) { - /* next point is also a curve point, so interpolate an on-point curve */ - sx = (x + (nk_int) vertices[off+i+1].x) >> 1; - sy = (y + (nk_int) vertices[off+i+1].y) >> 1; - } else { - /* otherwise just use the next point as our start point */ - sx = (nk_int) vertices[off+i+1].x; - sy = (nk_int) vertices[off+i+1].y; - ++i; /* we're using point i+1 as the starting point, so skip it */ - } - } else { - sx = x; - sy = y; - } - nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vmove,sx,sy,0,0); - was_off = 0; - next_move = 1 + nk_ttUSHORT(endPtsOfContours+j*2); - ++j; - } else { - if (!(flags & 1)) - { /* if it's a curve */ - if (was_off) /* two off-curve control points in a row means interpolate an on-curve midpoint */ - nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy); - cx = x; - cy = y; - was_off = 1; - } else { - if (was_off) - nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vcurve, x,y, cx, cy); - else nk_tt_setvertex(&vertices[num_vertices++], NK_TT_vline, x,y,0,0); - was_off = 0; - } - } - } - num_vertices = nk_tt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); - } else if (numberOfContours == -1) { - /* Compound shapes. */ - int more = 1; - const nk_byte *comp = data + g + 10; - num_vertices = 0; - vertices = 0; - - while (more) - { - nk_ushort flags, gidx; - int comp_num_verts = 0, i; - struct nk_tt_vertex *comp_verts = 0, *tmp = 0; - float mtx[6] = {1,0,0,1,0,0}, m, n; - - flags = (nk_ushort)nk_ttSHORT(comp); comp+=2; - gidx = (nk_ushort)nk_ttSHORT(comp); comp+=2; - - if (flags & 2) { /* XY values */ - if (flags & 1) { /* shorts */ - mtx[4] = nk_ttSHORT(comp); comp+=2; - mtx[5] = nk_ttSHORT(comp); comp+=2; - } else { - mtx[4] = nk_ttCHAR(comp); comp+=1; - mtx[5] = nk_ttCHAR(comp); comp+=1; - } - } else { - /* @TODO handle matching point */ - NK_ASSERT(0); - } - if (flags & (1<<3)) { /* WE_HAVE_A_SCALE */ - mtx[0] = mtx[3] = nk_ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = mtx[2] = 0; - } else if (flags & (1<<6)) { /* WE_HAVE_AN_X_AND_YSCALE */ - mtx[0] = nk_ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = mtx[2] = 0; - mtx[3] = nk_ttSHORT(comp)/16384.0f; comp+=2; - } else if (flags & (1<<7)) { /* WE_HAVE_A_TWO_BY_TWO */ - mtx[0] = nk_ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = nk_ttSHORT(comp)/16384.0f; comp+=2; - mtx[2] = nk_ttSHORT(comp)/16384.0f; comp+=2; - mtx[3] = nk_ttSHORT(comp)/16384.0f; comp+=2; - } - - /* Find transformation scales. */ - m = (float) NK_SQRT(mtx[0]*mtx[0] + mtx[1]*mtx[1]); - n = (float) NK_SQRT(mtx[2]*mtx[2] + mtx[3]*mtx[3]); - - /* Get indexed glyph. */ - comp_num_verts = nk_tt_GetGlyphShape(info, alloc, gidx, &comp_verts); - if (comp_num_verts > 0) - { - /* Transform vertices. */ - for (i = 0; i < comp_num_verts; ++i) { - struct nk_tt_vertex* v = &comp_verts[i]; - short x,y; - x=v->x; y=v->y; - v->x = (short)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); - v->y = (short)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); - x=v->cx; y=v->cy; - v->cx = (short)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); - v->cy = (short)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); - } - /* Append vertices. */ - tmp = (struct nk_tt_vertex*)alloc->alloc(alloc->userdata, 0, - (nk_size)(num_vertices+comp_num_verts)*sizeof(struct nk_tt_vertex)); - if (!tmp) { - if (vertices) alloc->free(alloc->userdata, vertices); - if (comp_verts) alloc->free(alloc->userdata, comp_verts); - return 0; - } - if (num_vertices > 0) NK_MEMCPY(tmp, vertices, (nk_size)num_vertices*sizeof(struct nk_tt_vertex)); - NK_MEMCPY(tmp+num_vertices, comp_verts, (nk_size)comp_num_verts*sizeof(struct nk_tt_vertex)); - if (vertices) alloc->free(alloc->userdata,vertices); - vertices = tmp; - alloc->free(alloc->userdata,comp_verts); - num_vertices += comp_num_verts; - } - /* More components ? */ - more = flags & (1<<5); - } - } else if (numberOfContours < 0) { - /* @TODO other compound variations? */ - NK_ASSERT(0); - } else { - /* numberOfCounters == 0, do nothing */ - } - *pvertices = vertices; - return num_vertices; -} - -NK_INTERN void -nk_tt_GetGlyphHMetrics(const struct nk_tt_fontinfo *info, int glyph_index, - int *advanceWidth, int *leftSideBearing) -{ - nk_ushort numOfLongHorMetrics = nk_ttUSHORT(info->data+info->hhea + 34); - if (glyph_index < numOfLongHorMetrics) { - if (advanceWidth) - *advanceWidth = nk_ttSHORT(info->data + info->hmtx + 4*glyph_index); - if (leftSideBearing) - *leftSideBearing = nk_ttSHORT(info->data + info->hmtx + 4*glyph_index + 2); - } else { - if (advanceWidth) - *advanceWidth = nk_ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1)); - if (leftSideBearing) - *leftSideBearing = nk_ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics)); - } -} - -NK_INTERN void -nk_tt_GetFontVMetrics(const struct nk_tt_fontinfo *info, - int *ascent, int *descent, int *lineGap) -{ - if (ascent ) *ascent = nk_ttSHORT(info->data+info->hhea + 4); - if (descent) *descent = nk_ttSHORT(info->data+info->hhea + 6); - if (lineGap) *lineGap = nk_ttSHORT(info->data+info->hhea + 8); -} - -NK_INTERN float -nk_tt_ScaleForPixelHeight(const struct nk_tt_fontinfo *info, float height) -{ - int fheight = nk_ttSHORT(info->data + info->hhea + 4) - nk_ttSHORT(info->data + info->hhea + 6); - return (float) height / (float)fheight; -} - -NK_INTERN float -nk_tt_ScaleForMappingEmToPixels(const struct nk_tt_fontinfo *info, float pixels) -{ - int unitsPerEm = nk_ttUSHORT(info->data + info->head + 18); - return pixels / (float)unitsPerEm; -} - -/*------------------------------------------------------------- - * antialiasing software rasterizer - * --------------------------------------------------------------*/ -NK_INTERN void -nk_tt_GetGlyphBitmapBoxSubpixel(const struct nk_tt_fontinfo *font, - int glyph, float scale_x, float scale_y,float shift_x, float shift_y, - int *ix0, int *iy0, int *ix1, int *iy1) -{ - int x0,y0,x1,y1; - if (!nk_tt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { - /* e.g. space character */ - if (ix0) *ix0 = 0; - if (iy0) *iy0 = 0; - if (ix1) *ix1 = 0; - if (iy1) *iy1 = 0; - } else { - /* move to integral bboxes (treating pixels as little squares, what pixels get touched)? */ - if (ix0) *ix0 = nk_ifloorf((float)x0 * scale_x + shift_x); - if (iy0) *iy0 = nk_ifloorf((float)-y1 * scale_y + shift_y); - if (ix1) *ix1 = nk_iceilf ((float)x1 * scale_x + shift_x); - if (iy1) *iy1 = nk_iceilf ((float)-y0 * scale_y + shift_y); - } -} - -NK_INTERN void -nk_tt_GetGlyphBitmapBox(const struct nk_tt_fontinfo *font, int glyph, - float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - nk_tt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1); -} - -/*------------------------------------------------------------- - * Rasterizer - * --------------------------------------------------------------*/ -NK_INTERN void* -nk_tt__hheap_alloc(struct nk_tt__hheap *hh, nk_size size) -{ - if (hh->first_free) { - void *p = hh->first_free; - hh->first_free = * (void **) p; - return p; - } else { - if (hh->num_remaining_in_head_chunk == 0) { - int count = (size < 32 ? 2000 : size < 128 ? 800 : 100); - struct nk_tt__hheap_chunk *c = (struct nk_tt__hheap_chunk *) - hh->alloc.alloc(hh->alloc.userdata, 0, - sizeof(struct nk_tt__hheap_chunk) + size * (nk_size)count); - if (c == 0) return 0; - c->next = hh->head; - hh->head = c; - hh->num_remaining_in_head_chunk = count; - } - --hh->num_remaining_in_head_chunk; - return (char *) (hh->head) + size * (nk_size)hh->num_remaining_in_head_chunk; - } -} - -NK_INTERN void -nk_tt__hheap_free(struct nk_tt__hheap *hh, void *p) -{ - *(void **) p = hh->first_free; - hh->first_free = p; -} - -NK_INTERN void -nk_tt__hheap_cleanup(struct nk_tt__hheap *hh) -{ - struct nk_tt__hheap_chunk *c = hh->head; - while (c) { - struct nk_tt__hheap_chunk *n = c->next; - hh->alloc.free(hh->alloc.userdata, c); - c = n; - } -} - -NK_INTERN struct nk_tt__active_edge* -nk_tt__new_active(struct nk_tt__hheap *hh, struct nk_tt__edge *e, - int off_x, float start_point) -{ - struct nk_tt__active_edge *z = (struct nk_tt__active_edge *) - nk_tt__hheap_alloc(hh, sizeof(*z)); - float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); - /*STBTT_assert(e->y0 <= start_point); */ - if (!z) return z; - z->fdx = dxdy; - z->fdy = (dxdy != 0) ? (1/dxdy): 0; - z->fx = e->x0 + dxdy * (start_point - e->y0); - z->fx -= (float)off_x; - z->direction = e->invert ? 1.0f : -1.0f; - z->sy = e->y0; - z->ey = e->y1; - z->next = 0; - return z; -} - -NK_INTERN void -nk_tt__handle_clipped_edge(float *scanline, int x, struct nk_tt__active_edge *e, - float x0, float y0, float x1, float y1) -{ - if (y0 == y1) return; - NK_ASSERT(y0 < y1); - NK_ASSERT(e->sy <= e->ey); - if (y0 > e->ey) return; - if (y1 < e->sy) return; - if (y0 < e->sy) { - x0 += (x1-x0) * (e->sy - y0) / (y1-y0); - y0 = e->sy; - } - if (y1 > e->ey) { - x1 += (x1-x0) * (e->ey - y1) / (y1-y0); - y1 = e->ey; - } - - if (x0 == x) NK_ASSERT(x1 <= x+1); - else if (x0 == x+1) NK_ASSERT(x1 >= x); - else if (x0 <= x) NK_ASSERT(x1 <= x); - else if (x0 >= x+1) NK_ASSERT(x1 >= x+1); - else NK_ASSERT(x1 >= x && x1 <= x+1); - - if (x0 <= x && x1 <= x) - scanline[x] += e->direction * (y1-y0); - else if (x0 >= x+1 && x1 >= x+1); - else { - NK_ASSERT(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1); - /* coverage = 1 - average x position */ - scanline[x] += (float)e->direction * (float)(y1-y0) * (1.0f-((x0-(float)x)+(x1-(float)x))/2.0f); - } -} - -NK_INTERN void -nk_tt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, - struct nk_tt__active_edge *e, float y_top) -{ - float y_bottom = y_top+1; - while (e) - { - /* brute force every pixel */ - /* compute intersection points with top & bottom */ - NK_ASSERT(e->ey >= y_top); - if (e->fdx == 0) { - float x0 = e->fx; - if (x0 < len) { - if (x0 >= 0) { - nk_tt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom); - nk_tt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom); - } else { - nk_tt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom); - } - } - } else { - float x0 = e->fx; - float dx = e->fdx; - float xb = x0 + dx; - float x_top, x_bottom; - float y0,y1; - float dy = e->fdy; - NK_ASSERT(e->sy <= y_bottom && e->ey >= y_top); - - /* compute endpoints of line segment clipped to this scanline (if the */ - /* line segment starts on this scanline. x0 is the intersection of the */ - /* line with y_top, but that may be off the line segment. */ - if (e->sy > y_top) { - x_top = x0 + dx * (e->sy - y_top); - y0 = e->sy; - } else { - x_top = x0; - y0 = y_top; - } - - if (e->ey < y_bottom) { - x_bottom = x0 + dx * (e->ey - y_top); - y1 = e->ey; - } else { - x_bottom = xb; - y1 = y_bottom; - } - - if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) - { - /* from here on, we don't have to range check x values */ - if ((int) x_top == (int) x_bottom) { - float height; - /* simple case, only spans one pixel */ - int x = (int) x_top; - height = y1 - y0; - NK_ASSERT(x >= 0 && x < len); - scanline[x] += e->direction * (1.0f-(((float)x_top - (float)x) + ((float)x_bottom-(float)x))/2.0f) * (float)height; - scanline_fill[x] += e->direction * (float)height; /* everything right of this pixel is filled */ - } else { - int x,x1,x2; - float y_crossing, step, sign, area; - /* covers 2+ pixels */ - if (x_top > x_bottom) - { - /* flip scanline vertically; signed area is the same */ - float t; - y0 = y_bottom - (y0 - y_top); - y1 = y_bottom - (y1 - y_top); - t = y0; y0 = y1; y1 = t; - t = x_bottom; x_bottom = x_top; x_top = t; - dx = -dx; - dy = -dy; - t = x0; x0 = xb; xb = t; - } - - x1 = (int) x_top; - x2 = (int) x_bottom; - /* compute intersection with y axis at x1+1 */ - y_crossing = ((float)x1+1 - (float)x0) * (float)dy + (float)y_top; - - sign = e->direction; - /* area of the rectangle covered from y0..y_crossing */ - area = sign * (y_crossing-y0); - /* area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing) */ - scanline[x1] += area * (1.0f-((float)((float)x_top - (float)x1)+(float)(x1+1-x1))/2.0f); - - step = sign * dy; - for (x = x1+1; x < x2; ++x) { - scanline[x] += area + step/2; - area += step; - } - y_crossing += (float)dy * (float)(x2 - (x1+1)); - - scanline[x2] += area + sign * (1.0f-((float)(x2-x2)+((float)x_bottom-(float)x2))/2.0f) * (y1-y_crossing); - scanline_fill[x2] += sign * (y1-y0); - } - } - else - { - /* if edge goes outside of box we're drawing, we require */ - /* clipping logic. since this does not match the intended use */ - /* of this library, we use a different, very slow brute */ - /* force implementation */ - int x; - for (x=0; x < len; ++x) - { - /* cases: */ - /* */ - /* there can be up to two intersections with the pixel. any intersection */ - /* with left or right edges can be handled by splitting into two (or three) */ - /* regions. intersections with top & bottom do not necessitate case-wise logic. */ - /* */ - /* the old way of doing this found the intersections with the left & right edges, */ - /* then used some simple logic to produce up to three segments in sorted order */ - /* from top-to-bottom. however, this had a problem: if an x edge was epsilon */ - /* across the x border, then the corresponding y position might not be distinct */ - /* from the other y segment, and it might ignored as an empty segment. to avoid */ - /* that, we need to explicitly produce segments based on x positions. */ - - /* rename variables to clear pairs */ - float ya = y_top; - float x1 = (float) (x); - float x2 = (float) (x+1); - float x3 = xb; - float y3 = y_bottom; - float yb,y2; - - yb = ((float)x - x0) / dx + y_top; - y2 = ((float)x+1 - x0) / dx + y_top; - - if (x0 < x1 && x3 > x2) { /* three segments descending down-right */ - nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x1,yb); - nk_tt__handle_clipped_edge(scanline,x,e, x1,yb, x2,y2); - nk_tt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); - } else if (x3 < x1 && x0 > x2) { /* three segments descending down-left */ - nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x2,y2); - nk_tt__handle_clipped_edge(scanline,x,e, x2,y2, x1,yb); - nk_tt__handle_clipped_edge(scanline,x,e, x1,yb, x3,y3); - } else if (x0 < x1 && x3 > x1) { /* two segments across x, down-right */ - nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x1,yb); - nk_tt__handle_clipped_edge(scanline,x,e, x1,yb, x3,y3); - } else if (x3 < x1 && x0 > x1) { /* two segments across x, down-left */ - nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x1,yb); - nk_tt__handle_clipped_edge(scanline,x,e, x1,yb, x3,y3); - } else if (x0 < x2 && x3 > x2) { /* two segments across x+1, down-right */ - nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x2,y2); - nk_tt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); - } else if (x3 < x2 && x0 > x2) { /* two segments across x+1, down-left */ - nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x2,y2); - nk_tt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); - } else { /* one segment */ - nk_tt__handle_clipped_edge(scanline,x,e, x0,ya, x3,y3); - } - } - } - } - e = e->next; - } -} - -/* directly AA rasterize edges w/o supersampling */ -NK_INTERN void -nk_tt__rasterize_sorted_edges(struct nk_tt__bitmap *result, struct nk_tt__edge *e, - int n, int vsubsample, int off_x, int off_y, struct nk_allocator *alloc) -{ - struct nk_tt__hheap hh; - struct nk_tt__active_edge *active = 0; - int y,j=0, i; - float scanline_data[129], *scanline, *scanline2; - - NK_UNUSED(vsubsample); - nk_zero_struct(hh); - hh.alloc = *alloc; - - if (result->w > 64) - scanline = (float *) alloc->alloc(alloc->userdata,0, (nk_size)(result->w*2+1) * sizeof(float)); - else scanline = scanline_data; - - scanline2 = scanline + result->w; - y = off_y; - e[n].y0 = (float) (off_y + result->h) + 1; - - while (j < result->h) - { - /* find center of pixel for this scanline */ - float scan_y_top = (float)y + 0.0f; - float scan_y_bottom = (float)y + 1.0f; - struct nk_tt__active_edge **step = &active; - - NK_MEMSET(scanline , 0, (nk_size)result->w*sizeof(scanline[0])); - NK_MEMSET(scanline2, 0, (nk_size)(result->w+1)*sizeof(scanline[0])); - - /* update all active edges; */ - /* remove all active edges that terminate before the top of this scanline */ - while (*step) { - struct nk_tt__active_edge * z = *step; - if (z->ey <= scan_y_top) { - *step = z->next; /* delete from list */ - NK_ASSERT(z->direction); - z->direction = 0; - nk_tt__hheap_free(&hh, z); - } else { - step = &((*step)->next); /* advance through list */ - } - } - - /* insert all edges that start before the bottom of this scanline */ - while (e->y0 <= scan_y_bottom) { - if (e->y0 != e->y1) { - struct nk_tt__active_edge *z = nk_tt__new_active(&hh, e, off_x, scan_y_top); - if (z != 0) { - NK_ASSERT(z->ey >= scan_y_top); - /* insert at front */ - z->next = active; - active = z; - } - } - ++e; - } - - /* now process all active edges */ - if (active) - nk_tt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top); - - { - float sum = 0; - for (i=0; i < result->w; ++i) { - float k; - int m; - sum += scanline2[i]; - k = scanline[i] + sum; - k = (float) NK_ABS(k) * 255.0f + 0.5f; - m = (int) k; - if (m > 255) m = 255; - result->pixels[j*result->stride + i] = (unsigned char) m; - } - } - /* advance all the edges */ - step = &active; - while (*step) { - struct nk_tt__active_edge *z = *step; - z->fx += z->fdx; /* advance to position for current scanline */ - step = &((*step)->next); /* advance through list */ - } - ++y; - ++j; - } - nk_tt__hheap_cleanup(&hh); - if (scanline != scanline_data) - alloc->free(alloc->userdata, scanline); -} - -#define NK_TT__COMPARE(a,b) ((a)->y0 < (b)->y0) -NK_INTERN void -nk_tt__sort_edges_ins_sort(struct nk_tt__edge *p, int n) -{ - int i,j; - for (i=1; i < n; ++i) { - struct nk_tt__edge t = p[i], *a = &t; - j = i; - while (j > 0) { - struct nk_tt__edge *b = &p[j-1]; - int c = NK_TT__COMPARE(a,b); - if (!c) break; - p[j] = p[j-1]; - --j; - } - if (i != j) - p[j] = t; - } -} - -NK_INTERN void -nk_tt__sort_edges_quicksort(struct nk_tt__edge *p, int n) -{ - /* threshold for transitioning to insertion sort */ - while (n > 12) { - struct nk_tt__edge t; - int c01,c12,c,m,i,j; - - /* compute median of three */ - m = n >> 1; - c01 = NK_TT__COMPARE(&p[0],&p[m]); - c12 = NK_TT__COMPARE(&p[m],&p[n-1]); - - /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ - if (c01 != c12) { - /* otherwise, we'll need to swap something else to middle */ - int z; - c = NK_TT__COMPARE(&p[0],&p[n-1]); - /* 0>mid && midn => n; 0 0 */ - /* 0n: 0>n => 0; 0 n */ - z = (c == c12) ? 0 : n-1; - t = p[z]; - p[z] = p[m]; - p[m] = t; - } - - /* now p[m] is the median-of-three */ - /* swap it to the beginning so it won't move around */ - t = p[0]; - p[0] = p[m]; - p[m] = t; - - /* partition loop */ - i=1; - j=n-1; - for(;;) { - /* handling of equality is crucial here */ - /* for sentinels & efficiency with duplicates */ - for (;;++i) { - if (!NK_TT__COMPARE(&p[i], &p[0])) break; - } - for (;;--j) { - if (!NK_TT__COMPARE(&p[0], &p[j])) break; - } - - /* make sure we haven't crossed */ - if (i >= j) break; - t = p[i]; - p[i] = p[j]; - p[j] = t; - - ++i; - --j; - - } - - /* recurse on smaller side, iterate on larger */ - if (j < (n-i)) { - nk_tt__sort_edges_quicksort(p,j); - p = p+i; - n = n-i; - } else { - nk_tt__sort_edges_quicksort(p+i, n-i); - n = j; - } - } -} - -NK_INTERN void -nk_tt__sort_edges(struct nk_tt__edge *p, int n) -{ - nk_tt__sort_edges_quicksort(p, n); - nk_tt__sort_edges_ins_sort(p, n); -} - -NK_INTERN void -nk_tt__rasterize(struct nk_tt__bitmap *result, struct nk_tt__point *pts, - int *wcount, int windings, float scale_x, float scale_y, - float shift_x, float shift_y, int off_x, int off_y, int invert, - struct nk_allocator *alloc) -{ - float y_scale_inv = invert ? -scale_y : scale_y; - struct nk_tt__edge *e; - int n,i,j,k,m; - int vsubsample = 1; - /* vsubsample should divide 255 evenly; otherwise we won't reach full opacity */ - - /* now we have to blow out the windings into explicit edge lists */ - n = 0; - for (i=0; i < windings; ++i) - n += wcount[i]; - - e = (struct nk_tt__edge*) - alloc->alloc(alloc->userdata, 0,(sizeof(*e) * (nk_size)(n+1))); - if (e == 0) return; - n = 0; - - m=0; - for (i=0; i < windings; ++i) - { - struct nk_tt__point *p = pts + m; - m += wcount[i]; - j = wcount[i]-1; - for (k=0; k < wcount[i]; j=k++) { - int a=k,b=j; - /* skip the edge if horizontal */ - if (p[j].y == p[k].y) - continue; - - /* add edge from j to k to the list */ - e[n].invert = 0; - if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { - e[n].invert = 1; - a=j,b=k; - } - e[n].x0 = p[a].x * scale_x + shift_x; - e[n].y0 = (p[a].y * y_scale_inv + shift_y) * (float)vsubsample; - e[n].x1 = p[b].x * scale_x + shift_x; - e[n].y1 = (p[b].y * y_scale_inv + shift_y) * (float)vsubsample; - ++n; - } - } - - /* now sort the edges by their highest point (should snap to integer, and then by x) */ - /*STBTT_sort(e, n, sizeof(e[0]), nk_tt__edge_compare); */ - nk_tt__sort_edges(e, n); - /* now, traverse the scanlines and find the intersections on each scanline, use xor winding rule */ - nk_tt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, alloc); - alloc->free(alloc->userdata, e); -} - -NK_INTERN void -nk_tt__add_point(struct nk_tt__point *points, int n, float x, float y) -{ - if (!points) return; /* during first pass, it's unallocated */ - points[n].x = x; - points[n].y = y; -} - -NK_INTERN int -nk_tt__tesselate_curve(struct nk_tt__point *points, int *num_points, - float x0, float y0, float x1, float y1, float x2, float y2, - float objspace_flatness_squared, int n) -{ - /* tesselate until threshold p is happy... - * @TODO warped to compensate for non-linear stretching */ - /* midpoint */ - float mx = (x0 + 2*x1 + x2)/4; - float my = (y0 + 2*y1 + y2)/4; - /* versus directly drawn line */ - float dx = (x0+x2)/2 - mx; - float dy = (y0+y2)/2 - my; - if (n > 16) /* 65536 segments on one curve better be enough! */ - return 1; - - /* half-pixel error allowed... need to be smaller if AA */ - if (dx*dx+dy*dy > objspace_flatness_squared) { - nk_tt__tesselate_curve(points, num_points, x0,y0, - (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1); - nk_tt__tesselate_curve(points, num_points, mx,my, - (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1); - } else { - nk_tt__add_point(points, *num_points,x2,y2); - *num_points = *num_points+1; - } - return 1; -} - -/* returns number of contours */ -NK_INTERN struct nk_tt__point* -nk_tt_FlattenCurves(struct nk_tt_vertex *vertices, int num_verts, - float objspace_flatness, int **contour_lengths, int *num_contours, - struct nk_allocator *alloc) -{ - struct nk_tt__point *points=0; - int num_points=0; - float objspace_flatness_squared = objspace_flatness * objspace_flatness; - int i; - int n=0; - int start=0; - int pass; - - /* count how many "moves" there are to get the contour count */ - for (i=0; i < num_verts; ++i) - if (vertices[i].type == NK_TT_vmove) ++n; - - *num_contours = n; - if (n == 0) return 0; - - *contour_lengths = (int *) - alloc->alloc(alloc->userdata,0, (sizeof(**contour_lengths) * (nk_size)n)); - if (*contour_lengths == 0) { - *num_contours = 0; - return 0; - } - - /* make two passes through the points so we don't need to realloc */ - for (pass=0; pass < 2; ++pass) - { - float x=0,y=0; - if (pass == 1) { - points = (struct nk_tt__point *) - alloc->alloc(alloc->userdata,0, (nk_size)num_points * sizeof(points[0])); - if (points == 0) goto error; - } - num_points = 0; - n= -1; - - for (i=0; i < num_verts; ++i) - { - switch (vertices[i].type) { - case NK_TT_vmove: - /* start the next contour */ - if (n >= 0) - (*contour_lengths)[n] = num_points - start; - ++n; - start = num_points; - - x = vertices[i].x, y = vertices[i].y; - nk_tt__add_point(points, num_points++, x,y); - break; - case NK_TT_vline: - x = vertices[i].x, y = vertices[i].y; - nk_tt__add_point(points, num_points++, x, y); - break; - case NK_TT_vcurve: - nk_tt__tesselate_curve(points, &num_points, x,y, - vertices[i].cx, vertices[i].cy, - vertices[i].x, vertices[i].y, - objspace_flatness_squared, 0); - x = vertices[i].x, y = vertices[i].y; - break; - default: break; - } - } - (*contour_lengths)[n] = num_points - start; - } - return points; - -error: - alloc->free(alloc->userdata, points); - alloc->free(alloc->userdata, *contour_lengths); - *contour_lengths = 0; - *num_contours = 0; - return 0; -} - -NK_INTERN void -nk_tt_Rasterize(struct nk_tt__bitmap *result, float flatness_in_pixels, - struct nk_tt_vertex *vertices, int num_verts, - float scale_x, float scale_y, float shift_x, float shift_y, - int x_off, int y_off, int invert, struct nk_allocator *alloc) -{ - float scale = scale_x > scale_y ? scale_y : scale_x; - int winding_count, *winding_lengths; - struct nk_tt__point *windings = nk_tt_FlattenCurves(vertices, num_verts, - flatness_in_pixels / scale, &winding_lengths, &winding_count, alloc); - - NK_ASSERT(alloc); - if (windings) { - nk_tt__rasterize(result, windings, winding_lengths, winding_count, - scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, alloc); - alloc->free(alloc->userdata, winding_lengths); - alloc->free(alloc->userdata, windings); - } -} - -NK_INTERN void -nk_tt_MakeGlyphBitmapSubpixel(const struct nk_tt_fontinfo *info, unsigned char *output, - int out_w, int out_h, int out_stride, float scale_x, float scale_y, - float shift_x, float shift_y, int glyph, struct nk_allocator *alloc) -{ - int ix0,iy0; - struct nk_tt_vertex *vertices; - int num_verts = nk_tt_GetGlyphShape(info, alloc, glyph, &vertices); - struct nk_tt__bitmap gbm; - - nk_tt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, - shift_y, &ix0,&iy0,0,0); - gbm.pixels = output; - gbm.w = out_w; - gbm.h = out_h; - gbm.stride = out_stride; - - if (gbm.w && gbm.h) - nk_tt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, - shift_x, shift_y, ix0,iy0, 1, alloc); - alloc->free(alloc->userdata, vertices); -} - -/*------------------------------------------------------------- - * Bitmap baking - * --------------------------------------------------------------*/ -NK_INTERN int -nk_tt_PackBegin(struct nk_tt_pack_context *spc, unsigned char *pixels, - int pw, int ph, int stride_in_bytes, int padding, struct nk_allocator *alloc) -{ - int num_nodes = pw - padding; - struct nk_rp_context *context = (struct nk_rp_context *) - alloc->alloc(alloc->userdata,0, sizeof(*context)); - struct nk_rp_node *nodes = (struct nk_rp_node*) - alloc->alloc(alloc->userdata,0, (sizeof(*nodes ) * (nk_size)num_nodes)); - - if (context == 0 || nodes == 0) { - if (context != 0) alloc->free(alloc->userdata, context); - if (nodes != 0) alloc->free(alloc->userdata, nodes); - return 0; - } - - spc->width = pw; - spc->height = ph; - spc->pixels = pixels; - spc->pack_info = context; - spc->nodes = nodes; - spc->padding = padding; - spc->stride_in_bytes = (stride_in_bytes != 0) ? stride_in_bytes : pw; - spc->h_oversample = 1; - spc->v_oversample = 1; - - nk_rp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); - if (pixels) - NK_MEMSET(pixels, 0, (nk_size)(pw*ph)); /* background of 0 around pixels */ - return 1; -} - -NK_INTERN void -nk_tt_PackEnd(struct nk_tt_pack_context *spc, struct nk_allocator *alloc) -{ - alloc->free(alloc->userdata, spc->nodes); - alloc->free(alloc->userdata, spc->pack_info); -} - -NK_INTERN void -nk_tt_PackSetOversampling(struct nk_tt_pack_context *spc, - unsigned int h_oversample, unsigned int v_oversample) -{ - NK_ASSERT(h_oversample <= NK_TT_MAX_OVERSAMPLE); - NK_ASSERT(v_oversample <= NK_TT_MAX_OVERSAMPLE); - if (h_oversample <= NK_TT_MAX_OVERSAMPLE) - spc->h_oversample = h_oversample; - if (v_oversample <= NK_TT_MAX_OVERSAMPLE) - spc->v_oversample = v_oversample; -} - -NK_INTERN void -nk_tt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, - int kernel_width) -{ - unsigned char buffer[NK_TT_MAX_OVERSAMPLE + 4]; - int safe_w = w - kernel_width; - int j; - - for (j=0; j < h; ++j) - { - int i; - unsigned int total; - NK_MEMSET(buffer, 0, (nk_size)kernel_width); - - total = 0; - - /* make kernel_width a constant in common cases so compiler can optimize out the divide */ - switch (kernel_width) { - case 2: - for (i=0; i <= safe_w; ++i) { - total += (unsigned int)(pixels[i] - buffer[i & NK_TT__OVER_MASK]); - buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 2); - } - break; - case 3: - for (i=0; i <= safe_w; ++i) { - total += (unsigned int)(pixels[i] - buffer[i & NK_TT__OVER_MASK]); - buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 3); - } - break; - case 4: - for (i=0; i <= safe_w; ++i) { - total += (unsigned int)pixels[i] - buffer[i & NK_TT__OVER_MASK]; - buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 4); - } - break; - case 5: - for (i=0; i <= safe_w; ++i) { - total += (unsigned int)(pixels[i] - buffer[i & NK_TT__OVER_MASK]); - buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 5); - } - break; - default: - for (i=0; i <= safe_w; ++i) { - total += (unsigned int)(pixels[i] - buffer[i & NK_TT__OVER_MASK]); - buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / (unsigned int)kernel_width); - } - break; - } - - for (; i < w; ++i) { - NK_ASSERT(pixels[i] == 0); - total -= (unsigned int)(buffer[i & NK_TT__OVER_MASK]); - pixels[i] = (unsigned char) (total / (unsigned int)kernel_width); - } - pixels += stride_in_bytes; - } -} - -NK_INTERN void -nk_tt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, - int kernel_width) -{ - unsigned char buffer[NK_TT_MAX_OVERSAMPLE + 4]; - int safe_h = h - kernel_width; - int j; - - for (j=0; j < w; ++j) - { - int i; - unsigned int total; - NK_MEMSET(buffer, 0, (nk_size)kernel_width); - - total = 0; - - /* make kernel_width a constant in common cases so compiler can optimize out the divide */ - switch (kernel_width) { - case 2: - for (i=0; i <= safe_h; ++i) { - total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]); - buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 2); - } - break; - case 3: - for (i=0; i <= safe_h; ++i) { - total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]); - buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 3); - } - break; - case 4: - for (i=0; i <= safe_h; ++i) { - total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]); - buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 4); - } - break; - case 5: - for (i=0; i <= safe_h; ++i) { - total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]); - buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 5); - } - break; - default: - for (i=0; i <= safe_h; ++i) { - total += (unsigned int)(pixels[i*stride_in_bytes] - buffer[i & NK_TT__OVER_MASK]); - buffer[(i+kernel_width) & NK_TT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / (unsigned int)kernel_width); - } - break; - } - - for (; i < h; ++i) { - NK_ASSERT(pixels[i*stride_in_bytes] == 0); - total -= (unsigned int)(buffer[i & NK_TT__OVER_MASK]); - pixels[i*stride_in_bytes] = (unsigned char) (total / (unsigned int)kernel_width); - } - pixels += 1; - } -} - -NK_INTERN float -nk_tt__oversample_shift(int oversample) -{ - if (!oversample) - return 0.0f; - - /* The prefilter is a box filter of width "oversample", */ - /* which shifts phase by (oversample - 1)/2 pixels in */ - /* oversampled space. We want to shift in the opposite */ - /* direction to counter this. */ - return (float)-(oversample - 1) / (2.0f * (float)oversample); -} - -/* rects array must be big enough to accommodate all characters in the given ranges */ -NK_INTERN int -nk_tt_PackFontRangesGatherRects(struct nk_tt_pack_context *spc, - struct nk_tt_fontinfo *info, struct nk_tt_pack_range *ranges, - int num_ranges, struct nk_rp_rect *rects) -{ - int i,j,k; - k = 0; - - for (i=0; i < num_ranges; ++i) { - float fh = ranges[i].font_size; - float scale = (fh > 0) ? nk_tt_ScaleForPixelHeight(info, fh): - nk_tt_ScaleForMappingEmToPixels(info, -fh); - ranges[i].h_oversample = (unsigned char) spc->h_oversample; - ranges[i].v_oversample = (unsigned char) spc->v_oversample; - for (j=0; j < ranges[i].num_chars; ++j) { - int x0,y0,x1,y1; - int codepoint = ranges[i].first_unicode_codepoint_in_range ? - ranges[i].first_unicode_codepoint_in_range + j : - ranges[i].array_of_unicode_codepoints[j]; - - int glyph = nk_tt_FindGlyphIndex(info, codepoint); - nk_tt_GetGlyphBitmapBoxSubpixel(info,glyph, scale * (float)spc->h_oversample, - scale * (float)spc->v_oversample, 0,0, &x0,&y0,&x1,&y1); - rects[k].w = (nk_rp_coord) (x1-x0 + spc->padding + (int)spc->h_oversample-1); - rects[k].h = (nk_rp_coord) (y1-y0 + spc->padding + (int)spc->v_oversample-1); - ++k; - } - } - return k; -} - -NK_INTERN int -nk_tt_PackFontRangesRenderIntoRects(struct nk_tt_pack_context *spc, - struct nk_tt_fontinfo *info, struct nk_tt_pack_range *ranges, - int num_ranges, struct nk_rp_rect *rects, struct nk_allocator *alloc) -{ - int i,j,k, return_value = 1; - /* save current values */ - int old_h_over = (int)spc->h_oversample; - int old_v_over = (int)spc->v_oversample; - /* rects array must be big enough to accommodate all characters in the given ranges */ - - k = 0; - for (i=0; i < num_ranges; ++i) - { - float fh = ranges[i].font_size; - float recip_h,recip_v,sub_x,sub_y; - float scale = fh > 0 ? nk_tt_ScaleForPixelHeight(info, fh): - nk_tt_ScaleForMappingEmToPixels(info, -fh); - - spc->h_oversample = ranges[i].h_oversample; - spc->v_oversample = ranges[i].v_oversample; - - recip_h = 1.0f / (float)spc->h_oversample; - recip_v = 1.0f / (float)spc->v_oversample; - - sub_x = nk_tt__oversample_shift((int)spc->h_oversample); - sub_y = nk_tt__oversample_shift((int)spc->v_oversample); - - for (j=0; j < ranges[i].num_chars; ++j) - { - struct nk_rp_rect *r = &rects[k]; - if (r->was_packed) - { - struct nk_tt_packedchar *bc = &ranges[i].chardata_for_range[j]; - int advance, lsb, x0,y0,x1,y1; - int codepoint = ranges[i].first_unicode_codepoint_in_range ? - ranges[i].first_unicode_codepoint_in_range + j : - ranges[i].array_of_unicode_codepoints[j]; - int glyph = nk_tt_FindGlyphIndex(info, codepoint); - nk_rp_coord pad = (nk_rp_coord) spc->padding; - - /* pad on left and top */ - r->x = (nk_rp_coord)((int)r->x + (int)pad); - r->y = (nk_rp_coord)((int)r->y + (int)pad); - r->w = (nk_rp_coord)((int)r->w - (int)pad); - r->h = (nk_rp_coord)((int)r->h - (int)pad); - - nk_tt_GetGlyphHMetrics(info, glyph, &advance, &lsb); - nk_tt_GetGlyphBitmapBox(info, glyph, scale * (float)spc->h_oversample, - (scale * (float)spc->v_oversample), &x0,&y0,&x1,&y1); - nk_tt_MakeGlyphBitmapSubpixel(info, spc->pixels + r->x + r->y*spc->stride_in_bytes, - (int)(r->w - spc->h_oversample+1), (int)(r->h - spc->v_oversample+1), - spc->stride_in_bytes, scale * (float)spc->h_oversample, - scale * (float)spc->v_oversample, 0,0, glyph, alloc); - - if (spc->h_oversample > 1) - nk_tt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w, r->h, spc->stride_in_bytes, (int)spc->h_oversample); - - if (spc->v_oversample > 1) - nk_tt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w, r->h, spc->stride_in_bytes, (int)spc->v_oversample); - - bc->x0 = (nk_ushort) r->x; - bc->y0 = (nk_ushort) r->y; - bc->x1 = (nk_ushort) (r->x + r->w); - bc->y1 = (nk_ushort) (r->y + r->h); - bc->xadvance = scale * (float)advance; - bc->xoff = (float) x0 * recip_h + sub_x; - bc->yoff = (float) y0 * recip_v + sub_y; - bc->xoff2 = ((float)x0 + r->w) * recip_h + sub_x; - bc->yoff2 = ((float)y0 + r->h) * recip_v + sub_y; - } else { - return_value = 0; /* if any fail, report failure */ - } - ++k; - } - } - /* restore original values */ - spc->h_oversample = (unsigned int)old_h_over; - spc->v_oversample = (unsigned int)old_v_over; - return return_value; -} - -NK_INTERN void -nk_tt_GetPackedQuad(struct nk_tt_packedchar *chardata, int pw, int ph, - int char_index, float *xpos, float *ypos, struct nk_tt_aligned_quad *q, - int align_to_integer) -{ - float ipw = 1.0f / (float)pw, iph = 1.0f / (float)ph; - struct nk_tt_packedchar *b = (struct nk_tt_packedchar*)(chardata + char_index); - if (align_to_integer) { - int tx = nk_ifloorf((*xpos + b->xoff) + 0.5f); - int ty = nk_ifloorf((*ypos + b->yoff) + 0.5f); - - float x = (float)tx; - float y = (float)ty; - - q->x0 = x; - q->y0 = y; - q->x1 = x + b->xoff2 - b->xoff; - q->y1 = y + b->yoff2 - b->yoff; - } else { - q->x0 = *xpos + b->xoff; - q->y0 = *ypos + b->yoff; - q->x1 = *xpos + b->xoff2; - q->y1 = *ypos + b->yoff2; - } - q->s0 = b->x0 * ipw; - q->t0 = b->y0 * iph; - q->s1 = b->x1 * ipw; - q->t1 = b->y1 * iph; - *xpos += b->xadvance; -} - -/* ------------------------------------------------------------- - * - * FONT BAKING - * - * --------------------------------------------------------------*/ -struct nk_font_bake_data { - struct nk_tt_fontinfo info; - struct nk_rp_rect *rects; - struct nk_tt_pack_range *ranges; - nk_rune range_count; -}; - -struct nk_font_baker { - struct nk_allocator alloc; - struct nk_tt_pack_context spc; - struct nk_font_bake_data *build; - struct nk_tt_packedchar *packed_chars; - struct nk_rp_rect *rects; - struct nk_tt_pack_range *ranges; -}; - -NK_GLOBAL const nk_size nk_rect_align = NK_ALIGNOF(struct nk_rp_rect); -NK_GLOBAL const nk_size nk_range_align = NK_ALIGNOF(struct nk_tt_pack_range); -NK_GLOBAL const nk_size nk_char_align = NK_ALIGNOF(struct nk_tt_packedchar); -NK_GLOBAL const nk_size nk_build_align = NK_ALIGNOF(struct nk_font_bake_data); -NK_GLOBAL const nk_size nk_baker_align = NK_ALIGNOF(struct nk_font_baker); - -NK_INTERN int -nk_range_count(const nk_rune *range) -{ - const nk_rune *iter = range; - NK_ASSERT(range); - if (!range) return 0; - while (*(iter++) != 0); - return (iter == range) ? 0 : (int)((iter - range)/2); -} - -NK_INTERN int -nk_range_glyph_count(const nk_rune *range, int count) -{ - int i = 0; - int total_glyphs = 0; - for (i = 0; i < count; ++i) { - int diff; - nk_rune f = range[(i*2)+0]; - nk_rune t = range[(i*2)+1]; - NK_ASSERT(t >= f); - diff = (int)((t - f) + 1); - total_glyphs += diff; - } - return total_glyphs; -} - -NK_API const nk_rune* -nk_font_default_glyph_ranges(void) -{ - NK_STORAGE const nk_rune ranges[] = {0x0020, 0x00FF, 0}; - return ranges; -} - -NK_API const nk_rune* -nk_font_chinese_glyph_ranges(void) -{ - NK_STORAGE const nk_rune ranges[] = { - 0x0020, 0x00FF, - 0x3000, 0x30FF, - 0x31F0, 0x31FF, - 0xFF00, 0xFFEF, - 0x4e00, 0x9FAF, - 0 - }; - return ranges; -} - -NK_API const nk_rune* -nk_font_cyrillic_glyph_ranges(void) -{ - NK_STORAGE const nk_rune ranges[] = { - 0x0020, 0x00FF, - 0x0400, 0x052F, - 0x2DE0, 0x2DFF, - 0xA640, 0xA69F, - 0 - }; - return ranges; -} - -NK_API const nk_rune* -nk_font_korean_glyph_ranges(void) -{ - NK_STORAGE const nk_rune ranges[] = { - 0x0020, 0x00FF, - 0x3131, 0x3163, - 0xAC00, 0xD79D, - 0 - }; - return ranges; -} - -NK_INTERN void -nk_font_baker_memory(nk_size *temp, int *glyph_count, - struct nk_font_config *config_list, int count) -{ - int range_count = 0; - int total_range_count = 0; - struct nk_font_config *iter, *i; - - NK_ASSERT(config_list); - NK_ASSERT(glyph_count); - if (!config_list) { - *temp = 0; - *glyph_count = 0; - return; - } - *glyph_count = 0; - for (iter = config_list; iter; iter = iter->next) { - i = iter; - do {if (!i->range) iter->range = nk_font_default_glyph_ranges(); - range_count = nk_range_count(i->range); - total_range_count += range_count; - *glyph_count += nk_range_glyph_count(i->range, range_count); - } while ((i = i->n) != iter); - } - *temp = (nk_size)*glyph_count * sizeof(struct nk_rp_rect); - *temp += (nk_size)total_range_count * sizeof(struct nk_tt_pack_range); - *temp += (nk_size)*glyph_count * sizeof(struct nk_tt_packedchar); - *temp += (nk_size)count * sizeof(struct nk_font_bake_data); - *temp += sizeof(struct nk_font_baker); - *temp += nk_rect_align + nk_range_align + nk_char_align; - *temp += nk_build_align + nk_baker_align; -} - -NK_INTERN struct nk_font_baker* -nk_font_baker(void *memory, int glyph_count, int count, struct nk_allocator *alloc) -{ - struct nk_font_baker *baker; - if (!memory) return 0; - /* setup baker inside a memory block */ - baker = (struct nk_font_baker*)NK_ALIGN_PTR(memory, nk_baker_align); - baker->build = (struct nk_font_bake_data*)NK_ALIGN_PTR((baker + 1), nk_build_align); - baker->packed_chars = (struct nk_tt_packedchar*)NK_ALIGN_PTR((baker->build + count), nk_char_align); - baker->rects = (struct nk_rp_rect*)NK_ALIGN_PTR((baker->packed_chars + glyph_count), nk_rect_align); - baker->ranges = (struct nk_tt_pack_range*)NK_ALIGN_PTR((baker->rects + glyph_count), nk_range_align); - baker->alloc = *alloc; - return baker; -} - -NK_INTERN int -nk_font_bake_pack(struct nk_font_baker *baker, - nk_size *image_memory, int *width, int *height, struct nk_recti *custom, - const struct nk_font_config *config_list, int count, - struct nk_allocator *alloc) -{ - NK_STORAGE const nk_size max_height = 1024 * 32; - const struct nk_font_config *config_iter, *it; - int total_glyph_count = 0; - int total_range_count = 0; - int range_count = 0; - int i = 0; - - NK_ASSERT(image_memory); - NK_ASSERT(width); - NK_ASSERT(height); - NK_ASSERT(config_list); - NK_ASSERT(count); - NK_ASSERT(alloc); - - if (!image_memory || !width || !height || !config_list || !count) return nk_false; - for (config_iter = config_list; config_iter; config_iter = config_iter->next) { - it = config_iter; - do {range_count = nk_range_count(it->range); - total_range_count += range_count; - total_glyph_count += nk_range_glyph_count(it->range, range_count); - } while ((it = it->n) != config_iter); - } - /* setup font baker from temporary memory */ - for (config_iter = config_list; config_iter; config_iter = config_iter->next) { - it = config_iter; - do {if (!nk_tt_InitFont(&baker->build[i++].info, (const unsigned char*)it->ttf_blob, 0)) - return nk_false; - } while ((it = it->n) != config_iter); - } - *height = 0; - *width = (total_glyph_count > 1000) ? 1024 : 512; - nk_tt_PackBegin(&baker->spc, 0, (int)*width, (int)max_height, 0, 1, alloc); - { - int input_i = 0; - int range_n = 0; - int rect_n = 0; - int char_n = 0; - - if (custom) { - /* pack custom user data first so it will be in the upper left corner*/ - struct nk_rp_rect custom_space; - nk_zero(&custom_space, sizeof(custom_space)); - custom_space.w = (nk_rp_coord)(custom->w); - custom_space.h = (nk_rp_coord)(custom->h); - - nk_tt_PackSetOversampling(&baker->spc, 1, 1); - nk_rp_pack_rects((struct nk_rp_context*)baker->spc.pack_info, &custom_space, 1); - *height = NK_MAX(*height, (int)(custom_space.y + custom_space.h)); - - custom->x = (short)custom_space.x; - custom->y = (short)custom_space.y; - custom->w = (short)custom_space.w; - custom->h = (short)custom_space.h; - } - - /* first font pass: pack all glyphs */ - for (input_i = 0, config_iter = config_list; input_i < count && config_iter; - config_iter = config_iter->next) { - it = config_iter; - do {int n = 0; - int glyph_count; - const nk_rune *in_range; - const struct nk_font_config *cfg = it; - struct nk_font_bake_data *tmp = &baker->build[input_i++]; - - /* count glyphs + ranges in current font */ - glyph_count = 0; range_count = 0; - for (in_range = cfg->range; in_range[0] && in_range[1]; in_range += 2) { - glyph_count += (int)(in_range[1] - in_range[0]) + 1; - range_count++; - } - - /* setup ranges */ - tmp->ranges = baker->ranges + range_n; - tmp->range_count = (nk_rune)range_count; - range_n += range_count; - for (i = 0; i < range_count; ++i) { - in_range = &cfg->range[i * 2]; - tmp->ranges[i].font_size = cfg->size; - tmp->ranges[i].first_unicode_codepoint_in_range = (int)in_range[0]; - tmp->ranges[i].num_chars = (int)(in_range[1]- in_range[0]) + 1; - tmp->ranges[i].chardata_for_range = baker->packed_chars + char_n; - char_n += tmp->ranges[i].num_chars; - } - - /* pack */ - tmp->rects = baker->rects + rect_n; - rect_n += glyph_count; - nk_tt_PackSetOversampling(&baker->spc, cfg->oversample_h, cfg->oversample_v); - n = nk_tt_PackFontRangesGatherRects(&baker->spc, &tmp->info, - tmp->ranges, (int)tmp->range_count, tmp->rects); - nk_rp_pack_rects((struct nk_rp_context*)baker->spc.pack_info, tmp->rects, (int)n); - - /* texture height */ - for (i = 0; i < n; ++i) { - if (tmp->rects[i].was_packed) - *height = NK_MAX(*height, tmp->rects[i].y + tmp->rects[i].h); - } - } while ((it = it->n) != config_iter); - } - NK_ASSERT(rect_n == total_glyph_count); - NK_ASSERT(char_n == total_glyph_count); - NK_ASSERT(range_n == total_range_count); - } - *height = (int)nk_round_up_pow2((nk_uint)*height); - *image_memory = (nk_size)(*width) * (nk_size)(*height); - return nk_true; -} - -NK_INTERN void -nk_font_bake(struct nk_font_baker *baker, void *image_memory, int width, int height, - struct nk_font_glyph *glyphs, int glyphs_count, - const struct nk_font_config *config_list, int font_count) -{ - int input_i = 0; - nk_rune glyph_n = 0; - const struct nk_font_config *config_iter; - const struct nk_font_config *it; - - NK_ASSERT(image_memory); - NK_ASSERT(width); - NK_ASSERT(height); - NK_ASSERT(config_list); - NK_ASSERT(baker); - NK_ASSERT(font_count); - NK_ASSERT(glyphs_count); - if (!image_memory || !width || !height || !config_list || - !font_count || !glyphs || !glyphs_count) - return; - - /* second font pass: render glyphs */ - nk_zero(image_memory, (nk_size)((nk_size)width * (nk_size)height)); - baker->spc.pixels = (unsigned char*)image_memory; - baker->spc.height = (int)height; - for (input_i = 0, config_iter = config_list; input_i < font_count && config_iter; - config_iter = config_iter->next) { - it = config_iter; - do {const struct nk_font_config *cfg = it; - struct nk_font_bake_data *tmp = &baker->build[input_i++]; - nk_tt_PackSetOversampling(&baker->spc, cfg->oversample_h, cfg->oversample_v); - nk_tt_PackFontRangesRenderIntoRects(&baker->spc, &tmp->info, tmp->ranges, - (int)tmp->range_count, tmp->rects, &baker->alloc); - } while ((it = it->n) != config_iter); - } nk_tt_PackEnd(&baker->spc, &baker->alloc); - - /* third pass: setup font and glyphs */ - for (input_i = 0, config_iter = config_list; input_i < font_count && config_iter; - config_iter = config_iter->next) { - it = config_iter; - do {nk_size i = 0; - int char_idx = 0; - nk_rune glyph_count = 0; - const struct nk_font_config *cfg = it; - struct nk_font_bake_data *tmp = &baker->build[input_i++]; - struct nk_baked_font *dst_font = cfg->font; - - float font_scale = nk_tt_ScaleForPixelHeight(&tmp->info, cfg->size); - int unscaled_ascent, unscaled_descent, unscaled_line_gap; - nk_tt_GetFontVMetrics(&tmp->info, &unscaled_ascent, &unscaled_descent, - &unscaled_line_gap); - - /* fill baked font */ - if (!cfg->merge_mode) { - dst_font->ranges = cfg->range; - dst_font->height = cfg->size; - dst_font->ascent = ((float)unscaled_ascent * font_scale); - dst_font->descent = ((float)unscaled_descent * font_scale); - dst_font->glyph_offset = glyph_n; - } - - /* fill own baked font glyph array */ - for (i = 0; i < tmp->range_count; ++i) { - struct nk_tt_pack_range *range = &tmp->ranges[i]; - for (char_idx = 0; char_idx < range->num_chars; char_idx++) - { - nk_rune codepoint = 0; - float dummy_x = 0, dummy_y = 0; - struct nk_tt_aligned_quad q; - struct nk_font_glyph *glyph; - - /* query glyph bounds from stb_truetype */ - const struct nk_tt_packedchar *pc = &range->chardata_for_range[char_idx]; - if (!pc->x0 && !pc->x1 && !pc->y0 && !pc->y1) continue; - codepoint = (nk_rune)(range->first_unicode_codepoint_in_range + char_idx); - nk_tt_GetPackedQuad(range->chardata_for_range, (int)width, - (int)height, char_idx, &dummy_x, &dummy_y, &q, 0); - - /* fill own glyph type with data */ - glyph = &glyphs[dst_font->glyph_offset + dst_font->glyph_count + (unsigned int)glyph_count]; - glyph->codepoint = codepoint; - glyph->x0 = q.x0; glyph->y0 = q.y0; - glyph->x1 = q.x1; glyph->y1 = q.y1; - glyph->y0 += (dst_font->ascent + 0.5f); - glyph->y1 += (dst_font->ascent + 0.5f); - glyph->w = glyph->x1 - glyph->x0 + 0.5f; - glyph->h = glyph->y1 - glyph->y0; - - if (cfg->coord_type == NK_COORD_PIXEL) { - glyph->u0 = q.s0 * (float)width; - glyph->v0 = q.t0 * (float)height; - glyph->u1 = q.s1 * (float)width; - glyph->v1 = q.t1 * (float)height; - } else { - glyph->u0 = q.s0; - glyph->v0 = q.t0; - glyph->u1 = q.s1; - glyph->v1 = q.t1; - } - glyph->xadvance = (pc->xadvance + cfg->spacing.x); - if (cfg->pixel_snap) - glyph->xadvance = (float)(int)(glyph->xadvance + 0.5f); - glyph_count++; - } - } - dst_font->glyph_count += glyph_count; - glyph_n += glyph_count; - } while ((it = it->n) != config_iter); - } -} - -NK_INTERN void -nk_font_bake_custom_data(void *img_memory, int img_width, int img_height, - struct nk_recti img_dst, const char *texture_data_mask, int tex_width, - int tex_height, char white, char black) -{ - nk_byte *pixels; - int y = 0; - int x = 0; - int n = 0; - - NK_ASSERT(img_memory); - NK_ASSERT(img_width); - NK_ASSERT(img_height); - NK_ASSERT(texture_data_mask); - NK_UNUSED(tex_height); - if (!img_memory || !img_width || !img_height || !texture_data_mask) - return; - - pixels = (nk_byte*)img_memory; - for (y = 0, n = 0; y < tex_height; ++y) { - for (x = 0; x < tex_width; ++x, ++n) { - const int off0 = ((img_dst.x + x) + (img_dst.y + y) * img_width); - const int off1 = off0 + 1 + tex_width; - pixels[off0] = (texture_data_mask[n] == white) ? 0xFF : 0x00; - pixels[off1] = (texture_data_mask[n] == black) ? 0xFF : 0x00; - } - } -} - -NK_INTERN void -nk_font_bake_convert(void *out_memory, int img_width, int img_height, - const void *in_memory) -{ - int n = 0; - nk_rune *dst; - const nk_byte *src; - - NK_ASSERT(out_memory); - NK_ASSERT(in_memory); - NK_ASSERT(img_width); - NK_ASSERT(img_height); - if (!out_memory || !in_memory || !img_height || !img_width) return; - - dst = (nk_rune*)out_memory; - src = (const nk_byte*)in_memory; - for (n = (int)(img_width * img_height); n > 0; n--) - *dst++ = ((nk_rune)(*src++) << 24) | 0x00FFFFFF; -} - -/* ------------------------------------------------------------- - * - * FONT - * - * --------------------------------------------------------------*/ -NK_INTERN float -nk_font_text_width(nk_handle handle, float height, const char *text, int len) -{ - nk_rune unicode; - int text_len = 0; - float text_width = 0; - int glyph_len = 0; - float scale = 0; - - struct nk_font *font = (struct nk_font*)handle.ptr; - NK_ASSERT(font); - NK_ASSERT(font->glyphs); - if (!font || !text || !len) - return 0; - - scale = height/font->info.height; - glyph_len = text_len = nk_utf_decode(text, &unicode, (int)len); - if (!glyph_len) return 0; - while (text_len <= (int)len && glyph_len) { - const struct nk_font_glyph *g; - if (unicode == NK_UTF_INVALID) break; - - /* query currently drawn glyph information */ - g = nk_font_find_glyph(font, unicode); - text_width += g->xadvance * scale; - - /* offset next glyph */ - glyph_len = nk_utf_decode(text + text_len, &unicode, (int)len - text_len); - text_len += glyph_len; - } - return text_width; -} - -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT -NK_INTERN void -nk_font_query_font_glyph(nk_handle handle, float height, - struct nk_user_font_glyph *glyph, nk_rune codepoint, nk_rune next_codepoint) -{ - float scale; - const struct nk_font_glyph *g; - struct nk_font *font; - - NK_ASSERT(glyph); - NK_UNUSED(next_codepoint); - - font = (struct nk_font*)handle.ptr; - NK_ASSERT(font); - NK_ASSERT(font->glyphs); - if (!font || !glyph) - return; - - scale = height/font->info.height; - g = nk_font_find_glyph(font, codepoint); - glyph->width = (g->x1 - g->x0) * scale; - glyph->height = (g->y1 - g->y0) * scale; - glyph->offset = nk_vec2(g->x0 * scale, g->y0 * scale); - glyph->xadvance = (g->xadvance * scale); - glyph->uv[0] = nk_vec2(g->u0, g->v0); - glyph->uv[1] = nk_vec2(g->u1, g->v1); -} -#endif - -NK_API const struct nk_font_glyph* -nk_font_find_glyph(struct nk_font *font, nk_rune unicode) -{ - int i = 0; - int count; - int total_glyphs = 0; - const struct nk_font_glyph *glyph = 0; - const struct nk_font_config *iter = 0; - - NK_ASSERT(font); - NK_ASSERT(font->glyphs); - NK_ASSERT(font->info.ranges); - if (!font || !font->glyphs) return 0; - - glyph = font->fallback; - iter = font->config; - do {count = nk_range_count(iter->range); - for (i = 0; i < count; ++i) { - nk_rune f = iter->range[(i*2)+0]; - nk_rune t = iter->range[(i*2)+1]; - int diff = (int)((t - f) + 1); - if (unicode >= f && unicode <= t) - return &font->glyphs[((nk_rune)total_glyphs + (unicode - f))]; - total_glyphs += diff; - } - } while ((iter = iter->n) != font->config); - return glyph; -} - -NK_INTERN void -nk_font_init(struct nk_font *font, float pixel_height, - nk_rune fallback_codepoint, struct nk_font_glyph *glyphs, - const struct nk_baked_font *baked_font, nk_handle atlas) -{ - struct nk_baked_font baked; - NK_ASSERT(font); - NK_ASSERT(glyphs); - NK_ASSERT(baked_font); - if (!font || !glyphs || !baked_font) - return; - - baked = *baked_font; - font->fallback = 0; - font->info = baked; - font->scale = (float)pixel_height / (float)font->info.height; - font->glyphs = &glyphs[baked_font->glyph_offset]; - font->texture = atlas; - font->fallback_codepoint = fallback_codepoint; - font->fallback = nk_font_find_glyph(font, fallback_codepoint); - - font->handle.height = font->info.height * font->scale; - font->handle.width = nk_font_text_width; - font->handle.userdata.ptr = font; -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT - font->handle.query = nk_font_query_font_glyph; - font->handle.texture = font->texture; -#endif -} - -/* --------------------------------------------------------------------------- - * - * DEFAULT FONT - * - * ProggyClean.ttf - * Copyright (c) 2004, 2005 Tristan Grimmer - * MIT license (see License.txt in http://www.upperbounds.net/download/ProggyClean.ttf.zip) - * Download and more information at http://upperbounds.net - *-----------------------------------------------------------------------------*/ -#ifdef NK_INCLUDE_DEFAULT_FONT - - #ifdef __clang__ -#pragma clang diagnostic push - -#pragma clang diagnostic ignored "-Woverlength-strings" -#elif defined(__GNUC__) || defined(__GNUG__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Woverlength-strings" -#endif - -NK_GLOBAL const char nk_proggy_clean_ttf_compressed_data_base85[11980+1] = - "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/" - "2*>]b(MC;$jPfY.;h^`IWM9Qo#t'X#(v#Y9w0#1D$CIf;W'#pWUPXOuxXuU(H9M(1=Ke$$'5F%)]0^#0X@U.a$FBjVQTSDgEKnIS7EM9>ZY9w0#L;>>#Mx&4Mvt//L[MkA#W@lK.N'[0#7RL_&#w+F%HtG9M#XL`N&.,GM4Pg;--VsM.M0rJfLH2eTM`*oJMHRC`N" - "kfimM2J,W-jXS:)r0wK#@Fge$U>`w'N7G#$#fB#$E^$#:9:hk+eOe--6x)F7*E%?76%^GMHePW-Z5l'&GiF#$956:rS?dA#fiK:)Yr+`�j@'DbG&#^$PG.Ll+DNa&VZ>1i%h1S9u5o@YaaW$e+bROPOpxTO7Stwi1::iB1q)C_=dV26J;2,]7op$]uQr@_V7$q^%lQwtuHY]=DX,n3L#0PHDO4f9>dC@O>HBuKPpP*E,N+b3L#lpR/MrTEH.IAQk.a>D[.e;mc." - "x]Ip.PH^'/aqUO/$1WxLoW0[iLAw=4h(9.`G" - "CRUxHPeR`5Mjol(dUWxZa(>STrPkrJiWx`5U7F#.g*jrohGg`cg:lSTvEY/EV_7H4Q9[Z%cnv;JQYZ5q.l7Zeas:HOIZOB?Ggv:[7MI2k).'2($5FNP&EQ(,)" - "U]W]+fh18.vsai00);D3@4ku5P?DP8aJt+;qUM]=+b'8@;mViBKx0DE[-auGl8:PJ&Dj+M6OC]O^((##]`0i)drT;-7X`=-H3[igUnPG-NZlo.#k@h#=Ork$m>a>$-?Tm$UV(?#P6YY#" - "'/###xe7q.73rI3*pP/$1>s9)W,JrM7SN]'/4C#v$U`0#V.[0>xQsH$fEmPMgY2u7Kh(G%siIfLSoS+MK2eTM$=5,M8p`A.;_R%#u[K#$x4AG8.kK/HSB==-'Ie/QTtG?-.*^N-4B/ZM" - "_3YlQC7(p7q)&](`6_c)$/*JL(L-^(]$wIM`dPtOdGA,U3:w2M-0+WomX2u7lqM2iEumMTcsF?-aT=Z-97UEnXglEn1K-bnEO`gu" - "Ft(c%=;Am_Qs@jLooI&NX;]0#j4#F14;gl8-GQpgwhrq8'=l_f-b49'UOqkLu7-##oDY2L(te+Mch&gLYtJ,MEtJfLh'x'M=$CS-ZZ%P]8bZ>#S?YY#%Q&q'3^Fw&?D)UDNrocM3A76/" - "/oL?#h7gl85[qW/NDOk%16ij;+:1a'iNIdb-ou8.P*w,v5#EI$TWS>Pot-R*H'-SEpA:g)f+O$%%`kA#G=8RMmG1&O`>to8bC]T&$,n.LoO>29sp3dt-52U%VM#q7'DHpg+#Z9%H[Ket`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO" - "j%2n8)),?ILR5^.Ibn<-X-Mq7[a82Lq:F&#ce+S9wsCK*x`569E8ew'He]h:sI[2LM$[guka3ZRd6:t%IG:;$%YiJ:Nq=?eAw;/:nnDq0(CYcMpG)qLN4$##&J-XTt,%OVU4)S1+R-#dg0/Nn?Ku1^0f$B*P:Rowwm-`0PKjYDDM'3]d39VZHEl4,.j']Pk-M.h^&:0FACm$maq-&sgw0t7/6(^xtk%" - "LuH88Fj-ekm>GA#_>568x6(OFRl-IZp`&b,_P'$MhLbxfc$mj`,O;&%W2m`Zh:/)Uetw:aJ%]K9h:TcF]u_-Sj9,VK3M.*'&0D[Ca]J9gp8,kAW]" - "%(?A%R$f<->Zts'^kn=-^@c4%-pY6qI%J%1IGxfLU9CP8cbPlXv);C=b),<2mOvP8up,UVf3839acAWAW-W?#ao/^#%KYo8fRULNd2.>%m]UK:n%r$'sw]J;5pAoO_#2mO3n,'=H5(et" - "Hg*`+RLgv>=4U8guD$I%D:W>-r5V*%j*W:Kvej.Lp$'?;++O'>()jLR-^u68PHm8ZFWe+ej8h:9r6L*0//c&iH&R8pRbA#Kjm%upV1g:" - "a_#Ur7FuA#(tRh#.Y5K+@?3<-8m0$PEn;J:rh6?I6uG<-`wMU'ircp0LaE_OtlMb&1#6T.#FDKu#1Lw%u%+GM+X'e?YLfjM[VO0MbuFp7;>Q&#WIo)0@F%q7c#4XAXN-U&VBpqB>0ie&jhZ[?iLR@@_AvA-iQC(=ksRZRVp7`.=+NpBC%rh&3]R:8XDmE5^V8O(x<-+k?'(^](H.aREZSi,#1:[IXaZFOm<-ui#qUq2$##Ri;u75OK#(RtaW-K-F`S+cF]uN`-KMQ%rP/Xri.LRcB##=YL3BgM/3M" - "D?@f&1'BW-)Ju#bmmWCMkk&#TR`C,5d>g)F;t,4:@_l8G/5h4vUd%&%950:VXD'QdWoY-F$BtUwmfe$YqL'8(PWX(" - "P?^@Po3$##`MSs?DWBZ/S>+4%>fX,VWv/w'KD`LP5IbH;rTV>n3cEK8U#bX]l-/V+^lj3;vlMb&[5YQ8#pekX9JP3XUC72L,,?+Ni&co7ApnO*5NK,((W-i:$,kp'UDAO(G0Sq7MVjJs" - "bIu)'Z,*[>br5fX^:FPAWr-m2KgLQ_nN6'8uTGT5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q" - "h4CB/5OvmA&,Q&QbUoi$a_%3M01H)4x7I^&KQVgtFnV+;[Pc>[m4k//,]1?#`VY[Jr*3&&slRfLiVZJ:]?=K3Sw=[$=uRB?3xk48@aege0jT6'N#(q%.O=?2S]u*(m<-" - "V8J'(1)G][68hW$5'q[GC&5j`TE?m'esFGNRM)j,ffZ?-qx8;->g4t*:CIP/[Qap7/9'#(1sao7w-.qNUdkJ)tCF&#B^;xGvn2r9FEPFFFcL@.iFNkTve$m%#QvQS8U@)2Z+3K:AKM5i" - "sZ88+dKQ)W6>J%CL`.d*(B`-n8D9oK-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P r+$%CE=68>K8r0=dSC%%(@p7" - ".m7jilQ02'0-VWAg
TlGW'b)Tq7VT9q^*^$$.:&N@@" - "$&)WHtPm*5_rO0&e%K&#-30j(E4#'Zb.o/(Tpm$>K'f@[PvFl,hfINTNU6u'0pao7%XUp9]5.>%h`8_=VYbxuel.NTSsJfLacFu3B'lQSu/m6-Oqem8T+oE--$0a/k]uj9EwsG>%veR*" - "hv^BFpQj:K'#SJ,sB-'#](j.Lg92rTw-*n%@/;39rrJF,l#qV%OrtBeC6/,;qB3ebNW[?,Hqj2L.1NP&GjUR=1D8QaS3Up&@*9wP?+lo7b?@%'k4`p0Z$22%K3+iCZj?XJN4Nm&+YF]u" - "@-W$U%VEQ/,,>>#)D#%8cY#YZ?=,`Wdxu/ae&#" - "w6)R89tI#6@s'(6Bf7a&?S=^ZI_kS&ai`&=tE72L_D,;^R)7[$so8lKN%5/$(vdfq7+ebA#" - "u1p]ovUKW&Y%q]'>$1@-[xfn$7ZTp7mM,G,Ko7a&Gu%G[RMxJs[0MM%wci.LFDK)(%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoFDoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8" - "6e%B/:=>)N4xeW.*wft-;$'58-ESqr#U`'6AQ]m&6/`Z>#S?YY#Vc;r7U2&326d=w&H####?TZ`*4?&.MK?LP8Vxg>$[QXc%QJv92.(Db*B)gb*BM9dM*hJMAo*c&#" - "b0v=Pjer]$gG&JXDf->'StvU7505l9$AFvgYRI^&<^b68?j#q9QX4SM'RO#&sL1IM.rJfLUAj221]d##DW=m83u5;'bYx,*Sl0hL(W;;$doB&O/TQ:(Z^xBdLjLV#*8U_72Lh+2Q8Cj0i:6hp&$C/:p(HK>T8Y[gHQ4`4)'$Ab(Nof%V'8hL&#SfD07&6D@M.*J:;$-rv29'M]8qMv-tLp,'886iaC=Hb*YJoKJ,(j%K=H`K.v9HggqBIiZu'QvBT.#=)0ukruV&.)3=(^1`o*Pj4<-#MJ+gLq9-##@HuZPN0]u:h7.T..G:;$/Usj(T7`Q8tT72LnYl<-qx8;-HV7Q-&Xdx%1a,hC=0u+HlsV>nuIQL-5" - "_>@kXQtMacfD.m-VAb8;IReM3$wf0''hra*so568'Ip&vRs849'MRYSp%:t:h5qSgwpEr$B>Q,;s(C#$)`svQuF$##-D,##,g68@2[T;.XSdN9Qe)rpt._K-#5wF)sP'##p#C0c%-Gb%" - "hd+<-j'Ai*x&&HMkT]C'OSl##5RG[JXaHN;d'uA#x._U;.`PU@(Z3dt4r152@:v,'R.Sj'w#0<-;kPI)FfJ&#AYJ&#//)>-k=m=*XnK$>=)72L]0I%>.G690a:$##<,);?;72#?x9+d;" - "^V'9;jY@;)br#q^YQpx:X#Te$Z^'=-=bGhLf:D6&bNwZ9-ZD#n^9HhLMr5G;']d&6'wYmTFmLq9wI>P(9mI[>kC-ekLC/R&CH+s'B;K-M6$EB%is00:" - "+A4[7xks.LrNk0&E)wILYF@2L'0Nb$+pv<(2.768/FrY&h$^3i&@+G%JT'<-,v`3;_)I9M^AE]CN?Cl2AZg+%4iTpT3$U4O]GKx'm9)b@p7YsvK3w^YR-" - "CdQ*:Ir<($u&)#(&?L9Rg3H)4fiEp^iI9O8KnTj,]H?D*r7'M;PwZ9K0E^k&-cpI;.p/6_vwoFMV<->#%Xi.LxVnrU(4&8/P+:hLSKj$#U%]49t'I:rgMi'FL@a:0Y-uA[39',(vbma*" - "hU%<-SRF`Tt:542R_VV$p@[p8DV[A,?1839FWdFTi1O*H&#(AL8[_P%.M>v^-))qOT*F5Cq0`Ye%+$B6i:7@0IXSsDiWP,##P`%/L-" - "S(qw%sf/@%#B6;/U7K]uZbi^Oc^2n%t<)'mEVE''n`WnJra$^TKvX5B>;_aSEK',(hwa0:i4G?.Bci.(X[?b*($,=-n<.Q%`(X=?+@Am*Js0&=3bh8K]mL69=Lb,OcZV/);TTm8VI;?%OtJ<(b4mq7M6:u?KRdFl*:xP?Yb.5)%w_I?7uk5JC+FS(m#i'k.'a0i)9<7b'fs'59hq$*5Uhv##pi^8+hIEBF`nvo`;'l0.^S1<-wUK2/Coh58KKhLj" - "M=SO*rfO`+qC`W-On.=AJ56>>i2@2LH6A:&5q`?9I3@@'04&p2/LVa*T-4<-i3;M9UvZd+N7>b*eIwg:CC)c<>nO&#$(>.Z-I&J(Q0Hd5Q%7Co-b`-cP)hI;*_F]u`Rb[.j8_Q/<&>uu+VsH$sM9TA%?)(vmJ80),P7E>)tjD%2L=-t#fK[%`v=Q8WlA2);Sa" - ">gXm8YB`1d@K#n]76-a$U,mF%Ul:#/'xoFM9QX-$.QN'>" - "[%$Z$uF6pA6Ki2O5:8w*vP1<-1`[G,)-m#>0`P&#eb#.3i)rtB61(o'$?X3B2Qft^ae_5tKL9MUe9b*sLEQ95C&`=G?@Mj=wh*'3E>=-<)Gt*Iw)'QG:`@I" - "wOf7&]1i'S01B+Ev/Nac#9S;=;YQpg_6U`*kVY39xK,[/6Aj7:'1Bm-_1EYfa1+o&o4hp7KN_Q(OlIo@S%;jVdn0'1h19w,WQhLI)3S#f$2(eb,jr*b;3Vw]*7NH%$c4Vs,eD9>XW8?N]o+(*pgC%/72LV-uW%iewS8W6m2rtCpo'RS1R84=@paTKt)>=%&1[)*vp'u+x,VrwN;&]kuO9JDbg=pO$J*.jVe;u'm0dr9l,<*wMK*Oe=g8lV_KEBFkO'oU]^=[-792#ok,)" - "i]lR8qQ2oA8wcRCZ^7w/Njh;?.stX?Q1>S1q4Bn$)K1<-rGdO'$Wr.Lc.CG)$/*JL4tNR/,SVO3,aUw'DJN:)Ss;wGn9A32ijw%FL+Z0Fn.U9;reSq)bmI32U==5ALuG&#Vf1398/pVo" - "1*c-(aY168o<`JsSbk-,1N;$>0:OUas(3:8Z972LSfF8eb=c-;>SPw7.6hn3m`9^Xkn(r.qS[0;T%&Qc=+STRxX'q1BNk3&*eu2;&8q$&x>Q#Q7^Tf+6<(d%ZVmj2bDi%.3L2n+4W'$P" - "iDDG)g,r%+?,$@?uou5tSe2aN_AQU*'IAO" - "URQ##V^Fv-XFbGM7Fl(N<3DhLGF%q.1rC$#:T__&Pi68%0xi_&[qFJ(77j_&JWoF.V735&T,[R*:xFR*K5>>#`bW-?4Ne_&6Ne_&6Ne_&n`kr-#GJcM6X;uM6X;uM(.a..^2TkL%oR(#" - ";u.T%fAr%4tJ8&><1=GHZ_+m9/#H1F^R#SC#*N=BA9(D?v[UiFY>>^8p,KKF.W]L29uLkLlu/+4T" - "w$)F./^n3+rlo+DB;5sIYGNk+i1t-69Jg--0pao7Sm#K)pdHW&;LuDNH@H>#/X-TI(;P>#,Gc>#0Su>#4`1?#8lC?#xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4" - "A1OY5EI0;6Ibgr6M$HS7Q<)58C5w,;WoA*#[%T*#`1g*#d=#+#hI5+#lUG+#pbY+#tnl+#x$),#&1;,#*=M,#.I`,#2Ur,#6b.-#;w[H#iQtA#m^0B#qjBB#uvTB##-hB#'9$C#+E6C#" - "/QHC#3^ZC#7jmC#;v)D#?,)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP" - "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp" - "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#"; -#endif /* NK_INCLUDE_DEFAULT_FONT */ - -#define NK_CURSOR_DATA_W 90 -#define NK_CURSOR_DATA_H 27 -NK_GLOBAL const char nk_custom_cursor_data[NK_CURSOR_DATA_W * NK_CURSOR_DATA_H + 1] = -{ - "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX" - "..- -X.....X- X.X - X.X -X.....X - X.....X" - "--- -XXX.XXX- X...X - X...X -X....X - X....X" - "X - X.X - X.....X - X.....X -X...X - X...X" - "XX - X.X -X.......X- X.......X -X..X.X - X.X..X" - "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X" - "X..X - X.X - X.X - X.X -XX X.X - X.X XX" - "X...X - X.X - X.X - XX X.X XX - X.X - X.X " - "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X " - "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X " - "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X " - "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X " - "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X " - "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X " - "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X " - "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X " - "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX " - "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------" - "X.X X..X - -X.......X- X.......X - XX XX - " - "XX X..X - - X.....X - X.....X - X.X X.X - " - " X..X - X...X - X...X - X..X X..X - " - " XX - X.X - X.X - X...XXXXXXXXXXXXX...X - " - "------------ - X - X -X.....................X- " - " ----------------------------------- X...XXXXXXXXXXXXX...X - " - " - X..X X..X - " - " - X.X X.X - " - " - XX XX - " -}; - -#ifdef __clang__ -#pragma clang diagnostic pop -#elif defined(__GNUC__) || defined(__GNUG__) -#pragma GCC diagnostic pop -#endif - -NK_INTERN unsigned int -nk_decompress_length(unsigned char *input) -{ - return (unsigned int)((input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11]); -} - -NK_GLOBAL unsigned char *nk__barrier; -NK_GLOBAL unsigned char *nk__barrier2; -NK_GLOBAL unsigned char *nk__barrier3; -NK_GLOBAL unsigned char *nk__barrier4; -NK_GLOBAL unsigned char *nk__dout; - -NK_INTERN void -nk__match(unsigned char *data, unsigned int length) -{ - /* INVERSE of memmove... write each byte before copying the next...*/ - NK_ASSERT (nk__dout + length <= nk__barrier); - if (nk__dout + length > nk__barrier) { nk__dout += length; return; } - if (data < nk__barrier4) { nk__dout = nk__barrier+1; return; } - while (length--) *nk__dout++ = *data++; -} - -NK_INTERN void -nk__lit(unsigned char *data, unsigned int length) -{ - NK_ASSERT (nk__dout + length <= nk__barrier); - if (nk__dout + length > nk__barrier) { nk__dout += length; return; } - if (data < nk__barrier2) { nk__dout = nk__barrier+1; return; } - NK_MEMCPY(nk__dout, data, length); - nk__dout += length; -} - -#define nk__in2(x) ((i[x] << 8) + i[(x)+1]) -#define nk__in3(x) ((i[x] << 16) + nk__in2((x)+1)) -#define nk__in4(x) ((i[x] << 24) + nk__in3((x)+1)) - -NK_INTERN unsigned char* -nk_decompress_token(unsigned char *i) -{ - if (*i >= 0x20) { /* use fewer if's for cases that expand small */ - if (*i >= 0x80) nk__match(nk__dout-i[1]-1, (unsigned int)i[0] - 0x80 + 1), i += 2; - else if (*i >= 0x40) nk__match(nk__dout-(nk__in2(0) - 0x4000 + 1), (unsigned int)i[2]+1), i += 3; - else /* *i >= 0x20 */ nk__lit(i+1, (unsigned int)i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1); - } else { /* more ifs for cases that expand large, since overhead is amortized */ - if (*i >= 0x18) nk__match(nk__dout-(unsigned int)(nk__in3(0) - 0x180000 + 1), (unsigned int)i[3]+1), i += 4; - else if (*i >= 0x10) nk__match(nk__dout-(unsigned int)(nk__in3(0) - 0x100000 + 1), (unsigned int)nk__in2(3)+1), i += 5; - else if (*i >= 0x08) nk__lit(i+2, (unsigned int)nk__in2(0) - 0x0800 + 1), i += 2 + (nk__in2(0) - 0x0800 + 1); - else if (*i == 0x07) nk__lit(i+3, (unsigned int)nk__in2(1) + 1), i += 3 + (nk__in2(1) + 1); - else if (*i == 0x06) nk__match(nk__dout-(unsigned int)(nk__in3(1)+1), i[4]+1u), i += 5; - else if (*i == 0x04) nk__match(nk__dout-(unsigned int)(nk__in3(1)+1), (unsigned int)nk__in2(4)+1u), i += 6; - } - return i; -} - -NK_INTERN unsigned int -nk_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen) -{ - const unsigned long ADLER_MOD = 65521; - unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16; - unsigned long blocklen, i; - - blocklen = buflen % 5552; - while (buflen) { - for (i=0; i + 7 < blocklen; i += 8) { - s1 += buffer[0]; s2 += s1; - s1 += buffer[1]; s2 += s1; - s1 += buffer[2]; s2 += s1; - s1 += buffer[3]; s2 += s1; - s1 += buffer[4]; s2 += s1; - s1 += buffer[5]; s2 += s1; - s1 += buffer[6]; s2 += s1; - s1 += buffer[7]; s2 += s1; - buffer += 8; - } - for (; i < blocklen; ++i) { - s1 += *buffer++; s2 += s1; - } - - s1 %= ADLER_MOD; s2 %= ADLER_MOD; - buflen -= (unsigned int)blocklen; - blocklen = 5552; - } - return (unsigned int)(s2 << 16) + (unsigned int)s1; -} - -NK_INTERN unsigned int -nk_decompress(unsigned char *output, unsigned char *i, unsigned int length) -{ - unsigned int olen; - if (nk__in4(0) != 0x57bC0000) return 0; - if (nk__in4(4) != 0) return 0; /* error! stream is > 4GB */ - olen = nk_decompress_length(i); - nk__barrier2 = i; - nk__barrier3 = i+length; - nk__barrier = output + olen; - nk__barrier4 = output; - i += 16; - - nk__dout = output; - for (;;) { - unsigned char *old_i = i; - i = nk_decompress_token(i); - if (i == old_i) { - if (*i == 0x05 && i[1] == 0xfa) { - NK_ASSERT(nk__dout == output + olen); - if (nk__dout != output + olen) return 0; - if (nk_adler32(1, output, olen) != (unsigned int) nk__in4(2)) - return 0; - return olen; - } else { - NK_ASSERT(0); /* NOTREACHED */ - return 0; - } - } - NK_ASSERT(nk__dout <= output + olen); - if (nk__dout > output + olen) - return 0; - } -} - -NK_INTERN unsigned int -nk_decode_85_byte(char c) -{ return (unsigned int)((c >= '\\') ? c-36 : c-35); } - -NK_INTERN void -nk_decode_85(unsigned char* dst, const unsigned char* src) -{ - while (*src) - { - unsigned int tmp = - nk_decode_85_byte((char)src[0]) + - 85 * (nk_decode_85_byte((char)src[1]) + - 85 * (nk_decode_85_byte((char)src[2]) + - 85 * (nk_decode_85_byte((char)src[3]) + - 85 * nk_decode_85_byte((char)src[4])))); - - /* we can't assume little-endianess. */ - dst[0] = (unsigned char)((tmp >> 0) & 0xFF); - dst[1] = (unsigned char)((tmp >> 8) & 0xFF); - dst[2] = (unsigned char)((tmp >> 16) & 0xFF); - dst[3] = (unsigned char)((tmp >> 24) & 0xFF); - - src += 5; - dst += 4; - } -} - -/* ------------------------------------------------------------- - * - * FONT ATLAS - * - * --------------------------------------------------------------*/ -NK_API struct nk_font_config -nk_font_config(float pixel_height) -{ - struct nk_font_config cfg; - nk_zero_struct(cfg); - cfg.ttf_blob = 0; - cfg.ttf_size = 0; - cfg.ttf_data_owned_by_atlas = 0; - cfg.size = pixel_height; - cfg.oversample_h = 3; - cfg.oversample_v = 1; - cfg.pixel_snap = 0; - cfg.coord_type = NK_COORD_UV; - cfg.spacing = nk_vec2(0,0); - cfg.range = nk_font_default_glyph_ranges(); - cfg.merge_mode = 0; - cfg.fallback_glyph = '?'; - cfg.font = 0; - cfg.n = 0; - return cfg; -} - -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API void -nk_font_atlas_init_default(struct nk_font_atlas *atlas) -{ - NK_ASSERT(atlas); - if (!atlas) return; - nk_zero_struct(*atlas); - atlas->temporary.userdata.ptr = 0; - atlas->temporary.alloc = nk_malloc; - atlas->temporary.free = nk_mfree; - atlas->permanent.userdata.ptr = 0; - atlas->permanent.alloc = nk_malloc; - atlas->permanent.free = nk_mfree; -} -#endif - -NK_API void -nk_font_atlas_init(struct nk_font_atlas *atlas, struct nk_allocator *alloc) -{ - NK_ASSERT(atlas); - NK_ASSERT(alloc); - if (!atlas || !alloc) return; - nk_zero_struct(*atlas); - atlas->permanent = *alloc; - atlas->temporary = *alloc; -} - -NK_API void -nk_font_atlas_init_custom(struct nk_font_atlas *atlas, - struct nk_allocator *permanent, struct nk_allocator *temporary) -{ - NK_ASSERT(atlas); - NK_ASSERT(permanent); - NK_ASSERT(temporary); - if (!atlas || !permanent || !temporary) return; - nk_zero_struct(*atlas); - atlas->permanent = *permanent; - atlas->temporary = *temporary; -} - -NK_API void -nk_font_atlas_begin(struct nk_font_atlas *atlas) -{ - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc && atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc && atlas->permanent.free); - if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free || - !atlas->temporary.alloc || !atlas->temporary.free) return; - if (atlas->glyphs) { - atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs); - atlas->glyphs = 0; - } - if (atlas->pixel) { - atlas->permanent.free(atlas->permanent.userdata, atlas->pixel); - atlas->pixel = 0; - } -} - -NK_API struct nk_font* -nk_font_atlas_add(struct nk_font_atlas *atlas, const struct nk_font_config *config) -{ - struct nk_font *font = 0; - struct nk_font_config *cfg; - - NK_ASSERT(atlas); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - - NK_ASSERT(config); - NK_ASSERT(config->ttf_blob); - NK_ASSERT(config->ttf_size); - NK_ASSERT(config->size > 0.0f); - - if (!atlas || !config || !config->ttf_blob || !config->ttf_size || config->size <= 0.0f|| - !atlas->permanent.alloc || !atlas->permanent.free || - !atlas->temporary.alloc || !atlas->temporary.free) - return 0; - - /* allocate font config */ - cfg = (struct nk_font_config*) - atlas->permanent.alloc(atlas->permanent.userdata,0, sizeof(struct nk_font_config)); - NK_MEMCPY(cfg, config, sizeof(*config)); - cfg->n = cfg; - cfg->p = cfg; - - if (!config->merge_mode) { - /* insert font config into list */ - if (!atlas->config) { - atlas->config = cfg; - cfg->next = 0; - } else { - struct nk_font_config *i = atlas->config; - while (i->next) i = i->next; - i->next = cfg; - cfg->next = 0; - } - /* allocate new font */ - font = (struct nk_font*) - atlas->permanent.alloc(atlas->permanent.userdata,0, sizeof(struct nk_font)); - NK_ASSERT(font); - nk_zero(font, sizeof(*font)); - if (!font) return 0; - font->config = cfg; - - /* insert font into list */ - if (!atlas->fonts) { - atlas->fonts = font; - font->next = 0; - } else { - struct nk_font *i = atlas->fonts; - while (i->next) i = i->next; - i->next = font; - font->next = 0; - } - cfg->font = &font->info; - } else { - /* extend previously added font */ - struct nk_font *f = 0; - struct nk_font_config *c = 0; - NK_ASSERT(atlas->font_num); - f = atlas->fonts; - c = f->config; - cfg->font = &f->info; - - cfg->n = c; - cfg->p = c->p; - c->p->n = cfg; - c->p = cfg; - } - /* create own copy of .TTF font blob */ - if (!config->ttf_data_owned_by_atlas) { - cfg->ttf_blob = atlas->permanent.alloc(atlas->permanent.userdata,0, cfg->ttf_size); - NK_ASSERT(cfg->ttf_blob); - if (!cfg->ttf_blob) { - atlas->font_num++; - return 0; - } - NK_MEMCPY(cfg->ttf_blob, config->ttf_blob, cfg->ttf_size); - cfg->ttf_data_owned_by_atlas = 1; - } - atlas->font_num++; - return font; -} - -NK_API struct nk_font* -nk_font_atlas_add_from_memory(struct nk_font_atlas *atlas, void *memory, - nk_size size, float height, const struct nk_font_config *config) -{ - struct nk_font_config cfg; - NK_ASSERT(memory); - NK_ASSERT(size); - - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - if (!atlas || !atlas->temporary.alloc || !atlas->temporary.free || !memory || !size || - !atlas->permanent.alloc || !atlas->permanent.free) - return 0; - - cfg = (config) ? *config: nk_font_config(height); - cfg.ttf_blob = memory; - cfg.ttf_size = size; - cfg.size = height; - cfg.ttf_data_owned_by_atlas = 0; - return nk_font_atlas_add(atlas, &cfg); -} - -#ifdef NK_INCLUDE_STANDARD_IO -NK_API struct nk_font* -nk_font_atlas_add_from_file(struct nk_font_atlas *atlas, const char *file_path, - float height, const struct nk_font_config *config) -{ - nk_size size; - char *memory; - struct nk_font_config cfg; - - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - - if (!atlas || !file_path) return 0; - memory = nk_file_load(file_path, &size, &atlas->permanent); - if (!memory) return 0; - - cfg = (config) ? *config: nk_font_config(height); - cfg.ttf_blob = memory; - cfg.ttf_size = size; - cfg.size = height; - cfg.ttf_data_owned_by_atlas = 1; - return nk_font_atlas_add(atlas, &cfg); -} -#endif - -NK_API struct nk_font* -nk_font_atlas_add_compressed(struct nk_font_atlas *atlas, - void *compressed_data, nk_size compressed_size, float height, - const struct nk_font_config *config) -{ - unsigned int decompressed_size; - void *decompressed_data; - struct nk_font_config cfg; - - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - - NK_ASSERT(compressed_data); - NK_ASSERT(compressed_size); - if (!atlas || !compressed_data || !atlas->temporary.alloc || !atlas->temporary.free || - !atlas->permanent.alloc || !atlas->permanent.free) - return 0; - - decompressed_size = nk_decompress_length((unsigned char*)compressed_data); - decompressed_data = atlas->permanent.alloc(atlas->permanent.userdata,0,decompressed_size); - NK_ASSERT(decompressed_data); - if (!decompressed_data) return 0; - nk_decompress((unsigned char*)decompressed_data, (unsigned char*)compressed_data, - (unsigned int)compressed_size); - - cfg = (config) ? *config: nk_font_config(height); - cfg.ttf_blob = decompressed_data; - cfg.ttf_size = decompressed_size; - cfg.size = height; - cfg.ttf_data_owned_by_atlas = 1; - return nk_font_atlas_add(atlas, &cfg); -} - -NK_API struct nk_font* -nk_font_atlas_add_compressed_base85(struct nk_font_atlas *atlas, - const char *data_base85, float height, const struct nk_font_config *config) -{ - int compressed_size; - void *compressed_data; - struct nk_font *font; - - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - - NK_ASSERT(data_base85); - if (!atlas || !data_base85 || !atlas->temporary.alloc || !atlas->temporary.free || - !atlas->permanent.alloc || !atlas->permanent.free) - return 0; - - compressed_size = (((int)nk_strlen(data_base85) + 4) / 5) * 4; - compressed_data = atlas->temporary.alloc(atlas->temporary.userdata,0, (nk_size)compressed_size); - NK_ASSERT(compressed_data); - if (!compressed_data) return 0; - nk_decode_85((unsigned char*)compressed_data, (const unsigned char*)data_base85); - font = nk_font_atlas_add_compressed(atlas, compressed_data, - (nk_size)compressed_size, height, config); - atlas->temporary.free(atlas->temporary.userdata, compressed_data); - return font; -} - -#ifdef NK_INCLUDE_DEFAULT_FONT -NK_API struct nk_font* -nk_font_atlas_add_default(struct nk_font_atlas *atlas, - float pixel_height, const struct nk_font_config *config) -{ - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - return nk_font_atlas_add_compressed_base85(atlas, - nk_proggy_clean_ttf_compressed_data_base85, pixel_height, config); -} -#endif - -NK_API const void* -nk_font_atlas_bake(struct nk_font_atlas *atlas, int *width, int *height, - enum nk_font_atlas_format fmt) -{ - int i = 0; - void *tmp = 0; - nk_size tmp_size, img_size; - struct nk_font *font_iter; - struct nk_font_baker *baker; - - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - - NK_ASSERT(width); - NK_ASSERT(height); - if (!atlas || !width || !height || - !atlas->temporary.alloc || !atlas->temporary.free || - !atlas->permanent.alloc || !atlas->permanent.free) - return 0; - -#ifdef NK_INCLUDE_DEFAULT_FONT - /* no font added so just use default font */ - if (!atlas->font_num) - atlas->default_font = nk_font_atlas_add_default(atlas, 13.0f, 0); -#endif - NK_ASSERT(atlas->font_num); - if (!atlas->font_num) return 0; - - /* allocate temporary baker memory required for the baking process */ - nk_font_baker_memory(&tmp_size, &atlas->glyph_count, atlas->config, atlas->font_num); - tmp = atlas->temporary.alloc(atlas->temporary.userdata,0, tmp_size); - NK_ASSERT(tmp); - if (!tmp) goto failed; - - /* allocate glyph memory for all fonts */ - baker = nk_font_baker(tmp, atlas->glyph_count, atlas->font_num, &atlas->temporary); - atlas->glyphs = (struct nk_font_glyph*)atlas->permanent.alloc( - atlas->permanent.userdata,0, sizeof(struct nk_font_glyph)*(nk_size)atlas->glyph_count); - NK_ASSERT(atlas->glyphs); - if (!atlas->glyphs) - goto failed; - - /* pack all glyphs into a tight fit space */ - atlas->custom.w = (NK_CURSOR_DATA_W*2)+1; - atlas->custom.h = NK_CURSOR_DATA_H + 1; - if (!nk_font_bake_pack(baker, &img_size, width, height, &atlas->custom, - atlas->config, atlas->font_num, &atlas->temporary)) - goto failed; - - /* allocate memory for the baked image font atlas */ - atlas->pixel = atlas->temporary.alloc(atlas->temporary.userdata,0, img_size); - NK_ASSERT(atlas->pixel); - if (!atlas->pixel) - goto failed; - - /* bake glyphs and custom white pixel into image */ - nk_font_bake(baker, atlas->pixel, *width, *height, - atlas->glyphs, atlas->glyph_count, atlas->config, atlas->font_num); - nk_font_bake_custom_data(atlas->pixel, *width, *height, atlas->custom, - nk_custom_cursor_data, NK_CURSOR_DATA_W, NK_CURSOR_DATA_H, '.', 'X'); - - if (fmt == NK_FONT_ATLAS_RGBA32) { - /* convert alpha8 image into rgba32 image */ - void *img_rgba = atlas->temporary.alloc(atlas->temporary.userdata,0, - (nk_size)(*width * *height * 4)); - NK_ASSERT(img_rgba); - if (!img_rgba) goto failed; - nk_font_bake_convert(img_rgba, *width, *height, atlas->pixel); - atlas->temporary.free(atlas->temporary.userdata, atlas->pixel); - atlas->pixel = img_rgba; - } - atlas->tex_width = *width; - atlas->tex_height = *height; - - /* initialize each font */ - for (font_iter = atlas->fonts; font_iter; font_iter = font_iter->next) { - struct nk_font *font = font_iter; - struct nk_font_config *config = font->config; - nk_font_init(font, config->size, config->fallback_glyph, atlas->glyphs, - config->font, nk_handle_ptr(0)); - } - - /* initialize each cursor */ - {NK_STORAGE const struct nk_vec2 nk_cursor_data[NK_CURSOR_COUNT][3] = { - /* Pos Size Offset */ - {{ 0, 3}, {12,19}, { 0, 0}}, - {{13, 0}, { 7,16}, { 4, 8}}, - {{31, 0}, {23,23}, {11,11}}, - {{21, 0}, { 9, 23}, { 5,11}}, - {{55,18}, {23, 9}, {11, 5}}, - {{73, 0}, {17,17}, { 9, 9}}, - {{55, 0}, {17,17}, { 9, 9}} - }; - for (i = 0; i < NK_CURSOR_COUNT; ++i) { - struct nk_cursor *cursor = &atlas->cursors[i]; - cursor->img.w = (unsigned short)*width; - cursor->img.h = (unsigned short)*height; - cursor->img.region[0] = (unsigned short)(atlas->custom.x + nk_cursor_data[i][0].x); - cursor->img.region[1] = (unsigned short)(atlas->custom.y + nk_cursor_data[i][0].y); - cursor->img.region[2] = (unsigned short)nk_cursor_data[i][1].x; - cursor->img.region[3] = (unsigned short)nk_cursor_data[i][1].y; - cursor->size = nk_cursor_data[i][1]; - cursor->offset = nk_cursor_data[i][2]; - }} - /* free temporary memory */ - atlas->temporary.free(atlas->temporary.userdata, tmp); - return atlas->pixel; - -failed: - /* error so cleanup all memory */ - if (tmp) atlas->temporary.free(atlas->temporary.userdata, tmp); - if (atlas->glyphs) { - atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs); - atlas->glyphs = 0; - } - if (atlas->pixel) { - atlas->temporary.free(atlas->temporary.userdata, atlas->pixel); - atlas->pixel = 0; - } - return 0; -} - -NK_API void -nk_font_atlas_end(struct nk_font_atlas *atlas, nk_handle texture, - struct nk_draw_null_texture *null) -{ - int i = 0; - struct nk_font *font_iter; - NK_ASSERT(atlas); - if (!atlas) { - if (!null) return; - null->texture = texture; - null->uv = nk_vec2(0.5f,0.5f); - } - if (null) { - null->texture = texture; - null->uv.x = (atlas->custom.x + 0.5f)/(float)atlas->tex_width; - null->uv.y = (atlas->custom.y + 0.5f)/(float)atlas->tex_height; - } - for (font_iter = atlas->fonts; font_iter; font_iter = font_iter->next) { - font_iter->texture = texture; -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT - font_iter->handle.texture = texture; -#endif - } - for (i = 0; i < NK_CURSOR_COUNT; ++i) - atlas->cursors[i].img.handle = texture; - - atlas->temporary.free(atlas->temporary.userdata, atlas->pixel); - atlas->pixel = 0; - atlas->tex_width = 0; - atlas->tex_height = 0; - atlas->custom.x = 0; - atlas->custom.y = 0; - atlas->custom.w = 0; - atlas->custom.h = 0; -} - -NK_API void -nk_font_atlas_cleanup(struct nk_font_atlas *atlas) -{ - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free) return; - if (atlas->config) { - struct nk_font_config *iter; - for (iter = atlas->config; iter; iter = iter->next) { - struct nk_font_config *i; - for (i = iter->n; i != iter; i = i->n) { - atlas->permanent.free(atlas->permanent.userdata, i->ttf_blob); - i->ttf_blob = 0; - } - atlas->permanent.free(atlas->permanent.userdata, iter->ttf_blob); - iter->ttf_blob = 0; - } - } -} - -NK_API void -nk_font_atlas_clear(struct nk_font_atlas *atlas) -{ - NK_ASSERT(atlas); - NK_ASSERT(atlas->temporary.alloc); - NK_ASSERT(atlas->temporary.free); - NK_ASSERT(atlas->permanent.alloc); - NK_ASSERT(atlas->permanent.free); - if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free) return; - - if (atlas->config) { - struct nk_font_config *iter, *next; - for (iter = atlas->config; iter; iter = next) { - struct nk_font_config *i, *n; - for (i = iter->n; i != iter; i = n) { - n = i->n; - if (i->ttf_blob) - atlas->permanent.free(atlas->permanent.userdata, i->ttf_blob); - atlas->permanent.free(atlas->permanent.userdata, i); - } - next = iter->next; - if (i->ttf_blob) - atlas->permanent.free(atlas->permanent.userdata, iter->ttf_blob); - atlas->permanent.free(atlas->permanent.userdata, iter); - } - atlas->config = 0; - } - if (atlas->fonts) { - struct nk_font *iter, *next; - for (iter = atlas->fonts; iter; iter = next) { - next = iter->next; - atlas->permanent.free(atlas->permanent.userdata, iter); - } - atlas->fonts = 0; - } - if (atlas->glyphs) - atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs); - nk_zero_struct(*atlas); -} -#endif -/* ============================================================== - * - * INPUT - * - * ===============================================================*/ -NK_API void -nk_input_begin(struct nk_context *ctx) -{ - int i; - struct nk_input *in; - NK_ASSERT(ctx); - if (!ctx) return; - in = &ctx->input; - for (i = 0; i < NK_BUTTON_MAX; ++i) - in->mouse.buttons[i].clicked = 0; - - in->keyboard.text_len = 0; - in->mouse.scroll_delta = nk_vec2(0,0); - in->mouse.prev.x = in->mouse.pos.x; - in->mouse.prev.y = in->mouse.pos.y; - in->mouse.delta.x = 0; - in->mouse.delta.y = 0; - for (i = 0; i < NK_KEY_MAX; i++) - in->keyboard.keys[i].clicked = 0; -} - -NK_API void -nk_input_end(struct nk_context *ctx) -{ - struct nk_input *in; - NK_ASSERT(ctx); - if (!ctx) return; - in = &ctx->input; - if (in->mouse.grab) - in->mouse.grab = 0; - if (in->mouse.ungrab) { - in->mouse.grabbed = 0; - in->mouse.ungrab = 0; - in->mouse.grab = 0; - } -} - -NK_API void -nk_input_motion(struct nk_context *ctx, int x, int y) -{ - struct nk_input *in; - NK_ASSERT(ctx); - if (!ctx) return; - in = &ctx->input; - in->mouse.pos.x = (float)x; - in->mouse.pos.y = (float)y; - in->mouse.delta.x = in->mouse.pos.x - in->mouse.prev.x; - in->mouse.delta.y = in->mouse.pos.y - in->mouse.prev.y; -} - -NK_API void -nk_input_key(struct nk_context *ctx, enum nk_keys key, int down) -{ - struct nk_input *in; - NK_ASSERT(ctx); - if (!ctx) return; - in = &ctx->input; - if (in->keyboard.keys[key].down != down) - in->keyboard.keys[key].clicked++; - in->keyboard.keys[key].down = down; -} - -NK_API void -nk_input_button(struct nk_context *ctx, enum nk_buttons id, int x, int y, int down) -{ - struct nk_mouse_button *btn; - struct nk_input *in; - NK_ASSERT(ctx); - if (!ctx) return; - in = &ctx->input; - if (in->mouse.buttons[id].down == down) return; - - btn = &in->mouse.buttons[id]; - btn->clicked_pos.x = (float)x; - btn->clicked_pos.y = (float)y; - btn->down = down; - btn->clicked++; -} - -NK_API void -nk_input_scroll(struct nk_context *ctx, struct nk_vec2 val) -{ - NK_ASSERT(ctx); - if (!ctx) return; - ctx->input.mouse.scroll_delta.x += val.x; - ctx->input.mouse.scroll_delta.y += val.y; -} - -NK_API void -nk_input_glyph(struct nk_context *ctx, const nk_glyph glyph) -{ - int len = 0; - nk_rune unicode; - struct nk_input *in; - - NK_ASSERT(ctx); - if (!ctx) return; - in = &ctx->input; - - len = nk_utf_decode(glyph, &unicode, NK_UTF_SIZE); - if (len && ((in->keyboard.text_len + len) < NK_INPUT_MAX)) { - nk_utf_encode(unicode, &in->keyboard.text[in->keyboard.text_len], - NK_INPUT_MAX - in->keyboard.text_len); - in->keyboard.text_len += len; - } -} - -NK_API void -nk_input_char(struct nk_context *ctx, char c) -{ - nk_glyph glyph; - NK_ASSERT(ctx); - if (!ctx) return; - glyph[0] = c; - nk_input_glyph(ctx, glyph); -} - -NK_API void -nk_input_unicode(struct nk_context *ctx, nk_rune unicode) -{ - nk_glyph rune; - NK_ASSERT(ctx); - if (!ctx) return; - nk_utf_encode(unicode, rune, NK_UTF_SIZE); - nk_input_glyph(ctx, rune); -} - -NK_API int -nk_input_has_mouse_click(const struct nk_input *i, enum nk_buttons id) -{ - const struct nk_mouse_button *btn; - if (!i) return nk_false; - btn = &i->mouse.buttons[id]; - return (btn->clicked && btn->down == nk_false) ? nk_true : nk_false; -} - -NK_API int -nk_input_has_mouse_click_in_rect(const struct nk_input *i, enum nk_buttons id, - struct nk_rect b) -{ - const struct nk_mouse_button *btn; - if (!i) return nk_false; - btn = &i->mouse.buttons[id]; - if (!NK_INBOX(btn->clicked_pos.x,btn->clicked_pos.y,b.x,b.y,b.w,b.h)) - return nk_false; - return nk_true; -} - -NK_API int -nk_input_has_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id, - struct nk_rect b, int down) -{ - const struct nk_mouse_button *btn; - if (!i) return nk_false; - btn = &i->mouse.buttons[id]; - return nk_input_has_mouse_click_in_rect(i, id, b) && (btn->down == down); -} - -NK_API int -nk_input_is_mouse_click_in_rect(const struct nk_input *i, enum nk_buttons id, - struct nk_rect b) -{ - const struct nk_mouse_button *btn; - if (!i) return nk_false; - btn = &i->mouse.buttons[id]; - return (nk_input_has_mouse_click_down_in_rect(i, id, b, nk_false) && - btn->clicked) ? nk_true : nk_false; -} - -NK_API int -nk_input_is_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id, - struct nk_rect b, int down) -{ - const struct nk_mouse_button *btn; - if (!i) return nk_false; - btn = &i->mouse.buttons[id]; - return (nk_input_has_mouse_click_down_in_rect(i, id, b, down) && - btn->clicked) ? nk_true : nk_false; -} - -NK_API int -nk_input_any_mouse_click_in_rect(const struct nk_input *in, struct nk_rect b) -{ - int i, down = 0; - for (i = 0; i < NK_BUTTON_MAX; ++i) - down = down || nk_input_is_mouse_click_in_rect(in, (enum nk_buttons)i, b); - return down; -} - -NK_API int -nk_input_is_mouse_hovering_rect(const struct nk_input *i, struct nk_rect rect) -{ - if (!i) return nk_false; - return NK_INBOX(i->mouse.pos.x, i->mouse.pos.y, rect.x, rect.y, rect.w, rect.h); -} - -NK_API int -nk_input_is_mouse_prev_hovering_rect(const struct nk_input *i, struct nk_rect rect) -{ - if (!i) return nk_false; - return NK_INBOX(i->mouse.prev.x, i->mouse.prev.y, rect.x, rect.y, rect.w, rect.h); -} - -NK_API int -nk_input_mouse_clicked(const struct nk_input *i, enum nk_buttons id, struct nk_rect rect) -{ - if (!i) return nk_false; - if (!nk_input_is_mouse_hovering_rect(i, rect)) return nk_false; - return nk_input_is_mouse_click_in_rect(i, id, rect); -} - -NK_API int -nk_input_is_mouse_down(const struct nk_input *i, enum nk_buttons id) -{ - if (!i) return nk_false; - return i->mouse.buttons[id].down; -} - -NK_API int -nk_input_is_mouse_pressed(const struct nk_input *i, enum nk_buttons id) -{ - const struct nk_mouse_button *b; - if (!i) return nk_false; - b = &i->mouse.buttons[id]; - if (b->down && b->clicked) - return nk_true; - return nk_false; -} - -NK_API int -nk_input_is_mouse_released(const struct nk_input *i, enum nk_buttons id) -{ - if (!i) return nk_false; - return (!i->mouse.buttons[id].down && i->mouse.buttons[id].clicked); -} - -NK_API int -nk_input_is_key_pressed(const struct nk_input *i, enum nk_keys key) -{ - const struct nk_key *k; - if (!i) return nk_false; - k = &i->keyboard.keys[key]; - if ((k->down && k->clicked) || (!k->down && k->clicked >= 2)) - return nk_true; - return nk_false; -} - -NK_API int -nk_input_is_key_released(const struct nk_input *i, enum nk_keys key) -{ - const struct nk_key *k; - if (!i) return nk_false; - k = &i->keyboard.keys[key]; - if ((!k->down && k->clicked) || (k->down && k->clicked >= 2)) - return nk_true; - return nk_false; -} - -NK_API int -nk_input_is_key_down(const struct nk_input *i, enum nk_keys key) -{ - const struct nk_key *k; - if (!i) return nk_false; - k = &i->keyboard.keys[key]; - if (k->down) return nk_true; - return nk_false; -} - -/* - * ============================================================== - * - * TEXT EDITOR - * - * =============================================================== - */ -/* stb_textedit.h - v1.8 - public domain - Sean Barrett */ -struct nk_text_find { - float x,y; /* position of n'th character */ - float height; /* height of line */ - int first_char, length; /* first char of row, and length */ - int prev_first; /*_ first char of previous row */ -}; - -struct nk_text_edit_row { - float x0,x1; - /* starting x location, end x location (allows for align=right, etc) */ - float baseline_y_delta; - /* position of baseline relative to previous row's baseline*/ - float ymin,ymax; - /* height of row above and below baseline */ - int num_chars; -}; - -/* forward declarations */ -NK_INTERN void nk_textedit_makeundo_delete(struct nk_text_edit*, int, int); -NK_INTERN void nk_textedit_makeundo_insert(struct nk_text_edit*, int, int); -NK_INTERN void nk_textedit_makeundo_replace(struct nk_text_edit*, int, int, int); -#define NK_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end) - -NK_INTERN float -nk_textedit_get_width(const struct nk_text_edit *edit, int line_start, int char_id, - const struct nk_user_font *font) -{ - int len = 0; - nk_rune unicode = 0; - const char *str = nk_str_at_const(&edit->string, line_start + char_id, &unicode, &len); - return font->width(font->userdata, font->height, str, len); -} - -NK_INTERN void -nk_textedit_layout_row(struct nk_text_edit_row *r, struct nk_text_edit *edit, - int line_start_id, float row_height, const struct nk_user_font *font) -{ - int l; - int glyphs = 0; - nk_rune unicode; - const char *remaining; - int len = nk_str_len_char(&edit->string); - const char *end = nk_str_get_const(&edit->string) + len; - const char *text = nk_str_at_const(&edit->string, line_start_id, &unicode, &l); - const struct nk_vec2 size = nk_text_calculate_text_bounds(font, - text, (int)(end - text), row_height, &remaining, 0, &glyphs, NK_STOP_ON_NEW_LINE); - - r->x0 = 0.0f; - r->x1 = size.x; - r->baseline_y_delta = size.y; - r->ymin = 0.0f; - r->ymax = size.y; - r->num_chars = glyphs; -} - -NK_INTERN int -nk_textedit_locate_coord(struct nk_text_edit *edit, float x, float y, - const struct nk_user_font *font, float row_height) -{ - struct nk_text_edit_row r; - int n = edit->string.len; - float base_y = 0, prev_x; - int i=0, k; - - r.x0 = r.x1 = 0; - r.ymin = r.ymax = 0; - r.num_chars = 0; - - /* search rows to find one that straddles 'y' */ - while (i < n) { - nk_textedit_layout_row(&r, edit, i, row_height, font); - if (r.num_chars <= 0) - return n; - - if (i==0 && y < base_y + r.ymin) - return 0; - - if (y < base_y + r.ymax) - break; - - i += r.num_chars; - base_y += r.baseline_y_delta; - } - - /* below all text, return 'after' last character */ - if (i >= n) - return n; - - /* check if it's before the beginning of the line */ - if (x < r.x0) - return i; - - /* check if it's before the end of the line */ - if (x < r.x1) { - /* search characters in row for one that straddles 'x' */ - k = i; - prev_x = r.x0; - for (i=0; i < r.num_chars; ++i) { - float w = nk_textedit_get_width(edit, k, i, font); - if (x < prev_x+w) { - if (x < prev_x+w/2) - return k+i; - else return k+i+1; - } - prev_x += w; - } - /* shouldn't happen, but if it does, fall through to end-of-line case */ - } - - /* if the last character is a newline, return that. - * otherwise return 'after' the last character */ - if (nk_str_rune_at(&edit->string, i+r.num_chars-1) == '\n') - return i+r.num_chars-1; - else return i+r.num_chars; -} - -NK_INTERN void -nk_textedit_click(struct nk_text_edit *state, float x, float y, - const struct nk_user_font *font, float row_height) -{ - /* API click: on mouse down, move the cursor to the clicked location, - * and reset the selection */ - state->cursor = nk_textedit_locate_coord(state, x, y, font, row_height); - state->select_start = state->cursor; - state->select_end = state->cursor; - state->has_preferred_x = 0; -} - -NK_INTERN void -nk_textedit_drag(struct nk_text_edit *state, float x, float y, - const struct nk_user_font *font, float row_height) -{ - /* API drag: on mouse drag, move the cursor and selection endpoint - * to the clicked location */ - int p = nk_textedit_locate_coord(state, x, y, font, row_height); - if (state->select_start == state->select_end) - state->select_start = state->cursor; - state->cursor = state->select_end = p; -} - -NK_INTERN void -nk_textedit_find_charpos(struct nk_text_find *find, struct nk_text_edit *state, - int n, int single_line, const struct nk_user_font *font, float row_height) -{ - /* find the x/y location of a character, and remember info about the previous - * row in case we get a move-up event (for page up, we'll have to rescan) */ - struct nk_text_edit_row r; - int prev_start = 0; - int z = state->string.len; - int i=0, first; - - nk_zero_struct(r); - if (n == z) { - /* if it's at the end, then find the last line -- simpler than trying to - explicitly handle this case in the regular code */ - nk_textedit_layout_row(&r, state, 0, row_height, font); - if (single_line) { - find->first_char = 0; - find->length = z; - } else { - while (i < z) { - prev_start = i; - i += r.num_chars; - nk_textedit_layout_row(&r, state, i, row_height, font); - } - - find->first_char = i; - find->length = r.num_chars; - } - find->x = r.x1; - find->y = r.ymin; - find->height = r.ymax - r.ymin; - find->prev_first = prev_start; - return; - } - - /* search rows to find the one that straddles character n */ - find->y = 0; - - for(;;) { - nk_textedit_layout_row(&r, state, i, row_height, font); - if (n < i + r.num_chars) break; - prev_start = i; - i += r.num_chars; - find->y += r.baseline_y_delta; - } - - find->first_char = first = i; - find->length = r.num_chars; - find->height = r.ymax - r.ymin; - find->prev_first = prev_start; - - /* now scan to find xpos */ - find->x = r.x0; - for (i=0; first+i < n; ++i) - find->x += nk_textedit_get_width(state, first, i, font); -} - -NK_INTERN void -nk_textedit_clamp(struct nk_text_edit *state) -{ - /* make the selection/cursor state valid if client altered the string */ - int n = state->string.len; - if (NK_TEXT_HAS_SELECTION(state)) { - if (state->select_start > n) state->select_start = n; - if (state->select_end > n) state->select_end = n; - /* if clamping forced them to be equal, move the cursor to match */ - if (state->select_start == state->select_end) - state->cursor = state->select_start; - } - if (state->cursor > n) state->cursor = n; -} - -NK_API void -nk_textedit_delete(struct nk_text_edit *state, int where, int len) -{ - /* delete characters while updating undo */ - nk_textedit_makeundo_delete(state, where, len); - nk_str_delete_runes(&state->string, where, len); - state->has_preferred_x = 0; -} - -NK_API void -nk_textedit_delete_selection(struct nk_text_edit *state) -{ - /* delete the section */ - nk_textedit_clamp(state); - if (NK_TEXT_HAS_SELECTION(state)) { - if (state->select_start < state->select_end) { - nk_textedit_delete(state, state->select_start, - state->select_end - state->select_start); - state->select_end = state->cursor = state->select_start; - } else { - nk_textedit_delete(state, state->select_end, - state->select_start - state->select_end); - state->select_start = state->cursor = state->select_end; - } - state->has_preferred_x = 0; - } -} - -NK_INTERN void -nk_textedit_sortselection(struct nk_text_edit *state) -{ - /* canonicalize the selection so start <= end */ - if (state->select_end < state->select_start) { - int temp = state->select_end; - state->select_end = state->select_start; - state->select_start = temp; - } -} - -NK_INTERN void -nk_textedit_move_to_first(struct nk_text_edit *state) -{ - /* move cursor to first character of selection */ - if (NK_TEXT_HAS_SELECTION(state)) { - nk_textedit_sortselection(state); - state->cursor = state->select_start; - state->select_end = state->select_start; - state->has_preferred_x = 0; - } -} - -NK_INTERN void -nk_textedit_move_to_last(struct nk_text_edit *state) -{ - /* move cursor to last character of selection */ - if (NK_TEXT_HAS_SELECTION(state)) { - nk_textedit_sortselection(state); - nk_textedit_clamp(state); - state->cursor = state->select_end; - state->select_start = state->select_end; - state->has_preferred_x = 0; - } -} - -NK_INTERN int -nk_is_word_boundary( struct nk_text_edit *state, int idx) -{ - int len; - nk_rune c; - if (idx <= 0) return 1; - if (!nk_str_at_rune(&state->string, idx, &c, &len)) return 1; - return (c == ' ' || c == '\t' ||c == 0x3000 || c == ',' || c == ';' || - c == '(' || c == ')' || c == '{' || c == '}' || c == '[' || c == ']' || - c == '|'); -} - -NK_INTERN int -nk_textedit_move_to_word_previous(struct nk_text_edit *state) -{ - int c = state->cursor - 1; - while( c >= 0 && !nk_is_word_boundary(state, c)) - --c; - - if( c < 0 ) - c = 0; - - return c; -} - -NK_INTERN int -nk_textedit_move_to_word_next(struct nk_text_edit *state) -{ - const int len = state->string.len; - int c = state->cursor+1; - while( c < len && !nk_is_word_boundary(state, c)) - ++c; - - if( c > len ) - c = len; - - return c; -} - -NK_INTERN void -nk_textedit_prep_selection_at_cursor(struct nk_text_edit *state) -{ - /* update selection and cursor to match each other */ - if (!NK_TEXT_HAS_SELECTION(state)) - state->select_start = state->select_end = state->cursor; - else state->cursor = state->select_end; -} - -NK_API int -nk_textedit_cut(struct nk_text_edit *state) -{ - /* API cut: delete selection */ - if (state->mode == NK_TEXT_EDIT_MODE_VIEW) - return 0; - if (NK_TEXT_HAS_SELECTION(state)) { - nk_textedit_delete_selection(state); /* implicitly clamps */ - state->has_preferred_x = 0; - return 1; - } - return 0; -} - -NK_API int -nk_textedit_paste(struct nk_text_edit *state, char const *ctext, int len) -{ - /* API paste: replace existing selection with passed-in text */ - int glyphs; - const char *text = (const char *) ctext; - if (state->mode == NK_TEXT_EDIT_MODE_VIEW) return 0; - - /* if there's a selection, the paste should delete it */ - nk_textedit_clamp(state); - nk_textedit_delete_selection(state); - - /* try to insert the characters */ - glyphs = nk_utf_len(ctext, len); - if (nk_str_insert_text_char(&state->string, state->cursor, text, len)) { - nk_textedit_makeundo_insert(state, state->cursor, glyphs); - state->cursor += len; - state->has_preferred_x = 0; - return 1; - } - /* remove the undo since we didn't actually insert the characters */ - if (state->undo.undo_point) - --state->undo.undo_point; - return 0; -} - -NK_API void -nk_textedit_text(struct nk_text_edit *state, const char *text, int total_len) -{ - nk_rune unicode; - int glyph_len; - int text_len = 0; - - NK_ASSERT(state); - NK_ASSERT(text); - if (!text || !total_len || state->mode == NK_TEXT_EDIT_MODE_VIEW) return; - - glyph_len = nk_utf_decode(text, &unicode, total_len); - while ((text_len < total_len) && glyph_len) - { - /* don't insert a backward delete, just process the event */ - if (unicode == 127) goto next; - /* can't add newline in single-line mode */ - if (unicode == '\n' && state->single_line) goto next; - /* filter incoming text */ - if (state->filter && !state->filter(state, unicode)) goto next; - - if (!NK_TEXT_HAS_SELECTION(state) && - state->cursor < state->string.len) - { - if (state->mode == NK_TEXT_EDIT_MODE_REPLACE) { - nk_textedit_makeundo_replace(state, state->cursor, 1, 1); - nk_str_delete_runes(&state->string, state->cursor, 1); - } - if (nk_str_insert_text_utf8(&state->string, state->cursor, - text+text_len, 1)) - { - ++state->cursor; - state->has_preferred_x = 0; - } - } else { - nk_textedit_delete_selection(state); /* implicitly clamps */ - if (nk_str_insert_text_utf8(&state->string, state->cursor, - text+text_len, 1)) - { - nk_textedit_makeundo_insert(state, state->cursor, 1); - ++state->cursor; - state->has_preferred_x = 0; - } - } - next: - text_len += glyph_len; - glyph_len = nk_utf_decode(text + text_len, &unicode, total_len-text_len); - } - - state->lexer.needs_refresh = 1; -} - -NK_INTERN void -nk_textedit_key(struct nk_text_edit *state, enum nk_keys key, int shift_mod, - const struct nk_user_font *font, float row_height) -{ -retry: - switch (key) - { - case NK_KEY_NONE: - case NK_KEY_CTRL: - case NK_KEY_ENTER: - case NK_KEY_SHIFT: - case NK_KEY_TAB: - case NK_KEY_COPY: - case NK_KEY_CUT: - case NK_KEY_PASTE: - case NK_KEY_MAX: - default: break; - case NK_KEY_TEXT_UNDO: - nk_textedit_undo(state); - state->has_preferred_x = 0; - break; - - case NK_KEY_TEXT_REDO: - nk_textedit_redo(state); - state->has_preferred_x = 0; - break; - - case NK_KEY_TEXT_SELECT_ALL: - nk_textedit_select_all(state); - state->has_preferred_x = 0; - break; - - case NK_KEY_TEXT_INSERT_MODE: - if (state->mode == NK_TEXT_EDIT_MODE_VIEW) - state->mode = NK_TEXT_EDIT_MODE_INSERT; - break; - case NK_KEY_TEXT_REPLACE_MODE: - if (state->mode == NK_TEXT_EDIT_MODE_VIEW) - state->mode = NK_TEXT_EDIT_MODE_REPLACE; - break; - case NK_KEY_TEXT_RESET_MODE: - if (state->mode == NK_TEXT_EDIT_MODE_INSERT || - state->mode == NK_TEXT_EDIT_MODE_REPLACE) - state->mode = NK_TEXT_EDIT_MODE_VIEW; - break; - - case NK_KEY_LEFT: - if (shift_mod) { - nk_textedit_clamp(state); - nk_textedit_prep_selection_at_cursor(state); - /* move selection left */ - if (state->select_end > 0) - --state->select_end; - state->cursor = state->select_end; - state->has_preferred_x = 0; - } else { - /* if currently there's a selection, - * move cursor to start of selection */ - if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_move_to_first(state); - else if (state->cursor > 0) - --state->cursor; - state->has_preferred_x = 0; - } break; - - case NK_KEY_RIGHT: - if (shift_mod) { - nk_textedit_prep_selection_at_cursor(state); - /* move selection right */ - ++state->select_end; - nk_textedit_clamp(state); - state->cursor = state->select_end; - state->has_preferred_x = 0; - } else { - /* if currently there's a selection, - * move cursor to end of selection */ - if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_move_to_last(state); - else ++state->cursor; - nk_textedit_clamp(state); - state->has_preferred_x = 0; - } break; - - case NK_KEY_TEXT_WORD_LEFT: - if (shift_mod) { - if( !NK_TEXT_HAS_SELECTION( state ) ) - nk_textedit_prep_selection_at_cursor(state); - state->cursor = nk_textedit_move_to_word_previous(state); - state->select_end = state->cursor; - nk_textedit_clamp(state ); - } else { - if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_move_to_first(state); - else { - state->cursor = nk_textedit_move_to_word_previous(state); - nk_textedit_clamp(state ); - } - } break; - - case NK_KEY_TEXT_WORD_RIGHT: - if (shift_mod) { - if( !NK_TEXT_HAS_SELECTION( state ) ) - nk_textedit_prep_selection_at_cursor(state); - state->cursor = nk_textedit_move_to_word_next(state); - state->select_end = state->cursor; - nk_textedit_clamp(state); - } else { - if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_move_to_last(state); - else { - state->cursor = nk_textedit_move_to_word_next(state); - nk_textedit_clamp(state ); - } - } break; - - case NK_KEY_DOWN: { - struct nk_text_find find; - struct nk_text_edit_row row; - int i, sel = shift_mod; - - if (state->single_line) { - /* on windows, up&down in single-line behave like left&right */ - key = NK_KEY_RIGHT; - goto retry; - } - - if (sel) - nk_textedit_prep_selection_at_cursor(state); - else if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_move_to_last(state); - - /* compute current position of cursor point */ - nk_textedit_clamp(state); - nk_textedit_find_charpos(&find, state, state->cursor, state->single_line, - font, row_height); - - /* now find character position down a row */ - if (find.length) - { - float x; - float goal_x = state->has_preferred_x ? state->preferred_x : find.x; - int start = find.first_char + find.length; - - state->cursor = start; - nk_textedit_layout_row(&row, state, state->cursor, row_height, font); - x = row.x0; - - for (i=0; i < row.num_chars && x < row.x1; ++i) { - float dx = nk_textedit_get_width(state, start, i, font); - x += dx; - if (x > goal_x) - break; - ++state->cursor; - } - nk_textedit_clamp(state); - - state->has_preferred_x = 1; - state->preferred_x = goal_x; - if (sel) - state->select_end = state->cursor; - } - } break; - - case NK_KEY_UP: { - struct nk_text_find find; - struct nk_text_edit_row row; - int i, sel = shift_mod; - - if (state->single_line) { - /* on windows, up&down become left&right */ - key = NK_KEY_LEFT; - goto retry; - } - - if (sel) - nk_textedit_prep_selection_at_cursor(state); - else if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_move_to_first(state); - - /* compute current position of cursor point */ - nk_textedit_clamp(state); - nk_textedit_find_charpos(&find, state, state->cursor, state->single_line, - font, row_height); - - /* can only go up if there's a previous row */ - if (find.prev_first != find.first_char) { - /* now find character position up a row */ - float x; - float goal_x = state->has_preferred_x ? state->preferred_x : find.x; - - state->cursor = find.prev_first; - nk_textedit_layout_row(&row, state, state->cursor, row_height, font); - x = row.x0; - - for (i=0; i < row.num_chars && x < row.x1; ++i) { - float dx = nk_textedit_get_width(state, find.prev_first, i, font); - x += dx; - if (x > goal_x) - break; - ++state->cursor; - } - nk_textedit_clamp(state); - - state->has_preferred_x = 1; - state->preferred_x = goal_x; - if (sel) state->select_end = state->cursor; - } - } break; - - case NK_KEY_DEL: - if (state->mode == NK_TEXT_EDIT_MODE_VIEW) - break; - if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_delete_selection(state); - else { - int n = state->string.len; - if (state->cursor < n) - nk_textedit_delete(state, state->cursor, 1); - } - state->has_preferred_x = 0; - break; - - case NK_KEY_BACKSPACE: - if (state->mode == NK_TEXT_EDIT_MODE_VIEW) - break; - if (NK_TEXT_HAS_SELECTION(state)) - nk_textedit_delete_selection(state); - else { - nk_textedit_clamp(state); - if (state->cursor > 0) { - nk_textedit_delete(state, state->cursor-1, 1); - --state->cursor; - } - } - state->has_preferred_x = 0; - break; - - case NK_KEY_TEXT_START: - if (shift_mod) { - nk_textedit_prep_selection_at_cursor(state); - state->cursor = state->select_end = 0; - state->has_preferred_x = 0; - } else { - state->cursor = state->select_start = state->select_end = 0; - state->has_preferred_x = 0; - } - break; - - case NK_KEY_TEXT_END: - if (shift_mod) { - nk_textedit_prep_selection_at_cursor(state); - state->cursor = state->select_end = state->string.len; - state->has_preferred_x = 0; - } else { - state->cursor = state->string.len; - state->select_start = state->select_end = 0; - state->has_preferred_x = 0; - } - break; - - case NK_KEY_TEXT_LINE_START: { - if (shift_mod) { - struct nk_text_find find; - nk_textedit_clamp(state); - nk_textedit_prep_selection_at_cursor(state); - if (state->string.len && state->cursor == state->string.len) - --state->cursor; - nk_textedit_find_charpos(&find, state,state->cursor, state->single_line, - font, row_height); - state->cursor = state->select_end = find.first_char; - state->has_preferred_x = 0; - } else { - struct nk_text_find find; - if (state->string.len && state->cursor == state->string.len) - --state->cursor; - nk_textedit_clamp(state); - nk_textedit_move_to_first(state); - nk_textedit_find_charpos(&find, state, state->cursor, state->single_line, - font, row_height); - state->cursor = find.first_char; - state->has_preferred_x = 0; - } - } break; - - case NK_KEY_TEXT_LINE_END: { - if (shift_mod) { - struct nk_text_find find; - nk_textedit_clamp(state); - nk_textedit_prep_selection_at_cursor(state); - nk_textedit_find_charpos(&find, state, state->cursor, state->single_line, - font, row_height); - state->has_preferred_x = 0; - state->cursor = find.first_char + find.length; - if (find.length > 0 && nk_str_rune_at(&state->string, state->cursor-1) == '\n') - --state->cursor; - state->select_end = state->cursor; - } else { - struct nk_text_find find; - nk_textedit_clamp(state); - nk_textedit_move_to_first(state); - nk_textedit_find_charpos(&find, state, state->cursor, state->single_line, - font, row_height); - - state->has_preferred_x = 0; - state->cursor = find.first_char + find.length; - if (find.length > 0 && nk_str_rune_at(&state->string, state->cursor-1) == '\n') - --state->cursor; - }} break; - } - - state->lexer.needs_refresh = 1; -} - -NK_INTERN void -nk_textedit_flush_redo(struct nk_text_undo_state *state) -{ - state->redo_point = NK_TEXTEDIT_UNDOSTATECOUNT; - state->redo_char_point = NK_TEXTEDIT_UNDOCHARCOUNT; -} - -NK_INTERN void -nk_textedit_discard_undo(struct nk_text_undo_state *state) -{ - /* discard the oldest entry in the undo list */ - if (state->undo_point > 0) { - /* if the 0th undo state has characters, clean those up */ - if (state->undo_rec[0].char_storage >= 0) { - int n = state->undo_rec[0].insert_length, i; - /* delete n characters from all other records */ - state->undo_char_point = (short)(state->undo_char_point - n); - NK_MEMCPY(state->undo_char, state->undo_char + n, - (nk_size)state->undo_char_point*sizeof(nk_rune)); - for (i=0; i < state->undo_point; ++i) { - if (state->undo_rec[i].char_storage >= 0) - state->undo_rec[i].char_storage = (short) - (state->undo_rec[i].char_storage - n); - } - } - --state->undo_point; - NK_MEMCPY(state->undo_rec, state->undo_rec+1, - (nk_size)((nk_size)state->undo_point * sizeof(state->undo_rec[0]))); - } -} - -NK_INTERN void -nk_textedit_discard_redo(struct nk_text_undo_state *state) -{ -/* discard the oldest entry in the redo list--it's bad if this - ever happens, but because undo & redo have to store the actual - characters in different cases, the redo character buffer can - fill up even though the undo buffer didn't */ - nk_size num; - int k = NK_TEXTEDIT_UNDOSTATECOUNT-1; - if (state->redo_point <= k) { - /* if the k'th undo state has characters, clean those up */ - if (state->undo_rec[k].char_storage >= 0) { - int n = state->undo_rec[k].insert_length, i; - /* delete n characters from all other records */ - state->redo_char_point = (short)(state->redo_char_point + n); - num = (nk_size)(NK_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point); - NK_MEMCPY(state->undo_char + state->redo_char_point, - state->undo_char + state->redo_char_point-n, num * sizeof(char)); - for (i = state->redo_point; i < k; ++i) { - if (state->undo_rec[i].char_storage >= 0) { - state->undo_rec[i].char_storage = (short) - (state->undo_rec[i].char_storage + n); - } - } - } - ++state->redo_point; - num = (nk_size)(NK_TEXTEDIT_UNDOSTATECOUNT - state->redo_point); - if (num) NK_MEMCPY(state->undo_rec + state->redo_point-1, - state->undo_rec + state->redo_point, num * sizeof(state->undo_rec[0])); - } -} - -NK_INTERN struct nk_text_undo_record* -nk_textedit_create_undo_record(struct nk_text_undo_state *state, int numchars) -{ - /* any time we create a new undo record, we discard redo*/ - nk_textedit_flush_redo(state); - - /* if we have no free records, we have to make room, - * by sliding the existing records down */ - if (state->undo_point == NK_TEXTEDIT_UNDOSTATECOUNT) - nk_textedit_discard_undo(state); - - /* if the characters to store won't possibly fit in the buffer, - * we can't undo */ - if (numchars > NK_TEXTEDIT_UNDOCHARCOUNT) { - state->undo_point = 0; - state->undo_char_point = 0; - return 0; - } - - /* if we don't have enough free characters in the buffer, - * we have to make room */ - while (state->undo_char_point + numchars > NK_TEXTEDIT_UNDOCHARCOUNT) - nk_textedit_discard_undo(state); - return &state->undo_rec[state->undo_point++]; -} - -NK_INTERN nk_rune* -nk_textedit_createundo(struct nk_text_undo_state *state, int pos, - int insert_len, int delete_len) -{ - struct nk_text_undo_record *r = nk_textedit_create_undo_record(state, insert_len); - if (r == 0) - return 0; - - r->where = pos; - r->insert_length = (short) insert_len; - r->delete_length = (short) delete_len; - - if (insert_len == 0) { - r->char_storage = -1; - return 0; - } else { - r->char_storage = state->undo_char_point; - state->undo_char_point = (short)(state->undo_char_point + insert_len); - return &state->undo_char[r->char_storage]; - } -} - -NK_API void -nk_textedit_undo(struct nk_text_edit *state) -{ - struct nk_text_undo_state *s = &state->undo; - struct nk_text_undo_record u, *r; - if (s->undo_point == 0) - return; - - /* we need to do two things: apply the undo record, and create a redo record */ - u = s->undo_rec[s->undo_point-1]; - r = &s->undo_rec[s->redo_point-1]; - r->char_storage = -1; - - r->insert_length = u.delete_length; - r->delete_length = u.insert_length; - r->where = u.where; - - if (u.delete_length) - { - /* if the undo record says to delete characters, then the redo record will - need to re-insert the characters that get deleted, so we need to store - them. - there are three cases: - - there's enough room to store the characters - - characters stored for *redoing* don't leave room for redo - - characters stored for *undoing* don't leave room for redo - if the last is true, we have to bail */ - if (s->undo_char_point + u.delete_length >= NK_TEXTEDIT_UNDOCHARCOUNT) { - /* the undo records take up too much character space; there's no space - * to store the redo characters */ - r->insert_length = 0; - } else { - int i; - /* there's definitely room to store the characters eventually */ - while (s->undo_char_point + u.delete_length > s->redo_char_point) { - /* there's currently not enough room, so discard a redo record */ - nk_textedit_discard_redo(s); - /* should never happen: */ - if (s->redo_point == NK_TEXTEDIT_UNDOSTATECOUNT) - return; - } - - r = &s->undo_rec[s->redo_point-1]; - r->char_storage = (short)(s->redo_char_point - u.delete_length); - s->redo_char_point = (short)(s->redo_char_point - u.delete_length); - - /* now save the characters */ - for (i=0; i < u.delete_length; ++i) - s->undo_char[r->char_storage + i] = - nk_str_rune_at(&state->string, u.where + i); - } - /* now we can carry out the deletion */ - nk_str_delete_runes(&state->string, u.where, u.delete_length); - } - - /* check type of recorded action: */ - if (u.insert_length) { - /* easy case: was a deletion, so we need to insert n characters */ - nk_str_insert_text_runes(&state->string, u.where, - &s->undo_char[u.char_storage], u.insert_length); - s->undo_char_point = (short)(s->undo_char_point - u.insert_length); - } - state->cursor = (short)(u.where + u.insert_length); - - s->undo_point--; - s->redo_point--; -} - -NK_API void -nk_textedit_redo(struct nk_text_edit *state) -{ - struct nk_text_undo_state *s = &state->undo; - struct nk_text_undo_record *u, r; - if (s->redo_point == NK_TEXTEDIT_UNDOSTATECOUNT) - return; - - /* we need to do two things: apply the redo record, and create an undo record */ - u = &s->undo_rec[s->undo_point]; - r = s->undo_rec[s->redo_point]; - - /* we KNOW there must be room for the undo record, because the redo record - was derived from an undo record */ - u->delete_length = r.insert_length; - u->insert_length = r.delete_length; - u->where = r.where; - u->char_storage = -1; - - if (r.delete_length) { - /* the redo record requires us to delete characters, so the undo record - needs to store the characters */ - if (s->undo_char_point + u->insert_length > s->redo_char_point) { - u->insert_length = 0; - u->delete_length = 0; - } else { - int i; - u->char_storage = s->undo_char_point; - s->undo_char_point = (short)(s->undo_char_point + u->insert_length); - - /* now save the characters */ - for (i=0; i < u->insert_length; ++i) { - s->undo_char[u->char_storage + i] = - nk_str_rune_at(&state->string, u->where + i); - } - } - nk_str_delete_runes(&state->string, r.where, r.delete_length); - } - - if (r.insert_length) { - /* easy case: need to insert n characters */ - nk_str_insert_text_runes(&state->string, r.where, - &s->undo_char[r.char_storage], r.insert_length); - } - state->cursor = r.where + r.insert_length; - - s->undo_point++; - s->redo_point++; -} - -NK_INTERN void -nk_textedit_makeundo_insert(struct nk_text_edit *state, int where, int length) -{ - nk_textedit_createundo(&state->undo, where, 0, length); -} - -NK_INTERN void -nk_textedit_makeundo_delete(struct nk_text_edit *state, int where, int length) -{ - int i; - nk_rune *p = nk_textedit_createundo(&state->undo, where, length, 0); - if (p) { - for (i=0; i < length; ++i) - p[i] = nk_str_rune_at(&state->string, where+i); - } -} - -NK_INTERN void -nk_textedit_makeundo_replace(struct nk_text_edit *state, int where, - int old_length, int new_length) -{ - int i; - nk_rune *p = nk_textedit_createundo(&state->undo, where, old_length, new_length); - if (p) { - for (i=0; i < old_length; ++i) - p[i] = nk_str_rune_at(&state->string, where+i); - } -} - -NK_INTERN void -nk_textedit_clear_state(struct nk_text_edit *state, enum nk_text_edit_type type, - nk_plugin_filter filter) -{ - /* reset the state to default */ - state->undo.undo_point = 0; - state->undo.undo_char_point = 0; - state->undo.redo_point = NK_TEXTEDIT_UNDOSTATECOUNT; - state->undo.redo_char_point = NK_TEXTEDIT_UNDOCHARCOUNT; - state->select_end = state->select_start = 0; - state->cursor = 0; - state->has_preferred_x = 0; - state->preferred_x = 0; - state->cursor_at_end_of_line = 0; - state->initialized = 1; - state->single_line = (unsigned char)(type == NK_TEXT_EDIT_SINGLE_LINE); - state->mode = NK_TEXT_EDIT_MODE_VIEW; - state->filter = filter; - state->scrollbar = nk_vec2(0,0); -} - -NK_INTERN void -nk_textedit_reset_state(struct nk_text_edit *state, enum nk_text_edit_type type, - nk_plugin_filter filter) -{ - /* reset the state to default */ - state->single_line = (unsigned char)(type == NK_TEXT_EDIT_SINGLE_LINE); - state->mode = NK_TEXT_EDIT_MODE_VIEW; - state->filter = filter; -} - -NK_API void -nk_textedit_init_fixed(struct nk_text_edit *state, void *memory, nk_size size) -{ - NK_ASSERT(state); - NK_ASSERT(memory); - if (!state || !memory || !size) return; - NK_MEMSET(state, 0, sizeof(struct nk_text_edit)); - nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0); - nk_str_init_fixed(&state->string, memory, size); -} - -NK_API void -nk_textedit_init(struct nk_text_edit *state, struct nk_allocator *alloc, nk_size size) -{ - NK_ASSERT(state); - NK_ASSERT(alloc); - if (!state || !alloc) return; - NK_MEMSET(state, 0, sizeof(struct nk_text_edit)); - nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0); - nk_str_init(&state->string, alloc, size); -} - -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API void -nk_textedit_init_default(struct nk_text_edit *state) -{ - NK_ASSERT(state); - if (!state) return; - NK_MEMSET(state, 0, sizeof(struct nk_text_edit)); - nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0); - nk_str_init_default(&state->string); -} -#endif - -NK_API void -nk_textedit_select_all(struct nk_text_edit *state) -{ - NK_ASSERT(state); - state->select_start = 0; - state->select_end = state->string.len; -} - -NK_API void -nk_textedit_free(struct nk_text_edit *state) -{ - NK_ASSERT(state); - if (!state) return; - nk_str_free(&state->string); -} - -/* =============================================================== - * - * TEXT WIDGET - * - * ===============================================================*/ -#define nk_widget_state_reset(s)\ - if ((*(s)) & NK_WIDGET_STATE_MODIFIED)\ - (*(s)) = NK_WIDGET_STATE_INACTIVE|NK_WIDGET_STATE_MODIFIED;\ - else (*(s)) = NK_WIDGET_STATE_INACTIVE; - -struct nk_text { - struct nk_vec2 padding; - struct nk_color background; - struct nk_color text; -}; - -NK_INTERN void -nk_widget_text(struct nk_command_buffer *o, struct nk_rect b, - const char *string, int len, const struct nk_text *t, - nk_flags a, const struct nk_user_font *f) -{ - struct nk_rect label; - float text_width; - - NK_ASSERT(o); - NK_ASSERT(t); - if (!o || !t) return; - - b.h = NK_MAX(b.h, 2 * t->padding.y); - label.x = 0; label.w = 0; - label.y = b.y + t->padding.y; - label.h = NK_MIN(f->height, b.h - 2 * t->padding.y); - - text_width = f->width(f->userdata, f->height, (const char*)string, len); - text_width += (2.0f * t->padding.x); - - /* align in x-axis */ - if (a & NK_TEXT_ALIGN_LEFT) { - label.x = b.x + t->padding.x; - label.w = NK_MAX(0, b.w - 2 * t->padding.x); - } else if (a & NK_TEXT_ALIGN_CENTERED) { - label.w = NK_MAX(1, 2 * t->padding.x + (float)text_width); - label.x = (b.x + t->padding.x + ((b.w - 2 * t->padding.x) - label.w) / 2); - label.x = NK_MAX(b.x + t->padding.x, label.x); - label.w = NK_MIN(b.x + b.w, label.x + label.w); - if (label.w >= label.x) label.w -= label.x; - } else if (a & NK_TEXT_ALIGN_RIGHT) { - label.x = NK_MAX(b.x + t->padding.x, (b.x + b.w) - (2 * t->padding.x + (float)text_width)); - label.w = (float)text_width + 2 * t->padding.x; - } else return; - - /* align in y-axis */ - if (a & NK_TEXT_ALIGN_MIDDLE) { - label.y = b.y + b.h/2.0f - (float)f->height/2.0f; - label.h = NK_MAX(b.h/2.0f, b.h - (b.h/2.0f + f->height/2.0f)); - } else if (a & NK_TEXT_ALIGN_BOTTOM) { - label.y = b.y + b.h - f->height; - label.h = f->height; - } - nk_draw_text(o, label, (const char*)string, - len, f, t->background, t->text); -} - -NK_INTERN void -nk_widget_text_lexed(struct nk_command_buffer *o, struct nk_rect b, - const char *string, int len, const struct nk_text *t, - nk_flags a, const struct nk_user_font *f, struct nk_token *tokens, - int offset) -{ - struct nk_rect label; - float text_width; - struct nk_token *token = tokens; - - NK_ASSERT(o); - NK_ASSERT(t); - if (!o || !t) return; - - b.h = NK_MAX(b.h, 2 * t->padding.y); - label.x = 0; label.w = 0; - label.y = b.y + t->padding.y; - label.h = NK_MIN(f->height, b.h - 2 * t->padding.y); - - text_width = f->width(f->userdata, f->height, (const char*)string, len); - text_width += (2.0f * t->padding.x); - - /* align in x-axis */ - if (a & NK_TEXT_ALIGN_LEFT) { - label.x = b.x + t->padding.x; - label.w = NK_MAX(0, b.w - 2 * t->padding.x); - } else if (a & NK_TEXT_ALIGN_CENTERED) { - label.w = NK_MAX(1, 2 * t->padding.x + (float)text_width); - label.x = (b.x + t->padding.x + ((b.w - 2 * t->padding.x) - label.w) / 2); - label.x = NK_MAX(b.x + t->padding.x, label.x); - label.w = NK_MIN(b.x + b.w, label.x + label.w); - if (label.w >= label.x) label.w -= label.x; - } else if (a & NK_TEXT_ALIGN_RIGHT) { - label.x = NK_MAX(b.x + t->padding.x, (b.x + b.w) - (2 * t->padding.x + (float)text_width)); - label.w = (float)text_width + 2 * t->padding.x; - } else return; - - /* align in y-axis */ - if (a & NK_TEXT_ALIGN_MIDDLE) { - label.y = b.y + b.h/2.0f - (float)f->height/2.0f; - label.h = NK_MAX(b.h/2.0f, b.h - (b.h/2.0f + f->height/2.0f)); - } else if (a & NK_TEXT_ALIGN_BOTTOM) { - label.y = b.y + b.h - f->height; - label.h = f->height; - } - - //FIXME do this chunk-wise instead of character-wise - const int glyph_max = nk_utf_len(string, len); - const float dd = text_width/glyph_max; - for(int i = 0, u = 0; i < len; u++) - { - nk_rune unicode; - const int glyph_len = nk_utf_decode(string + i, &unicode, len - i); - - const struct nk_rect dst = { - .x = label.x + u*dd, - .y = label.y, - .w = text_width, - .h = label.h - }; - - struct nk_color bg = t->background; - struct nk_color fg = t->text; - - while(offset + i >= token->offset) - token++; - - fg = token->color; - nk_draw_text(o, dst, string + i, glyph_len, f, bg, fg); - i += glyph_len; - } -} - -NK_INTERN void -nk_widget_text_wrap(struct nk_command_buffer *o, struct nk_rect b, - const char *string, int len, const struct nk_text *t, - const struct nk_user_font *f) -{ - float width; - int glyphs = 0; - int fitting = 0; - int done = 0; - struct nk_rect line; - struct nk_text text; - NK_INTERN nk_rune seperator[] = {' '}; - - NK_ASSERT(o); - NK_ASSERT(t); - if (!o || !t) return; - - text.padding = nk_vec2(0,0); - text.background = t->background; - text.text = t->text; - - b.w = NK_MAX(b.w, 2 * t->padding.x); - b.h = NK_MAX(b.h, 2 * t->padding.y); - b.h = b.h - 2 * t->padding.y; - - line.x = b.x + t->padding.x; - line.y = b.y + t->padding.y; - line.w = b.w - 2 * t->padding.x; - line.h = 2 * t->padding.y + f->height; - - fitting = nk_text_clamp(f, string, len, line.w, &glyphs, &width, seperator,NK_LEN(seperator)); - while (done < len) { - if (!fitting || line.y + line.h >= (b.y + b.h)) break; - nk_widget_text(o, line, &string[done], fitting, &text, NK_TEXT_LEFT, f); - done += fitting; - line.y += f->height + 2 * t->padding.y; - fitting = nk_text_clamp(f, &string[done], len - done, line.w, &glyphs, &width, seperator,NK_LEN(seperator)); - } -} - -/* =============================================================== - * - * BUTTON - * - * ===============================================================*/ -NK_INTERN void -nk_draw_symbol(struct nk_command_buffer *out, enum nk_symbol_type type, - struct nk_rect content, struct nk_color background, struct nk_color foreground, - float border_width, const struct nk_user_font *font) -{ - switch (type) { - case NK_SYMBOL_X: - case NK_SYMBOL_UNDERSCORE: - case NK_SYMBOL_PLUS: - case NK_SYMBOL_MINUS: { - /* single character text symbol */ - const char *X = (type == NK_SYMBOL_X) ? "x": - (type == NK_SYMBOL_UNDERSCORE) ? "_": - (type == NK_SYMBOL_PLUS) ? "+": "-"; - struct nk_text text; - text.padding = nk_vec2(0,0); - text.background = background; - text.text = foreground; - nk_widget_text(out, content, X, 1, &text, NK_TEXT_CENTERED, font); - } break; - case NK_SYMBOL_CIRCLE_SOLID: - case NK_SYMBOL_CIRCLE_OUTLINE: - case NK_SYMBOL_RECT_SOLID: - case NK_SYMBOL_RECT_OUTLINE: { - /* simple empty/filled shapes */ - if (type == NK_SYMBOL_RECT_SOLID || type == NK_SYMBOL_RECT_OUTLINE) { - nk_fill_rect(out, content, 0, foreground); - if (type == NK_SYMBOL_RECT_OUTLINE) - nk_fill_rect(out, nk_shrink_rect(content, border_width), 0, background); - } else { - nk_fill_circle(out, content, foreground); - if (type == NK_SYMBOL_CIRCLE_OUTLINE) - nk_fill_circle(out, nk_shrink_rect(content, 1), background); - } - } break; - case NK_SYMBOL_TRIANGLE_UP: - case NK_SYMBOL_TRIANGLE_DOWN: - case NK_SYMBOL_TRIANGLE_LEFT: - case NK_SYMBOL_TRIANGLE_RIGHT: { - enum nk_heading heading; - struct nk_vec2 points[3]; - heading = (type == NK_SYMBOL_TRIANGLE_RIGHT) ? NK_RIGHT : - (type == NK_SYMBOL_TRIANGLE_LEFT) ? NK_LEFT: - (type == NK_SYMBOL_TRIANGLE_UP) ? NK_UP: NK_DOWN; - nk_triangle_from_direction(points, content, 0, 0, heading); - nk_fill_triangle(out, points[0].x, points[0].y, points[1].x, points[1].y, - points[2].x, points[2].y, foreground); - } break; - default: - case NK_SYMBOL_NONE: - case NK_SYMBOL_MAX: break; - } -} - -NK_INTERN int -nk_button_behavior(nk_flags *state, struct nk_rect r, - const struct nk_input *i, enum nk_button_behavior behavior) -{ - int ret = 0; - nk_widget_state_reset(state); - if (!i) return 0; - if (nk_input_is_mouse_hovering_rect(i, r)) { - *state = NK_WIDGET_STATE_HOVERED; - if (nk_input_is_mouse_down(i, NK_BUTTON_LEFT)) - *state = NK_WIDGET_STATE_ACTIVE; - if (nk_input_has_mouse_click_in_rect(i, NK_BUTTON_LEFT, r)) { - ret = (behavior != NK_BUTTON_DEFAULT) ? - nk_input_is_mouse_down(i, NK_BUTTON_LEFT): -#ifdef NK_BUTTON_TRIGGER_ON_RELEASE - nk_input_is_mouse_released(i, NK_BUTTON_LEFT); -#else - nk_input_is_mouse_pressed(i, NK_BUTTON_LEFT); -#endif - } - } - if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(i, r)) - *state |= NK_WIDGET_STATE_ENTERED; - else if (nk_input_is_mouse_prev_hovering_rect(i, r)) - *state |= NK_WIDGET_STATE_LEFT; - return ret; -} - -NK_INTERN const struct nk_style_item* -nk_draw_button(struct nk_command_buffer *out, - const struct nk_rect *bounds, nk_flags state, - const struct nk_style_button *style) -{ - const struct nk_style_item *background; - if (state & NK_WIDGET_STATE_HOVER) - background = &style->hover; - else if (state & NK_WIDGET_STATE_ACTIVED) - background = &style->active; - else background = &style->normal; - - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(out, *bounds, &background->data.image, nk_white); - } else { - nk_fill_rect(out, *bounds, style->rounding, background->data.color); - nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color); - } - return background; -} - -NK_INTERN int -nk_do_button(nk_flags *state, struct nk_command_buffer *out, struct nk_rect r, - const struct nk_style_button *style, const struct nk_input *in, - enum nk_button_behavior behavior, struct nk_rect *content) -{ - struct nk_rect bounds; - NK_ASSERT(style); - NK_ASSERT(state); - NK_ASSERT(out); - if (!out || !style) - return nk_false; - - /* calculate button content space */ - content->x = r.x + style->padding.x + style->border + style->rounding; - content->y = r.y + style->padding.y + style->border + style->rounding; - content->w = r.w - (2 * style->padding.x + style->border + style->rounding*2); - content->h = r.h - (2 * style->padding.y + style->border + style->rounding*2); - - /* execute button behavior */ - bounds.x = r.x - style->touch_padding.x; - bounds.y = r.y - style->touch_padding.y; - bounds.w = r.w + 2 * style->touch_padding.x; - bounds.h = r.h + 2 * style->touch_padding.y; - return nk_button_behavior(state, bounds, in, behavior); -} - -NK_INTERN void -nk_draw_button_text(struct nk_command_buffer *out, - const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state, - const struct nk_style_button *style, const char *txt, int len, - nk_flags text_alignment, const struct nk_user_font *font) -{ - struct nk_text text; - const struct nk_style_item *background; - background = nk_draw_button(out, bounds, state, style); - - /* select correct colors/images */ - if (background->type == NK_STYLE_ITEM_COLOR) - text.background = background->data.color; - else text.background = style->text_background; - if (state & NK_WIDGET_STATE_HOVER) - text.text = style->text_hover; - else if (state & NK_WIDGET_STATE_ACTIVED) - text.text = style->text_active; - else text.text = style->text_normal; - - text.padding = nk_vec2(0,0); - nk_widget_text(out, *content, txt, len, &text, text_alignment, font); -} - -NK_INTERN int -nk_do_button_text(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect bounds, - const char *string, int len, nk_flags align, enum nk_button_behavior behavior, - const struct nk_style_button *style, const struct nk_input *in, - const struct nk_user_font *font) -{ - struct nk_rect content; - int ret = nk_false; - - NK_ASSERT(state); - NK_ASSERT(style); - NK_ASSERT(out); - NK_ASSERT(string); - NK_ASSERT(font); - if (!out || !style || !font || !string) - return nk_false; - - ret = nk_do_button(state, out, bounds, style, in, behavior, &content); - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_button_text(out, &bounds, &content, *state, style, string, len, align, font); - if (style->draw_end) style->draw_end(out, style->userdata); - return ret; -} - -NK_INTERN void -nk_draw_button_symbol(struct nk_command_buffer *out, - const struct nk_rect *bounds, const struct nk_rect *content, - nk_flags state, const struct nk_style_button *style, - enum nk_symbol_type type, const struct nk_user_font *font) -{ - struct nk_color sym, bg; - const struct nk_style_item *background; - - /* select correct colors/images */ - background = nk_draw_button(out, bounds, state, style); - if (background->type == NK_STYLE_ITEM_COLOR) - bg = background->data.color; - else bg = style->text_background; - - if (state & NK_WIDGET_STATE_HOVER) - sym = style->text_hover; - else if (state & NK_WIDGET_STATE_ACTIVED) - sym = style->text_active; - else sym = style->text_normal; - nk_draw_symbol(out, type, *content, bg, sym, 1, font); -} - -NK_INTERN int -nk_do_button_symbol(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect bounds, - enum nk_symbol_type symbol, enum nk_button_behavior behavior, - const struct nk_style_button *style, const struct nk_input *in, - const struct nk_user_font *font) -{ - int ret; - struct nk_rect content; - - NK_ASSERT(state); - NK_ASSERT(style); - NK_ASSERT(font); - NK_ASSERT(out); - if (!out || !style || !font || !state) - return nk_false; - - ret = nk_do_button(state, out, bounds, style, in, behavior, &content); - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_button_symbol(out, &bounds, &content, *state, style, symbol, font); - if (style->draw_end) style->draw_end(out, style->userdata); - return ret; -} - -NK_INTERN void -nk_draw_button_image(struct nk_command_buffer *out, - const struct nk_rect *bounds, const struct nk_rect *content, - nk_flags state, const struct nk_style_button *style, const struct nk_image *img) -{ - nk_draw_button(out, bounds, state, style); - nk_draw_image(out, *content, img, nk_white); -} - -NK_INTERN int -nk_do_button_image(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect bounds, - struct nk_image img, enum nk_button_behavior b, - const struct nk_style_button *style, const struct nk_input *in) -{ - int ret; - struct nk_rect content; - - NK_ASSERT(state); - NK_ASSERT(style); - NK_ASSERT(out); - if (!out || !style || !state) - return nk_false; - - ret = nk_do_button(state, out, bounds, style, in, b, &content); - content.x += style->image_padding.x; - content.y += style->image_padding.y; - content.w -= 2 * style->image_padding.x; - content.h -= 2 * style->image_padding.y; - - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_button_image(out, &bounds, &content, *state, style, &img); - if (style->draw_end) style->draw_end(out, style->userdata); - return ret; -} - -NK_INTERN void -nk_draw_button_text_symbol(struct nk_command_buffer *out, - const struct nk_rect *bounds, const struct nk_rect *label, - const struct nk_rect *symbol, nk_flags state, const struct nk_style_button *style, - const char *str, int len, enum nk_symbol_type type, - const struct nk_user_font *font) -{ - struct nk_color sym; - struct nk_text text; - const struct nk_style_item *background; - - /* select correct background colors/images */ - background = nk_draw_button(out, bounds, state, style); - if (background->type == NK_STYLE_ITEM_COLOR) - text.background = background->data.color; - else text.background = style->text_background; - - /* select correct text colors */ - if (state & NK_WIDGET_STATE_HOVER) { - sym = style->text_hover; - text.text = style->text_hover; - } else if (state & NK_WIDGET_STATE_ACTIVED) { - sym = style->text_active; - text.text = style->text_active; - } else { - sym = style->text_normal; - text.text = style->text_normal; - } - - text.padding = nk_vec2(0,0); - nk_draw_symbol(out, type, *symbol, style->text_background, sym, 0, font); - nk_widget_text(out, *label, str, len, &text, NK_TEXT_CENTERED, font); -} - -NK_INTERN int -nk_do_button_text_symbol(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect bounds, - enum nk_symbol_type symbol, const char *str, int len, nk_flags align, - enum nk_button_behavior behavior, const struct nk_style_button *style, - const struct nk_user_font *font, const struct nk_input *in) -{ - int ret; - struct nk_rect tri = {0,0,0,0}; - struct nk_rect content; - - NK_ASSERT(style); - NK_ASSERT(out); - NK_ASSERT(font); - if (!out || !style || !font) - return nk_false; - - ret = nk_do_button(state, out, bounds, style, in, behavior, &content); - tri.y = content.y + (content.h/2) - font->height/2; - tri.w = font->height; tri.h = font->height; - if (align & NK_TEXT_ALIGN_LEFT) { - tri.x = (content.x + content.w) - (2 * style->padding.x + tri.w); - tri.x = NK_MAX(tri.x, 0); - } else tri.x = content.x + 2 * style->padding.x; - - /* draw button */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_button_text_symbol(out, &bounds, &content, &tri, - *state, style, str, len, symbol, font); - if (style->draw_end) style->draw_end(out, style->userdata); - return ret; -} - -NK_INTERN void -nk_draw_button_text_image(struct nk_command_buffer *out, - const struct nk_rect *bounds, const struct nk_rect *label, - const struct nk_rect *image, nk_flags state, const struct nk_style_button *style, - const char *str, int len, const struct nk_user_font *font, - const struct nk_image *img) -{ - struct nk_text text; - const struct nk_style_item *background; - background = nk_draw_button(out, bounds, state, style); - - /* select correct colors */ - if (background->type == NK_STYLE_ITEM_COLOR) - text.background = background->data.color; - else text.background = style->text_background; - if (state & NK_WIDGET_STATE_HOVER) - text.text = style->text_hover; - else if (state & NK_WIDGET_STATE_ACTIVED) - text.text = style->text_active; - else text.text = style->text_normal; - - text.padding = nk_vec2(0,0); - nk_widget_text(out, *label, str, len, &text, NK_TEXT_CENTERED, font); - nk_draw_image(out, *image, img, nk_white); -} - -NK_INTERN int -nk_do_button_text_image(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect bounds, - struct nk_image img, const char* str, int len, nk_flags align, - enum nk_button_behavior behavior, const struct nk_style_button *style, - const struct nk_user_font *font, const struct nk_input *in) -{ - int ret; - struct nk_rect icon; - struct nk_rect content; - - NK_ASSERT(style); - NK_ASSERT(state); - NK_ASSERT(font); - NK_ASSERT(out); - if (!out || !font || !style || !str) - return nk_false; - - ret = nk_do_button(state, out, bounds, style, in, behavior, &content); - icon.y = bounds.y + style->padding.y; - icon.w = icon.h = bounds.h - 2 * style->padding.y; - if (align & NK_TEXT_ALIGN_LEFT) { - icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w); - icon.x = NK_MAX(icon.x, 0); - } else icon.x = bounds.x + 2 * style->padding.x; - - icon.x += style->image_padding.x; - icon.y += style->image_padding.y; - icon.w -= 2 * style->image_padding.x; - icon.h -= 2 * style->image_padding.y; - - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_button_text_image(out, &bounds, &content, &icon, *state, style, str, len, font, &img); - if (style->draw_end) style->draw_end(out, style->userdata); - return ret; -} - -/* =============================================================== - * - * TOGGLE - * - * ===============================================================*/ -enum nk_toggle_type { - NK_TOGGLE_CHECK, - NK_TOGGLE_OPTION -}; - -NK_INTERN int -nk_toggle_behavior(const struct nk_input *in, struct nk_rect select, - nk_flags *state, int active) -{ - nk_widget_state_reset(state); - if (nk_button_behavior(state, select, in, NK_BUTTON_DEFAULT)) { - *state = NK_WIDGET_STATE_ACTIVE; - active = !active; - } - if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, select)) - *state |= NK_WIDGET_STATE_ENTERED; - else if (nk_input_is_mouse_prev_hovering_rect(in, select)) - *state |= NK_WIDGET_STATE_LEFT; - return active; -} - -NK_INTERN void -nk_draw_checkbox(struct nk_command_buffer *out, - nk_flags state, const struct nk_style_toggle *style, int active, - const struct nk_rect *label, const struct nk_rect *selector, - const struct nk_rect *cursors, const char *string, int len, - const struct nk_user_font *font) -{ - const struct nk_style_item *background; - const struct nk_style_item *cursor; - struct nk_text text; - - /* select correct colors/images */ - if (state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - cursor = &style->cursor_hover; - text.text = style->text_hover; - } else if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->hover; - cursor = &style->cursor_hover; - text.text = style->text_active; - } else { - background = &style->normal; - cursor = &style->cursor_normal; - text.text = style->text_normal; - } - - /* draw background and cursor */ - if (background->type == NK_STYLE_ITEM_COLOR) { - nk_fill_rect(out, *selector, 0, style->border_color); - nk_fill_rect(out, nk_shrink_rect(*selector, style->border), 0, background->data.color); - } else nk_draw_image(out, *selector, &background->data.image, nk_white); - if (active) { - if (cursor->type == NK_STYLE_ITEM_IMAGE) - nk_draw_image(out, *cursors, &cursor->data.image, nk_white); - else nk_fill_rect(out, *cursors, 0, cursor->data.color); - } - - text.padding.x = 0; - text.padding.y = 0; - text.background = style->text_background; - nk_widget_text(out, *label, string, len, &text, NK_TEXT_LEFT, font); -} - -NK_INTERN void -nk_draw_option(struct nk_command_buffer *out, - nk_flags state, const struct nk_style_toggle *style, int active, - const struct nk_rect *label, const struct nk_rect *selector, - const struct nk_rect *cursors, const char *string, int len, - const struct nk_user_font *font) -{ - const struct nk_style_item *background; - const struct nk_style_item *cursor; - struct nk_text text; - - /* select correct colors/images */ - if (state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - cursor = &style->cursor_hover; - text.text = style->text_hover; - } else if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->hover; - cursor = &style->cursor_hover; - text.text = style->text_active; - } else { - background = &style->normal; - cursor = &style->cursor_normal; - text.text = style->text_normal; - } - - /* draw background and cursor */ - if (background->type == NK_STYLE_ITEM_COLOR) { - nk_fill_circle(out, *selector, style->border_color); - nk_fill_circle(out, nk_shrink_rect(*selector, style->border), background->data.color); - } else nk_draw_image(out, *selector, &background->data.image, nk_white); - if (active) { - if (cursor->type == NK_STYLE_ITEM_IMAGE) - nk_draw_image(out, *cursors, &cursor->data.image, nk_white); - else nk_fill_circle(out, *cursors, cursor->data.color); - } - - text.padding.x = 0; - text.padding.y = 0; - text.background = style->text_background; - nk_widget_text(out, *label, string, len, &text, NK_TEXT_LEFT, font); -} - -NK_INTERN int -nk_do_toggle(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect r, - int *active, const char *str, int len, enum nk_toggle_type type, - const struct nk_style_toggle *style, const struct nk_input *in, - const struct nk_user_font *font) -{ - int was_active; - struct nk_rect bounds; - struct nk_rect select; - struct nk_rect cursor; - struct nk_rect label; - - NK_ASSERT(style); - NK_ASSERT(out); - NK_ASSERT(font); - if (!out || !style || !font || !active) - return 0; - - r.w = NK_MAX(r.w, font->height + 2 * style->padding.x); - r.h = NK_MAX(r.h, font->height + 2 * style->padding.y); - - /* add additional touch padding for touch screen devices */ - bounds.x = r.x - style->touch_padding.x; - bounds.y = r.y - style->touch_padding.y; - bounds.w = r.w + 2 * style->touch_padding.x; - bounds.h = r.h + 2 * style->touch_padding.y; - - /* calculate the selector space */ - select.w = font->height; - select.h = select.w; - select.y = r.y + r.h/2.0f - select.h/2.0f; - select.x = r.x; - - /* calculate the bounds of the cursor inside the selector */ - cursor.x = select.x + style->padding.x + style->border; - cursor.y = select.y + style->padding.y + style->border; - cursor.w = select.w - (2 * style->padding.x + 2 * style->border); - cursor.h = select.h - (2 * style->padding.y + 2 * style->border); - - /* label behind the selector */ - label.x = select.x + select.w + style->spacing; - label.y = select.y; - label.w = NK_MAX(r.x + r.w, label.x) - label.x; - label.h = select.w; - - /* update selector */ - was_active = *active; - *active = nk_toggle_behavior(in, bounds, state, *active); - - /* draw selector */ - if (style->draw_begin) - style->draw_begin(out, style->userdata); - if (type == NK_TOGGLE_CHECK) { - nk_draw_checkbox(out, *state, style, *active, &label, &select, &cursor, str, len, font); - } else { - nk_draw_option(out, *state, style, *active, &label, &select, &cursor, str, len, font); - } - if (style->draw_end) - style->draw_end(out, style->userdata); - return (was_active != *active); -} - -/* =============================================================== - * - * SELECTABLE - * - * ===============================================================*/ -NK_INTERN void -nk_draw_selectable(struct nk_command_buffer *out, - nk_flags state, const struct nk_style_selectable *style, int active, - const struct nk_rect *bounds, const struct nk_rect *icon, const struct nk_image *img, - const char *string, int len, nk_flags align, const struct nk_user_font *font) -{ - const struct nk_style_item *background; - struct nk_text text; - text.padding = style->padding; - - /* select correct colors/images */ - if (!active) { - if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->pressed; - text.text = style->text_pressed; - } else if (state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - text.text = style->text_hover; - } else { - background = &style->normal; - text.text = style->text_normal; - } - } else { - if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->pressed_active; - text.text = style->text_pressed_active; - } else if (state & NK_WIDGET_STATE_HOVER) { - background = &style->hover_active; - text.text = style->text_hover_active; - } else { - background = &style->normal_active; - text.text = style->text_normal_active; - } - } - - - /* draw selectable background and text */ - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(out, *bounds, &background->data.image, nk_white); - text.background = nk_rgba(0,0,0,0); - } else { - nk_fill_rect(out, *bounds, style->rounding, background->data.color); - text.background = background->data.color; - } - if (img && icon) nk_draw_image(out, *icon, img, nk_white); - nk_widget_text(out, *bounds, string, len, &text, align, font); -} - -NK_INTERN int -nk_do_selectable(nk_flags *state, struct nk_command_buffer *out, - struct nk_rect bounds, const char *str, int len, nk_flags align, int *value, - const struct nk_style_selectable *style, const struct nk_input *in, - const struct nk_user_font *font) -{ - int old_value; - struct nk_rect touch; - - NK_ASSERT(state); - NK_ASSERT(out); - NK_ASSERT(str); - NK_ASSERT(len); - NK_ASSERT(value); - NK_ASSERT(style); - NK_ASSERT(font); - - if (!state || !out || !str || !len || !value || !style || !font) return 0; - old_value = *value; - - /* remove padding */ - touch.x = bounds.x - style->touch_padding.x; - touch.y = bounds.y - style->touch_padding.y; - touch.w = bounds.w + style->touch_padding.x * 2; - touch.h = bounds.h + style->touch_padding.y * 2; - - /* update button */ - if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT)) - *value = !(*value); - - /* draw selectable */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_selectable(out, *state, style, *value, &bounds, 0,0, str, len, align, font); - if (style->draw_end) style->draw_end(out, style->userdata); - return old_value != *value; -} - -NK_INTERN int -nk_do_selectable_image(nk_flags *state, struct nk_command_buffer *out, - struct nk_rect bounds, const char *str, int len, nk_flags align, int *value, - const struct nk_image *img, const struct nk_style_selectable *style, - const struct nk_input *in, const struct nk_user_font *font) -{ - int old_value; - struct nk_rect touch; - struct nk_rect icon; - - NK_ASSERT(state); - NK_ASSERT(out); - NK_ASSERT(str); - NK_ASSERT(len); - NK_ASSERT(value); - NK_ASSERT(style); - NK_ASSERT(font); - - if (!state || !out || !str || !len || !value || !style || !font) return 0; - old_value = *value; - - /* toggle behavior */ - touch.x = bounds.x - style->touch_padding.x; - touch.y = bounds.y - style->touch_padding.y; - touch.w = bounds.w + style->touch_padding.x * 2; - touch.h = bounds.h + style->touch_padding.y * 2; - if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT)) - *value = !(*value); - - icon.y = bounds.y + style->padding.y; - icon.w = icon.h = bounds.h - 2 * style->padding.y; - if (align & NK_TEXT_ALIGN_LEFT) { - icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w); - icon.x = NK_MAX(icon.x, 0); - } else icon.x = bounds.x + 2 * style->padding.x; - - icon.x += style->image_padding.x; - icon.y += style->image_padding.y; - icon.w -= 2 * style->image_padding.x; - icon.h -= 2 * style->image_padding.y; - - /* draw selectable */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_selectable(out, *state, style, *value, &bounds, &icon, img, str, len, align, font); - if (style->draw_end) style->draw_end(out, style->userdata); - return old_value != *value; -} - - -/* =============================================================== - * - * SLIDER - * - * ===============================================================*/ -NK_INTERN float -nk_slider_behavior(nk_flags *state, struct nk_rect *logical_cursor, - struct nk_rect *visual_cursor, struct nk_input *in, - struct nk_rect bounds, float slider_min, float slider_max, float slider_value, - float slider_step, float slider_steps) -{ - int left_mouse_down; - int left_mouse_click_in_cursor; - - /* check if visual cursor is being dragged */ - nk_widget_state_reset(state); - left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down; - left_mouse_click_in_cursor = in && nk_input_has_mouse_click_down_in_rect(in, - NK_BUTTON_LEFT, *visual_cursor, nk_true); - - if (left_mouse_down && left_mouse_click_in_cursor) { - float ratio = 0; - const float d = in->mouse.pos.x - (visual_cursor->x+visual_cursor->w*0.5f); - const float pxstep = bounds.w / slider_steps; - - /* only update value if the next slider step is reached */ - *state = NK_WIDGET_STATE_ACTIVE; - if (NK_ABS(d) >= pxstep) { - const float steps = (float)((int)(NK_ABS(d) / pxstep)); - slider_value += (d > 0) ? (slider_step*steps) : -(slider_step*steps); - slider_value = NK_CLAMP(slider_min, slider_value, slider_max); - ratio = (slider_value - slider_min)/slider_step; - logical_cursor->x = bounds.x + (logical_cursor->w * ratio); - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = logical_cursor->x; - } - } - - /* slider widget state */ - if (nk_input_is_mouse_hovering_rect(in, bounds)) - *state = NK_WIDGET_STATE_HOVERED; - if (*state & NK_WIDGET_STATE_HOVER && - !nk_input_is_mouse_prev_hovering_rect(in, bounds)) - *state |= NK_WIDGET_STATE_ENTERED; - else if (nk_input_is_mouse_prev_hovering_rect(in, bounds)) - *state |= NK_WIDGET_STATE_LEFT; - return slider_value; -} - -NK_INTERN void -nk_draw_slider(struct nk_command_buffer *out, nk_flags state, - const struct nk_style_slider *style, const struct nk_rect *bounds, - const struct nk_rect *visual_cursor, float min, float value, float max) -{ - struct nk_rect fill; - struct nk_rect bar; - const struct nk_style_item *background; - - /* select correct slider images/colors */ - struct nk_color bar_color; - const struct nk_style_item *cursor; - - NK_UNUSED(min); - NK_UNUSED(max); - NK_UNUSED(value); - - if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->active; - bar_color = style->bar_active; - cursor = &style->cursor_active; - } else if (state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - bar_color = style->bar_hover; - cursor = &style->cursor_hover; - } else { - background = &style->normal; - bar_color = style->bar_normal; - cursor = &style->cursor_normal; - } - - /* calculate slider background bar */ - bar.x = bounds->x; - bar.y = (visual_cursor->y + visual_cursor->h/2) - bounds->h/12; - bar.w = bounds->w; - bar.h = bounds->h/6; - - /* filled background bar style */ - fill.w = (visual_cursor->x + (visual_cursor->w/2.0f)) - bar.x; - fill.x = bar.x; - fill.y = bar.y; - fill.h = bar.h; - - /* draw background */ - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(out, *bounds, &background->data.image, nk_white); - } else { - nk_fill_rect(out, *bounds, style->rounding, background->data.color); - nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color); - } - - /* draw slider bar */ - nk_fill_rect(out, bar, style->rounding, bar_color); - nk_fill_rect(out, fill, style->rounding, style->bar_filled); - - /* draw cursor */ - if (cursor->type == NK_STYLE_ITEM_IMAGE) - nk_draw_image(out, *visual_cursor, &cursor->data.image, nk_white); - else nk_fill_circle(out, *visual_cursor, cursor->data.color); -} - -NK_INTERN float -nk_do_slider(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect bounds, - float min, float val, float max, float step, - const struct nk_style_slider *style, struct nk_input *in, - const struct nk_user_font *font) -{ - float slider_range; - float slider_min; - float slider_max; - float slider_value; - float slider_steps; - float cursor_offset; - - struct nk_rect visual_cursor; - struct nk_rect logical_cursor; - - NK_ASSERT(style); - NK_ASSERT(out); - if (!out || !style) - return 0; - - /* remove padding from slider bounds */ - bounds.x = bounds.x + style->padding.x; - bounds.y = bounds.y + style->padding.y; - bounds.h = NK_MAX(bounds.h, 2*style->padding.y); - bounds.w = NK_MAX(bounds.w, 2*style->padding.x + style->cursor_size.x); - bounds.w -= 2 * style->padding.x; - bounds.h -= 2 * style->padding.y; - - /* optional buttons */ - if (style->show_buttons) { - nk_flags ws; - struct nk_rect button; - button.y = bounds.y; - button.w = bounds.h; - button.h = bounds.h; - - /* decrement button */ - button.x = bounds.x; - if (nk_do_button_symbol(&ws, out, button, style->dec_symbol, NK_BUTTON_DEFAULT, - &style->dec_button, in, font)) - val -= step; - - /* increment button */ - button.x = (bounds.x + bounds.w) - button.w; - if (nk_do_button_symbol(&ws, out, button, style->inc_symbol, NK_BUTTON_DEFAULT, - &style->inc_button, in, font)) - val += step; - - bounds.x = bounds.x + button.w + style->spacing.x; - bounds.w = bounds.w - (2*button.w + 2*style->spacing.x); - } - - /* remove one cursor size to support visual cursor */ - bounds.x += style->cursor_size.x*0.5f; - bounds.w -= style->cursor_size.x; - - /* make sure the provided values are correct */ - slider_max = NK_MAX(min, max); - slider_min = NK_MIN(min, max); - slider_value = NK_CLAMP(slider_min, val, slider_max); - slider_range = slider_max - slider_min; - slider_steps = slider_range / step; - cursor_offset = (slider_value - slider_min) / step; - - /* calculate cursor - Basically you have two cursors. One for visual representation and interaction - and one for updating the actual cursor value. */ - logical_cursor.h = bounds.h; - logical_cursor.w = bounds.w / slider_steps; - logical_cursor.x = bounds.x + (logical_cursor.w * cursor_offset); - logical_cursor.y = bounds.y; - - visual_cursor.h = style->cursor_size.y; - visual_cursor.w = style->cursor_size.x; - visual_cursor.y = (bounds.y + bounds.h*0.5f) - visual_cursor.h*0.5f; - visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f; - - slider_value = nk_slider_behavior(state, &logical_cursor, &visual_cursor, - in, bounds, slider_min, slider_max, slider_value, step, slider_steps); - visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f; - - /* draw slider */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_slider(out, *state, style, &bounds, &visual_cursor, slider_min, slider_value, slider_max); - if (style->draw_end) style->draw_end(out, style->userdata); - return slider_value; -} - -/* =============================================================== - * - * PROGRESSBAR - * - * ===============================================================*/ -NK_INTERN nk_size -nk_progress_behavior(nk_flags *state, struct nk_input *in, - struct nk_rect r, struct nk_rect cursor, nk_size max, nk_size value, int modifiable) -{ - int left_mouse_down = 0; - int left_mouse_click_in_cursor = 0; - - nk_widget_state_reset(state); - if (!in || !modifiable) return value; - left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down; - left_mouse_click_in_cursor = in && nk_input_has_mouse_click_down_in_rect(in, - NK_BUTTON_LEFT, cursor, nk_true); - if (nk_input_is_mouse_hovering_rect(in, r)) - *state = NK_WIDGET_STATE_HOVERED; - - if (in && left_mouse_down && left_mouse_click_in_cursor) { - if (left_mouse_down && left_mouse_click_in_cursor) { - float ratio = NK_MAX(0, (float)(in->mouse.pos.x - cursor.x)) / (float)cursor.w; - value = (nk_size)NK_CLAMP(0, (float)max * ratio, (float)max); - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = cursor.x + cursor.w/2.0f; - *state |= NK_WIDGET_STATE_ACTIVE; - } - } - /* set progressbar widget state */ - if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, r)) - *state |= NK_WIDGET_STATE_ENTERED; - else if (nk_input_is_mouse_prev_hovering_rect(in, r)) - *state |= NK_WIDGET_STATE_LEFT; - return value; -} - -NK_INTERN void -nk_draw_progress(struct nk_command_buffer *out, nk_flags state, - const struct nk_style_progress *style, const struct nk_rect *bounds, - const struct nk_rect *scursor, nk_size value, nk_size max) -{ - const struct nk_style_item *background; - const struct nk_style_item *cursor; - - NK_UNUSED(max); - NK_UNUSED(value); - - /* select correct colors/images to draw */ - if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->active; - cursor = &style->cursor_active; - } else if (state & NK_WIDGET_STATE_HOVER){ - background = &style->hover; - cursor = &style->cursor_hover; - } else { - background = &style->normal; - cursor = &style->cursor_normal; - } - - /* draw background */ - if (background->type == NK_STYLE_ITEM_COLOR) { - nk_fill_rect(out, *bounds, style->rounding, background->data.color); - nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color); - } else nk_draw_image(out, *bounds, &background->data.image, nk_white); - - /* draw cursor */ - if (cursor->type == NK_STYLE_ITEM_COLOR) { - nk_fill_rect(out, *scursor, style->rounding, cursor->data.color); - nk_stroke_rect(out, *scursor, style->rounding, style->border, style->border_color); - } else nk_draw_image(out, *scursor, &cursor->data.image, nk_white); -} - -NK_INTERN nk_size -nk_do_progress(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect bounds, - nk_size value, nk_size max, int modifiable, - const struct nk_style_progress *style, struct nk_input *in) -{ - float prog_scale; - nk_size prog_value; - struct nk_rect cursor; - - NK_ASSERT(style); - NK_ASSERT(out); - if (!out || !style) return 0; - - /* calculate progressbar cursor */ - cursor.w = NK_MAX(bounds.w, 2 * style->padding.x + 2 * style->border); - cursor.h = NK_MAX(bounds.h, 2 * style->padding.y + 2 * style->border); - cursor = nk_pad_rect(bounds, nk_vec2(style->padding.x + style->border, style->padding.y + style->border)); - prog_scale = (float)value / (float)max; - - /* update progressbar */ - prog_value = NK_MIN(value, max); - prog_value = nk_progress_behavior(state, in, bounds, cursor,max, prog_value, modifiable); - cursor.w = cursor.w * prog_scale; - - /* draw progressbar */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_progress(out, *state, style, &bounds, &cursor, value, max); - if (style->draw_end) style->draw_end(out, style->userdata); - return prog_value; -} - -/* =============================================================== - * - * SCROLLBAR - * - * ===============================================================*/ -NK_INTERN float -nk_scrollbar_behavior(nk_flags *state, struct nk_input *in, - int has_scrolling, const struct nk_rect *scroll, - const struct nk_rect *cursor, const struct nk_rect *empty0, - const struct nk_rect *empty1, float scroll_offset, - float target, float scroll_step, enum nk_orientation o) -{ - nk_flags ws = 0; - int left_mouse_down; - int left_mouse_click_in_cursor; - float scroll_delta; - - nk_widget_state_reset(state); - if (!in) return scroll_offset; - - left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down; - left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in, - NK_BUTTON_LEFT, *cursor, nk_true); - if (nk_input_is_mouse_hovering_rect(in, *scroll)) - *state = NK_WIDGET_STATE_HOVERED; - - scroll_delta = (o == NK_VERTICAL) ? in->mouse.scroll_delta.y: in->mouse.scroll_delta.x; - if (left_mouse_down && left_mouse_click_in_cursor) { - /* update cursor by mouse dragging */ - float pixel, delta; - *state = NK_WIDGET_STATE_ACTIVE; - if (o == NK_VERTICAL) { - float cursor_y; - pixel = in->mouse.delta.y; - delta = (pixel / scroll->h) * target; - scroll_offset = NK_CLAMP(0, scroll_offset + delta, target - scroll->h); - cursor_y = scroll->y + ((scroll_offset/target) * scroll->h); - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = cursor_y + cursor->h/2.0f; - } else { - float cursor_x; - pixel = in->mouse.delta.x; - delta = (pixel / scroll->w) * target; - scroll_offset = NK_CLAMP(0, scroll_offset + delta, target - scroll->w); - cursor_x = scroll->x + ((scroll_offset/target) * scroll->w); - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = cursor_x + cursor->w/2.0f; - } - } else if ((nk_input_is_key_pressed(in, NK_KEY_SCROLL_UP) && o == NK_VERTICAL && has_scrolling)|| - nk_button_behavior(&ws, *empty0, in, NK_BUTTON_DEFAULT)) { - /* scroll page up by click on empty space or shortcut */ - if (o == NK_VERTICAL) - scroll_offset = NK_MAX(0, scroll_offset - scroll->h); - else scroll_offset = NK_MAX(0, scroll_offset - scroll->w); - } else if ((nk_input_is_key_pressed(in, NK_KEY_SCROLL_DOWN) && o == NK_VERTICAL && has_scrolling) || - nk_button_behavior(&ws, *empty1, in, NK_BUTTON_DEFAULT)) { - /* scroll page down by click on empty space or shortcut */ - if (o == NK_VERTICAL) - scroll_offset = NK_MIN(scroll_offset + scroll->h, target - scroll->h); - else scroll_offset = NK_MIN(scroll_offset + scroll->w, target - scroll->w); - } else if (has_scrolling) { - if ((scroll_delta < 0 || (scroll_delta > 0))) { - /* update cursor by mouse scrolling */ - scroll_offset = scroll_offset + scroll_step * (-scroll_delta); - if (o == NK_VERTICAL) - scroll_offset = NK_CLAMP(0, scroll_offset, target - scroll->h); - else scroll_offset = NK_CLAMP(0, scroll_offset, target - scroll->w); - } else if (nk_input_is_key_pressed(in, NK_KEY_SCROLL_START)) { - /* update cursor to the beginning */ - if (o == NK_VERTICAL) scroll_offset = 0; - } else if (nk_input_is_key_pressed(in, NK_KEY_SCROLL_END)) { - /* update cursor to the end */ - if (o == NK_VERTICAL) scroll_offset = target - scroll->h; - } - } - if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, *scroll)) - *state |= NK_WIDGET_STATE_ENTERED; - else if (nk_input_is_mouse_prev_hovering_rect(in, *scroll)) - *state |= NK_WIDGET_STATE_LEFT; - return scroll_offset; -} - -NK_INTERN void -nk_draw_scrollbar(struct nk_command_buffer *out, nk_flags state, - const struct nk_style_scrollbar *style, const struct nk_rect *bounds, - const struct nk_rect *scroll) -{ - const struct nk_style_item *background; - const struct nk_style_item *cursor; - - /* select correct colors/images to draw */ - if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->active; - cursor = &style->cursor_active; - } else if (state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - cursor = &style->cursor_hover; - } else { - background = &style->normal; - cursor = &style->cursor_normal; - } - - /* draw background */ - if (background->type == NK_STYLE_ITEM_COLOR) { - nk_fill_rect(out, *bounds, style->rounding, background->data.color); - nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color); - } else { - nk_draw_image(out, *bounds, &background->data.image, nk_white); - } - - /* draw cursor */ - if (background->type == NK_STYLE_ITEM_COLOR) { - nk_fill_rect(out, *scroll, style->rounding_cursor, cursor->data.color); - nk_stroke_rect(out, *scroll, style->rounding_cursor, style->border_cursor, style->cursor_border_color); - } else nk_draw_image(out, *scroll, &cursor->data.image, nk_white); -} - -NK_INTERN float -nk_do_scrollbarv(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling, - float offset, float target, float step, float button_pixel_inc, - const struct nk_style_scrollbar *style, struct nk_input *in, - const struct nk_user_font *font) -{ - struct nk_rect empty_north; - struct nk_rect empty_south; - struct nk_rect cursor; - - float scroll_step; - float scroll_offset; - float scroll_off; - float scroll_ratio; - - NK_ASSERT(out); - NK_ASSERT(style); - NK_ASSERT(state); - if (!out || !style) return 0; - - scroll.w = NK_MAX(scroll.w, 1); - scroll.h = NK_MAX(scroll.h, 0); - if (target <= scroll.h) return 0; - - /* optional scrollbar buttons */ - if (style->show_buttons) { - nk_flags ws; - float scroll_h; - struct nk_rect button; - - button.x = scroll.x; - button.w = scroll.w; - button.h = scroll.w; - - scroll_h = NK_MAX(scroll.h - 2 * button.h,0); - scroll_step = NK_MIN(step, button_pixel_inc); - - /* decrement button */ - button.y = scroll.y; - if (nk_do_button_symbol(&ws, out, button, style->dec_symbol, - NK_BUTTON_REPEATER, &style->dec_button, in, font)) - offset = offset - scroll_step; - - /* increment button */ - button.y = scroll.y + scroll.h - button.h; - if (nk_do_button_symbol(&ws, out, button, style->inc_symbol, - NK_BUTTON_REPEATER, &style->inc_button, in, font)) - offset = offset + scroll_step; - - scroll.y = scroll.y + button.h; - scroll.h = scroll_h; - } - - /* calculate scrollbar constants */ - scroll_step = NK_MIN(step, scroll.h); - scroll_offset = NK_CLAMP(0, offset, target - scroll.h); - scroll_ratio = scroll.h / target; - scroll_off = scroll_offset / target; - - /* calculate scrollbar cursor bounds */ - cursor.h = NK_MAX((scroll_ratio * scroll.h) - (2*style->border + 2*style->padding.y), 0); - cursor.y = scroll.y + (scroll_off * scroll.h) + style->border + style->padding.y; - cursor.w = scroll.w - (2 * style->border + 2 * style->padding.x); - cursor.x = scroll.x + style->border + style->padding.x; - - /* calculate empty space around cursor */ - empty_north.x = scroll.x; - empty_north.y = scroll.y; - empty_north.w = scroll.w; - empty_north.h = NK_MAX(cursor.y - scroll.y, 0); - - empty_south.x = scroll.x; - empty_south.y = cursor.y + cursor.h; - empty_south.w = scroll.w; - empty_south.h = NK_MAX((scroll.y + scroll.h) - (cursor.y + cursor.h), 0); - - /* update scrollbar */ - scroll_offset = nk_scrollbar_behavior(state, in, has_scrolling, &scroll, &cursor, - &empty_north, &empty_south, scroll_offset, target, scroll_step, NK_VERTICAL); - scroll_off = scroll_offset / target; - cursor.y = scroll.y + (scroll_off * scroll.h) + style->border_cursor + style->padding.y; - - /* draw scrollbar */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_scrollbar(out, *state, style, &scroll, &cursor); - if (style->draw_end) style->draw_end(out, style->userdata); - return scroll_offset; -} - -NK_INTERN float -nk_do_scrollbarh(nk_flags *state, - struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling, - float offset, float target, float step, float button_pixel_inc, - const struct nk_style_scrollbar *style, struct nk_input *in, - const struct nk_user_font *font) -{ - struct nk_rect cursor; - struct nk_rect empty_west; - struct nk_rect empty_east; - - float scroll_step; - float scroll_offset; - float scroll_off; - float scroll_ratio; - - NK_ASSERT(out); - NK_ASSERT(style); - if (!out || !style) return 0; - - /* scrollbar background */ - scroll.h = NK_MAX(scroll.h, 1); - scroll.w = NK_MAX(scroll.w, 2 * scroll.h); - if (target <= scroll.w) return 0; - - /* optional scrollbar buttons */ - if (style->show_buttons) { - nk_flags ws; - float scroll_w; - struct nk_rect button; - button.y = scroll.y; - button.w = scroll.h; - button.h = scroll.h; - - scroll_w = scroll.w - 2 * button.w; - scroll_step = NK_MIN(step, button_pixel_inc); - - /* decrement button */ - button.x = scroll.x; - if (nk_do_button_symbol(&ws, out, button, style->dec_symbol, - NK_BUTTON_REPEATER, &style->dec_button, in, font)) - offset = offset - scroll_step; - - /* increment button */ - button.x = scroll.x + scroll.w - button.w; - if (nk_do_button_symbol(&ws, out, button, style->inc_symbol, - NK_BUTTON_REPEATER, &style->inc_button, in, font)) - offset = offset + scroll_step; - - scroll.x = scroll.x + button.w; - scroll.w = scroll_w; - } - - /* calculate scrollbar constants */ - scroll_step = NK_MIN(step, scroll.w); - scroll_offset = NK_CLAMP(0, offset, target - scroll.w); - scroll_ratio = scroll.w / target; - scroll_off = scroll_offset / target; - - /* calculate cursor bounds */ - cursor.w = (scroll_ratio * scroll.w) - (2*style->border + 2*style->padding.x); - cursor.x = scroll.x + (scroll_off * scroll.w) + style->border + style->padding.x; - cursor.h = scroll.h - (2 * style->border + 2 * style->padding.y); - cursor.y = scroll.y + style->border + style->padding.y; - - /* calculate empty space around cursor */ - empty_west.x = scroll.x; - empty_west.y = scroll.y; - empty_west.w = cursor.x - scroll.x; - empty_west.h = scroll.h; - - empty_east.x = cursor.x + cursor.w; - empty_east.y = scroll.y; - empty_east.w = (scroll.x + scroll.w) - (cursor.x + cursor.w); - empty_east.h = scroll.h; - - /* update scrollbar */ - scroll_offset = nk_scrollbar_behavior(state, in, has_scrolling, &scroll, &cursor, - &empty_west, &empty_east, scroll_offset, target, scroll_step, NK_HORIZONTAL); - scroll_off = scroll_offset / target; - cursor.x = scroll.x + (scroll_off * scroll.w); - - /* draw scrollbar */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_scrollbar(out, *state, style, &scroll, &cursor); - if (style->draw_end) style->draw_end(out, style->userdata); - return scroll_offset; -} - -/* =============================================================== - * - * FILTER - * - * ===============================================================*/ -NK_API int nk_filter_default(const struct nk_text_edit *box, nk_rune unicode) -{(void)unicode;NK_UNUSED(box);return nk_true;} - -NK_API int -nk_filter_ascii(const struct nk_text_edit *box, nk_rune unicode) -{ - NK_UNUSED(box); - if (unicode > 128) return nk_false; - else return nk_true; -} - -NK_API int -nk_filter_float(const struct nk_text_edit *box, nk_rune unicode) -{ - NK_UNUSED(box); - if ((unicode < '0' || unicode > '9') && unicode != '.' && unicode != '-') - return nk_false; - else return nk_true; -} - -NK_API int -nk_filter_decimal(const struct nk_text_edit *box, nk_rune unicode) -{ - NK_UNUSED(box); - if ((unicode < '0' || unicode > '9') && unicode != '-') - return nk_false; - else return nk_true; -} - -NK_API int -nk_filter_hex(const struct nk_text_edit *box, nk_rune unicode) -{ - NK_UNUSED(box); - if ((unicode < '0' || unicode > '9') && - (unicode < 'a' || unicode > 'f') && - (unicode < 'A' || unicode > 'F')) - return nk_false; - else return nk_true; -} - -NK_API int -nk_filter_oct(const struct nk_text_edit *box, nk_rune unicode) -{ - NK_UNUSED(box); - if (unicode < '0' || unicode > '7') - return nk_false; - else return nk_true; -} - -NK_API int -nk_filter_binary(const struct nk_text_edit *box, nk_rune unicode) -{ - NK_UNUSED(box); - if (unicode != '0' && unicode != '1') - return nk_false; - else return nk_true; -} - -/* =============================================================== - * - * EDIT - * - * ===============================================================*/ -NK_INTERN void -nk_edit_draw_text(struct nk_command_buffer *out, - const struct nk_style_edit *style, float pos_x, float pos_y, - float x_offset, const char *text, int byte_len, float row_height, - const struct nk_user_font *font, struct nk_color background, - struct nk_color foreground, int is_selected, struct nk_lexer *lexer, - int offset) -{ - NK_ASSERT(out); - NK_ASSERT(font); - NK_ASSERT(style); - if (!text || !byte_len || !out || !style) return; - - {int glyph_len = 0; - nk_rune unicode = 0; - int text_len = 0; - float line_width = 0; - float glyph_width; - const char *line = text; - float line_offset = 0; - int line_count = 0; - - struct nk_text txt; - txt.padding = nk_vec2(0,0); - txt.background = background; - txt.text = foreground; - - glyph_len = nk_utf_decode(text+text_len, &unicode, byte_len-text_len); - if (!glyph_len) return; - while ((text_len < byte_len) && glyph_len) - { - if (unicode == '\n') { - /* new line separator so draw previous line */ - struct nk_rect label; - label.y = pos_y + line_offset; - label.h = row_height; - label.w = line_width; - label.x = pos_x; - if (!line_count) - label.x += x_offset; - - if (is_selected) /* selection needs to draw different background color */ - nk_fill_rect(out, label, 0, background); - if(lexer->tokens && !is_selected) - { - nk_widget_text_lexed(out, label, line, (int)((text + text_len) - line), - &txt, NK_TEXT_CENTERED, font, lexer->tokens, line - text + offset); - } - else - { - nk_widget_text(out, label, line, (int)((text + text_len) - line), - &txt, NK_TEXT_CENTERED, font); - } - - text_len++; - line_count++; - line_width = 0; - line = text + text_len; - line_offset += row_height; - glyph_len = nk_utf_decode(text + text_len, &unicode, (int)(byte_len-text_len)); - continue; - } - if (unicode == '\r') { - text_len++; - glyph_len = nk_utf_decode(text + text_len, &unicode, byte_len-text_len); - continue; - } - glyph_width = font->width(font->userdata, font->height, text+text_len, glyph_len); - line_width += (float)glyph_width; - text_len += glyph_len; - glyph_len = nk_utf_decode(text + text_len, &unicode, byte_len-text_len); - continue; - } - if (line_width > 0) { - /* draw last line */ - struct nk_rect label; - label.y = pos_y + line_offset; - label.h = row_height; - label.w = line_width; - label.x = pos_x; - if (!line_count) - label.x += x_offset; - - if (is_selected) - nk_fill_rect(out, label, 0, background); - if(lexer->tokens && !is_selected) - { - nk_widget_text_lexed(out, label, line, (int)((text + text_len) - line), - &txt, NK_TEXT_LEFT, font, lexer->tokens, line - text + offset); - } - else - { - nk_widget_text(out, label, line, (int)((text + text_len) - line), - &txt, NK_TEXT_LEFT, font); - } - }} -} - -NK_INTERN void -nk_edit_refresh_lex(struct nk_text_edit *edit) -{ - if(edit->lexer.needs_refresh || !edit->lexer.tokens) - { - if(edit->lexer.tokens) - free(edit->lexer.tokens); - - edit->lexer.tokens = edit->lexer.lex(edit->lexer.data, - nk_str_get_const(&edit->string), nk_str_len_char(&edit->string)); - - edit->lexer.needs_refresh = 0; - } -} - -NK_INTERN nk_flags -nk_do_edit(nk_flags *state, struct nk_command_buffer *out, - struct nk_rect bounds, nk_flags flags, nk_plugin_filter filter, - struct nk_text_edit *edit, const struct nk_style_edit *style, - struct nk_input *in, const struct nk_user_font *font) -{ - struct nk_rect area; - nk_flags ret = 0; - float row_height; - char prev_state = 0; - char is_hovered = 0; - char select_all = 0; - char cursor_follow = 0; - struct nk_rect old_clip; - struct nk_rect clip; - int has_changes = 0; - - NK_ASSERT(state); - NK_ASSERT(out); - NK_ASSERT(style); - if (!state || !out || !style) - return ret; - - /* visible text area calculation */ - area.x = bounds.x + style->padding.x + style->border; - area.y = bounds.y + style->padding.y + style->border; - area.w = bounds.w - (2.0f * style->padding.x + 2 * style->border); - area.h = bounds.h - (2.0f * style->padding.y + 2 * style->border); - if (flags & NK_EDIT_MULTILINE) - area.w = NK_MAX(0, area.w - style->scrollbar_size.x); - row_height = (flags & NK_EDIT_MULTILINE)? font->height + style->row_padding: area.h; - - /* calculate clipping rectangle */ - old_clip = out->clip; - nk_unify(&clip, &old_clip, area.x, area.y, area.x + area.w, area.y + area.h); - - /* update edit state */ - prev_state = (char)edit->active; - is_hovered = (char)nk_input_is_mouse_hovering_rect(in, bounds); - if (in && in->mouse.buttons[NK_BUTTON_LEFT].clicked && in->mouse.buttons[NK_BUTTON_LEFT].down) { - edit->active = NK_INBOX(in->mouse.pos.x, in->mouse.pos.y, - bounds.x, bounds.y, bounds.w, bounds.h); - } - - /* (de)activate text editor */ - if (!prev_state && edit->active) { - const enum nk_text_edit_type type = (flags & NK_EDIT_MULTILINE) ? - NK_TEXT_EDIT_MULTI_LINE: NK_TEXT_EDIT_SINGLE_LINE; - nk_textedit_reset_state(edit, type, filter); - if (flags & NK_EDIT_AUTO_SELECT) - select_all = nk_true; - if (flags & NK_EDIT_GOTO_END_ON_ACTIVATE) { - edit->cursor = edit->string.len; - in = 0; - } - } else if (!edit->active) edit->mode = NK_TEXT_EDIT_MODE_VIEW; - if (flags & NK_EDIT_READ_ONLY) - edit->mode = NK_TEXT_EDIT_MODE_VIEW; - else if (flags & NK_EDIT_ALWAYS_INSERT_MODE) - edit->mode = NK_TEXT_EDIT_MODE_INSERT; - - ret = (edit->active) ? NK_EDIT_ACTIVE: NK_EDIT_INACTIVE; - if (prev_state != edit->active) - ret |= (edit->active) ? NK_EDIT_ACTIVATED: NK_EDIT_DEACTIVATED; - - /* handle user input */ - if (edit->active && in) - { - int shift_mod = in->keyboard.keys[NK_KEY_SHIFT].down; - const float mouse_x = (in->mouse.pos.x - area.x) + edit->scrollbar.x; - const float mouse_y = (in->mouse.pos.y - area.y) + edit->scrollbar.y; - - /* mouse click handler */ - is_hovered = (char)nk_input_is_mouse_hovering_rect(in, area); - if (select_all) { - nk_textedit_select_all(edit); - } else if (is_hovered && in->mouse.buttons[NK_BUTTON_LEFT].down && - in->mouse.buttons[NK_BUTTON_LEFT].clicked) { - nk_textedit_click(edit, mouse_x, mouse_y, font, row_height); - } else if (is_hovered && in->mouse.buttons[NK_BUTTON_LEFT].down && - (in->mouse.delta.x != 0.0f || in->mouse.delta.y != 0.0f)) { - nk_textedit_drag(edit, mouse_x, mouse_y, font, row_height); - cursor_follow = nk_true; - } else if (is_hovered && in->mouse.buttons[NK_BUTTON_RIGHT].clicked && - in->mouse.buttons[NK_BUTTON_RIGHT].down) { - nk_textedit_key(edit, NK_KEY_TEXT_WORD_LEFT, nk_false, font, row_height); - nk_textedit_key(edit, NK_KEY_TEXT_WORD_RIGHT, nk_true, font, row_height); - cursor_follow = nk_true; - } - - {int i; /* keyboard input */ - int old_mode = edit->mode; - for (i = 0; i < NK_KEY_MAX; ++i) { - if (i == NK_KEY_ENTER || i == NK_KEY_TAB) continue; /* special case */ - if (nk_input_is_key_pressed(in, (enum nk_keys)i)) { - nk_textedit_key(edit, (enum nk_keys)i, shift_mod, font, row_height); - cursor_follow = nk_true; - } - } - if (old_mode != edit->mode) { - in->keyboard.text_len = 0; - }} - - /* text input */ - edit->filter = filter; - if (in->keyboard.text_len) { - nk_textedit_text(edit, in->keyboard.text, in->keyboard.text_len); - cursor_follow = nk_true; - in->keyboard.text_len = 0; - } - - /* enter key handler */ - if (nk_input_is_key_pressed(in, NK_KEY_ENTER)) { - cursor_follow = nk_true; - if (flags & NK_EDIT_CTRL_ENTER_NEWLINE && shift_mod) - nk_textedit_text(edit, "\n", 1); - else if (flags & NK_EDIT_SIG_ENTER) - ret |= NK_EDIT_COMMITED; - else nk_textedit_text(edit, "\n", 1); - } - - /* cut & copy handler */ - {int copy= nk_input_is_key_pressed(in, NK_KEY_COPY); - int cut = nk_input_is_key_pressed(in, NK_KEY_CUT); - if ((copy || cut) && (flags & NK_EDIT_CLIPBOARD)) - { - int glyph_len; - nk_rune unicode; - const char *text; - int b = edit->select_start; - int e = edit->select_end; - - int begin = NK_MIN(b, e); - int end = NK_MAX(b, e); - text = nk_str_at_const(&edit->string, begin, &unicode, &glyph_len); - if (edit->clip.copy) - edit->clip.copy(edit->clip.userdata, text, end - begin); - if (cut && !(flags & NK_EDIT_READ_ONLY)){ - nk_textedit_cut(edit); - cursor_follow = nk_true; - } - }} - - /* paste handler */ - {int paste = nk_input_is_key_pressed(in, NK_KEY_PASTE); - if (paste && (flags & NK_EDIT_CLIPBOARD) && edit->clip.paste) { - edit->clip.paste(edit->clip.userdata, edit); - cursor_follow = nk_true; - }} - - /* tab handler */ - {int tab = nk_input_is_key_pressed(in, NK_KEY_TAB); - if (tab && (flags & NK_EDIT_ALLOW_TAB)) { - nk_textedit_text(edit, " ", 2); - cursor_follow = nk_true; - }} - } - - /* set widget state */ - if (edit->active) - *state = NK_WIDGET_STATE_ACTIVE; - else nk_widget_state_reset(state); - - if (is_hovered) - *state |= NK_WIDGET_STATE_HOVERED; - - /* DRAW EDIT */ - {const char *text = nk_str_get_const(&edit->string); - int len = nk_str_len_char(&edit->string); - - {/* select background colors/images */ - const struct nk_style_item *background; - if (*state & NK_WIDGET_STATE_ACTIVED) - background = &style->active; - else if (*state & NK_WIDGET_STATE_HOVER) - background = &style->hover; - else background = &style->normal; - - /* draw background frame */ - if (background->type == NK_STYLE_ITEM_COLOR) { - nk_stroke_rect(out, bounds, style->rounding, style->border, style->border_color); - nk_fill_rect(out, bounds, style->rounding, background->data.color); - } else nk_draw_image(out, bounds, &background->data.image, nk_white);} - - area.w = NK_MAX(0, area.w - style->cursor_size); - if (edit->active) - { - int total_lines = 1; - struct nk_vec2 text_size = nk_vec2(0,0); - - /* text pointer positions */ - const char *cursor_ptr = 0; - const char *select_begin_ptr = 0; - const char *select_end_ptr = 0; - - /* 2D pixel positions */ - struct nk_vec2 cursor_pos = nk_vec2(0,0); - struct nk_vec2 selection_offset_start = nk_vec2(0,0); - struct nk_vec2 selection_offset_end = nk_vec2(0,0); - - int selection_begin = NK_MIN(edit->select_start, edit->select_end); - int selection_end = NK_MAX(edit->select_start, edit->select_end); - - /* calculate total line count + total space + cursor/selection position */ - float line_width = 0.0f; - if (text && len) - { - /* utf8 encoding */ - float glyph_width; - int glyph_len = 0; - nk_rune unicode = 0; - int text_len = 0; - int glyphs = 0; - int row_begin = 0; - - glyph_len = nk_utf_decode(text, &unicode, len); - glyph_width = font->width(font->userdata, font->height, text, glyph_len); - line_width = 0; - - /* iterate all lines */ - while ((text_len < len) && glyph_len) - { - /* set cursor 2D position and line */ - if (!cursor_ptr && glyphs == edit->cursor) - { - int glyph_offset; - struct nk_vec2 out_offset; - struct nk_vec2 row_size; - const char *remaining; - - /* calculate 2d position */ - cursor_pos.y = (float)(total_lines-1) * row_height; - row_size = nk_text_calculate_text_bounds(font, text+row_begin, - text_len-row_begin, row_height, &remaining, - &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE); - cursor_pos.x = row_size.x; - cursor_ptr = text + text_len; - } - - /* set start selection 2D position and line */ - if (!select_begin_ptr && edit->select_start != edit->select_end && - glyphs == selection_begin) - { - int glyph_offset; - struct nk_vec2 out_offset; - struct nk_vec2 row_size; - const char *remaining; - - /* calculate 2d position */ - selection_offset_start.y = (float)(NK_MAX(total_lines-1,0)) * row_height; - row_size = nk_text_calculate_text_bounds(font, text+row_begin, - text_len-row_begin, row_height, &remaining, - &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE); - selection_offset_start.x = row_size.x; - select_begin_ptr = text + text_len; - } - - /* set end selection 2D position and line */ - if (!select_end_ptr && edit->select_start != edit->select_end && - glyphs == selection_end) - { - int glyph_offset; - struct nk_vec2 out_offset; - struct nk_vec2 row_size; - const char *remaining; - - /* calculate 2d position */ - selection_offset_end.y = (float)(total_lines-1) * row_height; - row_size = nk_text_calculate_text_bounds(font, text+row_begin, - text_len-row_begin, row_height, &remaining, - &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE); - selection_offset_end.x = row_size.x; - select_end_ptr = text + text_len; - } - if (unicode == '\n') { - text_size.x = NK_MAX(text_size.x, line_width); - total_lines++; - line_width = 0; - text_len++; - glyphs++; - row_begin = text_len; - glyph_len = nk_utf_decode(text + text_len, &unicode, len-text_len); - glyph_width = font->width(font->userdata, font->height, text+text_len, glyph_len); - continue; - } - - glyphs++; - text_len += glyph_len; - line_width += (float)glyph_width; - - glyph_len = nk_utf_decode(text + text_len, &unicode, len-text_len); - glyph_width = font->width(font->userdata, font->height, - text+text_len, glyph_len); - continue; - } - text_size.y = (float)total_lines * row_height; - - /* handle case when cursor is at end of text buffer */ - if (!cursor_ptr && edit->cursor == edit->string.len) { - cursor_pos.x = line_width; - cursor_pos.y = text_size.y - row_height; - } - } - { - /* scrollbar */ - if (cursor_follow) - { - /* update scrollbar to follow cursor */ - if (!(flags & NK_EDIT_NO_HORIZONTAL_SCROLL)) { - /* horizontal scroll */ - const float scroll_increment = area.w * 0.25f; - if (cursor_pos.x < edit->scrollbar.x) - edit->scrollbar.x = (float)(int)NK_MAX(0.0f, cursor_pos.x - scroll_increment); - if (cursor_pos.x >= edit->scrollbar.x + area.w) - edit->scrollbar.x = (float)(int)NK_MAX(0.0f, cursor_pos.x); - } else edit->scrollbar.x = 0; - - if (flags & NK_EDIT_MULTILINE) { - /* vertical scroll */ - if (cursor_pos.y < edit->scrollbar.y) - edit->scrollbar.y = NK_MAX(0.0f, cursor_pos.y - row_height); - if (cursor_pos.y >= edit->scrollbar.y + area.h) - edit->scrollbar.y = edit->scrollbar.y + row_height; - } else edit->scrollbar.y = 0; - } - - /* scrollbar widget */ - if (flags & NK_EDIT_MULTILINE) - { - nk_flags ws; - struct nk_rect scroll; - float scroll_target; - float scroll_offset; - float scroll_step; - float scroll_inc; - - scroll = area; - scroll.x = (bounds.x + bounds.w - style->border) - style->scrollbar_size.x; - scroll.w = style->scrollbar_size.x; - - scroll_offset = edit->scrollbar.y; - scroll_step = scroll.h * 0.10f; - scroll_inc = scroll.h * 0.01f; - scroll_target = text_size.y; - edit->scrollbar.y = nk_do_scrollbarv(&ws, out, scroll, nk_true, - scroll_offset, scroll_target, scroll_step, scroll_inc, - &style->scrollbar, in, font); - } - } - - /* draw text */ - {struct nk_color background_color; - struct nk_color text_color; - struct nk_color sel_background_color; - struct nk_color sel_text_color; - struct nk_color cursor_color; - struct nk_color cursor_text_color; - const struct nk_style_item *background; - nk_push_scissor(out, clip); - - /* select correct colors to draw */ - if (*state & NK_WIDGET_STATE_ACTIVED) { - background = &style->active; - text_color = style->text_active; - sel_text_color = style->selected_text_hover; - sel_background_color = style->selected_hover; - cursor_color = style->cursor_hover; - cursor_text_color = style->cursor_text_hover; - } else if (*state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - text_color = style->text_hover; - sel_text_color = style->selected_text_hover; - sel_background_color = style->selected_hover; - cursor_text_color = style->cursor_text_hover; - cursor_color = style->cursor_hover; - } else { - background = &style->normal; - text_color = style->text_normal; - sel_text_color = style->selected_text_normal; - sel_background_color = style->selected_normal; - cursor_color = style->cursor_normal; - cursor_text_color = style->cursor_text_normal; - } - if (background->type == NK_STYLE_ITEM_IMAGE) - background_color = nk_rgba(0,0,0,0); - else background_color = background->data.color; - - if(edit->lexer.lex) - { - if(has_changes) - edit->lexer.needs_refresh = 1; - - nk_edit_refresh_lex(edit); - } - - if (edit->select_start == edit->select_end) { - /* no selection so just draw the complete text */ - const char *begin = nk_str_get_const(&edit->string); - int l = nk_str_len_char(&edit->string); - nk_edit_draw_text(out, style, area.x - edit->scrollbar.x, - area.y - edit->scrollbar.y, 0, begin, l, row_height, font, - background_color, text_color, nk_false, &edit->lexer, 0); - } else { - /* edit has selection so draw 1-3 text chunks */ - if (edit->select_start != edit->select_end && selection_begin > 0){ - /* draw unselected text before selection */ - const char *begin = nk_str_get_const(&edit->string); - NK_ASSERT(select_begin_ptr); - nk_edit_draw_text(out, style, area.x - edit->scrollbar.x, - area.y - edit->scrollbar.y, 0, begin, (int)(select_begin_ptr - begin), - row_height, font, background_color, text_color, nk_false, &edit->lexer, 0); - } - if (edit->select_start != edit->select_end) { - const int offset = edit->select_start < edit->select_end ? edit->select_start : edit->select_end; - int glyph_offset; - nk_rune unicode; - const char *ptr = nk_str_at_const(&edit->string, offset, &unicode, &glyph_offset); - const int offset2 = ptr - nk_str_get_const(&edit->string); - /* draw selected text */ - NK_ASSERT(select_begin_ptr); - if (!select_end_ptr) { - const char *begin = nk_str_get_const(&edit->string); - select_end_ptr = begin + nk_str_len_char(&edit->string); - } - nk_edit_draw_text(out, style, - area.x - edit->scrollbar.x, - area.y + selection_offset_start.y - edit->scrollbar.y, - selection_offset_start.x, - select_begin_ptr, (int)(select_end_ptr - select_begin_ptr), - row_height, font, sel_background_color, sel_text_color, nk_true, - &edit->lexer, offset2); - } - if ((edit->select_start != edit->select_end && - selection_end < edit->string.len)) - { - /* draw unselected text after selected text */ - const char *begin = select_end_ptr; - const char *end = nk_str_get_const(&edit->string) + - nk_str_len_char(&edit->string); - const int offset = edit->select_start < edit->select_end ? edit->select_end : edit->select_start; - int glyph_offset; - nk_rune unicode; - const char *ptr = nk_str_at_const(&edit->string, offset, &unicode, &glyph_offset); - const int offset2 = ptr - nk_str_get_const(&edit->string); - NK_ASSERT(select_end_ptr); - nk_edit_draw_text(out, style, - area.x - edit->scrollbar.x, - area.y + selection_offset_end.y - edit->scrollbar.y, - selection_offset_end.x, - begin, (int)(end - begin), row_height, font, - background_color, text_color, nk_false, - &edit->lexer, offset2); - } - } - - /* cursor */ - if (edit->select_start == edit->select_end) - { - if (edit->cursor >= nk_str_len(&edit->string) || - (cursor_ptr && *cursor_ptr == '\n')) { - /* draw cursor at end of line */ - struct nk_rect cursor; - cursor.w = style->cursor_size; - cursor.h = font->height; - cursor.x = area.x + cursor_pos.x - edit->scrollbar.x; - cursor.y = area.y + cursor_pos.y + row_height/2.0f - cursor.h/2.0f; - cursor.y -= edit->scrollbar.y; - nk_fill_rect(out, cursor, 0, cursor_color); - } else { - /* draw cursor inside text */ - int glyph_len; - struct nk_rect label; - struct nk_text txt; - - nk_rune unicode; - NK_ASSERT(cursor_ptr); - glyph_len = nk_utf_decode(cursor_ptr, &unicode, 4); - - label.x = area.x + cursor_pos.x - edit->scrollbar.x; - label.y = area.y + cursor_pos.y - edit->scrollbar.y; - label.w = font->width(font->userdata, font->height, cursor_ptr, glyph_len); - label.h = row_height; - - txt.padding = nk_vec2(0,0); - txt.background = cursor_color;; - txt.text = cursor_text_color; - nk_fill_rect(out, label, 0, cursor_color); - nk_widget_text(out, label, cursor_ptr, glyph_len, &txt, NK_TEXT_LEFT, font); - } - }} - } else { - /* not active so just draw text */ - int l = nk_str_len_char(&edit->string); - const char *begin = nk_str_get_const(&edit->string); - - if(edit->lexer.lex) - nk_edit_refresh_lex(edit); - - const struct nk_style_item *background; - struct nk_color background_color; - struct nk_color text_color; - nk_push_scissor(out, clip); - if (*state & NK_WIDGET_STATE_ACTIVED) { - background = &style->active; - text_color = style->text_active; - } else if (*state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - text_color = style->text_hover; - } else { - background = &style->normal; - text_color = style->text_normal; - } - if (background->type == NK_STYLE_ITEM_IMAGE) - background_color = nk_rgba(0,0,0,0); - else background_color = background->data.color; - nk_edit_draw_text(out, style, area.x - edit->scrollbar.x, - area.y - edit->scrollbar.y, 0, begin, l, row_height, font, - background_color, text_color, nk_false, &edit->lexer, 0); - } - nk_push_scissor(out, old_clip);} - return ret; -} - -/* =============================================================== - * - * PROPERTY - * - * ===============================================================*/ -enum nk_property_status { - NK_PROPERTY_DEFAULT, - NK_PROPERTY_EDIT, - NK_PROPERTY_DRAG -}; -enum nk_property_filter { - NK_FILTER_INT, - NK_FILTER_FLOAT -}; -enum nk_property_kind { - NK_PROPERTY_INT, - NK_PROPERTY_FLOAT, - NK_PROPERTY_DOUBLE -}; -union nk_property { - int i; - float f; - double d; -}; -struct nk_property_variant { - enum nk_property_kind kind; - union nk_property value; - union nk_property min_value; - union nk_property max_value; - union nk_property step; -}; - -NK_INTERN void -nk_drag_behavior(nk_flags *state, const struct nk_input *in, - struct nk_rect drag, struct nk_property_variant *variant, - float inc_per_pixel) -{ - int left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down; - int left_mouse_click_in_cursor = in && - nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, drag, nk_true); - - nk_widget_state_reset(state); - if (nk_input_is_mouse_hovering_rect(in, drag)) - *state = NK_WIDGET_STATE_HOVERED; - - if (left_mouse_down && left_mouse_click_in_cursor) { - float delta, pixels; - pixels = in->mouse.delta.x; - delta = pixels * inc_per_pixel; - switch (variant->kind) { - default: break; - case NK_PROPERTY_INT: - variant->value.i = variant->value.i + (int)delta; - variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i); - break; - case NK_PROPERTY_FLOAT: - variant->value.f = variant->value.f + (float)delta; - variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f); - break; - case NK_PROPERTY_DOUBLE: - variant->value.d = variant->value.d + (double)delta; - variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d); - break; - } - *state = NK_WIDGET_STATE_ACTIVE; - } - if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, drag)) - *state |= NK_WIDGET_STATE_ENTERED; - else if (nk_input_is_mouse_prev_hovering_rect(in, drag)) - *state |= NK_WIDGET_STATE_LEFT; -} - -NK_INTERN void -nk_property_behavior(nk_flags *ws, const struct nk_input *in, - struct nk_rect property, struct nk_rect label, struct nk_rect edit, - struct nk_rect empty, int *state, struct nk_property_variant *variant, - float inc_per_pixel) -{ - if (in && *state == NK_PROPERTY_DEFAULT) { - if (nk_button_behavior(ws, edit, in, NK_BUTTON_DEFAULT)) - *state = NK_PROPERTY_EDIT; - else if (nk_input_is_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, label, nk_true)) - *state = NK_PROPERTY_DRAG; - else if (nk_input_is_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, empty, nk_true)) - *state = NK_PROPERTY_DRAG; - } - if (*state == NK_PROPERTY_DRAG) { - nk_drag_behavior(ws, in, property, variant, inc_per_pixel); - if (!(*ws & NK_WIDGET_STATE_ACTIVED)) *state = NK_PROPERTY_DEFAULT; - } -} - -NK_INTERN void -nk_draw_property(struct nk_command_buffer *out, const struct nk_style_property *style, - const struct nk_rect *bounds, const struct nk_rect *label, nk_flags state, - const char *name, int len, const struct nk_user_font *font) -{ - struct nk_text text; - const struct nk_style_item *background; - - /* select correct background and text color */ - if (state & NK_WIDGET_STATE_ACTIVED) { - background = &style->active; - text.text = style->label_active; - } else if (state & NK_WIDGET_STATE_HOVER) { - background = &style->hover; - text.text = style->label_hover; - } else { - background = &style->normal; - text.text = style->label_normal; - } - - /* draw background */ - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(out, *bounds, &background->data.image, nk_white); - text.background = nk_rgba(0,0,0,0); - } else { - text.background = background->data.color; - nk_fill_rect(out, *bounds, style->rounding, background->data.color); - nk_stroke_rect(out, *bounds, style->rounding, style->border, background->data.color); - } - - /* draw label */ - text.padding = nk_vec2(0,0); - nk_widget_text(out, *label, name, len, &text, NK_TEXT_CENTERED, font); -} - -NK_INTERN void -nk_do_property(nk_flags *ws, - struct nk_command_buffer *out, struct nk_rect property, - const char *name, struct nk_property_variant *variant, - float inc_per_pixel, char *buffer, int *len, - int *state, int *cursor, int *select_begin, int *select_end, - const struct nk_style_property *style, - enum nk_property_filter filter, struct nk_input *in, - const struct nk_user_font *font, struct nk_text_edit *text_edit, - enum nk_button_behavior behavior) -{ - const nk_plugin_filter filters[] = { - nk_filter_decimal, - nk_filter_float - }; - int active, old; - int num_len, name_len; - char string[NK_MAX_NUMBER_BUFFER]; - float size; - - char *dst = 0; - int *length; - - struct nk_rect left; - struct nk_rect right; - struct nk_rect label; - struct nk_rect edit; - struct nk_rect empty; - - /* left decrement button */ - left.h = font->height/2; - left.w = left.h; - left.x = property.x + style->border + style->padding.x; - left.y = property.y + style->border + property.h/2.0f - left.h/2; - - /* text label */ - name_len = nk_strlen(name); - size = font->width(font->userdata, font->height, name, name_len); - label.x = left.x + left.w + style->padding.x; - label.w = (float)size + 2 * style->padding.x; - label.y = property.y + style->border + style->padding.y; - label.h = property.h - (2 * style->border + 2 * style->padding.y); - - /* right increment button */ - right.y = left.y; - right.w = left.w; - right.h = left.h; - right.x = property.x + property.w - (right.w + style->padding.x); - - /* edit */ - if (*state == NK_PROPERTY_EDIT) { - size = font->width(font->userdata, font->height, buffer, *len); - size += style->edit.cursor_size; - length = len; - dst = buffer; - } else { - switch (variant->kind) { - default: break; - case NK_PROPERTY_INT: - nk_itoa(string, variant->value.i); - num_len = nk_strlen(string); - break; - case NK_PROPERTY_FLOAT: - NK_DTOA(string, (double)variant->value.f); - num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION); - break; - case NK_PROPERTY_DOUBLE: - NK_DTOA(string, variant->value.d); - num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION); - break; - } - size = font->width(font->userdata, font->height, string, num_len); - dst = string; - length = &num_len; - } - - edit.w = (float)size + 2 * style->padding.x; - edit.w = NK_MIN(edit.w, right.x - (label.x + label.w)); - edit.x = right.x - (edit.w + style->padding.x); - edit.y = property.y + style->border; - edit.h = property.h - (2 * style->border); - - /* empty left space activator */ - empty.w = edit.x - (label.x + label.w); - empty.x = label.x + label.w; - empty.y = property.y; - empty.h = property.h; - - /* update property */ - old = (*state == NK_PROPERTY_EDIT); - nk_property_behavior(ws, in, property, label, edit, empty, state, variant, inc_per_pixel); - - /* draw property */ - if (style->draw_begin) style->draw_begin(out, style->userdata); - nk_draw_property(out, style, &property, &label, *ws, name, name_len, font); - if (style->draw_end) style->draw_end(out, style->userdata); - - /* execute right button */ - if (nk_do_button_symbol(ws, out, left, style->sym_left, behavior, &style->dec_button, in, font)) { - switch (variant->kind) { - default: break; - case NK_PROPERTY_INT: - variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i - variant->step.i, variant->max_value.i); break; - case NK_PROPERTY_FLOAT: - variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f - variant->step.f, variant->max_value.f); break; - case NK_PROPERTY_DOUBLE: - variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d - variant->step.d, variant->max_value.d); break; - } - } - /* execute left button */ - if (nk_do_button_symbol(ws, out, right, style->sym_right, behavior, &style->inc_button, in, font)) { - switch (variant->kind) { - default: break; - case NK_PROPERTY_INT: - variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i + variant->step.i, variant->max_value.i); break; - case NK_PROPERTY_FLOAT: - variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f + variant->step.f, variant->max_value.f); break; - case NK_PROPERTY_DOUBLE: - variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d + variant->step.d, variant->max_value.d); break; - } - } - if (old != NK_PROPERTY_EDIT && (*state == NK_PROPERTY_EDIT)) { - /* property has been activated so setup buffer */ - NK_MEMCPY(buffer, dst, (nk_size)*length); - *cursor = nk_utf_len(buffer, *length); - *len = *length; - length = len; - dst = buffer; - active = 0; - } else active = (*state == NK_PROPERTY_EDIT); - - /* execute and run text edit field */ - nk_textedit_clear_state(text_edit, NK_TEXT_EDIT_SINGLE_LINE, filters[filter]); - text_edit->active = (unsigned char)active; - text_edit->string.len = *length; - text_edit->cursor = NK_CLAMP(0, *cursor, *length); - text_edit->select_start = NK_CLAMP(0,*select_begin, *length); - text_edit->select_end = NK_CLAMP(0,*select_end, *length); - text_edit->string.buffer.allocated = (nk_size)*length; - text_edit->string.buffer.memory.size = NK_MAX_NUMBER_BUFFER; - text_edit->string.buffer.memory.ptr = dst; - text_edit->string.buffer.size = NK_MAX_NUMBER_BUFFER; - text_edit->mode = NK_TEXT_EDIT_MODE_INSERT; - nk_do_edit(ws, out, edit, NK_EDIT_FIELD|NK_EDIT_AUTO_SELECT, - filters[filter], text_edit, &style->edit, (*state == NK_PROPERTY_EDIT) ? in: 0, font); - - *length = text_edit->string.len; - *cursor = text_edit->cursor; - *select_begin = text_edit->select_start; - *select_end = text_edit->select_end; - if (text_edit->active && nk_input_is_key_pressed(in, NK_KEY_ENTER)) - text_edit->active = nk_false; - - if (active && !text_edit->active) { - /* property is now not active so convert edit text to value*/ - *state = NK_PROPERTY_DEFAULT; - buffer[*len] = '\0'; - switch (variant->kind) { - default: break; - case NK_PROPERTY_INT: - variant->value.i = nk_strtoi(buffer, 0); - variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i); - break; - case NK_PROPERTY_FLOAT: - nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION); - variant->value.f = nk_strtof(buffer, 0); - variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f); - break; - case NK_PROPERTY_DOUBLE: - nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION); - variant->value.d = nk_strtod(buffer, 0); - variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d); - break; - } - } -} -/* =============================================================== - * - * COLOR PICKER - * - * ===============================================================*/ -NK_INTERN int -nk_color_picker_behavior(nk_flags *state, - const struct nk_rect *bounds, const struct nk_rect *matrix, - const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar, - struct nk_colorf *color, const struct nk_input *in) -{ - float hsva[4]; - int value_changed = 0; - int hsv_changed = 0; - - NK_ASSERT(state); - NK_ASSERT(matrix); - NK_ASSERT(hue_bar); - NK_ASSERT(color); - - /* color matrix */ - nk_colorf_hsva_fv(hsva, *color); - if (nk_button_behavior(state, *matrix, in, NK_BUTTON_REPEATER)) { - hsva[1] = NK_SATURATE((in->mouse.pos.x - matrix->x) / (matrix->w-1)); - hsva[2] = 1.0f - NK_SATURATE((in->mouse.pos.y - matrix->y) / (matrix->h-1)); - value_changed = hsv_changed = 1; - } - /* hue bar */ - if (nk_button_behavior(state, *hue_bar, in, NK_BUTTON_REPEATER)) { - hsva[0] = NK_SATURATE((in->mouse.pos.y - hue_bar->y) / (hue_bar->h-1)); - value_changed = hsv_changed = 1; - } - /* alpha bar */ - if (alpha_bar) { - if (nk_button_behavior(state, *alpha_bar, in, NK_BUTTON_REPEATER)) { - hsva[3] = 1.0f - NK_SATURATE((in->mouse.pos.y - alpha_bar->y) / (alpha_bar->h-1)); - value_changed = 1; - } - } - nk_widget_state_reset(state); - if (hsv_changed) { - *color = nk_hsva_colorfv(hsva); - *state = NK_WIDGET_STATE_ACTIVE; - } - if (value_changed) { - color->a = hsva[3]; - *state = NK_WIDGET_STATE_ACTIVE; - } - /* set color picker widget state */ - if (nk_input_is_mouse_hovering_rect(in, *bounds)) - *state = NK_WIDGET_STATE_HOVERED; - if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, *bounds)) - *state |= NK_WIDGET_STATE_ENTERED; - else if (nk_input_is_mouse_prev_hovering_rect(in, *bounds)) - *state |= NK_WIDGET_STATE_LEFT; - return value_changed; -} - -NK_INTERN void -nk_draw_color_picker(struct nk_command_buffer *o, const struct nk_rect *matrix, - const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar, - struct nk_colorf col) -{ - NK_STORAGE const struct nk_color black = {0,0,0,255}; - NK_STORAGE const struct nk_color white = {255, 255, 255, 255}; - NK_STORAGE const struct nk_color black_trans = {0,0,0,0}; - - const float crosshair_size = 7.0f; - struct nk_color temp; - float hsva[4]; - float line_y; - int i; - - NK_ASSERT(o); - NK_ASSERT(matrix); - NK_ASSERT(hue_bar); - - /* draw hue bar */ - nk_colorf_hsva_fv(hsva, col); - for (i = 0; i < 6; ++i) { - NK_GLOBAL const struct nk_color hue_colors[] = { - {255, 0, 0, 255}, {255,255,0,255}, {0,255,0,255}, {0, 255,255,255}, - {0,0,255,255}, {255, 0, 255, 255}, {255, 0, 0, 255} - }; - nk_fill_rect_multi_color(o, - nk_rect(hue_bar->x, hue_bar->y + (float)i * (hue_bar->h/6.0f) + 0.5f, - hue_bar->w, (hue_bar->h/6.0f) + 0.5f), hue_colors[i], hue_colors[i], - hue_colors[i+1], hue_colors[i+1]); - } - line_y = (float)(int)(hue_bar->y + hsva[0] * matrix->h + 0.5f); - nk_stroke_line(o, hue_bar->x-1, line_y, hue_bar->x + hue_bar->w + 2, - line_y, 1, nk_rgb(255,255,255)); - - /* draw alpha bar */ - if (alpha_bar) { - float alpha = NK_SATURATE(col.a); - line_y = (float)(int)(alpha_bar->y + (1.0f - alpha) * matrix->h + 0.5f); - - nk_fill_rect_multi_color(o, *alpha_bar, white, white, black, black); - nk_stroke_line(o, alpha_bar->x-1, line_y, alpha_bar->x + alpha_bar->w + 2, - line_y, 1, nk_rgb(255,255,255)); - } - - /* draw color matrix */ - temp = nk_hsv_f(hsva[0], 1.0f, 1.0f); - nk_fill_rect_multi_color(o, *matrix, white, temp, temp, white); - nk_fill_rect_multi_color(o, *matrix, black_trans, black_trans, black, black); - - /* draw cross-hair */ - {struct nk_vec2 p; float S = hsva[1]; float V = hsva[2]; - p.x = (float)(int)(matrix->x + S * matrix->w); - p.y = (float)(int)(matrix->y + (1.0f - V) * matrix->h); - nk_stroke_line(o, p.x - crosshair_size, p.y, p.x-2, p.y, 1.0f, white); - nk_stroke_line(o, p.x + crosshair_size + 1, p.y, p.x+3, p.y, 1.0f, white); - nk_stroke_line(o, p.x, p.y + crosshair_size + 1, p.x, p.y+3, 1.0f, white); - nk_stroke_line(o, p.x, p.y - crosshair_size, p.x, p.y-2, 1.0f, white);} -} - -NK_INTERN int -nk_do_color_picker(nk_flags *state, - struct nk_command_buffer *out, struct nk_colorf *col, - enum nk_color_format fmt, struct nk_rect bounds, - struct nk_vec2 padding, const struct nk_input *in, - const struct nk_user_font *font) -{ - int ret = 0; - struct nk_rect matrix; - struct nk_rect hue_bar; - struct nk_rect alpha_bar; - float bar_w; - - NK_ASSERT(out); - NK_ASSERT(col); - NK_ASSERT(state); - NK_ASSERT(font); - if (!out || !col || !state || !font) - return ret; - - bar_w = font->height; - bounds.x += padding.x; - bounds.y += padding.x; - bounds.w -= 2 * padding.x; - bounds.h -= 2 * padding.y; - - matrix.x = bounds.x; - matrix.y = bounds.y; - matrix.h = bounds.h; - matrix.w = bounds.w - (3 * padding.x + 2 * bar_w); - - hue_bar.w = bar_w; - hue_bar.y = bounds.y; - hue_bar.h = matrix.h; - hue_bar.x = matrix.x + matrix.w + padding.x; - - alpha_bar.x = hue_bar.x + hue_bar.w + padding.x; - alpha_bar.y = bounds.y; - alpha_bar.w = bar_w; - alpha_bar.h = matrix.h; - - ret = nk_color_picker_behavior(state, &bounds, &matrix, &hue_bar, - (fmt == NK_RGBA) ? &alpha_bar:0, col, in); - nk_draw_color_picker(out, &matrix, &hue_bar, (fmt == NK_RGBA) ? &alpha_bar:0, *col); - return ret; -} - -/* ============================================================== - * - * STYLE - * - * ===============================================================*/ -NK_API void nk_style_default(struct nk_context *ctx){nk_style_from_table(ctx, 0);} -#define NK_COLOR_MAP(NK_COLOR)\ - NK_COLOR(NK_COLOR_TEXT, 175,175,175,255) \ - NK_COLOR(NK_COLOR_WINDOW, 45, 45, 45, 255) \ - NK_COLOR(NK_COLOR_HEADER, 40, 40, 40, 255) \ - NK_COLOR(NK_COLOR_BORDER, 65, 65, 65, 255) \ - NK_COLOR(NK_COLOR_BUTTON, 50, 50, 50, 255) \ - NK_COLOR(NK_COLOR_BUTTON_HOVER, 40, 40, 40, 255) \ - NK_COLOR(NK_COLOR_BUTTON_ACTIVE, 35, 35, 35, 255) \ - NK_COLOR(NK_COLOR_TOGGLE, 100,100,100,255) \ - NK_COLOR(NK_COLOR_TOGGLE_HOVER, 120,120,120,255) \ - NK_COLOR(NK_COLOR_TOGGLE_CURSOR, 45, 45, 45, 255) \ - NK_COLOR(NK_COLOR_SELECT, 45, 45, 45, 255) \ - NK_COLOR(NK_COLOR_SELECT_ACTIVE, 35, 35, 35,255) \ - NK_COLOR(NK_COLOR_SLIDER, 38, 38, 38, 255) \ - NK_COLOR(NK_COLOR_SLIDER_CURSOR, 100,100,100,255) \ - NK_COLOR(NK_COLOR_SLIDER_CURSOR_HOVER, 120,120,120,255) \ - NK_COLOR(NK_COLOR_SLIDER_CURSOR_ACTIVE, 150,150,150,255) \ - NK_COLOR(NK_COLOR_PROPERTY, 38, 38, 38, 255) \ - NK_COLOR(NK_COLOR_EDIT, 38, 38, 38, 255) \ - NK_COLOR(NK_COLOR_EDIT_CURSOR, 175,175,175,255) \ - NK_COLOR(NK_COLOR_COMBO, 45, 45, 45, 255) \ - NK_COLOR(NK_COLOR_CHART, 120,120,120,255) \ - NK_COLOR(NK_COLOR_CHART_COLOR, 45, 45, 45, 255) \ - NK_COLOR(NK_COLOR_CHART_COLOR_HIGHLIGHT,255, 0, 0, 255) \ - NK_COLOR(NK_COLOR_SCROLLBAR, 40, 40, 40, 255) \ - NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR, 100,100,100,255) \ - NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR_HOVER,120,120,120,255) \ - NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR_ACTIVE,150,150,150,255) \ - NK_COLOR(NK_COLOR_TAB_HEADER, 40, 40, 40,255) - -NK_GLOBAL const struct nk_color -nk_default_color_style[NK_COLOR_COUNT] = { -#define NK_COLOR(a,b,c,d,e) {b,c,d,e}, - NK_COLOR_MAP(NK_COLOR) -#undef NK_COLOR -}; - -NK_GLOBAL const char *nk_color_names[NK_COLOR_COUNT] = { -#define NK_COLOR(a,b,c,d,e) #a, - NK_COLOR_MAP(NK_COLOR) -#undef NK_COLOR -}; - -NK_API const char *nk_style_get_color_by_name(enum nk_style_colors c) -{return nk_color_names[c];} - -NK_API struct nk_style_item nk_style_item_image(struct nk_image img) -{struct nk_style_item i; i.type = NK_STYLE_ITEM_IMAGE; i.data.image = img; return i;} - -NK_API struct nk_style_item nk_style_item_color(struct nk_color col) -{struct nk_style_item i; i.type = NK_STYLE_ITEM_COLOR; i.data.color = col; return i;} - -NK_API struct nk_style_item nk_style_item_hide(void) -{struct nk_style_item i; i.type = NK_STYLE_ITEM_COLOR; i.data.color = nk_rgba(0,0,0,0); return i;} - -NK_API void -nk_style_from_table(struct nk_context *ctx, const struct nk_color *table) -{ - struct nk_style *style; - struct nk_style_text *text; - struct nk_style_button *button; - struct nk_style_toggle *toggle; - struct nk_style_selectable *select; - struct nk_style_slider *slider; - struct nk_style_progress *prog; - struct nk_style_scrollbar *scroll; - struct nk_style_edit *edit; - struct nk_style_property *property; - struct nk_style_combo *combo; - struct nk_style_chart *chart; - struct nk_style_tab *tab; - struct nk_style_window *win; - - NK_ASSERT(ctx); - if (!ctx) return; - style = &ctx->style; - table = (!table) ? nk_default_color_style: table; - - /* default text */ - text = &style->text; - text->color = table[NK_COLOR_TEXT]; - text->padding = nk_vec2(0,0); - - /* default button */ - button = &style->button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_BUTTON]); - button->hover = nk_style_item_color(table[NK_COLOR_BUTTON_HOVER]); - button->active = nk_style_item_color(table[NK_COLOR_BUTTON_ACTIVE]); - button->border_color = table[NK_COLOR_BORDER]; - button->text_background = table[NK_COLOR_BUTTON]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(2.0f,2.0f); - button->image_padding = nk_vec2(0.0f,0.0f); - button->touch_padding = nk_vec2(0.0f, 0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 1.0f; - button->rounding = 4.0f; - button->draw_begin = 0; - button->draw_end = 0; - - /* contextual button */ - button = &style->contextual_button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]); - button->hover = nk_style_item_color(table[NK_COLOR_BUTTON_HOVER]); - button->active = nk_style_item_color(table[NK_COLOR_BUTTON_ACTIVE]); - button->border_color = table[NK_COLOR_WINDOW]; - button->text_background = table[NK_COLOR_WINDOW]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(2.0f,2.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - - /* menu button */ - button = &style->menu_button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]); - button->hover = nk_style_item_color(table[NK_COLOR_WINDOW]); - button->active = nk_style_item_color(table[NK_COLOR_WINDOW]); - button->border_color = table[NK_COLOR_WINDOW]; - button->text_background = table[NK_COLOR_WINDOW]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(2.0f,2.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 1.0f; - button->draw_begin = 0; - button->draw_end = 0; - - /* checkbox toggle */ - toggle = &style->checkbox; - nk_zero_struct(*toggle); - toggle->normal = nk_style_item_color(table[NK_COLOR_TOGGLE]); - toggle->hover = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]); - toggle->active = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]); - toggle->cursor_normal = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]); - toggle->cursor_hover = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]); - toggle->userdata = nk_handle_ptr(0); - toggle->text_background = table[NK_COLOR_WINDOW]; - toggle->text_normal = table[NK_COLOR_TEXT]; - toggle->text_hover = table[NK_COLOR_TEXT]; - toggle->text_active = table[NK_COLOR_TEXT]; - toggle->padding = nk_vec2(2.0f, 2.0f); - toggle->touch_padding = nk_vec2(0,0); - toggle->border_color = nk_rgba(0,0,0,0); - toggle->border = 0.0f; - toggle->spacing = 4; - - /* option toggle */ - toggle = &style->option; - nk_zero_struct(*toggle); - toggle->normal = nk_style_item_color(table[NK_COLOR_TOGGLE]); - toggle->hover = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]); - toggle->active = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]); - toggle->cursor_normal = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]); - toggle->cursor_hover = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]); - toggle->userdata = nk_handle_ptr(0); - toggle->text_background = table[NK_COLOR_WINDOW]; - toggle->text_normal = table[NK_COLOR_TEXT]; - toggle->text_hover = table[NK_COLOR_TEXT]; - toggle->text_active = table[NK_COLOR_TEXT]; - toggle->padding = nk_vec2(3.0f, 3.0f); - toggle->touch_padding = nk_vec2(0,0); - toggle->border_color = nk_rgba(0,0,0,0); - toggle->border = 0.0f; - toggle->spacing = 4; - - /* selectable */ - select = &style->selectable; - nk_zero_struct(*select); - select->normal = nk_style_item_color(table[NK_COLOR_SELECT]); - select->hover = nk_style_item_color(table[NK_COLOR_SELECT]); - select->pressed = nk_style_item_color(table[NK_COLOR_SELECT]); - select->normal_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]); - select->hover_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]); - select->pressed_active = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]); - select->text_normal = table[NK_COLOR_TEXT]; - select->text_hover = table[NK_COLOR_TEXT]; - select->text_pressed = table[NK_COLOR_TEXT]; - select->text_normal_active = table[NK_COLOR_TEXT]; - select->text_hover_active = table[NK_COLOR_TEXT]; - select->text_pressed_active = table[NK_COLOR_TEXT]; - select->padding = nk_vec2(2.0f,2.0f); - select->touch_padding = nk_vec2(0,0); - select->userdata = nk_handle_ptr(0); - select->rounding = 0.0f; - select->draw_begin = 0; - select->draw_end = 0; - - /* slider */ - slider = &style->slider; - nk_zero_struct(*slider); - slider->normal = nk_style_item_hide(); - slider->hover = nk_style_item_hide(); - slider->active = nk_style_item_hide(); - slider->bar_normal = table[NK_COLOR_SLIDER]; - slider->bar_hover = table[NK_COLOR_SLIDER]; - slider->bar_active = table[NK_COLOR_SLIDER]; - slider->bar_filled = table[NK_COLOR_SLIDER_CURSOR]; - slider->cursor_normal = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR]); - slider->cursor_hover = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_HOVER]); - slider->cursor_active = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_ACTIVE]); - slider->inc_symbol = NK_SYMBOL_TRIANGLE_RIGHT; - slider->dec_symbol = NK_SYMBOL_TRIANGLE_LEFT; - slider->cursor_size = nk_vec2(16,16); - slider->padding = nk_vec2(2,2); - slider->spacing = nk_vec2(2,2); - slider->userdata = nk_handle_ptr(0); - slider->show_buttons = nk_false; - slider->bar_height = 8; - slider->rounding = 0; - slider->draw_begin = 0; - slider->draw_end = 0; - - /* slider buttons */ - button = &style->slider.inc_button; - button->normal = nk_style_item_color(nk_rgb(40,40,40)); - button->hover = nk_style_item_color(nk_rgb(42,42,42)); - button->active = nk_style_item_color(nk_rgb(44,44,44)); - button->border_color = nk_rgb(65,65,65); - button->text_background = nk_rgb(40,40,40); - button->text_normal = nk_rgb(175,175,175); - button->text_hover = nk_rgb(175,175,175); - button->text_active = nk_rgb(175,175,175); - button->padding = nk_vec2(8.0f,8.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 1.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - style->slider.dec_button = style->slider.inc_button; - - /* progressbar */ - prog = &style->progress; - nk_zero_struct(*prog); - prog->normal = nk_style_item_color(table[NK_COLOR_SLIDER]); - prog->hover = nk_style_item_color(table[NK_COLOR_SLIDER]); - prog->active = nk_style_item_color(table[NK_COLOR_SLIDER]); - prog->cursor_normal = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR]); - prog->cursor_hover = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_HOVER]); - prog->cursor_active = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_ACTIVE]); - prog->border_color = nk_rgba(0,0,0,0); - prog->cursor_border_color = nk_rgba(0,0,0,0); - prog->userdata = nk_handle_ptr(0); - prog->padding = nk_vec2(4,4); - prog->rounding = 0; - prog->border = 0; - prog->cursor_rounding = 0; - prog->cursor_border = 0; - prog->draw_begin = 0; - prog->draw_end = 0; - - /* scrollbars */ - scroll = &style->scrollh; - nk_zero_struct(*scroll); - scroll->normal = nk_style_item_color(table[NK_COLOR_SCROLLBAR]); - scroll->hover = nk_style_item_color(table[NK_COLOR_SCROLLBAR]); - scroll->active = nk_style_item_color(table[NK_COLOR_SCROLLBAR]); - scroll->cursor_normal = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR]); - scroll->cursor_hover = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR_HOVER]); - scroll->cursor_active = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE]); - scroll->dec_symbol = NK_SYMBOL_CIRCLE_SOLID; - scroll->inc_symbol = NK_SYMBOL_CIRCLE_SOLID; - scroll->userdata = nk_handle_ptr(0); - scroll->border_color = table[NK_COLOR_SCROLLBAR]; - scroll->cursor_border_color = table[NK_COLOR_SCROLLBAR]; - scroll->padding = nk_vec2(0,0); - scroll->show_buttons = nk_false; - scroll->border = 0; - scroll->rounding = 0; - scroll->border_cursor = 0; - scroll->rounding_cursor = 0; - scroll->draw_begin = 0; - scroll->draw_end = 0; - style->scrollv = style->scrollh; - - /* scrollbars buttons */ - button = &style->scrollh.inc_button; - button->normal = nk_style_item_color(nk_rgb(40,40,40)); - button->hover = nk_style_item_color(nk_rgb(42,42,42)); - button->active = nk_style_item_color(nk_rgb(44,44,44)); - button->border_color = nk_rgb(65,65,65); - button->text_background = nk_rgb(40,40,40); - button->text_normal = nk_rgb(175,175,175); - button->text_hover = nk_rgb(175,175,175); - button->text_active = nk_rgb(175,175,175); - button->padding = nk_vec2(4.0f,4.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 1.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - style->scrollh.dec_button = style->scrollh.inc_button; - style->scrollv.inc_button = style->scrollh.inc_button; - style->scrollv.dec_button = style->scrollh.inc_button; - - /* edit */ - edit = &style->edit; - nk_zero_struct(*edit); - edit->normal = nk_style_item_color(table[NK_COLOR_EDIT]); - edit->hover = nk_style_item_color(table[NK_COLOR_EDIT]); - edit->active = nk_style_item_color(table[NK_COLOR_EDIT]); - edit->cursor_normal = table[NK_COLOR_TEXT]; - edit->cursor_hover = table[NK_COLOR_TEXT]; - edit->cursor_text_normal= table[NK_COLOR_EDIT]; - edit->cursor_text_hover = table[NK_COLOR_EDIT]; - edit->border_color = table[NK_COLOR_BORDER]; - edit->text_normal = table[NK_COLOR_TEXT]; - edit->text_hover = table[NK_COLOR_TEXT]; - edit->text_active = table[NK_COLOR_TEXT]; - edit->selected_normal = table[NK_COLOR_TEXT]; - edit->selected_hover = table[NK_COLOR_TEXT]; - edit->selected_text_normal = table[NK_COLOR_EDIT]; - edit->selected_text_hover = table[NK_COLOR_EDIT]; - edit->scrollbar_size = nk_vec2(10,10); - edit->scrollbar = style->scrollv; - edit->padding = nk_vec2(4,4); - edit->row_padding = 2; - edit->cursor_size = 4; - edit->border = 1; - edit->rounding = 0; - - /* property */ - property = &style->property; - nk_zero_struct(*property); - property->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]); - property->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]); - property->active = nk_style_item_color(table[NK_COLOR_PROPERTY]); - property->border_color = table[NK_COLOR_BORDER]; - property->label_normal = table[NK_COLOR_TEXT]; - property->label_hover = table[NK_COLOR_TEXT]; - property->label_active = table[NK_COLOR_TEXT]; - property->sym_left = NK_SYMBOL_TRIANGLE_LEFT; - property->sym_right = NK_SYMBOL_TRIANGLE_RIGHT; - property->userdata = nk_handle_ptr(0); - property->padding = nk_vec2(4,4); - property->border = 1; - property->rounding = 10; - property->draw_begin = 0; - property->draw_end = 0; - - /* property buttons */ - button = &style->property.dec_button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]); - button->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]); - button->active = nk_style_item_color(table[NK_COLOR_PROPERTY]); - button->border_color = nk_rgba(0,0,0,0); - button->text_background = table[NK_COLOR_PROPERTY]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(0.0f,0.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - style->property.inc_button = style->property.dec_button; - - /* property edit */ - edit = &style->property.edit; - nk_zero_struct(*edit); - edit->normal = nk_style_item_color(table[NK_COLOR_PROPERTY]); - edit->hover = nk_style_item_color(table[NK_COLOR_PROPERTY]); - edit->active = nk_style_item_color(table[NK_COLOR_PROPERTY]); - edit->border_color = nk_rgba(0,0,0,0); - edit->cursor_normal = table[NK_COLOR_TEXT]; - edit->cursor_hover = table[NK_COLOR_TEXT]; - edit->cursor_text_normal= table[NK_COLOR_EDIT]; - edit->cursor_text_hover = table[NK_COLOR_EDIT]; - edit->text_normal = table[NK_COLOR_TEXT]; - edit->text_hover = table[NK_COLOR_TEXT]; - edit->text_active = table[NK_COLOR_TEXT]; - edit->selected_normal = table[NK_COLOR_TEXT]; - edit->selected_hover = table[NK_COLOR_TEXT]; - edit->selected_text_normal = table[NK_COLOR_EDIT]; - edit->selected_text_hover = table[NK_COLOR_EDIT]; - edit->padding = nk_vec2(0,0); - edit->cursor_size = 8; - edit->border = 0; - edit->rounding = 0; - - /* chart */ - chart = &style->chart; - nk_zero_struct(*chart); - chart->background = nk_style_item_color(table[NK_COLOR_CHART]); - chart->border_color = table[NK_COLOR_BORDER]; - chart->selected_color = table[NK_COLOR_CHART_COLOR_HIGHLIGHT]; - chart->color = table[NK_COLOR_CHART_COLOR]; - chart->padding = nk_vec2(4,4); - chart->border = 0; - chart->rounding = 0; - - /* combo */ - combo = &style->combo; - combo->normal = nk_style_item_color(table[NK_COLOR_COMBO]); - combo->hover = nk_style_item_color(table[NK_COLOR_COMBO]); - combo->active = nk_style_item_color(table[NK_COLOR_COMBO]); - combo->border_color = table[NK_COLOR_BORDER]; - combo->label_normal = table[NK_COLOR_TEXT]; - combo->label_hover = table[NK_COLOR_TEXT]; - combo->label_active = table[NK_COLOR_TEXT]; - combo->sym_normal = NK_SYMBOL_TRIANGLE_DOWN; - combo->sym_hover = NK_SYMBOL_TRIANGLE_DOWN; - combo->sym_active = NK_SYMBOL_TRIANGLE_DOWN; - combo->content_padding = nk_vec2(4,4); - combo->button_padding = nk_vec2(0,4); - combo->spacing = nk_vec2(4,0); - combo->border = 1; - combo->rounding = 0; - - /* combo button */ - button = &style->combo.button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_COMBO]); - button->hover = nk_style_item_color(table[NK_COLOR_COMBO]); - button->active = nk_style_item_color(table[NK_COLOR_COMBO]); - button->border_color = nk_rgba(0,0,0,0); - button->text_background = table[NK_COLOR_COMBO]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(2.0f,2.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - - /* tab */ - tab = &style->tab; - tab->background = nk_style_item_color(table[NK_COLOR_TAB_HEADER]); - tab->border_color = table[NK_COLOR_BORDER]; - tab->text = table[NK_COLOR_TEXT]; - tab->sym_minimize = NK_SYMBOL_TRIANGLE_RIGHT; - tab->sym_maximize = NK_SYMBOL_TRIANGLE_DOWN; - tab->padding = nk_vec2(4,4); - tab->spacing = nk_vec2(4,4); - tab->indent = 10.0f; - tab->border = 1; - tab->rounding = 0; - - /* tab button */ - button = &style->tab.tab_minimize_button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_TAB_HEADER]); - button->hover = nk_style_item_color(table[NK_COLOR_TAB_HEADER]); - button->active = nk_style_item_color(table[NK_COLOR_TAB_HEADER]); - button->border_color = nk_rgba(0,0,0,0); - button->text_background = table[NK_COLOR_TAB_HEADER]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(2.0f,2.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - style->tab.tab_maximize_button =*button; - - /* node button */ - button = &style->tab.node_minimize_button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_WINDOW]); - button->hover = nk_style_item_color(table[NK_COLOR_WINDOW]); - button->active = nk_style_item_color(table[NK_COLOR_WINDOW]); - button->border_color = nk_rgba(0,0,0,0); - button->text_background = table[NK_COLOR_TAB_HEADER]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(2.0f,2.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - style->tab.node_maximize_button =*button; - - /* window header */ - win = &style->window; - win->header.align = NK_HEADER_RIGHT; - win->header.close_symbol = NK_SYMBOL_X; - win->header.minimize_symbol = NK_SYMBOL_MINUS; - win->header.maximize_symbol = NK_SYMBOL_PLUS; - win->header.normal = nk_style_item_color(table[NK_COLOR_HEADER]); - win->header.hover = nk_style_item_color(table[NK_COLOR_HEADER]); - win->header.active = nk_style_item_color(table[NK_COLOR_HEADER]); - win->header.label_normal = table[NK_COLOR_TEXT]; - win->header.label_hover = table[NK_COLOR_TEXT]; - win->header.label_active = table[NK_COLOR_TEXT]; - win->header.label_padding = nk_vec2(4,4); - win->header.padding = nk_vec2(4,4); - win->header.spacing = nk_vec2(0,0); - - /* window header close button */ - button = &style->window.header.close_button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_HEADER]); - button->hover = nk_style_item_color(table[NK_COLOR_HEADER]); - button->active = nk_style_item_color(table[NK_COLOR_HEADER]); - button->border_color = nk_rgba(0,0,0,0); - button->text_background = table[NK_COLOR_HEADER]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(0.0f,0.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - - /* window header minimize button */ - button = &style->window.header.minimize_button; - nk_zero_struct(*button); - button->normal = nk_style_item_color(table[NK_COLOR_HEADER]); - button->hover = nk_style_item_color(table[NK_COLOR_HEADER]); - button->active = nk_style_item_color(table[NK_COLOR_HEADER]); - button->border_color = nk_rgba(0,0,0,0); - button->text_background = table[NK_COLOR_HEADER]; - button->text_normal = table[NK_COLOR_TEXT]; - button->text_hover = table[NK_COLOR_TEXT]; - button->text_active = table[NK_COLOR_TEXT]; - button->padding = nk_vec2(0.0f,0.0f); - button->touch_padding = nk_vec2(0.0f,0.0f); - button->userdata = nk_handle_ptr(0); - button->text_alignment = NK_TEXT_CENTERED; - button->border = 0.0f; - button->rounding = 0.0f; - button->draw_begin = 0; - button->draw_end = 0; - - /* window */ - win->background = table[NK_COLOR_WINDOW]; - win->fixed_background = nk_style_item_color(table[NK_COLOR_WINDOW]); - win->border_color = table[NK_COLOR_BORDER]; - win->popup_border_color = table[NK_COLOR_BORDER]; - win->combo_border_color = table[NK_COLOR_BORDER]; - win->contextual_border_color = table[NK_COLOR_BORDER]; - win->menu_border_color = table[NK_COLOR_BORDER]; - win->group_border_color = table[NK_COLOR_BORDER]; - win->tooltip_border_color = table[NK_COLOR_BORDER]; - win->scaler = nk_style_item_color(table[NK_COLOR_TEXT]); - - win->rounding = 0.0f; - win->spacing = nk_vec2(4,4); - win->scrollbar_size = nk_vec2(10,10); - win->min_size = nk_vec2(64,64); - - win->combo_border = 1.0f; - win->contextual_border = 1.0f; - win->menu_border = 1.0f; - win->group_border = 1.0f; - win->tooltip_border = 1.0f; - win->popup_border = 1.0f; - win->border = 2.0f; - win->min_row_height_padding = 8; - - win->padding = nk_vec2(4,4); - win->group_padding = nk_vec2(4,4); - win->popup_padding = nk_vec2(4,4); - win->combo_padding = nk_vec2(4,4); - win->contextual_padding = nk_vec2(4,4); - win->menu_padding = nk_vec2(4,4); - win->tooltip_padding = nk_vec2(4,4); -} - -NK_API void -nk_style_set_font(struct nk_context *ctx, const struct nk_user_font *font) -{ - struct nk_style *style; - NK_ASSERT(ctx); - - if (!ctx) return; - style = &ctx->style; - style->font = font; - ctx->stacks.fonts.head = 0; - if (ctx->current) - nk_layout_reset_min_row_height(ctx); -} - -NK_API int -nk_style_push_font(struct nk_context *ctx, const struct nk_user_font *font) -{ - struct nk_config_stack_user_font *font_stack; - struct nk_config_stack_user_font_element *element; - - NK_ASSERT(ctx); - if (!ctx) return 0; - - font_stack = &ctx->stacks.fonts; - NK_ASSERT(font_stack->head < (int)NK_LEN(font_stack->elements)); - if (font_stack->head >= (int)NK_LEN(font_stack->elements)) - return 0; - - element = &font_stack->elements[font_stack->head++]; - element->address = &ctx->style.font; - element->old_value = ctx->style.font; - ctx->style.font = font; - return 1; -} - -NK_API int -nk_style_pop_font(struct nk_context *ctx) -{ - struct nk_config_stack_user_font *font_stack; - struct nk_config_stack_user_font_element *element; - - NK_ASSERT(ctx); - if (!ctx) return 0; - - font_stack = &ctx->stacks.fonts; - NK_ASSERT(font_stack->head > 0); - if (font_stack->head < 1) - return 0; - - element = &font_stack->elements[--font_stack->head]; - *element->address = element->old_value; - return 1; -} - -#define NK_STYLE_PUSH_IMPLEMENATION(prefix, type, stack) \ -nk_style_push_##type(struct nk_context *ctx, prefix##_##type *address, prefix##_##type value)\ -{\ - struct nk_config_stack_##type * type_stack;\ - struct nk_config_stack_##type##_element *element;\ - NK_ASSERT(ctx);\ - if (!ctx) return 0;\ - type_stack = &ctx->stacks.stack;\ - NK_ASSERT(type_stack->head < (int)NK_LEN(type_stack->elements));\ - if (type_stack->head >= (int)NK_LEN(type_stack->elements))\ - return 0;\ - element = &type_stack->elements[type_stack->head++];\ - element->address = address;\ - element->old_value = *address;\ - *address = value;\ - return 1;\ -} - -#define NK_STYLE_POP_IMPLEMENATION(type, stack) \ -nk_style_pop_##type(struct nk_context *ctx)\ -{\ - struct nk_config_stack_##type *type_stack;\ - struct nk_config_stack_##type##_element *element;\ - NK_ASSERT(ctx);\ - if (!ctx) return 0;\ - type_stack = &ctx->stacks.stack;\ - NK_ASSERT(type_stack->head > 0);\ - if (type_stack->head < 1)\ - return 0;\ - element = &type_stack->elements[--type_stack->head];\ - *element->address = element->old_value;\ - return 1;\ -} - -NK_API int NK_STYLE_PUSH_IMPLEMENATION(struct nk, style_item, style_items) -NK_API int NK_STYLE_PUSH_IMPLEMENATION(nk,float, floats) -NK_API int NK_STYLE_PUSH_IMPLEMENATION(struct nk, vec2, vectors) -NK_API int NK_STYLE_PUSH_IMPLEMENATION(nk,flags, flags) -NK_API int NK_STYLE_PUSH_IMPLEMENATION(struct nk,color, colors) - -NK_API int NK_STYLE_POP_IMPLEMENATION(style_item, style_items) -NK_API int NK_STYLE_POP_IMPLEMENATION(float,floats) -NK_API int NK_STYLE_POP_IMPLEMENATION(vec2, vectors) -NK_API int NK_STYLE_POP_IMPLEMENATION(flags,flags) -NK_API int NK_STYLE_POP_IMPLEMENATION(color,colors) - -NK_API int -nk_style_set_cursor(struct nk_context *ctx, enum nk_style_cursor c) -{ - struct nk_style *style; - NK_ASSERT(ctx); - if (!ctx) return 0; - style = &ctx->style; - if (style->cursors[c]) { - style->cursor_active = style->cursors[c]; - return 1; - } - return 0; -} - -NK_API void -nk_style_show_cursor(struct nk_context *ctx) -{ - ctx->style.cursor_visible = nk_true; -} - -NK_API void -nk_style_hide_cursor(struct nk_context *ctx) -{ - ctx->style.cursor_visible = nk_false; -} - -NK_API void -nk_style_load_cursor(struct nk_context *ctx, enum nk_style_cursor cursor, - const struct nk_cursor *c) -{ - struct nk_style *style; - NK_ASSERT(ctx); - if (!ctx) return; - style = &ctx->style; - style->cursors[cursor] = c; -} - -NK_API void -nk_style_load_all_cursors(struct nk_context *ctx, struct nk_cursor *cursors) -{ - int i = 0; - struct nk_style *style; - NK_ASSERT(ctx); - if (!ctx) return; - style = &ctx->style; - for (i = 0; i < NK_CURSOR_COUNT; ++i) - style->cursors[i] = &cursors[i]; - style->cursor_visible = nk_true; -} - -/* =============================================================== - * - * POOL - * - * ===============================================================*/ -NK_INTERN void -nk_pool_init(struct nk_pool *pool, struct nk_allocator *alloc, - unsigned int capacity) -{ - nk_zero(pool, sizeof(*pool)); - pool->alloc = *alloc; - pool->capacity = capacity; - pool->type = NK_BUFFER_DYNAMIC; - pool->pages = 0; -} - -NK_INTERN void -nk_pool_free(struct nk_pool *pool) -{ - struct nk_page *iter = pool->pages; - if (!pool) return; - if (pool->type == NK_BUFFER_FIXED) return; - while (iter) { - struct nk_page *next = iter->next; - pool->alloc.free(pool->alloc.userdata, iter); - iter = next; - } -} - -NK_INTERN void -nk_pool_init_fixed(struct nk_pool *pool, void *memory, nk_size size) -{ - nk_zero(pool, sizeof(*pool)); - NK_ASSERT(size >= sizeof(struct nk_page)); - if (size < sizeof(struct nk_page)) return; - pool->capacity = (unsigned)(size - sizeof(struct nk_page)) / sizeof(struct nk_page_element); - pool->pages = (struct nk_page*)memory; - pool->type = NK_BUFFER_FIXED; - pool->size = size; -} - -NK_INTERN struct nk_page_element* -nk_pool_alloc(struct nk_pool *pool) -{ - if (!pool->pages || pool->pages->size >= pool->capacity) { - /* allocate new page */ - struct nk_page *page; - if (pool->type == NK_BUFFER_FIXED) { - if (!pool->pages) { - NK_ASSERT(pool->pages); - return 0; - } - NK_ASSERT(pool->pages->size < pool->capacity); - return 0; - } else { - nk_size size = sizeof(struct nk_page); - size += NK_POOL_DEFAULT_CAPACITY * sizeof(union nk_page_data); - page = (struct nk_page*)pool->alloc.alloc(pool->alloc.userdata,0, size); - page->next = pool->pages; - pool->pages = page; - page->size = 0; - } - } - return &pool->pages->win[pool->pages->size++]; -} - -/* =============================================================== - * - * CONTEXT - * - * ===============================================================*/ -NK_INTERN void* nk_create_window(struct nk_context *ctx); -NK_INTERN void nk_remove_window(struct nk_context*, struct nk_window*); -NK_INTERN void nk_free_window(struct nk_context *ctx, struct nk_window *win); -NK_INTERN void nk_free_table(struct nk_context *ctx, struct nk_table *tbl); -NK_INTERN void nk_remove_table(struct nk_window *win, struct nk_table *tbl); -NK_INTERN void* nk_create_panel(struct nk_context *ctx); -NK_INTERN void nk_free_panel(struct nk_context*, struct nk_panel *pan); - -NK_INTERN void -nk_setup(struct nk_context *ctx, const struct nk_user_font *font) -{ - NK_ASSERT(ctx); - if (!ctx) return; - nk_zero_struct(*ctx); - nk_style_default(ctx); - ctx->seq = 1; - if (font) ctx->style.font = font; -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT - nk_draw_list_init(&ctx->draw_list); -#endif -} - -#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR -NK_API int -nk_init_default(struct nk_context *ctx, const struct nk_user_font *font) -{ - struct nk_allocator alloc; - alloc.userdata.ptr = 0; - alloc.alloc = nk_malloc; - alloc.free = nk_mfree; - return nk_init(ctx, &alloc, font); -} -#endif - -NK_API int -nk_init_fixed(struct nk_context *ctx, void *memory, nk_size size, - const struct nk_user_font *font) -{ - NK_ASSERT(memory); - if (!memory) return 0; - nk_setup(ctx, font); - nk_buffer_init_fixed(&ctx->memory, memory, size); - ctx->use_pool = nk_false; - return 1; -} - -NK_API int -nk_init_custom(struct nk_context *ctx, struct nk_buffer *cmds, - struct nk_buffer *pool, const struct nk_user_font *font) -{ - NK_ASSERT(cmds); - NK_ASSERT(pool); - if (!cmds || !pool) return 0; - - nk_setup(ctx, font); - ctx->memory = *cmds; - if (pool->type == NK_BUFFER_FIXED) { - /* take memory from buffer and alloc fixed pool */ - nk_pool_init_fixed(&ctx->pool, pool->memory.ptr, pool->memory.size); - } else { - /* create dynamic pool from buffer allocator */ - struct nk_allocator *alloc = &pool->pool; - nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY); - } - ctx->use_pool = nk_true; - return 1; -} - -NK_API int -nk_init(struct nk_context *ctx, struct nk_allocator *alloc, - const struct nk_user_font *font) -{ - NK_ASSERT(alloc); - if (!alloc) return 0; - nk_setup(ctx, font); - nk_buffer_init(&ctx->memory, alloc, NK_DEFAULT_COMMAND_BUFFER_SIZE); - nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY); - ctx->use_pool = nk_true; - return 1; -} - -#ifdef NK_INCLUDE_COMMAND_USERDATA -NK_API void -nk_set_user_data(struct nk_context *ctx, nk_handle handle) -{ - if (!ctx) return; - ctx->userdata = handle; - if (ctx->current) - ctx->current->buffer.userdata = handle; -} -#endif - -NK_API void -nk_free(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - if (!ctx) return; - nk_buffer_free(&ctx->memory); - if (ctx->use_pool) - nk_pool_free(&ctx->pool); - - nk_zero(&ctx->input, sizeof(ctx->input)); - nk_zero(&ctx->style, sizeof(ctx->style)); - nk_zero(&ctx->memory, sizeof(ctx->memory)); - - ctx->seq = 0; - ctx->build = 0; - ctx->begin = 0; - ctx->end = 0; - ctx->active = 0; - ctx->current = 0; - ctx->freelist = 0; - ctx->count = 0; -} - -NK_API void -nk_clear(struct nk_context *ctx) -{ - struct nk_window *iter; - struct nk_window *next; - NK_ASSERT(ctx); - - if (!ctx) return; - if (ctx->use_pool) - nk_buffer_clear(&ctx->memory); - else nk_buffer_reset(&ctx->memory, NK_BUFFER_FRONT); - - ctx->build = 0; - ctx->memory.calls = 0; - ctx->last_widget_state = 0; - ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW]; - NK_MEMSET(&ctx->overlay, 0, sizeof(ctx->overlay)); -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT - //nk_draw_list_clear(&ctx->draw_list); -#endif - - /* garbage collector */ - iter = ctx->begin; - while (iter) { - /* make sure valid minimized windows do not get removed */ - if ((iter->flags & NK_WINDOW_MINIMIZED) && - !(iter->flags & NK_WINDOW_CLOSED) && - iter->seq == ctx->seq) { - iter = iter->next; - continue; - } - /* remove hotness from hidden or closed windows*/ - if (((iter->flags & NK_WINDOW_HIDDEN) || - (iter->flags & NK_WINDOW_CLOSED)) && - iter == ctx->active) { - ctx->active = iter->prev; - ctx->end = iter->prev; - if (!ctx->end) - ctx->begin = 0; - if (ctx->active) - ctx->active->flags &= ~(unsigned)NK_WINDOW_ROM; - } - /* free unused popup windows */ - if (iter->popup.win && iter->popup.win->seq != ctx->seq) { - nk_free_window(ctx, iter->popup.win); - iter->popup.win = 0; - } - /* remove unused window state tables */ - {struct nk_table *n, *it = iter->tables; - while (it) { - n = it->next; - if (it->seq != ctx->seq) { - nk_remove_table(iter, it); - nk_zero(it, sizeof(union nk_page_data)); - nk_free_table(ctx, it); - if (it == iter->tables) - iter->tables = n; - } it = n; - }} - /* window itself is not used anymore so free */ - if (iter->seq != ctx->seq || iter->flags & NK_WINDOW_CLOSED) { - next = iter->next; - nk_remove_window(ctx, iter); - nk_free_window(ctx, iter); - iter = next; - } else iter = iter->next; - } - ctx->seq++; -} - -/* ---------------------------------------------------------------- - * - * BUFFERING - * - * ---------------------------------------------------------------*/ -NK_INTERN void -nk_start_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer) -{ - NK_ASSERT(ctx); - NK_ASSERT(buffer); - if (!ctx || !buffer) return; - buffer->begin = ctx->memory.allocated; - buffer->end = buffer->begin; - buffer->last = buffer->begin; - buffer->clip = nk_null_rect; -} - -NK_INTERN void -nk_start(struct nk_context *ctx, struct nk_window *win) -{ - NK_ASSERT(ctx); - NK_ASSERT(win); - nk_start_buffer(ctx, &win->buffer); -} - -NK_INTERN void -nk_start_popup(struct nk_context *ctx, struct nk_window *win) -{ - struct nk_popup_buffer *buf; - NK_ASSERT(ctx); - NK_ASSERT(win); - if (!ctx || !win) return; - - /* save buffer fill state for popup */ - buf = &win->popup.buf; - buf->begin = win->buffer.end; - buf->end = win->buffer.end; - buf->parent = win->buffer.last; - buf->last = buf->begin; - buf->active = nk_true; -} - -NK_INTERN void -nk_finish_popup(struct nk_context *ctx, struct nk_window *win) -{ - struct nk_popup_buffer *buf; - NK_ASSERT(ctx); - NK_ASSERT(win); - if (!ctx || !win) return; - - buf = &win->popup.buf; - buf->last = win->buffer.last; - buf->end = win->buffer.end; -} - -NK_INTERN void -nk_finish_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer) -{ - NK_ASSERT(ctx); - NK_ASSERT(buffer); - if (!ctx || !buffer) return; - buffer->end = ctx->memory.allocated; -} - -NK_INTERN void -nk_finish(struct nk_context *ctx, struct nk_window *win) -{ - struct nk_popup_buffer *buf; - struct nk_command *parent_last; - void *memory; - - NK_ASSERT(ctx); - NK_ASSERT(win); - if (!ctx || !win) return; - nk_finish_buffer(ctx, &win->buffer); - if (!win->popup.buf.active) return; - - buf = &win->popup.buf; - memory = ctx->memory.memory.ptr; - parent_last = nk_ptr_add(struct nk_command, memory, buf->parent); - parent_last->next = buf->end; -} - -NK_INTERN void -nk_build(struct nk_context *ctx) -{ - struct nk_window *it = 0; - struct nk_command *cmd = 0; - nk_byte *buffer = 0; - - /* draw cursor overlay */ - if (!ctx->style.cursor_active) - ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW]; - if (ctx->style.cursor_active && !ctx->input.mouse.grabbed && ctx->style.cursor_visible) { - struct nk_rect mouse_bounds; - const struct nk_cursor *cursor = ctx->style.cursor_active; - nk_command_buffer_init(&ctx->overlay, &ctx->memory, NK_CLIPPING_OFF); - nk_start_buffer(ctx, &ctx->overlay); - - mouse_bounds.x = ctx->input.mouse.pos.x - cursor->offset.x; - mouse_bounds.y = ctx->input.mouse.pos.y - cursor->offset.y; - mouse_bounds.w = cursor->size.x; - mouse_bounds.h = cursor->size.y; - - nk_draw_image(&ctx->overlay, mouse_bounds, &cursor->img, nk_white); - nk_finish_buffer(ctx, &ctx->overlay); - } - /* build one big draw command list out of all window buffers */ - it = ctx->begin; - buffer = (nk_byte*)ctx->memory.memory.ptr; - while (it != 0) { - struct nk_window *next = it->next; - if (it->buffer.last == it->buffer.begin || (it->flags & NK_WINDOW_HIDDEN)|| - it->seq != ctx->seq) - goto cont; - - cmd = nk_ptr_add(struct nk_command, buffer, it->buffer.last); - while (next && ((next->buffer.last == next->buffer.begin) || - (next->flags & NK_WINDOW_HIDDEN) || next->seq != ctx->seq)) - next = next->next; /* skip empty command buffers */ - - if (next) cmd->next = next->buffer.begin; - cont: it = next; - } - /* append all popup draw commands into lists */ - it = ctx->begin; - while (it != 0) { - struct nk_window *next = it->next; - struct nk_popup_buffer *buf; - if (!it->popup.buf.active) - goto skip; - - buf = &it->popup.buf; - cmd->next = buf->begin; - cmd = nk_ptr_add(struct nk_command, buffer, buf->last); - buf->active = nk_false; - skip: it = next; - } - if (cmd) { - /* append overlay commands */ - if (ctx->overlay.end != ctx->overlay.begin) - cmd->next = ctx->overlay.begin; - else cmd->next = ctx->memory.allocated; - } -} - -NK_API const struct nk_command* -nk__begin(struct nk_context *ctx) -{ - struct nk_window *iter; - nk_byte *buffer; - NK_ASSERT(ctx); - if (!ctx) return 0; - if (!ctx->count) return 0; - - buffer = (nk_byte*)ctx->memory.memory.ptr; - if (!ctx->build) { - nk_build(ctx); - ctx->build = nk_true; - } - iter = ctx->begin; - while (iter && ((iter->buffer.begin == iter->buffer.end) || - (iter->flags & NK_WINDOW_HIDDEN) || iter->seq != ctx->seq)) - iter = iter->next; - if (!iter) return 0; - return nk_ptr_add_const(struct nk_command, buffer, iter->buffer.begin); -} - -NK_API const struct nk_command* -nk__next(struct nk_context *ctx, const struct nk_command *cmd) -{ - nk_byte *buffer; - const struct nk_command *next; - NK_ASSERT(ctx); - if (!ctx || !cmd || !ctx->count) return 0; - if (cmd->next >= ctx->memory.allocated) return 0; - buffer = (nk_byte*)ctx->memory.memory.ptr; - next = nk_ptr_add_const(struct nk_command, buffer, cmd->next); - return next; -} - -/* ---------------------------------------------------------------- - * - * PANEL - * - * ---------------------------------------------------------------*/ -static int -nk_panel_has_header(nk_flags flags, const char *title) -{ - int active = 0; - active = (flags & (NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE)); - active = active || (flags & NK_WINDOW_TITLE); - active = active && !(flags & NK_WINDOW_HIDDEN) && title; - return active; -} - -NK_INTERN struct nk_vec2 -nk_panel_get_padding(const struct nk_style *style, enum nk_panel_type type) -{ - switch (type) { - default: - case NK_PANEL_WINDOW: return style->window.padding; - case NK_PANEL_GROUP: return style->window.group_padding; - case NK_PANEL_POPUP: return style->window.popup_padding; - case NK_PANEL_CONTEXTUAL: return style->window.contextual_padding; - case NK_PANEL_COMBO: return style->window.combo_padding; - case NK_PANEL_MENU: return style->window.menu_padding; - case NK_PANEL_TOOLTIP: return style->window.menu_padding; - } -} - -NK_INTERN float -nk_panel_get_border(const struct nk_style *style, nk_flags flags, - enum nk_panel_type type) -{ - if (flags & NK_WINDOW_BORDER) { - switch (type) { - default: - case NK_PANEL_WINDOW: return style->window.border; - case NK_PANEL_GROUP: return style->window.group_border; - case NK_PANEL_POPUP: return style->window.popup_border; - case NK_PANEL_CONTEXTUAL: return style->window.contextual_border; - case NK_PANEL_COMBO: return style->window.combo_border; - case NK_PANEL_MENU: return style->window.menu_border; - case NK_PANEL_TOOLTIP: return style->window.menu_border; - }} else return 0; -} - -NK_INTERN struct nk_color -nk_panel_get_border_color(const struct nk_style *style, enum nk_panel_type type) -{ - switch (type) { - default: - case NK_PANEL_WINDOW: return style->window.border_color; - case NK_PANEL_GROUP: return style->window.group_border_color; - case NK_PANEL_POPUP: return style->window.popup_border_color; - case NK_PANEL_CONTEXTUAL: return style->window.contextual_border_color; - case NK_PANEL_COMBO: return style->window.combo_border_color; - case NK_PANEL_MENU: return style->window.menu_border_color; - case NK_PANEL_TOOLTIP: return style->window.menu_border_color; - } -} - -NK_INTERN int -nk_panel_is_sub(enum nk_panel_type type) -{ - return (type & NK_PANEL_SET_SUB)?1:0; -} - -NK_INTERN int -nk_panel_is_nonblock(enum nk_panel_type type) -{ - return (type & NK_PANEL_SET_NONBLOCK)?1:0; -} - -NK_INTERN int -nk_panel_begin(struct nk_context *ctx, const char *title, enum nk_panel_type panel_type) -{ - struct nk_input *in; - struct nk_window *win; - struct nk_panel *layout; - struct nk_command_buffer *out; - const struct nk_style *style; - const struct nk_user_font *font; - - struct nk_vec2 scrollbar_size; - struct nk_vec2 panel_padding; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) return 0; - nk_zero(ctx->current->layout, sizeof(*ctx->current->layout)); - if ((ctx->current->flags & NK_WINDOW_HIDDEN) || (ctx->current->flags & NK_WINDOW_CLOSED)) { - nk_zero(ctx->current->layout, sizeof(struct nk_panel)); - ctx->current->layout->type = panel_type; - return 0; - } - /* pull state into local stack */ - style = &ctx->style; - font = style->font; - win = ctx->current; - layout = win->layout; - out = &win->buffer; - in = (win->flags & NK_WINDOW_NO_INPUT) ? 0: &ctx->input; -#ifdef NK_INCLUDE_COMMAND_USERDATA - win->buffer.userdata = ctx->userdata; -#endif - /* pull style configuration into local stack */ - scrollbar_size = style->window.scrollbar_size; - panel_padding = nk_panel_get_padding(style, panel_type); - - /* window movement */ - if ((win->flags & NK_WINDOW_MOVABLE) && !(win->flags & NK_WINDOW_ROM)) { - int left_mouse_down; - int left_mouse_click_in_cursor; - - /* calculate draggable window space */ - struct nk_rect header; - header.x = win->bounds.x; - header.y = win->bounds.y; - header.w = win->bounds.w; - if (nk_panel_has_header(win->flags, title)) { - header.h = font->height + 2.0f * style->window.header.padding.y; - header.h += 2.0f * style->window.header.label_padding.y; - } else header.h = panel_padding.y; - - /* window movement by dragging */ - left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down; - left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in, - NK_BUTTON_LEFT, header, nk_true); - if (left_mouse_down && left_mouse_click_in_cursor) { - win->bounds.x = win->bounds.x + in->mouse.delta.x; - win->bounds.y = win->bounds.y + in->mouse.delta.y; - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x += in->mouse.delta.x; - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y += in->mouse.delta.y; - ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_MOVE]; - } - } - - /* setup panel */ - layout->type = panel_type; - layout->flags = win->flags; - layout->bounds = win->bounds; - layout->bounds.x += panel_padding.x; - layout->bounds.w -= 2*panel_padding.x; - if (win->flags & NK_WINDOW_BORDER) { - layout->border = nk_panel_get_border(style, win->flags, panel_type); - layout->bounds = nk_shrink_rect(layout->bounds, layout->border); - } else layout->border = 0; - layout->at_y = layout->bounds.y; - layout->at_x = layout->bounds.x; - layout->max_x = 0; - layout->header_height = 0; - layout->footer_height = 0; - nk_layout_reset_min_row_height(ctx); - layout->row.index = 0; - layout->row.columns = 0; - layout->row.ratio = 0; - layout->row.item_width = 0; - layout->row.tree_depth = 0; - layout->row.height = panel_padding.y; - layout->has_scrolling = nk_true; - if (!(win->flags & NK_WINDOW_NO_SCROLLBAR)) - layout->bounds.w -= scrollbar_size.x; - if (!nk_panel_is_nonblock(panel_type)) { - layout->footer_height = 0; - if (!(win->flags & NK_WINDOW_NO_SCROLLBAR) || win->flags & NK_WINDOW_SCALABLE) - layout->footer_height = scrollbar_size.y; - layout->bounds.h -= layout->footer_height; - } - - /* panel header */ - if (nk_panel_has_header(win->flags, title)) - { - struct nk_text text; - struct nk_rect header; - const struct nk_style_item *background = 0; - - /* calculate header bounds */ - header.x = win->bounds.x; - header.y = win->bounds.y; - header.w = win->bounds.w; - header.h = font->height + 2.0f * style->window.header.padding.y; - header.h += (2.0f * style->window.header.label_padding.y); - - /* shrink panel by header */ - layout->header_height = header.h; - layout->bounds.y += header.h; - layout->bounds.h -= header.h; - layout->at_y += header.h; - - /* select correct header background and text color */ - if (ctx->active == win) { - background = &style->window.header.active; - text.text = style->window.header.label_active; - } else if (nk_input_is_mouse_hovering_rect(&ctx->input, header)) { - background = &style->window.header.hover; - text.text = style->window.header.label_hover; - } else { - background = &style->window.header.normal; - text.text = style->window.header.label_normal; - } - - /* draw header background */ - header.h += 1.0f; - if (background->type == NK_STYLE_ITEM_IMAGE) { - text.background = nk_rgba(0,0,0,0); - nk_draw_image(&win->buffer, header, &background->data.image, nk_white); - } else { - text.background = background->data.color; - nk_fill_rect(out, header, 0, background->data.color); - } - - /* window close button */ - {struct nk_rect button; - button.y = header.y + style->window.header.padding.y; - button.h = header.h - 2 * style->window.header.padding.y; - button.w = button.h; - if (win->flags & NK_WINDOW_CLOSABLE) { - nk_flags ws = 0; - if (style->window.header.align == NK_HEADER_RIGHT) { - button.x = (header.w + header.x) - (button.w + style->window.header.padding.x); - header.w -= button.w + style->window.header.spacing.x + style->window.header.padding.x; - } else { - button.x = header.x + style->window.header.padding.x; - header.x += button.w + style->window.header.spacing.x + style->window.header.padding.x; - } - - if (nk_do_button_symbol(&ws, &win->buffer, button, - style->window.header.close_symbol, NK_BUTTON_DEFAULT, - &style->window.header.close_button, in, style->font) && !(win->flags & NK_WINDOW_ROM)) - { - layout->flags |= NK_WINDOW_HIDDEN; - layout->flags &= (nk_flags)~NK_WINDOW_MINIMIZED; - } - } - - /* window minimize button */ - if (win->flags & NK_WINDOW_MINIMIZABLE) { - nk_flags ws = 0; - if (style->window.header.align == NK_HEADER_RIGHT) { - button.x = (header.w + header.x) - button.w; - if (!(win->flags & NK_WINDOW_CLOSABLE)) { - button.x -= style->window.header.padding.x; - header.w -= style->window.header.padding.x; - } - header.w -= button.w + style->window.header.spacing.x; - } else { - button.x = header.x; - header.x += button.w + style->window.header.spacing.x + style->window.header.padding.x; - } - if (nk_do_button_symbol(&ws, &win->buffer, button, (layout->flags & NK_WINDOW_MINIMIZED)? - style->window.header.maximize_symbol: style->window.header.minimize_symbol, - NK_BUTTON_DEFAULT, &style->window.header.minimize_button, in, style->font) && !(win->flags & NK_WINDOW_ROM)) - layout->flags = (layout->flags & NK_WINDOW_MINIMIZED) ? - layout->flags & (nk_flags)~NK_WINDOW_MINIMIZED: - layout->flags | NK_WINDOW_MINIMIZED; - }} - - {/* window header title */ - int text_len = nk_strlen(title); - struct nk_rect label = {0,0,0,0}; - float t = font->width(font->userdata, font->height, title, text_len); - text.padding = nk_vec2(0,0); - - label.x = header.x + style->window.header.padding.x; - label.x += style->window.header.label_padding.x; - label.y = header.y + style->window.header.label_padding.y; - label.h = font->height + 2 * style->window.header.label_padding.y; - label.w = t + 2 * style->window.header.spacing.x; - label.w = NK_CLAMP(0, label.w, header.x + header.w - label.x); - nk_widget_text(out, label,(const char*)title, text_len, &text, NK_TEXT_LEFT, font);} - } - - /* draw window background */ - if (!(layout->flags & NK_WINDOW_MINIMIZED) && !(layout->flags & NK_WINDOW_DYNAMIC)) { - struct nk_rect body; - body.x = win->bounds.x; - body.w = win->bounds.w; - body.y = (win->bounds.y + layout->header_height); - body.h = (win->bounds.h - layout->header_height); - if (style->window.fixed_background.type == NK_STYLE_ITEM_IMAGE) - nk_draw_image(out, body, &style->window.fixed_background.data.image, nk_white); - else nk_fill_rect(out, body, 0, style->window.fixed_background.data.color); - } - - /* set clipping rectangle */ - {struct nk_rect clip; - layout->clip = layout->bounds; - nk_unify(&clip, &win->buffer.clip, layout->clip.x, layout->clip.y, - layout->clip.x + layout->clip.w, layout->clip.y + layout->clip.h); - nk_push_scissor(out, clip); - layout->clip = clip;} - return !(layout->flags & NK_WINDOW_HIDDEN) && !(layout->flags & NK_WINDOW_MINIMIZED); -} - -NK_INTERN void -nk_panel_end(struct nk_context *ctx) -{ - struct nk_input *in; - struct nk_window *window; - struct nk_panel *layout; - const struct nk_style *style; - struct nk_command_buffer *out; - - struct nk_vec2 scrollbar_size; - struct nk_vec2 panel_padding; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - window = ctx->current; - layout = window->layout; - style = &ctx->style; - out = &window->buffer; - in = (layout->flags & NK_WINDOW_ROM || layout->flags & NK_WINDOW_NO_INPUT) ? 0 :&ctx->input; - if (!nk_panel_is_sub(layout->type)) - nk_push_scissor(out, nk_null_rect); - - /* cache configuration data */ - scrollbar_size = style->window.scrollbar_size; - panel_padding = nk_panel_get_padding(style, layout->type); - - /* update the current cursor Y-position to point over the last added widget */ - layout->at_y += layout->row.height; - - /* dynamic panels */ - if (layout->flags & NK_WINDOW_DYNAMIC && !(layout->flags & NK_WINDOW_MINIMIZED)) - { - /* update panel height to fit dynamic growth */ - struct nk_rect empty_space; - if (layout->at_y < (layout->bounds.y + layout->bounds.h)) - layout->bounds.h = layout->at_y - layout->bounds.y; - - /* fill top empty space */ - empty_space.x = window->bounds.x; - empty_space.y = layout->bounds.y; - empty_space.h = panel_padding.y; - empty_space.w = window->bounds.w; - nk_fill_rect(out, empty_space, 0, style->window.background); - - /* fill left empty space */ - empty_space.x = window->bounds.x; - empty_space.y = layout->bounds.y; - empty_space.w = panel_padding.x + layout->border; - empty_space.h = layout->bounds.h; - nk_fill_rect(out, empty_space, 0, style->window.background); - - /* fill right empty space */ - empty_space.x = layout->bounds.x + layout->bounds.w - layout->border; - empty_space.y = layout->bounds.y; - empty_space.w = panel_padding.x + layout->border; - empty_space.h = layout->bounds.h; - if (*layout->offset_y == 0 && !(layout->flags & NK_WINDOW_NO_SCROLLBAR)) - empty_space.w += scrollbar_size.x; - nk_fill_rect(out, empty_space, 0, style->window.background); - - /* fill bottom empty space */ - if (*layout->offset_x != 0 && !(layout->flags & NK_WINDOW_NO_SCROLLBAR)) { - empty_space.x = window->bounds.x; - empty_space.y = layout->bounds.y + layout->bounds.h; - empty_space.w = window->bounds.w; - empty_space.h = scrollbar_size.y; - nk_fill_rect(out, empty_space, 0, style->window.background); - } - } - - /* scrollbars */ - if (!(layout->flags & NK_WINDOW_NO_SCROLLBAR) && - !(layout->flags & NK_WINDOW_MINIMIZED) && - window->scrollbar_hiding_timer < NK_SCROLLBAR_HIDING_TIMEOUT) - { - struct nk_rect scroll; - int scroll_has_scrolling; - float scroll_target; - float scroll_offset; - float scroll_step; - float scroll_inc; - - /* mouse wheel scrolling */ - if (nk_panel_is_sub(layout->type)) - { - /* sub-window mouse wheel scrolling */ - struct nk_window *root_window = window; - struct nk_panel *root_panel = window->layout; - while (root_panel->parent) - root_panel = root_panel->parent; - while (root_window->parent) - root_window = root_window->parent; - - /* only allow scrolling if parent window is active */ - scroll_has_scrolling = 0; - if ((root_window == ctx->active) && layout->has_scrolling) { - /* and panel is being hovered and inside clip rect*/ - if (nk_input_is_mouse_hovering_rect(in, layout->bounds) && - NK_INTERSECT(layout->bounds.x, layout->bounds.y, layout->bounds.w, layout->bounds.h, - root_panel->clip.x, root_panel->clip.y, root_panel->clip.w, root_panel->clip.h)) - { - /* deactivate all parent scrolling */ - root_panel = window->layout; - while (root_panel->parent) { - root_panel->has_scrolling = nk_false; - root_panel = root_panel->parent; - } - root_panel->has_scrolling = nk_false; - scroll_has_scrolling = nk_true; - } - } - } else if (!nk_panel_is_sub(layout->type)) { - /* window mouse wheel scrolling */ - scroll_has_scrolling = (window == ctx->active) && layout->has_scrolling; - if (in && (in->mouse.scroll_delta.y > 0 || in->mouse.scroll_delta.x > 0) && scroll_has_scrolling) - window->scrolled = nk_true; - else window->scrolled = nk_false; - } else scroll_has_scrolling = nk_false; - - { - /* vertical scrollbar */ - nk_flags state = 0; - scroll.x = layout->bounds.x + layout->bounds.w + panel_padding.x; - scroll.y = layout->bounds.y; - scroll.w = scrollbar_size.x; - scroll.h = layout->bounds.h; - - scroll_offset = (float)*layout->offset_y; - scroll_step = scroll.h * 0.10f; - scroll_inc = scroll.h * 0.01f; - scroll_target = (float)(int)(layout->at_y - scroll.y); - scroll_offset = nk_do_scrollbarv(&state, out, scroll, scroll_has_scrolling, - scroll_offset, scroll_target, scroll_step, scroll_inc, - &ctx->style.scrollv, in, style->font); - *layout->offset_y = (nk_uint)scroll_offset; - if (in && scroll_has_scrolling) - in->mouse.scroll_delta.y = 0; - } - { - /* horizontal scrollbar */ - nk_flags state = 0; - scroll.x = layout->bounds.x; - scroll.y = layout->bounds.y + layout->bounds.h; - scroll.w = layout->bounds.w; - scroll.h = scrollbar_size.y; - - scroll_offset = (float)*layout->offset_x; - scroll_target = (float)(int)(layout->max_x - scroll.x); - scroll_step = layout->max_x * 0.05f; - scroll_inc = layout->max_x * 0.005f; - scroll_offset = nk_do_scrollbarh(&state, out, scroll, scroll_has_scrolling, - scroll_offset, scroll_target, scroll_step, scroll_inc, - &ctx->style.scrollh, in, style->font); - *layout->offset_x = (nk_uint)scroll_offset; - } - } - - /* hide scroll if no user input */ - if (window->flags & NK_WINDOW_SCROLL_AUTO_HIDE) { - int has_input = ctx->input.mouse.delta.x != 0 || ctx->input.mouse.delta.y != 0 || ctx->input.mouse.scroll_delta.y != 0; - int is_window_hovered = nk_window_is_hovered(ctx); - int any_item_active = (ctx->last_widget_state & NK_WIDGET_STATE_MODIFIED); - if ((!has_input && is_window_hovered) || (!is_window_hovered && !any_item_active)) - window->scrollbar_hiding_timer += ctx->delta_time_seconds; - else window->scrollbar_hiding_timer = 0; - } else window->scrollbar_hiding_timer = 0; - - /* window border */ - if (layout->flags & NK_WINDOW_BORDER) - { - struct nk_color border_color = nk_panel_get_border_color(style, layout->type); - const float padding_y = (layout->flags & NK_WINDOW_MINIMIZED) - ? (style->window.border + window->bounds.y + layout->header_height) - : ((layout->flags & NK_WINDOW_DYNAMIC) - ? (layout->bounds.y + layout->bounds.h + layout->footer_height) - : (window->bounds.y + window->bounds.h)); - struct nk_rect b = window->bounds; - b.h = padding_y - window->bounds.y; - nk_stroke_rect(out, b, 0, layout->border, border_color); - } - - /* scaler */ - if ((layout->flags & NK_WINDOW_SCALABLE) && in && !(layout->flags & NK_WINDOW_MINIMIZED)) - { - /* calculate scaler bounds */ - struct nk_rect scaler; - scaler.w = scrollbar_size.x; - scaler.h = scrollbar_size.y; - scaler.y = layout->bounds.y + layout->bounds.h; - if (layout->flags & NK_WINDOW_SCALE_LEFT) - scaler.x = layout->bounds.x - panel_padding.x * 0.5f; - else scaler.x = layout->bounds.x + layout->bounds.w + panel_padding.x; - if (layout->flags & NK_WINDOW_NO_SCROLLBAR) - scaler.x -= scaler.w; - - /* draw scaler */ - {const struct nk_style_item *item = &style->window.scaler; - if (item->type == NK_STYLE_ITEM_IMAGE) - nk_draw_image(out, scaler, &item->data.image, nk_white); - else { - if (layout->flags & NK_WINDOW_SCALE_LEFT) { - nk_fill_triangle(out, scaler.x, scaler.y, scaler.x, - scaler.y + scaler.h, scaler.x + scaler.w, - scaler.y + scaler.h, item->data.color); - } else { - nk_fill_triangle(out, scaler.x + scaler.w, scaler.y, scaler.x + scaler.w, - scaler.y + scaler.h, scaler.x, scaler.y + scaler.h, item->data.color); - } - }} - - /* do window scaling */ - if (!(window->flags & NK_WINDOW_ROM)) { - struct nk_vec2 window_size = style->window.min_size; - int left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down; - int left_mouse_click_in_scaler = nk_input_has_mouse_click_down_in_rect(in, - NK_BUTTON_LEFT, scaler, nk_true); - - if (left_mouse_down && left_mouse_click_in_scaler) { - float delta_x = in->mouse.delta.x; - if (layout->flags & NK_WINDOW_SCALE_LEFT) { - delta_x = -delta_x; - window->bounds.x += in->mouse.delta.x; - } - /* dragging in x-direction */ - if (window->bounds.w + delta_x >= window_size.x) { - if ((delta_x < 0) || (delta_x > 0 && in->mouse.pos.x >= scaler.x)) { - window->bounds.w = window->bounds.w + delta_x; - scaler.x += in->mouse.delta.x; - } - } - /* dragging in y-direction (only possible if static window) */ - if (!(layout->flags & NK_WINDOW_DYNAMIC)) { - if (window_size.y < window->bounds.h + in->mouse.delta.y) { - if ((in->mouse.delta.y < 0) || (in->mouse.delta.y > 0 && in->mouse.pos.y >= scaler.y)) { - window->bounds.h = window->bounds.h + in->mouse.delta.y; - scaler.y += in->mouse.delta.y; - } - } - } - ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT]; - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = scaler.x + scaler.w/2.0f; - in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = scaler.y + scaler.h/2.0f; - } - } - } - if (!nk_panel_is_sub(layout->type)) { - /* window is hidden so clear command buffer */ - if (layout->flags & NK_WINDOW_HIDDEN) - nk_command_buffer_reset(&window->buffer); - /* window is visible and not tab */ - else nk_finish(ctx, window); - } - - /* NK_WINDOW_REMOVE_ROM flag was set so remove NK_WINDOW_ROM */ - if (layout->flags & NK_WINDOW_REMOVE_ROM) { - layout->flags &= ~(nk_flags)NK_WINDOW_ROM; - layout->flags &= ~(nk_flags)NK_WINDOW_REMOVE_ROM; - } - window->flags = layout->flags; - - /* property garbage collector */ - if (window->property.active && window->property.old != window->property.seq && - window->property.active == window->property.prev) { - nk_zero(&window->property, sizeof(window->property)); - } else { - window->property.old = window->property.seq; - window->property.prev = window->property.active; - window->property.seq = 0; - } - /* edit garbage collector */ - if (window->edit.active && window->edit.old != window->edit.seq && - window->edit.active == window->edit.prev) { - nk_zero(&window->edit, sizeof(window->edit)); - } else { - window->edit.old = window->edit.seq; - window->edit.prev = window->edit.active; - window->edit.seq = 0; - } - /* contextual garbage collector */ - if (window->popup.active_con && window->popup.con_old != window->popup.con_count) { - window->popup.con_count = 0; - window->popup.con_old = 0; - window->popup.active_con = 0; - } else { - window->popup.con_old = window->popup.con_count; - window->popup.con_count = 0; - } - window->popup.combo_count = 0; - /* helper to make sure you have a 'nk_tree_push' for every 'nk_tree_pop' */ - NK_ASSERT(!layout->row.tree_depth); -} - -/* ---------------------------------------------------------------- - * - * PAGE ELEMENT - * - * ---------------------------------------------------------------*/ -NK_INTERN struct nk_page_element* -nk_create_page_element(struct nk_context *ctx) -{ - struct nk_page_element *elem; - if (ctx->freelist) { - /* unlink page element from free list */ - elem = ctx->freelist; - ctx->freelist = elem->next; - } else if (ctx->use_pool) { - /* allocate page element from memory pool */ - elem = nk_pool_alloc(&ctx->pool); - NK_ASSERT(elem); - if (!elem) return 0; - } else { - /* allocate new page element from back of fixed size memory buffer */ - NK_STORAGE const nk_size size = sizeof(struct nk_page_element); - NK_STORAGE const nk_size align = NK_ALIGNOF(struct nk_page_element); - elem = (struct nk_page_element*)nk_buffer_alloc(&ctx->memory, NK_BUFFER_BACK, size, align); - NK_ASSERT(elem); - if (!elem) return 0; - } - nk_zero_struct(*elem); - elem->next = 0; - elem->prev = 0; - return elem; -} - -NK_INTERN void -nk_link_page_element_into_freelist(struct nk_context *ctx, - struct nk_page_element *elem) -{ - /* link table into freelist */ - if (!ctx->freelist) { - ctx->freelist = elem; - } else { - elem->next = ctx->freelist; - ctx->freelist = elem; - } -} - -NK_INTERN void -nk_free_page_element(struct nk_context *ctx, struct nk_page_element *elem) -{ - /* we have a pool so just add to free list */ - if (ctx->use_pool) { - nk_link_page_element_into_freelist(ctx, elem); - return; - } - /* if possible remove last element from back of fixed memory buffer */ - {void *elem_end = (void*)(elem + 1); - void *buffer_end = (nk_byte*)ctx->memory.memory.ptr + ctx->memory.size; - if (elem_end == buffer_end) - ctx->memory.size -= sizeof(struct nk_page_element); - else nk_link_page_element_into_freelist(ctx, elem);} -} - -/* ---------------------------------------------------------------- - * - * PANEL - * - * ---------------------------------------------------------------*/ -NK_INTERN void* -nk_create_panel(struct nk_context *ctx) -{ - struct nk_page_element *elem; - elem = nk_create_page_element(ctx); - if (!elem) return 0; - nk_zero_struct(*elem); - return &elem->data.pan; -} - -NK_INTERN void -nk_free_panel(struct nk_context *ctx, struct nk_panel *pan) -{ - union nk_page_data *pd = NK_CONTAINER_OF(pan, union nk_page_data, pan); - struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data); - nk_free_page_element(ctx, pe); -} - -/* ---------------------------------------------------------------- - * - * TABLES - * - * ---------------------------------------------------------------*/ -NK_INTERN struct nk_table* -nk_create_table(struct nk_context *ctx) -{ - struct nk_page_element *elem; - elem = nk_create_page_element(ctx); - if (!elem) return 0; - nk_zero_struct(*elem); - return &elem->data.tbl; -} - -NK_INTERN void -nk_free_table(struct nk_context *ctx, struct nk_table *tbl) -{ - union nk_page_data *pd = NK_CONTAINER_OF(tbl, union nk_page_data, tbl); - struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data); - nk_free_page_element(ctx, pe); -} - -NK_INTERN void -nk_push_table(struct nk_window *win, struct nk_table *tbl) -{ - if (!win->tables) { - win->tables = tbl; - tbl->next = 0; - tbl->prev = 0; - tbl->size = 0; - win->table_count = 1; - return; - } - win->tables->prev = tbl; - tbl->next = win->tables; - tbl->prev = 0; - tbl->size = 0; - win->tables = tbl; - win->table_count++; -} - -NK_INTERN void -nk_remove_table(struct nk_window *win, struct nk_table *tbl) -{ - if (win->tables == tbl) - win->tables = tbl->next; - if (tbl->next) - tbl->next->prev = tbl->prev; - if (tbl->prev) - tbl->prev->next = tbl->next; - tbl->next = 0; - tbl->prev = 0; -} - -NK_INTERN nk_uint* -nk_add_value(struct nk_context *ctx, struct nk_window *win, - nk_hash name, nk_uint value) -{ - NK_ASSERT(ctx); - NK_ASSERT(win); - if (!win || !ctx) return 0; - if (!win->tables || win->tables->size >= NK_VALUE_PAGE_CAPACITY) { - struct nk_table *tbl = nk_create_table(ctx); - NK_ASSERT(tbl); - if (!tbl) return 0; - nk_push_table(win, tbl); - } - win->tables->seq = win->seq; - win->tables->keys[win->tables->size] = name; - win->tables->values[win->tables->size] = value; - return &win->tables->values[win->tables->size++]; -} - -NK_INTERN nk_uint* -nk_find_value(struct nk_window *win, nk_hash name) -{ - struct nk_table *iter = win->tables; - while (iter) { - unsigned int i = 0; - unsigned int size = iter->size; - for (i = 0; i < size; ++i) { - if (iter->keys[i] == name) { - iter->seq = win->seq; - return &iter->values[i]; - } - } size = NK_VALUE_PAGE_CAPACITY; - iter = iter->next; - } - return 0; -} - -/* ---------------------------------------------------------------- - * - * WINDOW - * - * ---------------------------------------------------------------*/ -NK_INTERN void* -nk_create_window(struct nk_context *ctx) -{ - struct nk_page_element *elem; - elem = nk_create_page_element(ctx); - if (!elem) return 0; - elem->data.win.seq = ctx->seq; - return &elem->data.win; -} - -NK_INTERN void -nk_free_window(struct nk_context *ctx, struct nk_window *win) -{ - /* unlink windows from list */ - struct nk_table *it = win->tables; - if (win->popup.win) { - nk_free_window(ctx, win->popup.win); - win->popup.win = 0; - } - win->next = 0; - win->prev = 0; - - while (it) { - /*free window state tables */ - struct nk_table *n = it->next; - nk_remove_table(win, it); - nk_free_table(ctx, it); - if (it == win->tables) - win->tables = n; - it = n; - } - - /* link windows into freelist */ - {union nk_page_data *pd = NK_CONTAINER_OF(win, union nk_page_data, win); - struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data); - nk_free_page_element(ctx, pe);} -} - -NK_INTERN struct nk_window* -nk_find_window(struct nk_context *ctx, nk_hash hash, const char *name) -{ - struct nk_window *iter; - iter = ctx->begin; - while (iter) { - NK_ASSERT(iter != iter->next); - if (iter->name == hash) { - int max_len = nk_strlen(iter->name_string); - if (!nk_stricmpn(iter->name_string, name, max_len)) - return iter; - } - iter = iter->next; - } - return 0; -} - -enum nk_window_insert_location { - NK_INSERT_BACK, /* inserts window into the back of list (front of screen) */ - NK_INSERT_FRONT /* inserts window into the front of list (back of screen) */ -}; -NK_INTERN void -nk_insert_window(struct nk_context *ctx, struct nk_window *win, - enum nk_window_insert_location loc) -{ - const struct nk_window *iter; - NK_ASSERT(ctx); - NK_ASSERT(win); - if (!win || !ctx) return; - - iter = ctx->begin; - while (iter) { - NK_ASSERT(iter != iter->next); - NK_ASSERT(iter != win); - if (iter == win) return; - iter = iter->next; - } - - if (!ctx->begin) { - win->next = 0; - win->prev = 0; - ctx->begin = win; - ctx->end = win; - ctx->count = 1; - return; - } - if (loc == NK_INSERT_BACK) { - struct nk_window *end; - end = ctx->end; - end->flags |= NK_WINDOW_ROM; - end->next = win; - win->prev = ctx->end; - win->next = 0; - ctx->end = win; - ctx->active = ctx->end; - ctx->end->flags &= ~(nk_flags)NK_WINDOW_ROM; - } else { - /*ctx->end->flags |= NK_WINDOW_ROM;*/ - ctx->begin->prev = win; - win->next = ctx->begin; - win->prev = 0; - ctx->begin = win; - ctx->begin->flags &= ~(nk_flags)NK_WINDOW_ROM; - } - ctx->count++; -} - -NK_INTERN void -nk_remove_window(struct nk_context *ctx, struct nk_window *win) -{ - if (win == ctx->begin || win == ctx->end) { - if (win == ctx->begin) { - ctx->begin = win->next; - if (win->next) - win->next->prev = 0; - } - if (win == ctx->end) { - ctx->end = win->prev; - if (win->prev) - win->prev->next = 0; - } - } else { - if (win->next) - win->next->prev = win->prev; - if (win->prev) - win->prev->next = win->next; - } - if (win == ctx->active || !ctx->active) { - ctx->active = ctx->end; - if (ctx->end) - ctx->end->flags &= ~(nk_flags)NK_WINDOW_ROM; - } - win->next = 0; - win->prev = 0; - ctx->count--; -} - -NK_API int -nk_begin(struct nk_context *ctx, const char *title, - struct nk_rect bounds, nk_flags flags) -{ - return nk_begin_titled(ctx, title, title, bounds, flags); -} - -NK_API int -nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, - struct nk_rect bounds, nk_flags flags) -{ - struct nk_window *win; - struct nk_style *style; - nk_hash title_hash; - int title_len; - int ret = 0; - - NK_ASSERT(ctx); - NK_ASSERT(name); - NK_ASSERT(title); - NK_ASSERT(ctx->style.font && ctx->style.font->width && "if this triggers you forgot to add a font"); - NK_ASSERT(!ctx->current && "if this triggers you missed a `nk_end` call"); - if (!ctx || ctx->current || !title || !name) - return 0; - - /* find or create window */ - style = &ctx->style; - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (!win) { - /* create new window */ - nk_size name_length = (nk_size)nk_strlen(name); - win = (struct nk_window*)nk_create_window(ctx); - NK_ASSERT(win); - if (!win) return 0; - - if (flags & NK_WINDOW_BACKGROUND) - nk_insert_window(ctx, win, NK_INSERT_FRONT); - else nk_insert_window(ctx, win, NK_INSERT_BACK); - nk_command_buffer_init(&win->buffer, &ctx->memory, NK_CLIPPING_ON); - - win->flags = flags; - win->bounds = bounds; - win->name = title_hash; - name_length = NK_MIN(name_length, NK_WINDOW_MAX_NAME-1); - NK_MEMCPY(win->name_string, name, name_length); - win->name_string[name_length] = 0; - win->popup.win = 0; - if (!ctx->active) - ctx->active = win; - } else { - /* update window */ - win->flags &= ~(nk_flags)(NK_WINDOW_PRIVATE-1); - win->flags |= flags; - if (!(win->flags & (NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE))) - win->bounds = bounds; - /* If this assert triggers you either: - * - * I.) Have more than one window with the same name or - * II.) You forgot to actually draw the window. - * More specific you did not call `nk_clear` (nk_clear will be - * automatically called for you if you are using one of the - * provided demo backends). */ - NK_ASSERT(win->seq != ctx->seq); - win->seq = ctx->seq; - if (!ctx->active && !(win->flags & NK_WINDOW_HIDDEN)) { - ctx->active = win; - ctx->end = win; - } - } - if (win->flags & NK_WINDOW_HIDDEN) { - ctx->current = win; - win->layout = 0; - return 0; - } else nk_start(ctx, win); - - /* window overlapping */ - if (!(win->flags & NK_WINDOW_HIDDEN) && !(win->flags & NK_WINDOW_NO_INPUT)) - { - int inpanel, ishovered; - struct nk_window *iter = win; - float h = ctx->style.font->height + 2.0f * style->window.header.padding.y + - (2.0f * style->window.header.label_padding.y); - struct nk_rect win_bounds = (!(win->flags & NK_WINDOW_MINIMIZED))? - win->bounds: nk_rect(win->bounds.x, win->bounds.y, win->bounds.w, h); - - /* activate window if hovered and no other window is overlapping this window */ - inpanel = nk_input_has_mouse_click_down_in_rect(&ctx->input, NK_BUTTON_LEFT, win_bounds, nk_true); - inpanel = inpanel && ctx->input.mouse.buttons[NK_BUTTON_LEFT].clicked; - ishovered = nk_input_is_mouse_hovering_rect(&ctx->input, win_bounds); - if ((win != ctx->active) && ishovered && !ctx->input.mouse.buttons[NK_BUTTON_LEFT].down) { - iter = win->next; - while (iter) { - struct nk_rect iter_bounds = (!(iter->flags & NK_WINDOW_MINIMIZED))? - iter->bounds: nk_rect(iter->bounds.x, iter->bounds.y, iter->bounds.w, h); - if (NK_INTERSECT(win_bounds.x, win_bounds.y, win_bounds.w, win_bounds.h, - iter_bounds.x, iter_bounds.y, iter_bounds.w, iter_bounds.h) && - (!(iter->flags & NK_WINDOW_HIDDEN))) - break; - - if (iter->popup.win && iter->popup.active && !(iter->flags & NK_WINDOW_HIDDEN) && - NK_INTERSECT(win->bounds.x, win_bounds.y, win_bounds.w, win_bounds.h, - iter->popup.win->bounds.x, iter->popup.win->bounds.y, - iter->popup.win->bounds.w, iter->popup.win->bounds.h)) - break; - iter = iter->next; - } - } - - /* activate window if clicked */ - if (iter && inpanel && (win != ctx->end)) { - iter = win->next; - while (iter) { - /* try to find a panel with higher priority in the same position */ - struct nk_rect iter_bounds = (!(iter->flags & NK_WINDOW_MINIMIZED))? - iter->bounds: nk_rect(iter->bounds.x, iter->bounds.y, iter->bounds.w, h); - if (NK_INBOX(ctx->input.mouse.pos.x, ctx->input.mouse.pos.y, - iter_bounds.x, iter_bounds.y, iter_bounds.w, iter_bounds.h) && - !(iter->flags & NK_WINDOW_HIDDEN)) - break; - if (iter->popup.win && iter->popup.active && !(iter->flags & NK_WINDOW_HIDDEN) && - NK_INTERSECT(win_bounds.x, win_bounds.y, win_bounds.w, win_bounds.h, - iter->popup.win->bounds.x, iter->popup.win->bounds.y, - iter->popup.win->bounds.w, iter->popup.win->bounds.h)) - break; - iter = iter->next; - } - } - if (iter && !(win->flags & NK_WINDOW_ROM) && (win->flags & NK_WINDOW_BACKGROUND)) { - win->flags |= (nk_flags)NK_WINDOW_ROM; - iter->flags &= ~(nk_flags)NK_WINDOW_ROM; - ctx->active = iter; - if (!(iter->flags & NK_WINDOW_BACKGROUND)) { - /* current window is active in that position so transfer to top - * at the highest priority in stack */ - nk_remove_window(ctx, iter); - nk_insert_window(ctx, iter, NK_INSERT_BACK); - } - } else { - if (!iter && ctx->end != win) { - if (!(win->flags & NK_WINDOW_BACKGROUND)) { - /* current window is active in that position so transfer to top - * at the highest priority in stack */ - nk_remove_window(ctx, win); - nk_insert_window(ctx, win, NK_INSERT_BACK); - } - win->flags &= ~(nk_flags)NK_WINDOW_ROM; - ctx->active = win; - } - if (ctx->end != win && !(win->flags & NK_WINDOW_BACKGROUND)) - win->flags |= NK_WINDOW_ROM; - } - } - win->layout = (struct nk_panel*)nk_create_panel(ctx); - ctx->current = win; - ret = nk_panel_begin(ctx, title, NK_PANEL_WINDOW); - win->layout->offset_x = &win->scrollbar.x; - win->layout->offset_y = &win->scrollbar.y; - return ret; -} - -NK_API void -nk_end(struct nk_context *ctx) -{ - struct nk_panel *layout; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current && "if this triggers you forgot to call `nk_begin`"); - if (!ctx || !ctx->current) - return; - - layout = ctx->current->layout; - if (!layout || (layout->type == NK_PANEL_WINDOW && (ctx->current->flags & NK_WINDOW_HIDDEN))) { - ctx->current = 0; - return; - } - nk_panel_end(ctx); - nk_free_panel(ctx, ctx->current->layout); - ctx->current = 0; -} - -NK_API struct nk_rect -nk_window_get_bounds(const struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return nk_rect(0,0,0,0); - return ctx->current->bounds; -} - -NK_API struct nk_vec2 -nk_window_get_position(const struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return nk_vec2(0,0); - return nk_vec2(ctx->current->bounds.x, ctx->current->bounds.y); -} - -NK_API struct nk_vec2 -nk_window_get_size(const struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return nk_vec2(0,0); - return nk_vec2(ctx->current->bounds.w, ctx->current->bounds.h); -} - -NK_API float -nk_window_get_width(const struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return 0; - return ctx->current->bounds.w; -} - -NK_API float -nk_window_get_height(const struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return 0; - return ctx->current->bounds.h; -} - -NK_API struct nk_rect -nk_window_get_content_region(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return nk_rect(0,0,0,0); - return ctx->current->layout->clip; -} - -NK_API struct nk_vec2 -nk_window_get_content_region_min(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current) return nk_vec2(0,0); - return nk_vec2(ctx->current->layout->clip.x, ctx->current->layout->clip.y); -} - -NK_API struct nk_vec2 -nk_window_get_content_region_max(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current) return nk_vec2(0,0); - return nk_vec2(ctx->current->layout->clip.x + ctx->current->layout->clip.w, - ctx->current->layout->clip.y + ctx->current->layout->clip.h); -} - -NK_API struct nk_vec2 -nk_window_get_content_region_size(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current) return nk_vec2(0,0); - return nk_vec2(ctx->current->layout->clip.w, ctx->current->layout->clip.h); -} - -NK_API struct nk_command_buffer* -nk_window_get_canvas(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current) return 0; - return &ctx->current->buffer; -} - -NK_API struct nk_panel* -nk_window_get_panel(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return 0; - return ctx->current->layout; -} - -NK_API int -nk_window_has_focus(const struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current) return 0; - return ctx->current == ctx->active; -} - -NK_API int -nk_window_is_hovered(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return 0; - if(ctx->current->flags & NK_WINDOW_HIDDEN) - return 0; - return nk_input_is_mouse_hovering_rect(&ctx->input, ctx->current->bounds); -} - -NK_API int -nk_window_is_any_hovered(struct nk_context *ctx) -{ - struct nk_window *iter; - NK_ASSERT(ctx); - if (!ctx) return 0; - iter = ctx->begin; - while (iter) { - /* check if window is being hovered */ - if(!(iter->flags & NK_WINDOW_HIDDEN)) { - /* check if window popup is being hovered */ - if (iter->popup.active && iter->popup.win && nk_input_is_mouse_hovering_rect(&ctx->input, iter->popup.win->bounds)) - return 1; - - if (iter->flags & NK_WINDOW_MINIMIZED) { - struct nk_rect header = iter->bounds; - header.h = ctx->style.font->height + 2 * ctx->style.window.header.padding.y; - if (nk_input_is_mouse_hovering_rect(&ctx->input, header)) - return 1; - } else if (nk_input_is_mouse_hovering_rect(&ctx->input, iter->bounds)) { - return 1; - } - } - iter = iter->next; - } - return 0; -} - -NK_API int -nk_item_is_any_active(struct nk_context *ctx) -{ - int any_hovered = nk_window_is_any_hovered(ctx); - int any_active = (ctx->last_widget_state & NK_WIDGET_STATE_MODIFIED); - return any_hovered || any_active; -} - -NK_API int -nk_window_is_collapsed(struct nk_context *ctx, const char *name) -{ - int title_len; - nk_hash title_hash; - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return 0; - - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (!win) return 0; - return win->flags & NK_WINDOW_MINIMIZED; -} - -NK_API int -nk_window_is_closed(struct nk_context *ctx, const char *name) -{ - int title_len; - nk_hash title_hash; - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return 1; - - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (!win) return 1; - return (win->flags & NK_WINDOW_CLOSED); -} - -NK_API int -nk_window_is_hidden(struct nk_context *ctx, const char *name) -{ - int title_len; - nk_hash title_hash; - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return 1; - - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (!win) return 1; - return (win->flags & NK_WINDOW_HIDDEN); -} - -NK_API int -nk_window_is_active(struct nk_context *ctx, const char *name) -{ - int title_len; - nk_hash title_hash; - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return 0; - - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (!win) return 0; - return win == ctx->active; -} - -NK_API struct nk_window* -nk_window_find(struct nk_context *ctx, const char *name) -{ - int title_len; - nk_hash title_hash; - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - return nk_find_window(ctx, title_hash, name); -} - -NK_API void -nk_window_close(struct nk_context *ctx, const char *name) -{ - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return; - win = nk_window_find(ctx, name); - if (!win) return; - NK_ASSERT(ctx->current != win && "You cannot close a currently active window"); - if (ctx->current == win) return; - win->flags |= NK_WINDOW_HIDDEN; - win->flags |= NK_WINDOW_CLOSED; -} - -NK_API void -nk_window_set_bounds(struct nk_context *ctx, - const char *name, struct nk_rect bounds) -{ - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return; - win = nk_window_find(ctx, name); - if (!win) return; - NK_ASSERT(ctx->current != win && "You cannot update a currently in procecss window"); - win->bounds = bounds; -} - -NK_API void -nk_window_set_position(struct nk_context *ctx, - const char *name, struct nk_vec2 pos) -{ - struct nk_window *win = nk_window_find(ctx, name); - if (!win) return; - win->bounds.x = pos.x; - win->bounds.y = pos.y; -} - -NK_API void -nk_window_set_size(struct nk_context *ctx, - const char *name, struct nk_vec2 size) -{ - struct nk_window *win = nk_window_find(ctx, name); - if (!win) return; - win->bounds.w = size.x; - win->bounds.h = size.y; -} - -NK_API void -nk_window_collapse(struct nk_context *ctx, const char *name, - enum nk_collapse_states c) -{ - int title_len; - nk_hash title_hash; - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return; - - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (!win) return; - if (c == NK_MINIMIZED) - win->flags |= NK_WINDOW_MINIMIZED; - else win->flags &= ~(nk_flags)NK_WINDOW_MINIMIZED; -} - -NK_API void -nk_window_collapse_if(struct nk_context *ctx, const char *name, - enum nk_collapse_states c, int cond) -{ - NK_ASSERT(ctx); - if (!ctx || !cond) return; - nk_window_collapse(ctx, name, c); -} - -NK_API void -nk_window_show(struct nk_context *ctx, const char *name, enum nk_show_states s) -{ - int title_len; - nk_hash title_hash; - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return; - - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (!win) return; - if (s == NK_HIDDEN) { - win->flags |= NK_WINDOW_HIDDEN; - } else win->flags &= ~(nk_flags)NK_WINDOW_HIDDEN; -} - -NK_API void -nk_window_show_if(struct nk_context *ctx, const char *name, - enum nk_show_states s, int cond) -{ - NK_ASSERT(ctx); - if (!ctx || !cond) return; - nk_window_show(ctx, name, s); -} - -NK_API void -nk_window_set_focus(struct nk_context *ctx, const char *name) -{ - int title_len; - nk_hash title_hash; - struct nk_window *win; - NK_ASSERT(ctx); - if (!ctx) return; - - title_len = (int)nk_strlen(name); - title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE); - win = nk_find_window(ctx, title_hash, name); - if (win && ctx->end != win) { - nk_remove_window(ctx, win); - nk_insert_window(ctx, win, NK_INSERT_BACK); - } - ctx->active = win; -} - -/*---------------------------------------------------------------- - * - * MENUBAR - * - * --------------------------------------------------------------*/ -NK_API void -nk_menubar_begin(struct nk_context *ctx) -{ - struct nk_panel *layout; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - layout = ctx->current->layout; - NK_ASSERT(layout->at_y == layout->bounds.y); - /* if this assert triggers you allocated space between nk_begin and nk_menubar_begin. - If you want a menubar the first nuklear function after `nk_begin` has to be a - `nk_menubar_begin` call. Inside the menubar you then have to allocate space for - widgets (also supports multiple rows). - Example: - if (nk_begin(...)) { - nk_menubar_begin(...); - nk_layout_xxxx(...); - nk_button(...); - nk_layout_xxxx(...); - nk_button(...); - nk_menubar_end(...); - } - nk_end(...); - */ - if (layout->flags & NK_WINDOW_HIDDEN || layout->flags & NK_WINDOW_MINIMIZED) - return; - - layout->menu.x = layout->at_x; - layout->menu.y = layout->at_y + layout->row.height; - layout->menu.w = layout->bounds.w; - layout->menu.offset.x = *layout->offset_x; - layout->menu.offset.y = *layout->offset_y; - *layout->offset_y = 0; -} - -NK_API void -nk_menubar_end(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *layout; - struct nk_command_buffer *out; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - out = &win->buffer; - layout = win->layout; - if (layout->flags & NK_WINDOW_HIDDEN || layout->flags & NK_WINDOW_MINIMIZED) - return; - - layout->menu.h = layout->at_y - layout->menu.y; - layout->bounds.y += layout->menu.h + ctx->style.window.spacing.y + layout->row.height; - layout->bounds.h -= layout->menu.h + ctx->style.window.spacing.y + layout->row.height; - - *layout->offset_x = layout->menu.offset.x; - *layout->offset_y = layout->menu.offset.y; - layout->at_y = layout->bounds.y - layout->row.height; - - layout->clip.y = layout->bounds.y; - layout->clip.h = layout->bounds.h; - nk_push_scissor(out, layout->clip); -} -/* ------------------------------------------------------------- - * - * LAYOUT - * - * --------------------------------------------------------------*/ -NK_API void -nk_layout_set_min_row_height(struct nk_context *ctx, float height) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - layout->row.min_height = height; -} - -NK_API void -nk_layout_reset_min_row_height(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - layout->row.min_height = ctx->style.font->height; - layout->row.min_height += ctx->style.text.padding.y*2; - layout->row.min_height += ctx->style.window.min_row_height_padding*2; -} - -NK_INTERN float -nk_layout_row_calculate_usable_space(const struct nk_style *style, enum nk_panel_type type, - float total_space, int columns) -{ - float panel_padding; - float panel_spacing; - float panel_space; - - struct nk_vec2 spacing; - struct nk_vec2 padding; - - spacing = style->window.spacing; - padding = nk_panel_get_padding(style, type); - - /* calculate the usable panel space */ - panel_padding = 2 * padding.x; - panel_spacing = (float)NK_MAX(columns - 1, 0) * spacing.x; - panel_space = total_space - panel_padding - panel_spacing; - return panel_space; -} - -NK_INTERN void -nk_panel_layout(const struct nk_context *ctx, struct nk_window *win, - float height, int cols) -{ - struct nk_panel *layout; - const struct nk_style *style; - struct nk_command_buffer *out; - - struct nk_vec2 item_spacing; - struct nk_color color; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - /* prefetch some configuration data */ - layout = win->layout; - style = &ctx->style; - out = &win->buffer; - color = style->window.background; - item_spacing = style->window.spacing; - - /* if one of these triggers you forgot to add an `if` condition around either - a window, group, popup, combobox or contextual menu `begin` and `end` block. - Example: - if (nk_begin(...) {...} nk_end(...); or - if (nk_group_begin(...) { nk_group_end(...);} */ - NK_ASSERT(!(layout->flags & NK_WINDOW_MINIMIZED)); - NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN)); - NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED)); - - /* update the current row and set the current row layout */ - layout->row.index = 0; - layout->at_y += layout->row.height; - layout->row.columns = cols; - if (height == 0.0f) - layout->row.height = NK_MAX(height, layout->row.min_height) + item_spacing.y; - else layout->row.height = height + item_spacing.y; - - layout->row.item_offset = 0; - if (layout->flags & NK_WINDOW_DYNAMIC) { - /* draw background for dynamic panels */ - struct nk_rect background; - background.x = win->bounds.x; - background.w = win->bounds.w; - background.y = layout->at_y - 1.0f; - background.h = layout->row.height + 1.0f; - nk_fill_rect(out, background, 0, color); - } -} - -NK_INTERN void -nk_row_layout(struct nk_context *ctx, enum nk_layout_format fmt, - float height, int cols, int width) -{ - /* update the current row and set the current row layout */ - struct nk_window *win; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - nk_panel_layout(ctx, win, height, cols); - if (fmt == NK_DYNAMIC) - win->layout->row.type = NK_LAYOUT_DYNAMIC_FIXED; - else win->layout->row.type = NK_LAYOUT_STATIC_FIXED; - - win->layout->row.ratio = 0; - win->layout->row.filled = 0; - win->layout->row.item_offset = 0; - win->layout->row.item_width = (float)width; -} - -NK_API float -nk_layout_ratio_from_pixel(struct nk_context *ctx, float pixel_width) -{ - struct nk_window *win; - NK_ASSERT(ctx); - NK_ASSERT(pixel_width); - if (!ctx || !ctx->current || !ctx->current->layout) return 0; - win = ctx->current; - return NK_CLAMP(0.0f, pixel_width/win->bounds.x, 1.0f); -} - -NK_API void -nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols) -{ - nk_row_layout(ctx, NK_DYNAMIC, height, cols, 0); -} - -NK_API void -nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols) -{ - nk_row_layout(ctx, NK_STATIC, height, cols, item_width); -} - -NK_API void -nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt, - float row_height, int cols) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - nk_panel_layout(ctx, win, row_height, cols); - if (fmt == NK_DYNAMIC) - layout->row.type = NK_LAYOUT_DYNAMIC_ROW; - else layout->row.type = NK_LAYOUT_STATIC_ROW; - - layout->row.ratio = 0; - layout->row.filled = 0; - layout->row.item_width = 0; - layout->row.item_offset = 0; - layout->row.columns = cols; -} - -NK_API void -nk_layout_row_push(struct nk_context *ctx, float ratio_or_width) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - NK_ASSERT(layout->row.type == NK_LAYOUT_STATIC_ROW || layout->row.type == NK_LAYOUT_DYNAMIC_ROW); - if (layout->row.type != NK_LAYOUT_STATIC_ROW && layout->row.type != NK_LAYOUT_DYNAMIC_ROW) - return; - - if (layout->row.type == NK_LAYOUT_DYNAMIC_ROW) { - float ratio = ratio_or_width; - if ((ratio + layout->row.filled) > 1.0f) return; - if (ratio > 0.0f) - layout->row.item_width = NK_SATURATE(ratio); - else layout->row.item_width = 1.0f - layout->row.filled; - } else layout->row.item_width = ratio_or_width; -} - -NK_API void -nk_layout_row_end(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - NK_ASSERT(layout->row.type == NK_LAYOUT_STATIC_ROW || layout->row.type == NK_LAYOUT_DYNAMIC_ROW); - if (layout->row.type != NK_LAYOUT_STATIC_ROW && layout->row.type != NK_LAYOUT_DYNAMIC_ROW) - return; - layout->row.item_width = 0; - layout->row.item_offset = 0; -} - -NK_API void -nk_layout_row(struct nk_context *ctx, enum nk_layout_format fmt, - float height, int cols, const float *ratio) -{ - int i; - int n_undef = 0; - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - nk_panel_layout(ctx, win, height, cols); - if (fmt == NK_DYNAMIC) { - /* calculate width of undefined widget ratios */ - float r = 0; - layout->row.ratio = ratio; - for (i = 0; i < cols; ++i) { - if (ratio[i] < 0.0f) - n_undef++; - else r += ratio[i]; - } - r = NK_SATURATE(1.0f - r); - layout->row.type = NK_LAYOUT_DYNAMIC; - layout->row.item_width = (r > 0 && n_undef > 0) ? (r / (float)n_undef):0; - } else { - layout->row.ratio = ratio; - layout->row.type = NK_LAYOUT_STATIC; - layout->row.item_width = 0; - layout->row.item_offset = 0; - } - layout->row.item_offset = 0; - layout->row.filled = 0; -} - -NK_API void -nk_layout_row_template_begin(struct nk_context *ctx, float height) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - nk_panel_layout(ctx, win, height, 1); - layout->row.type = NK_LAYOUT_TEMPLATE; - layout->row.columns = 0; - layout->row.ratio = 0; - layout->row.item_width = 0; - layout->row.item_height = 0; - layout->row.item_offset = 0; - layout->row.filled = 0; - layout->row.item.x = 0; - layout->row.item.y = 0; - layout->row.item.w = 0; - layout->row.item.h = 0; -} - -NK_API void -nk_layout_row_template_push_dynamic(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE); - NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS); - if (layout->row.type != NK_LAYOUT_TEMPLATE) return; - if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return; - layout->row.templates[layout->row.columns++] = -1.0f; -} - -NK_API void -nk_layout_row_template_push_variable(struct nk_context *ctx, float min_width) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE); - NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS); - if (layout->row.type != NK_LAYOUT_TEMPLATE) return; - if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return; - layout->row.templates[layout->row.columns++] = -min_width; -} - -NK_API void -nk_layout_row_template_push_static(struct nk_context *ctx, float width) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE); - NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS); - if (layout->row.type != NK_LAYOUT_TEMPLATE) return; - if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return; - layout->row.templates[layout->row.columns++] = width; -} - -NK_API void -nk_layout_row_template_end(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *layout; - - int i = 0; - int variable_count = 0; - int min_variable_count = 0; - float min_fixed_width = 0.0f; - float total_fixed_width = 0.0f; - float max_variable_width = 0.0f; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE); - if (layout->row.type != NK_LAYOUT_TEMPLATE) return; - for (i = 0; i < layout->row.columns; ++i) { - float width = layout->row.templates[i]; - if (width >= 0.0f) { - total_fixed_width += width; - min_fixed_width += width; - } else if (width < -1.0f) { - width = -width; - total_fixed_width += width; - max_variable_width = NK_MAX(max_variable_width, width); - variable_count++; - } else { - min_variable_count++; - variable_count++; - } - } - if (variable_count) { - float space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type, - layout->bounds.w, layout->row.columns); - float var_width = (NK_MAX(space-min_fixed_width,0.0f)) / (float)variable_count; - int enough_space = var_width >= max_variable_width; - if (!enough_space) - var_width = (NK_MAX(space-total_fixed_width,0)) / (float)min_variable_count; - for (i = 0; i < layout->row.columns; ++i) { - float *width = &layout->row.templates[i]; - *width = (*width >= 0.0f)? *width: (*width < -1.0f && !enough_space)? -(*width): var_width; - } - } -} - -NK_API void -nk_layout_space_begin(struct nk_context *ctx, enum nk_layout_format fmt, - float height, int widget_count) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - nk_panel_layout(ctx, win, height, widget_count); - if (fmt == NK_STATIC) - layout->row.type = NK_LAYOUT_STATIC_FREE; - else layout->row.type = NK_LAYOUT_DYNAMIC_FREE; - - layout->row.ratio = 0; - layout->row.filled = 0; - layout->row.item_width = 0; - layout->row.item_offset = 0; -} - -NK_API void -nk_layout_space_end(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - layout->row.item_width = 0; - layout->row.item_height = 0; - layout->row.item_offset = 0; - nk_zero(&layout->row.item, sizeof(layout->row.item)); -} - -NK_API void -nk_layout_space_push(struct nk_context *ctx, struct nk_rect rect) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - layout->row.item = rect; -} - -NK_API struct nk_rect -nk_layout_space_bounds(struct nk_context *ctx) -{ - struct nk_rect ret; - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - win = ctx->current; - layout = win->layout; - - ret.x = layout->clip.x; - ret.y = layout->clip.y; - ret.w = layout->clip.w; - ret.h = layout->row.height; - return ret; -} - -NK_API struct nk_rect -nk_layout_widget_bounds(struct nk_context *ctx) -{ - struct nk_rect ret; - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - win = ctx->current; - layout = win->layout; - - ret.x = layout->at_x; - ret.y = layout->at_y; - ret.w = layout->bounds.w - NK_MAX(layout->at_x - layout->bounds.x,0); - ret.h = layout->row.height; - return ret; -} - -NK_API struct nk_vec2 -nk_layout_space_to_screen(struct nk_context *ctx, struct nk_vec2 ret) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - win = ctx->current; - layout = win->layout; - - ret.x += layout->at_x - (float)*layout->offset_x; - ret.y += layout->at_y - (float)*layout->offset_y; - return ret; -} - -NK_API struct nk_vec2 -nk_layout_space_to_local(struct nk_context *ctx, struct nk_vec2 ret) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - win = ctx->current; - layout = win->layout; - - ret.x += -layout->at_x + (float)*layout->offset_x; - ret.y += -layout->at_y + (float)*layout->offset_y; - return ret; -} - -NK_API struct nk_rect -nk_layout_space_rect_to_screen(struct nk_context *ctx, struct nk_rect ret) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - win = ctx->current; - layout = win->layout; - - ret.x += layout->at_x - (float)*layout->offset_x; - ret.y += layout->at_y - (float)*layout->offset_y; - return ret; -} - -NK_API struct nk_rect -nk_layout_space_rect_to_local(struct nk_context *ctx, struct nk_rect ret) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - win = ctx->current; - layout = win->layout; - - ret.x += -layout->at_x + (float)*layout->offset_x; - ret.y += -layout->at_y + (float)*layout->offset_y; - return ret; -} - -NK_INTERN void -nk_panel_alloc_row(const struct nk_context *ctx, struct nk_window *win) -{ - struct nk_panel *layout = win->layout; - struct nk_vec2 spacing = ctx->style.window.spacing; - const float row_height = layout->row.height - spacing.y; - nk_panel_layout(ctx, win, row_height, layout->row.columns); -} - -NK_INTERN void -nk_layout_widget_space(struct nk_rect *bounds, const struct nk_context *ctx, - struct nk_window *win, int modify) -{ - struct nk_panel *layout; - const struct nk_style *style; - - struct nk_vec2 spacing; - struct nk_vec2 padding; - - float item_offset = 0; - float item_width = 0; - float item_spacing = 0; - float panel_space = 0; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - style = &ctx->style; - NK_ASSERT(bounds); - - spacing = style->window.spacing; - padding = nk_panel_get_padding(style, layout->type); - panel_space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type, - layout->bounds.w, layout->row.columns); - - /* calculate the width of one item inside the current layout space */ - switch (layout->row.type) { - case NK_LAYOUT_DYNAMIC_FIXED: { - /* scaling fixed size widgets item width */ - item_width = NK_MAX(1.0f,panel_space) / (float)layout->row.columns; - item_offset = (float)layout->row.index * item_width; - item_spacing = (float)layout->row.index * spacing.x; - } break; - case NK_LAYOUT_DYNAMIC_ROW: { - /* scaling single ratio widget width */ - item_width = layout->row.item_width * panel_space; - item_offset = layout->row.item_offset; - item_spacing = 0; - - if (modify) { - layout->row.item_offset += item_width + spacing.x; - layout->row.filled += layout->row.item_width; - layout->row.index = 0; - } - } break; - case NK_LAYOUT_DYNAMIC_FREE: { - /* panel width depended free widget placing */ - bounds->x = layout->at_x + (layout->bounds.w * layout->row.item.x); - bounds->x -= (float)*layout->offset_x; - bounds->y = layout->at_y + (layout->row.height * layout->row.item.y); - bounds->y -= (float)*layout->offset_y; - bounds->w = layout->bounds.w * layout->row.item.w; - bounds->h = layout->row.height * layout->row.item.h; - return; - } break; - case NK_LAYOUT_DYNAMIC: { - /* scaling arrays of panel width ratios for every widget */ - float ratio; - NK_ASSERT(layout->row.ratio); - ratio = (layout->row.ratio[layout->row.index] < 0) ? - layout->row.item_width : layout->row.ratio[layout->row.index]; - - item_spacing = (float)layout->row.index * spacing.x; - item_width = (ratio * panel_space); - item_offset = layout->row.item_offset; - - if (modify) { - layout->row.item_offset += item_width; - layout->row.filled += ratio; - } - } break; - case NK_LAYOUT_STATIC_FIXED: { - /* non-scaling fixed widgets item width */ - item_width = layout->row.item_width; - item_offset = (float)layout->row.index * item_width; - item_spacing = (float)layout->row.index * spacing.x; - } break; - case NK_LAYOUT_STATIC_ROW: { - /* scaling single ratio widget width */ - item_width = layout->row.item_width; - item_offset = layout->row.item_offset; - item_spacing = (float)layout->row.index * spacing.x; - if (modify) layout->row.item_offset += item_width; - } break; - case NK_LAYOUT_STATIC_FREE: { - /* free widget placing */ - bounds->x = layout->at_x + layout->row.item.x; - bounds->w = layout->row.item.w; - if (((bounds->x + bounds->w) > layout->max_x) && modify) - layout->max_x = (bounds->x + bounds->w); - bounds->x -= (float)*layout->offset_x; - bounds->y = layout->at_y + layout->row.item.y; - bounds->y -= (float)*layout->offset_y; - bounds->h = layout->row.item.h; - return; - } break; - case NK_LAYOUT_STATIC: { - /* non-scaling array of panel pixel width for every widget */ - item_spacing = (float)layout->row.index * spacing.x; - item_width = layout->row.ratio[layout->row.index]; - item_offset = layout->row.item_offset; - if (modify) layout->row.item_offset += item_width; - } break; - case NK_LAYOUT_TEMPLATE: { - /* stretchy row layout with combined dynamic/static widget width*/ - NK_ASSERT(layout->row.index < layout->row.columns); - NK_ASSERT(layout->row.index < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS); - item_width = layout->row.templates[layout->row.index]; - item_offset = layout->row.item_offset; - item_spacing = (float)layout->row.index * spacing.x; - if (modify) layout->row.item_offset += item_width; - } break; - default: NK_ASSERT(0); break; - }; - - /* set the bounds of the newly allocated widget */ - bounds->w = item_width; - bounds->h = layout->row.height - spacing.y; - bounds->y = layout->at_y - (float)*layout->offset_y; - bounds->x = layout->at_x + item_offset + item_spacing + padding.x; - if (((bounds->x + bounds->w) > layout->max_x) && modify) - layout->max_x = bounds->x + bounds->w; - bounds->x -= (float)*layout->offset_x; -} - -NK_INTERN void -nk_panel_alloc_space(struct nk_rect *bounds, const struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - /* check if the end of the row has been hit and begin new row if so */ - win = ctx->current; - layout = win->layout; - if (layout->row.index >= layout->row.columns) - nk_panel_alloc_row(ctx, win); - - /* calculate widget position and size */ - nk_layout_widget_space(bounds, ctx, win, nk_true); - layout->row.index++; -} - -NK_INTERN void -nk_layout_peek(struct nk_rect *bounds, struct nk_context *ctx) -{ - float y; - int index; - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - y = layout->at_y; - index = layout->row.index; - if (layout->row.index >= layout->row.columns) { - layout->at_y += layout->row.height; - layout->row.index = 0; - } - nk_layout_widget_space(bounds, ctx, win, nk_false); - if (!layout->row.index) { - bounds->x -= layout->row.item_offset; - } - layout->at_y = y; - layout->row.index = index; -} - -NK_INTERN int -nk_tree_state_base(struct nk_context *ctx, enum nk_tree_type type, - struct nk_image *img, const char *title, enum nk_collapse_states *state) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_style *style; - struct nk_command_buffer *out; - const struct nk_input *in; - const struct nk_style_button *button; - enum nk_symbol_type symbol; - float row_height; - - struct nk_vec2 item_spacing; - struct nk_rect header = {0,0,0,0}; - struct nk_rect sym = {0,0,0,0}; - struct nk_text text; - - nk_flags ws = 0; - enum nk_widget_layout_states widget_state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - /* cache some data */ - win = ctx->current; - layout = win->layout; - out = &win->buffer; - style = &ctx->style; - item_spacing = style->window.spacing; - - /* calculate header bounds and draw background */ - row_height = style->font->height + 2 * style->tab.padding.y; - nk_layout_set_min_row_height(ctx, row_height); - nk_layout_row_dynamic(ctx, row_height, 1); - nk_layout_reset_min_row_height(ctx); - - widget_state = nk_widget(&header, ctx); - if (type == NK_TREE_TAB) { - const struct nk_style_item *background = &style->tab.background; - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(out, header, &background->data.image, nk_white); - text.background = nk_rgba(0,0,0,0); - } else { - text.background = background->data.color; - nk_fill_rect(out, header, 0, style->tab.border_color); - nk_fill_rect(out, nk_shrink_rect(header, style->tab.border), - style->tab.rounding, background->data.color); - } - } else text.background = style->window.background; - - /* update node state */ - in = (!(layout->flags & NK_WINDOW_ROM)) ? &ctx->input: 0; - in = (in && widget_state == NK_WIDGET_VALID) ? &ctx->input : 0; - if (nk_button_behavior(&ws, header, in, NK_BUTTON_DEFAULT)) - *state = (*state == NK_MAXIMIZED) ? NK_MINIMIZED : NK_MAXIMIZED; - - /* select correct button style */ - if (*state == NK_MAXIMIZED) { - symbol = style->tab.sym_maximize; - if (type == NK_TREE_TAB) - button = &style->tab.tab_maximize_button; - else button = &style->tab.node_maximize_button; - } else { - symbol = style->tab.sym_minimize; - if (type == NK_TREE_TAB) - button = &style->tab.tab_minimize_button; - else button = &style->tab.node_minimize_button; - } - - {/* draw triangle button */ - sym.w = sym.h = style->font->height; - sym.y = header.y + style->tab.padding.y; - sym.x = header.x + style->tab.padding.x; - nk_do_button_symbol(&ws, &win->buffer, sym, symbol, NK_BUTTON_DEFAULT, - button, 0, style->font); - - if (img) { - /* draw optional image icon */ - sym.x = sym.x + sym.w + 4 * item_spacing.x; - nk_draw_image(&win->buffer, sym, img, nk_white); - sym.w = style->font->height + style->tab.spacing.x;} - } - - {/* draw label */ - struct nk_rect label; - header.w = NK_MAX(header.w, sym.w + item_spacing.x); - label.x = sym.x + sym.w + item_spacing.x; - label.y = sym.y; - label.w = header.w - (sym.w + item_spacing.y + style->tab.indent); - label.h = style->font->height; - text.text = style->tab.text; - text.padding = nk_vec2(0,0); - nk_widget_text(out, label, title, nk_strlen(title), &text, - NK_TEXT_LEFT, style->font);} - - /* increase x-axis cursor widget position pointer */ - if (*state == NK_MAXIMIZED) { - layout->at_x = header.x + (float)*layout->offset_x + style->tab.indent; - layout->bounds.w = NK_MAX(layout->bounds.w, style->tab.indent); - layout->bounds.w -= (style->tab.indent + style->window.padding.x); - layout->row.tree_depth++; - return nk_true; - } else return nk_false; -} - -NK_INTERN int -nk_tree_base(struct nk_context *ctx, enum nk_tree_type type, - struct nk_image *img, const char *title, enum nk_collapse_states initial_state, - const char *hash, int len, int line) -{ - struct nk_window *win = ctx->current; - int title_len = 0; - nk_hash tree_hash = 0; - nk_uint *state = 0; - - /* retrieve tree state from internal widget state tables */ - if (!hash) { - title_len = (int)nk_strlen(title); - tree_hash = nk_murmur_hash(title, (int)title_len, (nk_hash)line); - } else tree_hash = nk_murmur_hash(hash, len, (nk_hash)line); - state = nk_find_value(win, tree_hash); - if (!state) { - state = nk_add_value(ctx, win, tree_hash, 0); - *state = initial_state; - } - return nk_tree_state_base(ctx, type, img, title, (enum nk_collapse_states*)state); -} - -NK_API int -nk_tree_state_push(struct nk_context *ctx, enum nk_tree_type type, - const char *title, enum nk_collapse_states *state) -{return nk_tree_state_base(ctx, type, 0, title, state);} - -NK_API int -nk_tree_state_image_push(struct nk_context *ctx, enum nk_tree_type type, - struct nk_image img, const char *title, enum nk_collapse_states *state) -{return nk_tree_state_base(ctx, type, &img, title, state);} - -NK_API void -nk_tree_state_pop(struct nk_context *ctx) -{ - struct nk_window *win = 0; - struct nk_panel *layout = 0; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - layout->at_x -= ctx->style.tab.indent + ctx->style.window.padding.x; - layout->bounds.w += ctx->style.tab.indent + ctx->style.window.padding.x; - NK_ASSERT(layout->row.tree_depth); - layout->row.tree_depth--; -} - -NK_API int -nk_tree_push_hashed(struct nk_context *ctx, enum nk_tree_type type, - const char *title, enum nk_collapse_states initial_state, - const char *hash, int len, int line) -{return nk_tree_base(ctx, type, 0, title, initial_state, hash, len, line);} - -NK_API int -nk_tree_image_push_hashed(struct nk_context *ctx, enum nk_tree_type type, - struct nk_image img, const char *title, enum nk_collapse_states initial_state, - const char *hash, int len,int seed) -{return nk_tree_base(ctx, type, &img, title, initial_state, hash, len, seed);} - -NK_API void -nk_tree_pop(struct nk_context *ctx) -{nk_tree_state_pop(ctx);} - -/*---------------------------------------------------------------- - * - * WIDGETS - * - * --------------------------------------------------------------*/ -NK_API struct nk_rect -nk_widget_bounds(struct nk_context *ctx) -{ - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return nk_rect(0,0,0,0); - nk_layout_peek(&bounds, ctx); - return bounds; -} - -NK_API struct nk_vec2 -nk_widget_position(struct nk_context *ctx) -{ - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return nk_vec2(0,0); - - nk_layout_peek(&bounds, ctx); - return nk_vec2(bounds.x, bounds.y); -} - -NK_API struct nk_vec2 -nk_widget_size(struct nk_context *ctx) -{ - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return nk_vec2(0,0); - - nk_layout_peek(&bounds, ctx); - return nk_vec2(bounds.w, bounds.h); -} - -NK_API float -nk_widget_width(struct nk_context *ctx) -{ - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return 0; - - nk_layout_peek(&bounds, ctx); - return bounds.w; -} - -NK_API float -nk_widget_height(struct nk_context *ctx) -{ - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return 0; - - nk_layout_peek(&bounds, ctx); - return bounds.h; -} - -NK_API int -nk_widget_is_hovered(struct nk_context *ctx) -{ - struct nk_rect c, v; - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current || ctx->active != ctx->current) - return 0; - - c = ctx->current->layout->clip; - c.x = (float)((int)c.x); - c.y = (float)((int)c.y); - c.w = (float)((int)c.w); - c.h = (float)((int)c.h); - - nk_layout_peek(&bounds, ctx); - nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h); - if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h)) - return 0; - return nk_input_is_mouse_hovering_rect(&ctx->input, bounds); -} - -NK_API int -nk_widget_is_mouse_clicked(struct nk_context *ctx, enum nk_buttons btn) -{ - struct nk_rect c, v; - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current || ctx->active != ctx->current) - return 0; - - c = ctx->current->layout->clip; - c.x = (float)((int)c.x); - c.y = (float)((int)c.y); - c.w = (float)((int)c.w); - c.h = (float)((int)c.h); - - nk_layout_peek(&bounds, ctx); - nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h); - if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h)) - return 0; - return nk_input_mouse_clicked(&ctx->input, btn, bounds); -} - -NK_API int -nk_widget_has_mouse_click_down(struct nk_context *ctx, enum nk_buttons btn, int down) -{ - struct nk_rect c, v; - struct nk_rect bounds; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current || ctx->active != ctx->current) - return 0; - - c = ctx->current->layout->clip; - c.x = (float)((int)c.x); - c.y = (float)((int)c.y); - c.w = (float)((int)c.w); - c.h = (float)((int)c.h); - - nk_layout_peek(&bounds, ctx); - nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h); - if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h)) - return 0; - return nk_input_has_mouse_click_down_in_rect(&ctx->input, btn, bounds, down); -} - -NK_API enum nk_widget_layout_states -nk_widget(struct nk_rect *bounds, const struct nk_context *ctx) -{ - struct nk_rect c, v; - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return NK_WIDGET_INVALID; - - /* allocate space and check if the widget needs to be updated and drawn */ - nk_panel_alloc_space(bounds, ctx); - win = ctx->current; - layout = win->layout; - in = &ctx->input; - c = layout->clip; - - /* if one of these triggers you forgot to add an `if` condition around either - a window, group, popup, combobox or contextual menu `begin` and `end` block. - Example: - if (nk_begin(...) {...} nk_end(...); or - if (nk_group_begin(...) { nk_group_end(...);} */ - NK_ASSERT(!(layout->flags & NK_WINDOW_MINIMIZED)); - NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN)); - NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED)); - - /* need to convert to int here to remove floating point errors */ - bounds->x = (float)((int)bounds->x); - bounds->y = (float)((int)bounds->y); - bounds->w = (float)((int)bounds->w); - bounds->h = (float)((int)bounds->h); - - c.x = (float)((int)c.x); - c.y = (float)((int)c.y); - c.w = (float)((int)c.w); - c.h = (float)((int)c.h); - - nk_unify(&v, &c, bounds->x, bounds->y, bounds->x + bounds->w, bounds->y + bounds->h); - if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds->x, bounds->y, bounds->w, bounds->h)) - return NK_WIDGET_INVALID; - if (!NK_INBOX(in->mouse.pos.x, in->mouse.pos.y, v.x, v.y, v.w, v.h)) - return NK_WIDGET_ROM; - return NK_WIDGET_VALID; -} - -NK_API enum nk_widget_layout_states -nk_widget_fitting(struct nk_rect *bounds, struct nk_context *ctx, - struct nk_vec2 item_padding) -{ - /* update the bounds to stand without padding */ - struct nk_window *win; - struct nk_style *style; - struct nk_panel *layout; - enum nk_widget_layout_states state; - struct nk_vec2 panel_padding; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return NK_WIDGET_INVALID; - - win = ctx->current; - style = &ctx->style; - layout = win->layout; - state = nk_widget(bounds, ctx); - - panel_padding = nk_panel_get_padding(style, layout->type); - if (layout->row.index == 1) { - bounds->w += panel_padding.x; - bounds->x -= panel_padding.x; - } else bounds->x -= item_padding.x; - - if (layout->row.index == layout->row.columns) - bounds->w += panel_padding.x; - else bounds->w += item_padding.x; - return state; -} - -/*---------------------------------------------------------------- - * - * MISC - * - * --------------------------------------------------------------*/ -NK_API void -nk_spacing(struct nk_context *ctx, int cols) -{ - struct nk_window *win; - struct nk_panel *layout; - struct nk_rect none; - int i, index, rows; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - /* spacing over row boundaries */ - win = ctx->current; - layout = win->layout; - index = (layout->row.index + cols) % layout->row.columns; - rows = (layout->row.index + cols) / layout->row.columns; - if (rows) { - for (i = 0; i < rows; ++i) - nk_panel_alloc_row(ctx, win); - cols = index; - } - /* non table layout need to allocate space */ - if (layout->row.type != NK_LAYOUT_DYNAMIC_FIXED && - layout->row.type != NK_LAYOUT_STATIC_FIXED) { - for (i = 0; i < cols; ++i) - nk_panel_alloc_space(&none, ctx); - } - layout->row.index = index; -} - -/*---------------------------------------------------------------- - * - * TEXT - * - * --------------------------------------------------------------*/ -NK_API void -nk_text_colored(struct nk_context *ctx, const char *str, int len, - nk_flags alignment, struct nk_color color) -{ - struct nk_window *win; - const struct nk_style *style; - - struct nk_vec2 item_padding; - struct nk_rect bounds; - struct nk_text text; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) return; - - win = ctx->current; - style = &ctx->style; - nk_panel_alloc_space(&bounds, ctx); - item_padding = style->text.padding; - - text.padding.x = item_padding.x; - text.padding.y = item_padding.y; - text.background = style->window.background; - text.text = color; - nk_widget_text(&win->buffer, bounds, str, len, &text, alignment, style->font); -} - -NK_API void -nk_text_wrap_colored(struct nk_context *ctx, const char *str, - int len, struct nk_color color) -{ - struct nk_window *win; - const struct nk_style *style; - - struct nk_vec2 item_padding; - struct nk_rect bounds; - struct nk_text text; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) return; - - win = ctx->current; - style = &ctx->style; - nk_panel_alloc_space(&bounds, ctx); - item_padding = style->text.padding; - - text.padding.x = item_padding.x; - text.padding.y = item_padding.y; - text.background = style->window.background; - text.text = color; - nk_widget_text_wrap(&win->buffer, bounds, str, len, &text, style->font); -} - -#ifdef NK_INCLUDE_STANDARD_VARARGS -NK_API void -nk_labelf_colored(struct nk_context *ctx, nk_flags flags, - struct nk_color color, const char *fmt, ...) -{ - char buf[256]; - va_list args; - va_start(args, fmt); - nk_strfmt(buf, NK_LEN(buf), fmt, args); - nk_label_colored(ctx, buf, flags, color); - va_end(args); -} - -NK_API void -nk_labelf_colored_wrap(struct nk_context *ctx, struct nk_color color, - const char *fmt, ...) -{ - char buf[256]; - va_list args; - va_start(args, fmt); - nk_strfmt(buf, NK_LEN(buf), fmt, args); - nk_label_colored_wrap(ctx, buf, color); - va_end(args); -} - -NK_API void -nk_labelf(struct nk_context *ctx, nk_flags flags, const char *fmt, ...) -{ - char buf[256]; - va_list args; - va_start(args, fmt); - nk_strfmt(buf, NK_LEN(buf), fmt, args); - nk_label(ctx, buf, flags); - va_end(args); -} - -NK_API void -nk_labelf_wrap(struct nk_context *ctx, const char *fmt,...) -{ - char buf[256]; - va_list args; - va_start(args, fmt); - nk_strfmt(buf, NK_LEN(buf), fmt, args); - nk_label_wrap(ctx, buf); - va_end(args); -} - -NK_API void -nk_value_bool(struct nk_context *ctx, const char *prefix, int value) -{nk_labelf(ctx, NK_TEXT_LEFT, "%s: %s", prefix, ((value) ? "true": "false"));} - -NK_API void -nk_value_int(struct nk_context *ctx, const char *prefix, int value) -{nk_labelf(ctx, NK_TEXT_LEFT, "%s: %d", prefix, value);} - -NK_API void -nk_value_uint(struct nk_context *ctx, const char *prefix, unsigned int value) -{nk_labelf(ctx, NK_TEXT_LEFT, "%s: %u", prefix, value);} - -NK_API void -nk_value_float(struct nk_context *ctx, const char *prefix, float value) -{ - double double_value = (double)value; - nk_labelf(ctx, NK_TEXT_LEFT, "%s: %.3f", prefix, double_value); -} - -NK_API void -nk_value_color_byte(struct nk_context *ctx, const char *p, struct nk_color c) -{nk_labelf(ctx, NK_TEXT_LEFT, "%s: (%d, %d, %d, %d)", p, c.r, c.g, c.b, c.a);} - -NK_API void -nk_value_color_float(struct nk_context *ctx, const char *p, struct nk_color color) -{ - double c[4]; nk_color_dv(c, color); - nk_labelf(ctx, NK_TEXT_LEFT, "%s: (%.2f, %.2f, %.2f, %.2f)", - p, c[0], c[1], c[2], c[3]); -} - -NK_API void -nk_value_color_hex(struct nk_context *ctx, const char *prefix, struct nk_color color) -{ - char hex[16]; - nk_color_hex_rgba(hex, color); - nk_labelf(ctx, NK_TEXT_LEFT, "%s: %s", prefix, hex); -} -#endif - -NK_API void -nk_text(struct nk_context *ctx, const char *str, int len, nk_flags alignment) -{ - NK_ASSERT(ctx); - if (!ctx) return; - nk_text_colored(ctx, str, len, alignment, ctx->style.text.color); -} - -NK_API void -nk_text_wrap(struct nk_context *ctx, const char *str, int len) -{ - NK_ASSERT(ctx); - if (!ctx) return; - nk_text_wrap_colored(ctx, str, len, ctx->style.text.color); -} - -NK_API void -nk_label(struct nk_context *ctx, const char *str, nk_flags alignment) -{nk_text(ctx, str, nk_strlen(str), alignment);} - -NK_API void -nk_label_colored(struct nk_context *ctx, const char *str, nk_flags align, - struct nk_color color) -{nk_text_colored(ctx, str, nk_strlen(str), align, color);} - -NK_API void -nk_label_wrap(struct nk_context *ctx, const char *str) -{nk_text_wrap(ctx, str, nk_strlen(str));} - -NK_API void -nk_label_colored_wrap(struct nk_context *ctx, const char *str, struct nk_color color) -{nk_text_wrap_colored(ctx, str, nk_strlen(str), color);} - -NK_API void -nk_image(struct nk_context *ctx, struct nk_image img) -{ - struct nk_window *win; - struct nk_rect bounds; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) return; - - win = ctx->current; - if (!nk_widget(&bounds, ctx)) return; - nk_draw_image(&win->buffer, bounds, &img, nk_white); -} -NK_API void -nk_image_color(struct nk_context *ctx, struct nk_image img, struct nk_color col) -{ - struct nk_window *win; - struct nk_rect bounds; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) return; - - win = ctx->current; - if (!nk_widget(&bounds, ctx)) return; - nk_draw_image(&win->buffer, bounds, &img, col); -} -/*---------------------------------------------------------------- - * - * BUTTON - * - * --------------------------------------------------------------*/ -NK_API void -nk_button_set_behavior(struct nk_context *ctx, enum nk_button_behavior behavior) -{ - NK_ASSERT(ctx); - if (!ctx) return; - ctx->button_behavior = behavior; -} - -NK_API int -nk_button_push_behavior(struct nk_context *ctx, enum nk_button_behavior behavior) -{ - struct nk_config_stack_button_behavior *button_stack; - struct nk_config_stack_button_behavior_element *element; - - NK_ASSERT(ctx); - if (!ctx) return 0; - - button_stack = &ctx->stacks.button_behaviors; - NK_ASSERT(button_stack->head < (int)NK_LEN(button_stack->elements)); - if (button_stack->head >= (int)NK_LEN(button_stack->elements)) - return 0; - - element = &button_stack->elements[button_stack->head++]; - element->address = &ctx->button_behavior; - element->old_value = ctx->button_behavior; - ctx->button_behavior = behavior; - return 1; -} - -NK_API int -nk_button_pop_behavior(struct nk_context *ctx) -{ - struct nk_config_stack_button_behavior *button_stack; - struct nk_config_stack_button_behavior_element *element; - - NK_ASSERT(ctx); - if (!ctx) return 0; - - button_stack = &ctx->stacks.button_behaviors; - NK_ASSERT(button_stack->head > 0); - if (button_stack->head < 1) - return 0; - - element = &button_stack->elements[--button_stack->head]; - *element->address = element->old_value; - return 1; -} - -NK_API int -nk_button_text_styled(struct nk_context *ctx, - const struct nk_style_button *style, const char *title, int len) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(style); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!style || !ctx || !ctx->current || !ctx->current->layout) return 0; - - win = ctx->current; - layout = win->layout; - state = nk_widget(&bounds, ctx); - - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_button_text(&ctx->last_widget_state, &win->buffer, bounds, - title, len, style->text_alignment, ctx->button_behavior, - style, in, ctx->style.font); -} - -NK_API int -nk_button_text(struct nk_context *ctx, const char *title, int len) -{ - NK_ASSERT(ctx); - if (!ctx) return 0; - return nk_button_text_styled(ctx, &ctx->style.button, title, len); -} - -NK_API int nk_button_label_styled(struct nk_context *ctx, - const struct nk_style_button *style, const char *title) -{return nk_button_text_styled(ctx, style, title, nk_strlen(title));} - -NK_API int nk_button_label(struct nk_context *ctx, const char *title) -{return nk_button_text(ctx, title, nk_strlen(title));} - -NK_API int -nk_button_color(struct nk_context *ctx, struct nk_color color) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - struct nk_style_button button; - - int ret = 0; - struct nk_rect bounds; - struct nk_rect content; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - layout = win->layout; - - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - - button = ctx->style.button; - button.normal = nk_style_item_color(color); - button.hover = nk_style_item_color(color); - button.active = nk_style_item_color(color); - ret = nk_do_button(&ctx->last_widget_state, &win->buffer, bounds, - &button, in, ctx->button_behavior, &content); - nk_draw_button(&win->buffer, &bounds, ctx->last_widget_state, &button); - return ret; -} - -NK_API int -nk_button_symbol_styled(struct nk_context *ctx, - const struct nk_style_button *style, enum nk_symbol_type symbol) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - layout = win->layout; - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_button_symbol(&ctx->last_widget_state, &win->buffer, bounds, - symbol, ctx->button_behavior, style, in, ctx->style.font); -} - -NK_API int -nk_button_symbol(struct nk_context *ctx, enum nk_symbol_type symbol) -{ - NK_ASSERT(ctx); - if (!ctx) return 0; - return nk_button_symbol_styled(ctx, &ctx->style.button, symbol); -} - -NK_API int -nk_button_image_styled(struct nk_context *ctx, const struct nk_style_button *style, - struct nk_image img) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - layout = win->layout; - - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_button_image(&ctx->last_widget_state, &win->buffer, bounds, - img, ctx->button_behavior, style, in); -} - -NK_API int -nk_button_image(struct nk_context *ctx, struct nk_image img) -{ - NK_ASSERT(ctx); - if (!ctx) return 0; - return nk_button_image_styled(ctx, &ctx->style.button, img); -} - -NK_API int -nk_button_symbol_text_styled(struct nk_context *ctx, - const struct nk_style_button *style, enum nk_symbol_type symbol, - const char *text, int len, nk_flags align) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - layout = win->layout; - - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, bounds, - symbol, text, len, align, ctx->button_behavior, - style, ctx->style.font, in); -} - -NK_API int -nk_button_symbol_text(struct nk_context *ctx, enum nk_symbol_type symbol, - const char* text, int len, nk_flags align) -{ - NK_ASSERT(ctx); - if (!ctx) return 0; - return nk_button_symbol_text_styled(ctx, &ctx->style.button, symbol, text, len, align); -} - -NK_API int nk_button_symbol_label(struct nk_context *ctx, enum nk_symbol_type symbol, - const char *label, nk_flags align) -{return nk_button_symbol_text(ctx, symbol, label, nk_strlen(label), align);} - -NK_API int nk_button_symbol_label_styled(struct nk_context *ctx, - const struct nk_style_button *style, enum nk_symbol_type symbol, - const char *title, nk_flags align) -{return nk_button_symbol_text_styled(ctx, style, symbol, title, nk_strlen(title), align);} - -NK_API int -nk_button_image_text_styled(struct nk_context *ctx, - const struct nk_style_button *style, struct nk_image img, const char *text, - int len, nk_flags align) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - layout = win->layout; - - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_button_text_image(&ctx->last_widget_state, &win->buffer, - bounds, img, text, len, align, ctx->button_behavior, - style, ctx->style.font, in); -} - -NK_API int -nk_button_image_text(struct nk_context *ctx, struct nk_image img, - const char *text, int len, nk_flags align) -{return nk_button_image_text_styled(ctx, &ctx->style.button,img, text, len, align);} - - -NK_API int nk_button_image_label(struct nk_context *ctx, struct nk_image img, - const char *label, nk_flags align) -{return nk_button_image_text(ctx, img, label, nk_strlen(label), align);} - -NK_API int nk_button_image_label_styled(struct nk_context *ctx, - const struct nk_style_button *style, struct nk_image img, - const char *label, nk_flags text_alignment) -{return nk_button_image_text_styled(ctx, style, img, label, nk_strlen(label), text_alignment);} - -/*---------------------------------------------------------------- - * - * SELECTABLE - * - * --------------------------------------------------------------*/ -NK_API int -nk_selectable_text(struct nk_context *ctx, const char *str, int len, - nk_flags align, int *value) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - const struct nk_style *style; - - enum nk_widget_layout_states state; - struct nk_rect bounds; - - NK_ASSERT(ctx); - NK_ASSERT(value); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout || !value) - return 0; - - win = ctx->current; - layout = win->layout; - style = &ctx->style; - - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_selectable(&ctx->last_widget_state, &win->buffer, bounds, - str, len, align, value, &style->selectable, in, style->font); -} - -NK_API int -nk_selectable_image_text(struct nk_context *ctx, struct nk_image img, - const char *str, int len, nk_flags align, int *value) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - const struct nk_style *style; - - enum nk_widget_layout_states state; - struct nk_rect bounds; - - NK_ASSERT(ctx); - NK_ASSERT(value); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout || !value) - return 0; - - win = ctx->current; - layout = win->layout; - style = &ctx->style; - - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_selectable_image(&ctx->last_widget_state, &win->buffer, bounds, - str, len, align, value, &img, &style->selectable, in, style->font); -} - -NK_API int nk_select_text(struct nk_context *ctx, const char *str, int len, - nk_flags align, int value) -{nk_selectable_text(ctx, str, len, align, &value);return value;} - -NK_API int nk_selectable_label(struct nk_context *ctx, const char *str, nk_flags align, int *value) -{return nk_selectable_text(ctx, str, nk_strlen(str), align, value);} - -NK_API int nk_selectable_image_label(struct nk_context *ctx,struct nk_image img, - const char *str, nk_flags align, int *value) -{return nk_selectable_image_text(ctx, img, str, nk_strlen(str), align, value);} - -NK_API int nk_select_label(struct nk_context *ctx, const char *str, nk_flags align, int value) -{nk_selectable_text(ctx, str, nk_strlen(str), align, &value);return value;} - -NK_API int nk_select_image_label(struct nk_context *ctx, struct nk_image img, - const char *str, nk_flags align, int value) -{nk_selectable_image_text(ctx, img, str, nk_strlen(str), align, &value);return value;} - -NK_API int nk_select_image_text(struct nk_context *ctx, struct nk_image img, - const char *str, int len, nk_flags align, int value) -{nk_selectable_image_text(ctx, img, str, len, align, &value);return value;} - -/*---------------------------------------------------------------- - * - * CHECKBOX - * - * --------------------------------------------------------------*/ -NK_API int -nk_check_text(struct nk_context *ctx, const char *text, int len, int active) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - const struct nk_style *style; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return active; - - win = ctx->current; - style = &ctx->style; - layout = win->layout; - - state = nk_widget(&bounds, ctx); - if (!state) return active; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &active, - text, len, NK_TOGGLE_CHECK, &style->checkbox, in, style->font); - return active; -} - -NK_API unsigned int -nk_check_flags_text(struct nk_context *ctx, const char *text, int len, - unsigned int flags, unsigned int value) -{ - int old_active; - NK_ASSERT(ctx); - NK_ASSERT(text); - if (!ctx || !text) return flags; - old_active = (int)((flags & value) & value); - if (nk_check_text(ctx, text, len, old_active)) - flags |= value; - else flags &= ~value; - return flags; -} - -NK_API int -nk_checkbox_text(struct nk_context *ctx, const char *text, int len, int *active) -{ - int old_val; - NK_ASSERT(ctx); - NK_ASSERT(text); - NK_ASSERT(active); - if (!ctx || !text || !active) return 0; - old_val = *active; - *active = nk_check_text(ctx, text, len, *active); - return old_val != *active; -} - -NK_API int -nk_checkbox_flags_text(struct nk_context *ctx, const char *text, int len, - unsigned int *flags, unsigned int value) -{ - int active; - NK_ASSERT(ctx); - NK_ASSERT(text); - NK_ASSERT(flags); - if (!ctx || !text || !flags) return 0; - - active = (int)((*flags & value) & value); - if (nk_checkbox_text(ctx, text, len, &active)) { - if (active) *flags |= value; - else *flags &= ~value; - return 1; - } - return 0; -} - -NK_API int nk_check_label(struct nk_context *ctx, const char *label, int active) -{return nk_check_text(ctx, label, nk_strlen(label), active);} - -NK_API unsigned int nk_check_flags_label(struct nk_context *ctx, const char *label, - unsigned int flags, unsigned int value) -{return nk_check_flags_text(ctx, label, nk_strlen(label), flags, value);} - -NK_API int nk_checkbox_label(struct nk_context *ctx, const char *label, int *active) -{return nk_checkbox_text(ctx, label, nk_strlen(label), active);} - -NK_API int nk_checkbox_flags_label(struct nk_context *ctx, const char *label, - unsigned int *flags, unsigned int value) -{return nk_checkbox_flags_text(ctx, label, nk_strlen(label), flags, value);} - -/*---------------------------------------------------------------- - * - * OPTION - * - * --------------------------------------------------------------*/ -NK_API int -nk_option_text(struct nk_context *ctx, const char *text, int len, int is_active) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_input *in; - const struct nk_style *style; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return is_active; - - win = ctx->current; - style = &ctx->style; - layout = win->layout; - - state = nk_widget(&bounds, ctx); - if (!state) return state; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &is_active, - text, len, NK_TOGGLE_OPTION, &style->option, in, style->font); - return is_active; -} - -NK_API int -nk_radio_text(struct nk_context *ctx, const char *text, int len, int *active) -{ - int old_value; - NK_ASSERT(ctx); - NK_ASSERT(text); - NK_ASSERT(active); - if (!ctx || !text || !active) return 0; - old_value = *active; - *active = nk_option_text(ctx, text, len, old_value); - return old_value != *active; -} - -NK_API int -nk_option_label(struct nk_context *ctx, const char *label, int active) -{return nk_option_text(ctx, label, nk_strlen(label), active);} - -NK_API int -nk_radio_label(struct nk_context *ctx, const char *label, int *active) -{return nk_radio_text(ctx, label, nk_strlen(label), active);} - -/*---------------------------------------------------------------- - * - * SLIDER - * - * --------------------------------------------------------------*/ -NK_API int -nk_slider_float(struct nk_context *ctx, float min_value, float *value, float max_value, - float value_step) -{ - struct nk_window *win; - struct nk_panel *layout; - struct nk_input *in; - const struct nk_style *style; - - int ret = 0; - float old_value; - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - NK_ASSERT(value); - if (!ctx || !ctx->current || !ctx->current->layout || !value) - return ret; - - win = ctx->current; - style = &ctx->style; - layout = win->layout; - - state = nk_widget(&bounds, ctx); - if (!state) return ret; - in = (/*state == NK_WIDGET_ROM || */ layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - - old_value = *value; - *value = nk_do_slider(&ctx->last_widget_state, &win->buffer, bounds, min_value, - old_value, max_value, value_step, &style->slider, in, style->font); - return (old_value > *value || old_value < *value); -} - -NK_API float -nk_slide_float(struct nk_context *ctx, float min, float val, float max, float step) -{ - nk_slider_float(ctx, min, &val, max, step); return val; -} - -NK_API int -nk_slide_int(struct nk_context *ctx, int min, int val, int max, int step) -{ - float value = (float)val; - nk_slider_float(ctx, (float)min, &value, (float)max, (float)step); - return (int)value; -} - -NK_API int -nk_slider_int(struct nk_context *ctx, int min, int *val, int max, int step) -{ - int ret; - float value = (float)*val; - ret = nk_slider_float(ctx, (float)min, &value, (float)max, (float)step); - *val = (int)value; - return ret; -} - -/*---------------------------------------------------------------- - * - * PROGRESSBAR - * - * --------------------------------------------------------------*/ -NK_API int -nk_progress(struct nk_context *ctx, nk_size *cur, nk_size max, int is_modifyable) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_style *style; - struct nk_input *in; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - nk_size old_value; - - NK_ASSERT(ctx); - NK_ASSERT(cur); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout || !cur) - return 0; - - win = ctx->current; - style = &ctx->style; - layout = win->layout; - state = nk_widget(&bounds, ctx); - if (!state) return 0; - - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - old_value = *cur; - *cur = nk_do_progress(&ctx->last_widget_state, &win->buffer, bounds, - *cur, max, is_modifyable, &style->progress, in); - return (*cur != old_value); -} - -NK_API nk_size nk_prog(struct nk_context *ctx, nk_size cur, nk_size max, int modifyable) -{nk_progress(ctx, &cur, max, modifyable);return cur;} - -/*---------------------------------------------------------------- - * - * EDIT - * - * --------------------------------------------------------------*/ -NK_API void -nk_edit_focus(struct nk_context *ctx, nk_flags flags) -{ - nk_hash hash; - struct nk_window *win; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return; - - win = ctx->current; - hash = win->edit.seq; - win->edit.active = nk_true; - win->edit.name = hash; - if (flags & NK_EDIT_ALWAYS_INSERT_MODE) - win->edit.mode = NK_TEXT_EDIT_MODE_INSERT; -} - -NK_API void -nk_edit_unfocus(struct nk_context *ctx) -{ - struct nk_window *win; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return; - - win = ctx->current; - win->edit.active = nk_false; - win->edit.name = 0; -} - -NK_API nk_flags -nk_edit_string(struct nk_context *ctx, nk_flags flags, - char *memory, int *len, int max, nk_plugin_filter filter) -{ - nk_hash hash; - nk_flags state; - struct nk_text_edit *edit; - struct nk_window *win; - - NK_ASSERT(ctx); - NK_ASSERT(memory); - NK_ASSERT(len); - if (!ctx || !memory || !len) - return 0; - - filter = (!filter) ? nk_filter_default: filter; - win = ctx->current; - hash = win->edit.seq; - edit = &ctx->text_edit; - nk_textedit_clear_state(&ctx->text_edit, (flags & NK_EDIT_MULTILINE)? - NK_TEXT_EDIT_MULTI_LINE: NK_TEXT_EDIT_SINGLE_LINE, filter); - - if (win->edit.active && hash == win->edit.name) { - if (flags & NK_EDIT_NO_CURSOR) - edit->cursor = nk_utf_len(memory, *len); - else edit->cursor = win->edit.cursor; - if (!(flags & NK_EDIT_SELECTABLE)) { - edit->select_start = win->edit.cursor; - edit->select_end = win->edit.cursor; - } else { - edit->select_start = win->edit.sel_start; - edit->select_end = win->edit.sel_end; - } - edit->mode = win->edit.mode; - edit->scrollbar.x = (float)win->edit.scrollbar.x; - edit->scrollbar.y = (float)win->edit.scrollbar.y; - edit->active = nk_true; - } else edit->active = nk_false; - - max = NK_MAX(1, max); - *len = NK_MIN(*len, max-1); - nk_str_init_fixed(&edit->string, memory, (nk_size)max); - edit->string.buffer.allocated = (nk_size)*len; - edit->string.len = nk_utf_len(memory, *len); - state = nk_edit_buffer(ctx, flags, edit, filter); - *len = (int)edit->string.buffer.allocated; - - if (edit->active) { - win->edit.cursor = edit->cursor; - win->edit.sel_start = edit->select_start; - win->edit.sel_end = edit->select_end; - win->edit.mode = edit->mode; - win->edit.scrollbar.x = (nk_uint)edit->scrollbar.x; - win->edit.scrollbar.y = (nk_uint)edit->scrollbar.y; - } return state; -} - -NK_API nk_flags -nk_edit_buffer(struct nk_context *ctx, nk_flags flags, - struct nk_text_edit *edit, nk_plugin_filter filter) -{ - struct nk_window *win; - struct nk_style *style; - struct nk_input *in; - - enum nk_widget_layout_states state; - struct nk_rect bounds; - - nk_flags ret_flags = 0; - unsigned char prev_state; - nk_hash hash; - - /* make sure correct values */ - NK_ASSERT(ctx); - NK_ASSERT(edit); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - state = nk_widget(&bounds, ctx); - if (!state) return state; - in = (win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - - /* check if edit is currently hot item */ - hash = win->edit.seq++; - if (win->edit.active && hash == win->edit.name) { - if (flags & NK_EDIT_NO_CURSOR) - edit->cursor = edit->string.len; - if (!(flags & NK_EDIT_SELECTABLE)) { - edit->select_start = edit->cursor; - edit->select_end = edit->cursor; - } - if (flags & NK_EDIT_CLIPBOARD) - edit->clip = ctx->clip; - edit->active = (unsigned char)win->edit.active; - } else edit->active = nk_false; - edit->mode = win->edit.mode; - - filter = (!filter) ? nk_filter_default: filter; - prev_state = (unsigned char)edit->active; - in = (flags & NK_EDIT_READ_ONLY) ? 0: in; - ret_flags = nk_do_edit(&ctx->last_widget_state, &win->buffer, bounds, flags, - filter, edit, &style->edit, in, style->font); - - if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_TEXT]; - if (edit->active && prev_state != edit->active) { - /* current edit is now hot */ - win->edit.active = nk_true; - win->edit.name = hash; - } else if (prev_state && !edit->active) { - /* current edit is now cold */ - win->edit.active = nk_false; - } return ret_flags; -} - -NK_API nk_flags -nk_edit_string_zero_terminated(struct nk_context *ctx, nk_flags flags, - char *buffer, int max, nk_plugin_filter filter) -{ - nk_flags result; - int len = nk_strlen(buffer); - result = nk_edit_string(ctx, flags, buffer, &len, max, filter); - buffer[NK_MIN(NK_MAX(max-1,0), len)] = '\0'; - return result; -} - -/*---------------------------------------------------------------- - * - * PROPERTY - * - * --------------------------------------------------------------*/ -NK_INTERN struct nk_property_variant -nk_property_variant_int(int value, int min_value, int max_value, int step) -{ - struct nk_property_variant result; - result.kind = NK_PROPERTY_INT; - result.value.i = value; - result.min_value.i = min_value; - result.max_value.i = max_value; - result.step.i = step; - return result; -} - -NK_INTERN struct nk_property_variant -nk_property_variant_float(float value, float min_value, float max_value, float step) -{ - struct nk_property_variant result; - result.kind = NK_PROPERTY_FLOAT; - result.value.f = value; - result.min_value.f = min_value; - result.max_value.f = max_value; - result.step.f = step; - return result; -} - -NK_INTERN struct nk_property_variant -nk_property_variant_double(double value, double min_value, double max_value, - double step) -{ - struct nk_property_variant result; - result.kind = NK_PROPERTY_DOUBLE; - result.value.d = value; - result.min_value.d = min_value; - result.max_value.d = max_value; - result.step.d = step; - return result; -} - -NK_INTERN void -nk_property(struct nk_context *ctx, const char *name, struct nk_property_variant *variant, - float inc_per_pixel, const enum nk_property_filter filter) -{ - struct nk_window *win; - struct nk_panel *layout; - struct nk_input *in; - const struct nk_style *style; - - struct nk_rect bounds; - enum nk_widget_layout_states s; - - int *state = 0; - nk_hash hash = 0; - char *buffer = 0; - int *len = 0; - int *cursor = 0; - int *select_begin = 0; - int *select_end = 0; - int old_state; - - char dummy_buffer[NK_MAX_NUMBER_BUFFER]; - int dummy_state = NK_PROPERTY_DEFAULT; - int dummy_length = 0; - int dummy_cursor = 0; - int dummy_select_begin = 0; - int dummy_select_end = 0; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - win = ctx->current; - layout = win->layout; - style = &ctx->style; - s = nk_widget(&bounds, ctx); - if (!s) return; - - /* calculate hash from name */ - if (name[0] == '#') { - hash = nk_murmur_hash(name, (int)nk_strlen(name), win->property.seq++); - name++; /* special number hash */ - } else hash = nk_murmur_hash(name, (int)nk_strlen(name), 42); - - /* check if property is currently hot item */ - if (win->property.active && hash == win->property.name) { - buffer = win->property.buffer; - len = &win->property.length; - cursor = &win->property.cursor; - state = &win->property.state; - select_begin = &win->property.select_start; - select_end = &win->property.select_end; - } else { - buffer = dummy_buffer; - len = &dummy_length; - cursor = &dummy_cursor; - state = &dummy_state; - select_begin = &dummy_select_begin; - select_end = &dummy_select_end; - } - - /* execute property widget */ - old_state = *state; - ctx->text_edit.clip = ctx->clip; - in = ((s == NK_WIDGET_ROM && !win->property.active) || - layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - nk_do_property(&ctx->last_widget_state, &win->buffer, bounds, name, - variant, inc_per_pixel, buffer, len, state, cursor, select_begin, - select_end, &style->property, filter, in, style->font, &ctx->text_edit, - ctx->button_behavior); - - if (in && *state != NK_PROPERTY_DEFAULT && !win->property.active) { - /* current property is now hot */ - win->property.active = 1; - NK_MEMCPY(win->property.buffer, buffer, (nk_size)*len); - win->property.length = *len; - win->property.cursor = *cursor; - win->property.state = *state; - win->property.name = hash; - win->property.select_start = *select_begin; - win->property.select_end = *select_end; - if (*state == NK_PROPERTY_DRAG) { - ctx->input.mouse.grab = nk_true; - ctx->input.mouse.grabbed = nk_true; - } - } - /* check if previously active property is now inactive */ - if (*state == NK_PROPERTY_DEFAULT && old_state != NK_PROPERTY_DEFAULT) { - if (old_state == NK_PROPERTY_DRAG) { - ctx->input.mouse.grab = nk_false; - ctx->input.mouse.grabbed = nk_false; - ctx->input.mouse.ungrab = nk_true; - } - win->property.select_start = 0; - win->property.select_end = 0; - win->property.active = 0; - } -} - -NK_API void -nk_property_int(struct nk_context *ctx, const char *name, - int min, int *val, int max, int step, float inc_per_pixel) -{ - struct nk_property_variant variant; - NK_ASSERT(ctx); - NK_ASSERT(name); - NK_ASSERT(val); - - if (!ctx || !ctx->current || !name || !val) return; - variant = nk_property_variant_int(*val, min, max, step); - nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_INT); - *val = variant.value.i; -} - -NK_API void -nk_property_float(struct nk_context *ctx, const char *name, - float min, float *val, float max, float step, float inc_per_pixel) -{ - struct nk_property_variant variant; - NK_ASSERT(ctx); - NK_ASSERT(name); - NK_ASSERT(val); - - if (!ctx || !ctx->current || !name || !val) return; - variant = nk_property_variant_float(*val, min, max, step); - nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT); - *val = variant.value.f; -} - -NK_API void -nk_property_double(struct nk_context *ctx, const char *name, - double min, double *val, double max, double step, float inc_per_pixel) -{ - struct nk_property_variant variant; - NK_ASSERT(ctx); - NK_ASSERT(name); - NK_ASSERT(val); - - if (!ctx || !ctx->current || !name || !val) return; - variant = nk_property_variant_double(*val, min, max, step); - nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT); - *val = variant.value.d; -} - -NK_API int -nk_propertyi(struct nk_context *ctx, const char *name, int min, int val, - int max, int step, float inc_per_pixel) -{ - struct nk_property_variant variant; - NK_ASSERT(ctx); - NK_ASSERT(name); - - if (!ctx || !ctx->current || !name) return val; - variant = nk_property_variant_int(val, min, max, step); - nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_INT); - val = variant.value.i; - return val; -} - -NK_API float -nk_propertyf(struct nk_context *ctx, const char *name, float min, - float val, float max, float step, float inc_per_pixel) -{ - struct nk_property_variant variant; - NK_ASSERT(ctx); - NK_ASSERT(name); - - if (!ctx || !ctx->current || !name) return val; - variant = nk_property_variant_float(val, min, max, step); - nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT); - val = variant.value.f; - return val; -} - -NK_API double -nk_propertyd(struct nk_context *ctx, const char *name, double min, - double val, double max, double step, float inc_per_pixel) -{ - struct nk_property_variant variant; - NK_ASSERT(ctx); - NK_ASSERT(name); - - if (!ctx || !ctx->current || !name) return val; - variant = nk_property_variant_double(val, min, max, step); - nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT); - val = variant.value.d; - return val; -} - -/*---------------------------------------------------------------- - * - * COLOR PICKER - * - * --------------------------------------------------------------*/ -NK_API int -nk_color_pick(struct nk_context * ctx, struct nk_colorf *color, - enum nk_color_format fmt) -{ - struct nk_window *win; - struct nk_panel *layout; - const struct nk_style *config; - const struct nk_input *in; - - enum nk_widget_layout_states state; - struct nk_rect bounds; - - NK_ASSERT(ctx); - NK_ASSERT(color); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout || !color) - return 0; - - win = ctx->current; - config = &ctx->style; - layout = win->layout; - state = nk_widget(&bounds, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - return nk_do_color_picker(&ctx->last_widget_state, &win->buffer, color, fmt, bounds, - nk_vec2(0,0), in, config->font); -} - -NK_API struct nk_colorf -nk_color_picker(struct nk_context *ctx, struct nk_colorf color, - enum nk_color_format fmt) -{ - nk_color_pick(ctx, &color, fmt); - return color; -} - -/* ------------------------------------------------------------- - * - * CHART - * - * --------------------------------------------------------------*/ -NK_API int -nk_chart_begin_colored(struct nk_context *ctx, enum nk_chart_type type, - struct nk_color color, struct nk_color highlight, - int count, float min_value, float max_value) -{ - struct nk_window *win; - struct nk_chart *chart; - const struct nk_style *config; - const struct nk_style_chart *style; - - const struct nk_style_item *background; - struct nk_rect bounds = {0, 0, 0, 0}; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - - if (!ctx || !ctx->current || !ctx->current->layout) return 0; - if (!nk_widget(&bounds, ctx)) { - chart = &ctx->current->layout->chart; - nk_zero(chart, sizeof(*chart)); - return 0; - } - - win = ctx->current; - config = &ctx->style; - chart = &win->layout->chart; - style = &config->chart; - - /* setup basic generic chart */ - nk_zero(chart, sizeof(*chart)); - chart->x = bounds.x + style->padding.x; - chart->y = bounds.y + style->padding.y; - chart->w = bounds.w - 2 * style->padding.x; - chart->h = bounds.h - 2 * style->padding.y; - chart->w = NK_MAX(chart->w, 2 * style->padding.x); - chart->h = NK_MAX(chart->h, 2 * style->padding.y); - - /* add first slot into chart */ - {struct nk_chart_slot *slot = &chart->slots[chart->slot++]; - slot->type = type; - slot->count = count; - slot->color = color; - slot->highlight = highlight; - slot->min = NK_MIN(min_value, max_value); - slot->max = NK_MAX(min_value, max_value); - slot->range = slot->max - slot->min;} - - /* draw chart background */ - background = &style->background; - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(&win->buffer, bounds, &background->data.image, nk_white); - } else { - nk_fill_rect(&win->buffer, bounds, style->rounding, style->border_color); - nk_fill_rect(&win->buffer, nk_shrink_rect(bounds, style->border), - style->rounding, style->background.data.color); - } - return 1; -} - -NK_API int -nk_chart_begin(struct nk_context *ctx, const enum nk_chart_type type, - int count, float min_value, float max_value) -{return nk_chart_begin_colored(ctx, type, ctx->style.chart.color, ctx->style.chart.selected_color, count, min_value, max_value);} - -NK_API void -nk_chart_add_slot_colored(struct nk_context *ctx, const enum nk_chart_type type, - struct nk_color color, struct nk_color highlight, - int count, float min_value, float max_value) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - NK_ASSERT(ctx->current->layout->chart.slot < NK_CHART_MAX_SLOT); - if (!ctx || !ctx->current || !ctx->current->layout) return; - if (ctx->current->layout->chart.slot >= NK_CHART_MAX_SLOT) return; - - /* add another slot into the graph */ - {struct nk_chart *chart = &ctx->current->layout->chart; - struct nk_chart_slot *slot = &chart->slots[chart->slot++]; - slot->type = type; - slot->count = count; - slot->color = color; - slot->highlight = highlight; - slot->min = NK_MIN(min_value, max_value); - slot->max = NK_MAX(min_value, max_value); - slot->range = slot->max - slot->min;} -} - -NK_API void -nk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type type, - int count, float min_value, float max_value) -{nk_chart_add_slot_colored(ctx, type, ctx->style.chart.color, ctx->style.chart.selected_color, count, min_value, max_value);} - -NK_INTERN nk_flags -nk_chart_push_line(struct nk_context *ctx, struct nk_window *win, - struct nk_chart *g, float value, int slot) -{ - struct nk_panel *layout = win->layout; - const struct nk_input *i = &ctx->input; - struct nk_command_buffer *out = &win->buffer; - - nk_flags ret = 0; - struct nk_vec2 cur; - struct nk_rect bounds; - struct nk_color color; - float step; - float range; - float ratio; - - NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT); - step = g->w / (float)g->slots[slot].count; - range = g->slots[slot].max - g->slots[slot].min; - ratio = (value - g->slots[slot].min) / range; - - if (g->slots[slot].index == 0) { - /* first data point does not have a connection */ - g->slots[slot].last.x = g->x; - g->slots[slot].last.y = (g->y + g->h) - ratio * (float)g->h; - - bounds.x = g->slots[slot].last.x - 2; - bounds.y = g->slots[slot].last.y - 2; - bounds.w = bounds.h = 4; - - color = g->slots[slot].color; - if (!(layout->flags & NK_WINDOW_ROM) && - NK_INBOX(i->mouse.pos.x,i->mouse.pos.y, g->slots[slot].last.x-3, g->slots[slot].last.y-3, 6, 6)){ - ret = nk_input_is_mouse_hovering_rect(i, bounds) ? NK_CHART_HOVERING : 0; - ret |= (i->mouse.buttons[NK_BUTTON_LEFT].down && - i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0; - color = g->slots[slot].highlight; - } - nk_fill_rect(out, bounds, 0, color); - g->slots[slot].index += 1; - return ret; - } - - /* draw a line between the last data point and the new one */ - color = g->slots[slot].color; - cur.x = g->x + (float)(step * (float)g->slots[slot].index); - cur.y = (g->y + g->h) - (ratio * (float)g->h); - nk_stroke_line(out, g->slots[slot].last.x, g->slots[slot].last.y, cur.x, cur.y, 1.0f, color); - - bounds.x = cur.x - 3; - bounds.y = cur.y - 3; - bounds.w = bounds.h = 6; - - /* user selection of current data point */ - if (!(layout->flags & NK_WINDOW_ROM)) { - if (nk_input_is_mouse_hovering_rect(i, bounds)) { - ret = NK_CHART_HOVERING; - ret |= (!i->mouse.buttons[NK_BUTTON_LEFT].down && - i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0; - color = g->slots[slot].highlight; - } - } - nk_fill_rect(out, nk_rect(cur.x - 2, cur.y - 2, 4, 4), 0, color); - - /* save current data point position */ - g->slots[slot].last.x = cur.x; - g->slots[slot].last.y = cur.y; - g->slots[slot].index += 1; - return ret; -} - -NK_INTERN nk_flags -nk_chart_push_column(const struct nk_context *ctx, struct nk_window *win, - struct nk_chart *chart, float value, int slot) -{ - struct nk_command_buffer *out = &win->buffer; - const struct nk_input *in = &ctx->input; - struct nk_panel *layout = win->layout; - - float ratio; - nk_flags ret = 0; - struct nk_color color; - struct nk_rect item = {0,0,0,0}; - - NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT); - if (chart->slots[slot].index >= chart->slots[slot].count) - return nk_false; - if (chart->slots[slot].count) { - float padding = (float)(chart->slots[slot].count-1); - item.w = (chart->w - padding) / (float)(chart->slots[slot].count); - } - - /* calculate bounds of current bar chart entry */ - color = chart->slots[slot].color;; - item.h = chart->h * NK_ABS((value/chart->slots[slot].range)); - if (value >= 0) { - ratio = (value + NK_ABS(chart->slots[slot].min)) / NK_ABS(chart->slots[slot].range); - item.y = (chart->y + chart->h) - chart->h * ratio; - } else { - ratio = (value - chart->slots[slot].max) / chart->slots[slot].range; - item.y = chart->y + (chart->h * NK_ABS(ratio)) - item.h; - } - item.x = chart->x + ((float)chart->slots[slot].index * item.w); - item.x = item.x + ((float)chart->slots[slot].index); - - /* user chart bar selection */ - if (!(layout->flags & NK_WINDOW_ROM) && - NK_INBOX(in->mouse.pos.x,in->mouse.pos.y,item.x,item.y,item.w,item.h)) { - ret = NK_CHART_HOVERING; - ret |= (!in->mouse.buttons[NK_BUTTON_LEFT].down && - in->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0; - color = chart->slots[slot].highlight; - } - nk_fill_rect(out, item, 0, color); - chart->slots[slot].index += 1; - return ret; -} - -NK_API nk_flags -nk_chart_push_slot(struct nk_context *ctx, float value, int slot) -{ - nk_flags flags; - struct nk_window *win; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT); - NK_ASSERT(slot < ctx->current->layout->chart.slot); - if (!ctx || !ctx->current || slot >= NK_CHART_MAX_SLOT) return nk_false; - if (slot >= ctx->current->layout->chart.slot) return nk_false; - - win = ctx->current; - if (win->layout->chart.slot < slot) return nk_false; - switch (win->layout->chart.slots[slot].type) { - case NK_CHART_LINES: - flags = nk_chart_push_line(ctx, win, &win->layout->chart, value, slot); break; - case NK_CHART_COLUMN: - flags = nk_chart_push_column(ctx, win, &win->layout->chart, value, slot); break; - default: - case NK_CHART_MAX: - flags = 0; - } - return flags; -} - -NK_API nk_flags -nk_chart_push(struct nk_context *ctx, float value) -{return nk_chart_push_slot(ctx, value, 0);} - -NK_API void -nk_chart_end(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_chart *chart; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return; - - win = ctx->current; - chart = &win->layout->chart; - NK_MEMSET(chart, 0, sizeof(*chart)); - return; -} - -NK_API void -nk_plot(struct nk_context *ctx, enum nk_chart_type type, const float *values, - int count, int offset) -{ - int i = 0; - float min_value; - float max_value; - - NK_ASSERT(ctx); - NK_ASSERT(values); - if (!ctx || !values || !count) return; - - min_value = values[offset]; - max_value = values[offset]; - for (i = 0; i < count; ++i) { - min_value = NK_MIN(values[i + offset], min_value); - max_value = NK_MAX(values[i + offset], max_value); - } - - if (nk_chart_begin(ctx, type, count, min_value, max_value)) { - for (i = 0; i < count; ++i) - nk_chart_push(ctx, values[i + offset]); - nk_chart_end(ctx); - } -} - -NK_API void -nk_plot_function(struct nk_context *ctx, enum nk_chart_type type, void *userdata, - float(*value_getter)(void* user, int index), int count, int offset) -{ - int i = 0; - float min_value; - float max_value; - - NK_ASSERT(ctx); - NK_ASSERT(value_getter); - if (!ctx || !value_getter || !count) return; - - max_value = min_value = value_getter(userdata, offset); - for (i = 0; i < count; ++i) { - float value = value_getter(userdata, i + offset); - min_value = NK_MIN(value, min_value); - max_value = NK_MAX(value, max_value); - } - - if (nk_chart_begin(ctx, type, count, min_value, max_value)) { - for (i = 0; i < count; ++i) - nk_chart_push(ctx, value_getter(userdata, i + offset)); - nk_chart_end(ctx); - } -} - -/* ------------------------------------------------------------- - * - * GROUP - * - * --------------------------------------------------------------*/ -NK_API int -nk_group_scrolled_offset_begin(struct nk_context *ctx, - nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags) -{ - struct nk_rect bounds; - struct nk_window panel; - struct nk_window *win; - - win = ctx->current; - nk_panel_alloc_space(&bounds, ctx); - {const struct nk_rect *c = &win->layout->clip; - if (!NK_INTERSECT(c->x, c->y, c->w, c->h, bounds.x, bounds.y, bounds.w, bounds.h) && - !(flags & NK_WINDOW_MOVABLE)) { - return 0; - }} - if (win->flags & NK_WINDOW_ROM) - flags |= NK_WINDOW_ROM; - - /* initialize a fake window to create the panel from */ - nk_zero(&panel, sizeof(panel)); - panel.bounds = bounds; - panel.flags = flags; - panel.scrollbar.x = *x_offset; - panel.scrollbar.y = *y_offset; - panel.buffer = win->buffer; - panel.layout = (struct nk_panel*)nk_create_panel(ctx); - ctx->current = &panel; - nk_panel_begin(ctx, (flags & NK_WINDOW_TITLE) ? title: 0, NK_PANEL_GROUP); - - win->buffer = panel.buffer; - win->buffer.clip = panel.layout->clip; - panel.layout->offset_x = x_offset; - panel.layout->offset_y = y_offset; - panel.layout->parent = win->layout; - win->layout = panel.layout; - - ctx->current = win; - if ((panel.layout->flags & NK_WINDOW_CLOSED) || - (panel.layout->flags & NK_WINDOW_MINIMIZED)) - { - nk_flags f = panel.layout->flags; - nk_group_scrolled_end(ctx); - if (f & NK_WINDOW_CLOSED) - return NK_WINDOW_CLOSED; - if (f & NK_WINDOW_MINIMIZED) - return NK_WINDOW_MINIMIZED; - } - return 1; -} - -NK_API void -nk_group_scrolled_end(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_panel *parent; - struct nk_panel *g; - - struct nk_rect clip; - struct nk_window pan; - struct nk_vec2 panel_padding; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) - return; - - /* make sure nk_group_begin was called correctly */ - NK_ASSERT(ctx->current); - win = ctx->current; - NK_ASSERT(win->layout); - g = win->layout; - NK_ASSERT(g->parent); - parent = g->parent; - - /* dummy window */ - nk_zero_struct(pan); - panel_padding = nk_panel_get_padding(&ctx->style, NK_PANEL_GROUP); - pan.bounds.y = g->bounds.y - (g->header_height + g->menu.h); - pan.bounds.x = g->bounds.x - panel_padding.x; - pan.bounds.w = g->bounds.w + 2 * panel_padding.x; - pan.bounds.h = g->bounds.h + g->header_height + g->menu.h; - if (g->flags & NK_WINDOW_BORDER) { - pan.bounds.x -= g->border; - pan.bounds.y -= g->border; - pan.bounds.w += 2*g->border; - pan.bounds.h += 2*g->border; - } - if (!(g->flags & NK_WINDOW_NO_SCROLLBAR)) { - pan.bounds.w += ctx->style.window.scrollbar_size.x; - pan.bounds.h += ctx->style.window.scrollbar_size.y; - } - pan.scrollbar.x = *g->offset_x; - pan.scrollbar.y = *g->offset_y; - pan.flags = g->flags; - pan.buffer = win->buffer; - pan.layout = g; - pan.parent = win; - ctx->current = &pan; - - /* make sure group has correct clipping rectangle */ - nk_unify(&clip, &parent->clip, pan.bounds.x, pan.bounds.y, - pan.bounds.x + pan.bounds.w, pan.bounds.y + pan.bounds.h + panel_padding.x); - nk_push_scissor(&pan.buffer, clip); - nk_end(ctx); - - win->buffer = pan.buffer; - nk_push_scissor(&win->buffer, parent->clip); - ctx->current = win; - win->layout = parent; - g->bounds = pan.bounds; - return; -} - -NK_API int -nk_group_scrolled_begin(struct nk_context *ctx, - struct nk_scroll *scroll, const char *title, nk_flags flags) -{return nk_group_scrolled_offset_begin(ctx, &scroll->x, &scroll->y, title, flags);} - -NK_API int -nk_group_begin_titled(struct nk_context *ctx, const char *id, - const char *title, nk_flags flags) -{ - int id_len; - nk_hash id_hash; - struct nk_window *win; - nk_uint *x_offset; - nk_uint *y_offset; - - NK_ASSERT(ctx); - NK_ASSERT(id); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout || !id) - return 0; - - /* find persistent group scrollbar value */ - win = ctx->current; - id_len = (int)nk_strlen(id); - id_hash = nk_murmur_hash(id, (int)id_len, NK_PANEL_GROUP); - x_offset = nk_find_value(win, id_hash); - y_offset = nk_find_value(win, id_hash+1); - if (!x_offset) { - x_offset = nk_add_value(ctx, win, id_hash, 0); - NK_ASSERT(x_offset); - if (!x_offset) return 0; - *x_offset = 0; - } - if (!y_offset) { - y_offset = nk_add_value(ctx, win, id_hash+1, 0); - NK_ASSERT(y_offset); - if (!y_offset) return 0; - *y_offset = 0; - } - return nk_group_scrolled_offset_begin(ctx, x_offset, y_offset, title, flags); -} - -NK_API int -nk_group_begin(struct nk_context *ctx, const char *title, nk_flags flags) -{ - return nk_group_begin_titled(ctx, title, title, flags); -} - -NK_API void -nk_group_end(struct nk_context *ctx) -{nk_group_scrolled_end(ctx);} - -NK_API int -nk_list_view_begin(struct nk_context *ctx, struct nk_list_view *view, - const char *title, nk_flags flags, int row_height, int row_count) -{ - int title_len; - nk_hash title_hash; - nk_uint *x_offset; - nk_uint *y_offset; - - int result; - struct nk_window *win; - struct nk_panel *layout; - const struct nk_style *style; - struct nk_vec2 item_spacing; - - NK_ASSERT(ctx); - NK_ASSERT(view); - NK_ASSERT(title); - if (!ctx || !view || !title) return 0; - - win = ctx->current; - style = &ctx->style; - item_spacing = style->window.spacing; - row_height += NK_MAX(0, (int)item_spacing.y); - - /* find persistent list view scrollbar offset */ - title_len = (int)nk_strlen(title); - title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_GROUP); - x_offset = nk_find_value(win, title_hash); - y_offset = nk_find_value(win, title_hash+1); - if (!x_offset) { - x_offset = nk_add_value(ctx, win, title_hash, 0); - NK_ASSERT(x_offset); - if (!x_offset) return 0; - *x_offset = 0; - } - if (!y_offset) { - y_offset = nk_add_value(ctx, win, title_hash+1, 0); - NK_ASSERT(y_offset); - if (!y_offset) return 0; - *y_offset = 0; - } - view->scroll_value = *y_offset; - view->scroll_pointer = y_offset; - - *y_offset = 0; - result = nk_group_scrolled_offset_begin(ctx, x_offset, y_offset, title, flags); - win = ctx->current; - layout = win->layout; - - view->total_height = row_height * NK_MAX(row_count,1); - view->begin = (int)NK_MAX(((float)view->scroll_value / (float)row_height), 0.0f); - view->count = (int)NK_MAX(nk_iceilf((layout->clip.h)/(float)row_height), 0); - view->end = view->begin + view->count; - view->ctx = ctx; - return result; -} - -NK_API void -nk_list_view_end(struct nk_list_view *view) -{ - struct nk_context *ctx; - struct nk_window *win; - struct nk_panel *layout; - - NK_ASSERT(view); - NK_ASSERT(view->ctx); - NK_ASSERT(view->scroll_pointer); - if (!view || !view->ctx) return; - - ctx = view->ctx; - win = ctx->current; - layout = win->layout; - layout->at_y = layout->bounds.y + (float)view->total_height; - *view->scroll_pointer = *view->scroll_pointer + view->scroll_value; - nk_group_end(view->ctx); -} - -/* -------------------------------------------------------------- - * - * POPUP - * - * --------------------------------------------------------------*/ -NK_API int -nk_popup_begin(struct nk_context *ctx, enum nk_popup_type type, - const char *title, nk_flags flags, struct nk_rect rect) -{ - struct nk_window *popup; - struct nk_window *win; - struct nk_panel *panel; - - int title_len; - nk_hash title_hash; - nk_size allocated; - - NK_ASSERT(ctx); - NK_ASSERT(title); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - panel = win->layout; - NK_ASSERT(!(panel->type & NK_PANEL_SET_POPUP) && "popups are not allowed to have popups"); - (void)panel; - title_len = (int)nk_strlen(title); - title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_POPUP); - - popup = win->popup.win; - if (!popup) { - popup = (struct nk_window*)nk_create_window(ctx); - popup->parent = win; - win->popup.win = popup; - win->popup.active = 0; - win->popup.type = NK_PANEL_POPUP; - } - - /* make sure we have correct popup */ - if (win->popup.name != title_hash) { - if (!win->popup.active) { - nk_zero(popup, sizeof(*popup)); - win->popup.name = title_hash; - win->popup.active = 1; - win->popup.type = NK_PANEL_POPUP; - } else return 0; - } - - /* popup position is local to window */ - ctx->current = popup; - rect.x += win->layout->clip.x; - rect.y += win->layout->clip.y; - - /* setup popup data */ - popup->parent = win; - popup->bounds = rect; - popup->seq = ctx->seq; - popup->layout = (struct nk_panel*)nk_create_panel(ctx); - popup->flags = flags; - popup->flags |= NK_WINDOW_BORDER; - if (type == NK_POPUP_DYNAMIC) - popup->flags |= NK_WINDOW_DYNAMIC; - - popup->buffer = win->buffer; - nk_start_popup(ctx, win); - allocated = ctx->memory.allocated; - nk_push_scissor(&popup->buffer, nk_null_rect); - - if (nk_panel_begin(ctx, title, NK_PANEL_POPUP)) { - /* popup is running therefore invalidate parent panels */ - struct nk_panel *root; - root = win->layout; - while (root) { - root->flags |= NK_WINDOW_ROM; - root->flags &= ~(nk_flags)NK_WINDOW_REMOVE_ROM; - root = root->parent; - } - win->popup.active = 1; - popup->layout->offset_x = &popup->scrollbar.x; - popup->layout->offset_y = &popup->scrollbar.y; - popup->layout->parent = win->layout; - return 1; - } else { - /* popup was closed/is invalid so cleanup */ - struct nk_panel *root; - root = win->layout; - while (root) { - root->flags |= NK_WINDOW_REMOVE_ROM; - root = root->parent; - } - win->popup.buf.active = 0; - win->popup.active = 0; - ctx->memory.allocated = allocated; - ctx->current = win; - nk_free_panel(ctx, popup->layout); - popup->layout = 0; - return 0; - } -} - -NK_INTERN int -nk_nonblock_begin(struct nk_context *ctx, - nk_flags flags, struct nk_rect body, struct nk_rect header, - enum nk_panel_type panel_type) -{ - struct nk_window *popup; - struct nk_window *win; - struct nk_panel *panel; - int is_active = nk_true; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - /* popups cannot have popups */ - win = ctx->current; - panel = win->layout; - NK_ASSERT(!(panel->type & NK_PANEL_SET_POPUP)); - (void)panel; - popup = win->popup.win; - if (!popup) { - /* create window for nonblocking popup */ - popup = (struct nk_window*)nk_create_window(ctx); - popup->parent = win; - win->popup.win = popup; - win->popup.type = panel_type; - nk_command_buffer_init(&popup->buffer, &ctx->memory, NK_CLIPPING_ON); - } else { - /* close the popup if user pressed outside or in the header */ - int pressed, in_body, in_header; - pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT); - in_body = nk_input_is_mouse_hovering_rect(&ctx->input, body); - in_header = nk_input_is_mouse_hovering_rect(&ctx->input, header); - if (pressed && (!in_body || in_header)) - is_active = nk_false; - } - win->popup.header = header; - - if (!is_active) { - /* remove read only mode from all parent panels */ - struct nk_panel *root = win->layout; - while (root) { - root->flags |= NK_WINDOW_REMOVE_ROM; - root = root->parent; - } - return is_active; - } - - popup->bounds = body; - popup->parent = win; - popup->layout = (struct nk_panel*)nk_create_panel(ctx); - popup->flags = flags; - popup->flags |= NK_WINDOW_BORDER; - popup->flags |= NK_WINDOW_DYNAMIC; - popup->seq = ctx->seq; - win->popup.active = 1; - NK_ASSERT(popup->layout); - - nk_start_popup(ctx, win); - popup->buffer = win->buffer; - nk_push_scissor(&popup->buffer, nk_null_rect); - ctx->current = popup; - - nk_panel_begin(ctx, 0, panel_type); - win->buffer = popup->buffer; - popup->layout->parent = win->layout; - popup->layout->offset_x = &popup->scrollbar.x; - popup->layout->offset_y = &popup->scrollbar.y; - - /* set read only mode to all parent panels */ - {struct nk_panel *root; - root = win->layout; - while (root) { - root->flags |= NK_WINDOW_ROM; - root = root->parent; - }} - return is_active; -} - -NK_API void -nk_popup_close(struct nk_context *ctx) -{ - struct nk_window *popup; - NK_ASSERT(ctx); - if (!ctx || !ctx->current) return; - - popup = ctx->current; - NK_ASSERT(popup->parent); - NK_ASSERT(popup->layout->type & NK_PANEL_SET_POPUP); - popup->flags |= NK_WINDOW_HIDDEN; -} - -NK_API void -nk_popup_end(struct nk_context *ctx) -{ - struct nk_window *win; - struct nk_window *popup; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return; - - popup = ctx->current; - if (!popup->parent) return; - win = popup->parent; - if (popup->flags & NK_WINDOW_HIDDEN) { - struct nk_panel *root; - root = win->layout; - while (root) { - root->flags |= NK_WINDOW_REMOVE_ROM; - root = root->parent; - } - win->popup.active = 0; - } - nk_push_scissor(&popup->buffer, nk_null_rect); - nk_end(ctx); - - win->buffer = popup->buffer; - nk_finish_popup(ctx, win); - ctx->current = win; - nk_push_scissor(&win->buffer, win->layout->clip); -} -/* ------------------------------------------------------------- - * - * TOOLTIP - * - * -------------------------------------------------------------- */ -NK_API int -nk_tooltip_begin(struct nk_context *ctx, float width) -{ - int x,y,w,h; - struct nk_window *win; - const struct nk_input *in; - struct nk_rect bounds; - int ret; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - /* make sure that no nonblocking popup is currently active */ - win = ctx->current; - in = &ctx->input; - if (win->popup.win && (win->popup.type & NK_PANEL_SET_NONBLOCK)) - return 0; - - w = nk_iceilf(width); - h = nk_iceilf(nk_null_rect.h); - x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x; - y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y; - - bounds.x = (float)x; - bounds.y = (float)y; - bounds.w = (float)w; - bounds.h = (float)h; - - ret = nk_popup_begin(ctx, NK_POPUP_DYNAMIC, - "__##Tooltip##__", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER, bounds); - if (ret) win->layout->flags &= ~(nk_flags)NK_WINDOW_ROM; - win->popup.type = NK_PANEL_TOOLTIP; - ctx->current->layout->type = NK_PANEL_TOOLTIP; - return ret; -} - -NK_API void -nk_tooltip_end(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return; - ctx->current->seq--; - nk_popup_close(ctx); - nk_popup_end(ctx); -} - -NK_API void -nk_tooltip(struct nk_context *ctx, const char *text) -{ - const struct nk_style *style; - struct nk_vec2 padding; - - int text_len; - float text_width; - float text_height; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - NK_ASSERT(text); - if (!ctx || !ctx->current || !ctx->current->layout || !text) - return; - - /* fetch configuration data */ - style = &ctx->style; - padding = style->window.padding; - - /* calculate size of the text and tooltip */ - text_len = nk_strlen(text); - text_width = style->font->width(style->font->userdata, - style->font->height, text, text_len); - text_width += (4 * padding.x); - text_height = (style->font->height + 2 * padding.y); - - /* execute tooltip and fill with text */ - if (nk_tooltip_begin(ctx, (float)text_width)) { - nk_layout_row_dynamic(ctx, (float)text_height, 1); - nk_text(ctx, text, text_len, NK_TEXT_LEFT); - nk_tooltip_end(ctx); - } -} -#ifdef NK_INCLUDE_STANDARD_VARARGS -NK_API void -nk_tooltipf(struct nk_context *ctx, const char *fmt, ...) -{ - char buf[256]; - va_list args; - va_start(args, fmt); - nk_strfmt(buf, NK_LEN(buf), fmt, args); - va_end(args); - nk_tooltip(ctx, buf); -} -#endif - -/* ------------------------------------------------------------- - * - * CONTEXTUAL - * - * -------------------------------------------------------------- */ -NK_API int -nk_contextual_begin(struct nk_context *ctx, nk_flags flags, struct nk_vec2 size, - struct nk_rect trigger_bounds) -{ - struct nk_window *win; - struct nk_window *popup; - struct nk_rect body; - - NK_STORAGE const struct nk_rect null_rect = {0,0,0,0}; - int is_clicked = 0; - int is_active = 0; - int is_open = 0; - int ret = 0; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - ++win->popup.con_count; - - /* check if currently active contextual is active */ - popup = win->popup.win; - is_open = (popup && win->popup.type == NK_PANEL_CONTEXTUAL); - is_clicked = nk_input_mouse_clicked(&ctx->input, NK_BUTTON_RIGHT, trigger_bounds); - if (win->popup.active_con && win->popup.con_count != win->popup.active_con) - return 0; - if ((is_clicked && is_open && !is_active) || (!is_open && !is_active && !is_clicked)) - return 0; - - /* calculate contextual position on click */ - win->popup.active_con = win->popup.con_count; - if (is_clicked) { - body.x = ctx->input.mouse.pos.x; - body.y = ctx->input.mouse.pos.y; - } else { - body.x = popup->bounds.x; - body.y = popup->bounds.y; - } - body.w = size.x; - body.h = size.y; - - /* start nonblocking contextual popup */ - ret = nk_nonblock_begin(ctx, flags|NK_WINDOW_NO_SCROLLBAR, body, - null_rect, NK_PANEL_CONTEXTUAL); - if (ret) win->popup.type = NK_PANEL_CONTEXTUAL; - else { - win->popup.active_con = 0; - if (win->popup.win) - win->popup.win->flags = 0; - } - return ret; -} - -NK_API int -nk_contextual_item_text(struct nk_context *ctx, const char *text, int len, - nk_flags alignment) -{ - struct nk_window *win; - const struct nk_input *in; - const struct nk_style *style; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding); - if (!state) return nk_false; - - in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_text(&ctx->last_widget_state, &win->buffer, bounds, - text, len, alignment, NK_BUTTON_DEFAULT, &style->contextual_button, in, style->font)) { - nk_contextual_close(ctx); - return nk_true; - } - return nk_false; -} - -NK_API int nk_contextual_item_label(struct nk_context *ctx, const char *label, nk_flags align) -{return nk_contextual_item_text(ctx, label, nk_strlen(label), align);} - -NK_API int -nk_contextual_item_image_text(struct nk_context *ctx, struct nk_image img, - const char *text, int len, nk_flags align) -{ - struct nk_window *win; - const struct nk_input *in; - const struct nk_style *style; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding); - if (!state) return nk_false; - - in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_text_image(&ctx->last_widget_state, &win->buffer, bounds, - img, text, len, align, NK_BUTTON_DEFAULT, &style->contextual_button, style->font, in)){ - nk_contextual_close(ctx); - return nk_true; - } - return nk_false; -} - -NK_API int nk_contextual_item_image_label(struct nk_context *ctx, struct nk_image img, - const char *label, nk_flags align) -{return nk_contextual_item_image_text(ctx, img, label, nk_strlen(label), align);} - -NK_API int -nk_contextual_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type symbol, - const char *text, int len, nk_flags align) -{ - struct nk_window *win; - const struct nk_input *in; - const struct nk_style *style; - - struct nk_rect bounds; - enum nk_widget_layout_states state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding); - if (!state) return nk_false; - - in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, bounds, - symbol, text, len, align, NK_BUTTON_DEFAULT, &style->contextual_button, style->font, in)) { - nk_contextual_close(ctx); - return nk_true; - } - return nk_false; -} - -NK_API int nk_contextual_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type symbol, - const char *text, nk_flags align) -{return nk_contextual_item_symbol_text(ctx, symbol, text, nk_strlen(text), align);} - -NK_API void -nk_contextual_close(struct nk_context *ctx) -{ - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) return; - nk_popup_close(ctx); -} - -NK_API void -nk_contextual_end(struct nk_context *ctx) -{ - struct nk_window *popup; - struct nk_panel *panel; - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return; - - popup = ctx->current; - panel = popup->layout; - NK_ASSERT(popup->parent); - NK_ASSERT(panel->type & NK_PANEL_SET_POPUP); - if (panel->flags & NK_WINDOW_DYNAMIC) { - /* Close behavior - This is a bit of a hack solution since we do not know before we end our popup - how big it will be. We therefore do not directly know when a - click outside the non-blocking popup must close it at that direct frame. - Instead it will be closed in the next frame.*/ - struct nk_rect body = {0,0,0,0}; - if (panel->at_y < (panel->bounds.y + panel->bounds.h)) { - struct nk_vec2 padding = nk_panel_get_padding(&ctx->style, panel->type); - body = panel->bounds; - body.y = (panel->at_y + panel->footer_height + panel->border + padding.y + panel->row.height); - body.h = (panel->bounds.y + panel->bounds.h) - body.y; - } - {int pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT); - int in_body = nk_input_is_mouse_hovering_rect(&ctx->input, body); - if (pressed && in_body) - popup->flags |= NK_WINDOW_HIDDEN; - } - } - if (popup->flags & NK_WINDOW_HIDDEN) - popup->seq = 0; - nk_popup_end(ctx); - return; -} -/* ------------------------------------------------------------- - * - * COMBO - * - * --------------------------------------------------------------*/ -NK_INTERN int -nk_combo_begin(struct nk_context *ctx, struct nk_window *win, - struct nk_vec2 size, int is_clicked, struct nk_rect header) -{ - struct nk_window *popup; - int is_open = 0; - int is_active = 0; - struct nk_rect body; - nk_hash hash; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - popup = win->popup.win; - body.x = header.x; - body.w = size.x; - body.y = header.y + header.h-ctx->style.window.combo_border; - body.h = size.y; - - hash = win->popup.combo_count++; - is_open = (popup) ? nk_true:nk_false; - is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_COMBO); - if ((is_clicked && is_open && !is_active) || (is_open && !is_active) || - (!is_open && !is_active && !is_clicked)) return 0; - if (!nk_nonblock_begin(ctx, 0, body, - (is_clicked && is_open)?nk_rect(0,0,0,0):header, NK_PANEL_COMBO)) return 0; - - win->popup.type = NK_PANEL_COMBO; - win->popup.name = hash; - return 1; -} - -NK_API int -nk_combo_begin_text(struct nk_context *ctx, const char *selected, int len, - struct nk_vec2 size) -{ - const struct nk_input *in; - struct nk_window *win; - struct nk_style *style; - - enum nk_widget_layout_states s; - int is_clicked = nk_false; - struct nk_rect header; - const struct nk_style_item *background; - struct nk_text text; - - NK_ASSERT(ctx); - NK_ASSERT(selected); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout || !selected) - return 0; - - win = ctx->current; - style = &ctx->style; - s = nk_widget(&header, ctx); - if (s == NK_WIDGET_INVALID) - return 0; - - in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; - if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) - is_clicked = nk_true; - - /* draw combo box header background and border */ - if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) { - background = &style->combo.active; - text.text = style->combo.label_active; - } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) { - background = &style->combo.hover; - text.text = style->combo.label_hover; - } else { - background = &style->combo.normal; - text.text = style->combo.label_normal; - } - if (background->type == NK_STYLE_ITEM_IMAGE) { - text.background = nk_rgba(0,0,0,0); - nk_draw_image(&win->buffer, header, &background->data.image, nk_white); - } else { - text.background = background->data.color; - nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); - nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); - } - { - /* print currently selected text item */ - struct nk_rect label; - struct nk_rect button; - struct nk_rect content; - - enum nk_symbol_type sym; - if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - sym = style->combo.sym_hover; - else if (is_clicked) - sym = style->combo.sym_active; - else sym = style->combo.sym_normal; - - /* calculate button */ - button.w = header.h - 2 * style->combo.button_padding.y; - button.x = (header.x + header.w - header.h) - style->combo.button_padding.x; - button.y = header.y + style->combo.button_padding.y; - button.h = button.w; - - content.x = button.x + style->combo.button.padding.x; - content.y = button.y + style->combo.button.padding.y; - content.w = button.w - 2 * style->combo.button.padding.x; - content.h = button.h - 2 * style->combo.button.padding.y; - - /* draw selected label */ - text.padding = nk_vec2(0,0); - label.x = header.x + style->combo.content_padding.x; - label.y = header.y + style->combo.content_padding.y; - label.w = button.x - (style->combo.content_padding.x + style->combo.spacing.x) - label.x;; - label.h = header.h - 2 * style->combo.content_padding.y; - nk_widget_text(&win->buffer, label, selected, len, &text, - NK_TEXT_LEFT, ctx->style.font); - - /* draw open/close button */ - nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state, - &ctx->style.combo.button, sym, style->font); - } - return nk_combo_begin(ctx, win, size, is_clicked, header); -} - -NK_API int nk_combo_begin_label(struct nk_context *ctx, const char *selected, struct nk_vec2 size) -{return nk_combo_begin_text(ctx, selected, nk_strlen(selected), size);} - -NK_API int -nk_combo_begin_color(struct nk_context *ctx, struct nk_color color, struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_style *style; - const struct nk_input *in; - - struct nk_rect header; - int is_clicked = nk_false; - enum nk_widget_layout_states s; - const struct nk_style_item *background; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - s = nk_widget(&header, ctx); - if (s == NK_WIDGET_INVALID) - return 0; - - in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; - if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) - is_clicked = nk_true; - - /* draw combo box header background and border */ - if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) - background = &style->combo.active; - else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - background = &style->combo.hover; - else background = &style->combo.normal; - - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(&win->buffer, header, &background->data.image,nk_white); - } else { - nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); - nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); - } - { - struct nk_rect content; - struct nk_rect button; - struct nk_rect bounds; - - enum nk_symbol_type sym; - if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - sym = style->combo.sym_hover; - else if (is_clicked) - sym = style->combo.sym_active; - else sym = style->combo.sym_normal; - - /* calculate button */ - button.w = header.h - 2 * style->combo.button_padding.y; - button.x = (header.x + header.w - header.h) - style->combo.button_padding.x; - button.y = header.y + style->combo.button_padding.y; - button.h = button.w; - - content.x = button.x + style->combo.button.padding.x; - content.y = button.y + style->combo.button.padding.y; - content.w = button.w - 2 * style->combo.button.padding.x; - content.h = button.h - 2 * style->combo.button.padding.y; - - /* draw color */ - bounds.h = header.h - 4 * style->combo.content_padding.y; - bounds.y = header.y + 2 * style->combo.content_padding.y; - bounds.x = header.x + 2 * style->combo.content_padding.x; - bounds.w = (button.x - (style->combo.content_padding.x + style->combo.spacing.x)) - bounds.x; - nk_fill_rect(&win->buffer, bounds, 0, color); - - /* draw open/close button */ - nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state, - &ctx->style.combo.button, sym, style->font); - } - return nk_combo_begin(ctx, win, size, is_clicked, header); -} - -NK_API int -nk_combo_begin_symbol(struct nk_context *ctx, enum nk_symbol_type symbol, struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_style *style; - const struct nk_input *in; - - struct nk_rect header; - int is_clicked = nk_false; - enum nk_widget_layout_states s; - const struct nk_style_item *background; - struct nk_color sym_background; - struct nk_color symbol_color; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - s = nk_widget(&header, ctx); - if (s == NK_WIDGET_INVALID) - return 0; - - in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; - if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) - is_clicked = nk_true; - - /* draw combo box header background and border */ - if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) { - background = &style->combo.active; - symbol_color = style->combo.symbol_active; - } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) { - background = &style->combo.hover; - symbol_color = style->combo.symbol_hover; - } else { - background = &style->combo.normal; - symbol_color = style->combo.symbol_hover; - } - - if (background->type == NK_STYLE_ITEM_IMAGE) { - sym_background = nk_rgba(0,0,0,0); - nk_draw_image(&win->buffer, header, &background->data.image, nk_white); - } else { - sym_background = background->data.color; - nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); - nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); - } - { - struct nk_rect bounds = {0,0,0,0}; - struct nk_rect content; - struct nk_rect button; - - enum nk_symbol_type sym; - if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - sym = style->combo.sym_hover; - else if (is_clicked) - sym = style->combo.sym_active; - else sym = style->combo.sym_normal; - - /* calculate button */ - button.w = header.h - 2 * style->combo.button_padding.y; - button.x = (header.x + header.w - header.h) - style->combo.button_padding.y; - button.y = header.y + style->combo.button_padding.y; - button.h = button.w; - - content.x = button.x + style->combo.button.padding.x; - content.y = button.y + style->combo.button.padding.y; - content.w = button.w - 2 * style->combo.button.padding.x; - content.h = button.h - 2 * style->combo.button.padding.y; - - /* draw symbol */ - bounds.h = header.h - 2 * style->combo.content_padding.y; - bounds.y = header.y + style->combo.content_padding.y; - bounds.x = header.x + style->combo.content_padding.x; - bounds.w = (button.x - style->combo.content_padding.y) - bounds.x; - nk_draw_symbol(&win->buffer, symbol, bounds, sym_background, symbol_color, - 1.0f, style->font); - - /* draw open/close button */ - nk_draw_button_symbol(&win->buffer, &bounds, &content, ctx->last_widget_state, - &ctx->style.combo.button, sym, style->font); - } - return nk_combo_begin(ctx, win, size, is_clicked, header); -} - -NK_API int -nk_combo_begin_symbol_text(struct nk_context *ctx, const char *selected, int len, - enum nk_symbol_type symbol, struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_style *style; - struct nk_input *in; - - struct nk_rect header; - int is_clicked = nk_false; - enum nk_widget_layout_states s; - const struct nk_style_item *background; - struct nk_color symbol_color; - struct nk_text text; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - s = nk_widget(&header, ctx); - if (!s) return 0; - - in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; - if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) - is_clicked = nk_true; - - /* draw combo box header background and border */ - if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) { - background = &style->combo.active; - symbol_color = style->combo.symbol_active; - text.text = style->combo.label_active; - } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) { - background = &style->combo.hover; - symbol_color = style->combo.symbol_hover; - text.text = style->combo.label_hover; - } else { - background = &style->combo.normal; - symbol_color = style->combo.symbol_normal; - text.text = style->combo.label_normal; - } - if (background->type == NK_STYLE_ITEM_IMAGE) { - text.background = nk_rgba(0,0,0,0); - nk_draw_image(&win->buffer, header, &background->data.image, nk_white); - } else { - text.background = background->data.color; - nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); - nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); - } - { - struct nk_rect content; - struct nk_rect button; - struct nk_rect label; - struct nk_rect image; - - enum nk_symbol_type sym; - if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - sym = style->combo.sym_hover; - else if (is_clicked) - sym = style->combo.sym_active; - else sym = style->combo.sym_normal; - - /* calculate button */ - button.w = header.h - 2 * style->combo.button_padding.y; - button.x = (header.x + header.w - header.h) - style->combo.button_padding.x; - button.y = header.y + style->combo.button_padding.y; - button.h = button.w; - - content.x = button.x + style->combo.button.padding.x; - content.y = button.y + style->combo.button.padding.y; - content.w = button.w - 2 * style->combo.button.padding.x; - content.h = button.h - 2 * style->combo.button.padding.y; - nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state, - &ctx->style.combo.button, sym, style->font); - - /* draw symbol */ - image.x = header.x + style->combo.content_padding.x; - image.y = header.y + style->combo.content_padding.y; - image.h = header.h - 2 * style->combo.content_padding.y; - image.w = image.h; - nk_draw_symbol(&win->buffer, symbol, image, text.background, symbol_color, - 1.0f, style->font); - - /* draw label */ - text.padding = nk_vec2(0,0); - label.x = image.x + image.w + style->combo.spacing.x + style->combo.content_padding.x; - label.y = header.y + style->combo.content_padding.y; - label.w = (button.x - style->combo.content_padding.x) - label.x; - label.h = header.h - 2 * style->combo.content_padding.y; - nk_widget_text(&win->buffer, label, selected, len, &text, NK_TEXT_LEFT, style->font); - } - return nk_combo_begin(ctx, win, size, is_clicked, header); -} - -NK_API int -nk_combo_begin_image(struct nk_context *ctx, struct nk_image img, struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_style *style; - const struct nk_input *in; - - struct nk_rect header; - int is_clicked = nk_false; - enum nk_widget_layout_states s; - const struct nk_style_item *background; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - s = nk_widget(&header, ctx); - if (s == NK_WIDGET_INVALID) - return 0; - - in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; - if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) - is_clicked = nk_true; - - /* draw combo box header background and border */ - if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) - background = &style->combo.active; - else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - background = &style->combo.hover; - else background = &style->combo.normal; - - if (background->type == NK_STYLE_ITEM_IMAGE) { - nk_draw_image(&win->buffer, header, &background->data.image, nk_white); - } else { - nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); - nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); - } - { - struct nk_rect bounds = {0,0,0,0}; - struct nk_rect content; - struct nk_rect button; - - enum nk_symbol_type sym; - if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - sym = style->combo.sym_hover; - else if (is_clicked) - sym = style->combo.sym_active; - else sym = style->combo.sym_normal; - - /* calculate button */ - button.w = header.h - 2 * style->combo.button_padding.y; - button.x = (header.x + header.w - header.h) - style->combo.button_padding.y; - button.y = header.y + style->combo.button_padding.y; - button.h = button.w; - - content.x = button.x + style->combo.button.padding.x; - content.y = button.y + style->combo.button.padding.y; - content.w = button.w - 2 * style->combo.button.padding.x; - content.h = button.h - 2 * style->combo.button.padding.y; - - /* draw image */ - bounds.h = header.h - 2 * style->combo.content_padding.y; - bounds.y = header.y + style->combo.content_padding.y; - bounds.x = header.x + style->combo.content_padding.x; - bounds.w = (button.x - style->combo.content_padding.y) - bounds.x; - nk_draw_image(&win->buffer, bounds, &img, nk_white); - - /* draw open/close button */ - nk_draw_button_symbol(&win->buffer, &bounds, &content, ctx->last_widget_state, - &ctx->style.combo.button, sym, style->font); - } - return nk_combo_begin(ctx, win, size, is_clicked, header); -} - -NK_API int -nk_combo_begin_image_text(struct nk_context *ctx, const char *selected, int len, - struct nk_image img, struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_style *style; - struct nk_input *in; - - struct nk_rect header; - int is_clicked = nk_false; - enum nk_widget_layout_states s; - const struct nk_style_item *background; - struct nk_text text; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - style = &ctx->style; - s = nk_widget(&header, ctx); - if (!s) return 0; - - in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_ROM)? 0: &ctx->input; - if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT)) - is_clicked = nk_true; - - /* draw combo box header background and border */ - if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) { - background = &style->combo.active; - text.text = style->combo.label_active; - } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) { - background = &style->combo.hover; - text.text = style->combo.label_hover; - } else { - background = &style->combo.normal; - text.text = style->combo.label_normal; - } - if (background->type == NK_STYLE_ITEM_IMAGE) { - text.background = nk_rgba(0,0,0,0); - nk_draw_image(&win->buffer, header, &background->data.image, nk_white); - } else { - text.background = background->data.color; - nk_fill_rect(&win->buffer, header, style->combo.rounding, background->data.color); - nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, style->combo.border_color); - } - { - struct nk_rect content; - struct nk_rect button; - struct nk_rect label; - struct nk_rect image; - - enum nk_symbol_type sym; - if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) - sym = style->combo.sym_hover; - else if (is_clicked) - sym = style->combo.sym_active; - else sym = style->combo.sym_normal; - - /* calculate button */ - button.w = header.h - 2 * style->combo.button_padding.y; - button.x = (header.x + header.w - header.h) - style->combo.button_padding.x; - button.y = header.y + style->combo.button_padding.y; - button.h = button.w; - - content.x = button.x + style->combo.button.padding.x; - content.y = button.y + style->combo.button.padding.y; - content.w = button.w - 2 * style->combo.button.padding.x; - content.h = button.h - 2 * style->combo.button.padding.y; - nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state, - &ctx->style.combo.button, sym, style->font); - - /* draw image */ - image.x = header.x + style->combo.content_padding.x; - image.y = header.y + style->combo.content_padding.y; - image.h = header.h - 2 * style->combo.content_padding.y; - image.w = image.h; - nk_draw_image(&win->buffer, image, &img, nk_white); - - /* draw label */ - text.padding = nk_vec2(0,0); - label.x = image.x + image.w + style->combo.spacing.x + style->combo.content_padding.x; - label.y = header.y + style->combo.content_padding.y; - label.w = (button.x - style->combo.content_padding.x) - label.x; - label.h = header.h - 2 * style->combo.content_padding.y; - nk_widget_text(&win->buffer, label, selected, len, &text, NK_TEXT_LEFT, style->font); - } - return nk_combo_begin(ctx, win, size, is_clicked, header); -} - -NK_API int nk_combo_begin_symbol_label(struct nk_context *ctx, - const char *selected, enum nk_symbol_type type, struct nk_vec2 size) -{return nk_combo_begin_symbol_text(ctx, selected, nk_strlen(selected), type, size);} - -NK_API int nk_combo_begin_image_label(struct nk_context *ctx, - const char *selected, struct nk_image img, struct nk_vec2 size) -{return nk_combo_begin_image_text(ctx, selected, nk_strlen(selected), img, size);} - -NK_API int nk_combo_item_text(struct nk_context *ctx, const char *text, int len,nk_flags align) -{return nk_contextual_item_text(ctx, text, len, align);} - -NK_API int nk_combo_item_label(struct nk_context *ctx, const char *label, nk_flags align) -{return nk_contextual_item_label(ctx, label, align);} - -NK_API int nk_combo_item_image_text(struct nk_context *ctx, struct nk_image img, const char *text, - int len, nk_flags alignment) -{return nk_contextual_item_image_text(ctx, img, text, len, alignment);} - -NK_API int nk_combo_item_image_label(struct nk_context *ctx, struct nk_image img, - const char *text, nk_flags alignment) -{return nk_contextual_item_image_label(ctx, img, text, alignment);} - -NK_API int nk_combo_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym, - const char *text, int len, nk_flags alignment) -{return nk_contextual_item_symbol_text(ctx, sym, text, len, alignment);} - -NK_API int nk_combo_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym, - const char *label, nk_flags alignment) -{return nk_contextual_item_symbol_label(ctx, sym, label, alignment);} - -NK_API void nk_combo_end(struct nk_context *ctx) -{nk_contextual_end(ctx);} - -NK_API void nk_combo_close(struct nk_context *ctx) -{nk_contextual_close(ctx);} - -NK_API int -nk_combo(struct nk_context *ctx, const char **items, int count, - int selected, int item_height, struct nk_vec2 size) -{ - int i = 0; - int max_height; - struct nk_vec2 item_spacing; - struct nk_vec2 window_padding; - - NK_ASSERT(ctx); - NK_ASSERT(items); - NK_ASSERT(ctx->current); - if (!ctx || !items ||!count) - return selected; - - item_spacing = ctx->style.window.spacing; - window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type); - max_height = count * item_height + count * (int)item_spacing.y; - max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2; - size.y = NK_MIN(size.y, (float)max_height); - if (nk_combo_begin_label(ctx, items[selected], size)) { - nk_layout_row_dynamic(ctx, (float)item_height, 1); - for (i = 0; i < count; ++i) { - if (nk_combo_item_label(ctx, items[i], NK_TEXT_LEFT)) - selected = i; - } - nk_combo_end(ctx); - } - return selected; -} - -NK_API int -nk_combo_separator(struct nk_context *ctx, const char *items_separated_by_separator, - int separator, int selected, int count, int item_height, struct nk_vec2 size) -{ - int i; - int max_height; - struct nk_vec2 item_spacing; - struct nk_vec2 window_padding; - const char *current_item; - const char *iter; - int length = 0; - - NK_ASSERT(ctx); - NK_ASSERT(items_separated_by_separator); - if (!ctx || !items_separated_by_separator) - return selected; - - /* calculate popup window */ - item_spacing = ctx->style.window.spacing; - window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type); - max_height = count * item_height + count * (int)item_spacing.y; - max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2; - size.y = NK_MIN(size.y, (float)max_height); - - /* find selected item */ - current_item = items_separated_by_separator; - for (i = 0; i < count; ++i) { - iter = current_item; - while (*iter && *iter != separator) iter++; - length = (int)(iter - current_item); - if (i == selected) break; - current_item = iter + 1; - } - - if (nk_combo_begin_text(ctx, current_item, length, size)) { - current_item = items_separated_by_separator; - nk_layout_row_dynamic(ctx, (float)item_height, 1); - for (i = 0; i < count; ++i) { - iter = current_item; - while (*iter && *iter != separator) iter++; - length = (int)(iter - current_item); - if (nk_combo_item_text(ctx, current_item, length, NK_TEXT_LEFT)) - selected = i; - current_item = current_item + length + 1; - } - nk_combo_end(ctx); - } - return selected; -} - -NK_API int -nk_combo_string(struct nk_context *ctx, const char *items_separated_by_zeros, - int selected, int count, int item_height, struct nk_vec2 size) -{return nk_combo_separator(ctx, items_separated_by_zeros, '\0', selected, count, item_height, size);} - -NK_API int -nk_combo_callback(struct nk_context *ctx, void(*item_getter)(void*, int, const char**), - void *userdata, int selected, int count, int item_height, struct nk_vec2 size) -{ - int i; - int max_height; - struct nk_vec2 item_spacing; - struct nk_vec2 window_padding; - const char *item; - - NK_ASSERT(ctx); - NK_ASSERT(item_getter); - if (!ctx || !item_getter) - return selected; - - /* calculate popup window */ - item_spacing = ctx->style.window.spacing; - window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type); - max_height = count * item_height + count * (int)item_spacing.y; - max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2; - size.y = NK_MIN(size.y, (float)max_height); - - item_getter(userdata, selected, &item); - if (nk_combo_begin_label(ctx, item, size)) { - nk_layout_row_dynamic(ctx, (float)item_height, 1); - for (i = 0; i < count; ++i) { - item_getter(userdata, i, &item); - if (nk_combo_item_label(ctx, item, NK_TEXT_LEFT)) - selected = i; - } - nk_combo_end(ctx); - } - return selected; -} - -NK_API void nk_combobox(struct nk_context *ctx, const char **items, int count, - int *selected, int item_height, struct nk_vec2 size) -{*selected = nk_combo(ctx, items, count, *selected, item_height, size);} - -NK_API void nk_combobox_string(struct nk_context *ctx, const char *items_separated_by_zeros, - int *selected, int count, int item_height, struct nk_vec2 size) -{*selected = nk_combo_string(ctx, items_separated_by_zeros, *selected, count, item_height, size);} - -NK_API void nk_combobox_separator(struct nk_context *ctx, const char *items_separated_by_separator, - int separator,int *selected, int count, int item_height, struct nk_vec2 size) -{*selected = nk_combo_separator(ctx, items_separated_by_separator, separator, - *selected, count, item_height, size);} - -NK_API void nk_combobox_callback(struct nk_context *ctx, - void(*item_getter)(void* data, int id, const char **out_text), - void *userdata, int *selected, int count, int item_height, struct nk_vec2 size) -{*selected = nk_combo_callback(ctx, item_getter, userdata, *selected, count, item_height, size);} - -/* - * ------------------------------------------------------------- - * - * MENU - * - * -------------------------------------------------------------- - */ -NK_INTERN int -nk_menu_begin(struct nk_context *ctx, struct nk_window *win, - const char *id, int is_clicked, struct nk_rect header, struct nk_vec2 size) -{ - int is_open = 0; - int is_active = 0; - struct nk_rect body; - struct nk_window *popup; - nk_hash hash = nk_murmur_hash(id, (int)nk_strlen(id), NK_PANEL_MENU); - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - body.x = header.x; - body.w = size.x; - body.y = header.y + header.h; - body.h = size.y; - - popup = win->popup.win; - is_open = popup ? nk_true : nk_false; - is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_MENU); - if ((is_clicked && is_open && !is_active) || (is_open && !is_active) || - (!is_open && !is_active && !is_clicked)) return 0; - if (!nk_nonblock_begin(ctx, NK_WINDOW_NO_SCROLLBAR, body, header, NK_PANEL_MENU)) - return 0; - - win->popup.type = NK_PANEL_MENU; - win->popup.name = hash; - return 1; -} - -NK_API int -nk_menu_begin_text(struct nk_context *ctx, const char *title, int len, - nk_flags align, struct nk_vec2 size) -{ - struct nk_window *win; - const struct nk_input *in; - struct nk_rect header; - int is_clicked = nk_false; - nk_flags state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - state = nk_widget(&header, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || win->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_text(&ctx->last_widget_state, &win->buffer, header, - title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in, ctx->style.font)) - is_clicked = nk_true; - return nk_menu_begin(ctx, win, title, is_clicked, header, size); -} - -NK_API int nk_menu_begin_label(struct nk_context *ctx, - const char *text, nk_flags align, struct nk_vec2 size) -{return nk_menu_begin_text(ctx, text, nk_strlen(text), align, size);} - -NK_API int -nk_menu_begin_image(struct nk_context *ctx, const char *id, struct nk_image img, - struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_rect header; - const struct nk_input *in; - int is_clicked = nk_false; - nk_flags state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - state = nk_widget(&header, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_image(&ctx->last_widget_state, &win->buffer, header, - img, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in)) - is_clicked = nk_true; - return nk_menu_begin(ctx, win, id, is_clicked, header, size); -} - -NK_API int -nk_menu_begin_symbol(struct nk_context *ctx, const char *id, - enum nk_symbol_type sym, struct nk_vec2 size) -{ - struct nk_window *win; - const struct nk_input *in; - struct nk_rect header; - int is_clicked = nk_false; - nk_flags state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - state = nk_widget(&header, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_symbol(&ctx->last_widget_state, &win->buffer, header, - sym, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in, ctx->style.font)) - is_clicked = nk_true; - return nk_menu_begin(ctx, win, id, is_clicked, header, size); -} - -NK_API int -nk_menu_begin_image_text(struct nk_context *ctx, const char *title, int len, - nk_flags align, struct nk_image img, struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_rect header; - const struct nk_input *in; - int is_clicked = nk_false; - nk_flags state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - state = nk_widget(&header, ctx); - if (!state) return 0; - in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_text_image(&ctx->last_widget_state, &win->buffer, - header, img, title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button, - ctx->style.font, in)) - is_clicked = nk_true; - return nk_menu_begin(ctx, win, title, is_clicked, header, size); -} - -NK_API int nk_menu_begin_image_label(struct nk_context *ctx, - const char *title, nk_flags align, struct nk_image img, struct nk_vec2 size) -{return nk_menu_begin_image_text(ctx, title, nk_strlen(title), align, img, size);} - -NK_API int -nk_menu_begin_symbol_text(struct nk_context *ctx, const char *title, int len, - nk_flags align, enum nk_symbol_type sym, struct nk_vec2 size) -{ - struct nk_window *win; - struct nk_rect header; - const struct nk_input *in; - int is_clicked = nk_false; - nk_flags state; - - NK_ASSERT(ctx); - NK_ASSERT(ctx->current); - NK_ASSERT(ctx->current->layout); - if (!ctx || !ctx->current || !ctx->current->layout) - return 0; - - win = ctx->current; - state = nk_widget(&header, ctx); - if (!state) return 0; - - in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; - if (nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, - header, sym, title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button, - ctx->style.font, in)) is_clicked = nk_true; - return nk_menu_begin(ctx, win, title, is_clicked, header, size); -} - -NK_API int nk_menu_begin_symbol_label(struct nk_context *ctx, - const char *title, nk_flags align, enum nk_symbol_type sym, struct nk_vec2 size ) -{return nk_menu_begin_symbol_text(ctx, title, nk_strlen(title), align,sym,size);} - -NK_API int nk_menu_item_text(struct nk_context *ctx, const char *title, int len, nk_flags align) -{return nk_contextual_item_text(ctx, title, len, align);} - -NK_API int nk_menu_item_label(struct nk_context *ctx, const char *label, nk_flags align) -{return nk_contextual_item_label(ctx, label, align);} - -NK_API int nk_menu_item_image_label(struct nk_context *ctx, struct nk_image img, - const char *label, nk_flags align) -{return nk_contextual_item_image_label(ctx, img, label, align);} - -NK_API int nk_menu_item_image_text(struct nk_context *ctx, struct nk_image img, - const char *text, int len, nk_flags align) -{return nk_contextual_item_image_text(ctx, img, text, len, align);} - -NK_API int nk_menu_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym, - const char *text, int len, nk_flags align) -{return nk_contextual_item_symbol_text(ctx, sym, text, len, align);} - -NK_API int nk_menu_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym, - const char *label, nk_flags align) -{return nk_contextual_item_symbol_label(ctx, sym, label, align);} - -NK_API void nk_menu_close(struct nk_context *ctx) -{nk_contextual_close(ctx);} - -NK_API void -nk_menu_end(struct nk_context *ctx) -{nk_contextual_end(ctx);} - -#endif /* NK_IMPLEMENTATION */ - -/* -/// ## License -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~none -/// ------------------------------------------------------------------------------ -/// This software is available under 2 licenses -- choose whichever you prefer. -/// ------------------------------------------------------------------------------ -/// ALTERNATIVE A - MIT License -/// Copyright (c) 2016-2018 Micha Mettke -/// Permission is hereby granted, free of charge, to any person obtaining a copy of -/// this software and associated documentation files (the "Software"), to deal in -/// the Software without restriction, including without limitation the rights to -/// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -/// of the Software, and to permit persons to whom the Software is furnished to do -/// so, subject to the following conditions: -/// The above copyright notice and this permission notice shall be included in all -/// copies or substantial portions of the Software. -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. -/// ------------------------------------------------------------------------------ -/// ALTERNATIVE B - Public Domain (www.unlicense.org) -/// This is free and unencumbered software released into the public domain. -/// Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -/// software, either in source code form or as a compiled binary, for any purpose, -/// commercial or non-commercial, and by any means. -/// In jurisdictions that recognize copyright laws, the author or authors of this -/// software dedicate any and all copyright interest in the software to the public -/// domain. We make this dedication for the benefit of the public at large and to -/// the detriment of our heirs and successors. We intend this dedication to be an -/// overt act of relinquishment in perpetuity of all present and future rights to -/// this software under copyright law. -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -/// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -/// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -/// ------------------------------------------------------------------------------ -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -/// ## Changelog -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~none -/// [date][x.yy.zz]-[description] -/// -[date]: date on which the change has been pushed -/// -[x.yy.zz]: Numerical version string representation. Each version number on the right -/// resets back to zero if version on the left is incremented. -/// - [x]: Major version with API and library breaking -/// - [yy]: Minor version with non-breaking API and library changes -/// - [zz]: Bug fix version with no direct changes to API -/// -/// - 2018/02/23 (3.00.6) - Fixed slider dragging behavior -/// - 2018/01/31 (3.00.5) - Fixed overcalculation of cursor data in font baking process -/// - 2018/01/31 (3.00.4) - Removed name collision with stb_truetype -/// - 2018/01/28 (3.00.3) - Fixed panel window border drawing bug -/// - 2018/01/12 (3.00.2) - Added `nk_group_begin_titled` for separed group identifier and title -/// - 2018/01/07 (3.00.1) - Started to change documentation style -/// - 2018/01/05 (3.00.0) - BREAKING CHANGE: The previous color picker API was broken -/// because of conversions between float and byte color representation. -/// Color pickers now use floating point values to represent -/// HSV values. To get back the old behavior I added some additional -/// color conversion functions to cast between nk_color and -/// nk_colorf. -/// - 2017/12/23 (2.00.7) - Fixed small warning -/// - 2017/12/23 (2.00.7) - Fixed nk_edit_buffer behavior if activated to allow input -/// - 2017/12/23 (2.00.7) - Fixed modifyable progressbar dragging visuals and input behavior -/// - 2017/12/04 (2.00.6) - Added formated string tooltip widget -/// - 2017/11/18 (2.00.5) - Fixed window becoming hidden with flag NK_WINDOW_NO_INPUT -/// - 2017/11/15 (2.00.4) - Fixed font merging -/// - 2017/11/07 (2.00.3) - Fixed window size and position modifier functions -/// - 2017/09/14 (2.00.2) - Fixed nk_edit_buffer and nk_edit_focus behavior -/// - 2017/09/14 (2.00.1) - Fixed window closing behavior -/// - 2017/09/14 (2.00.0) - BREAKING CHANGE: Modifing window position and size funtions now -/// require the name of the window and must happen outside the window -/// building process (between function call nk_begin and nk_end). -/// - 2017/09/11 (1.40.9) - Fixed window background flag if background window is declared last -/// - 2017/08/27 (1.40.8) - Fixed `nk_item_is_any_active` for hidden windows -/// - 2017/08/27 (1.40.7) - Fixed window background flag -/// - 2017/07/07 (1.40.6) - Fixed missing clipping rect check for hovering/clicked -/// query for widgets -/// - 2017/07/07 (1.40.5) - Fixed drawing bug for vertex output for lines and stroked -/// and filled rectangles -/// - 2017/07/07 (1.40.4) - Fixed bug in nk_convert trying to add windows that are in -/// process of being destroyed. -/// - 2017/07/07 (1.40.3) - Fixed table internal bug caused by storing table size in -/// window instead of directly in table. -/// - 2017/06/30 (1.40.2) - Removed unneeded semicolon in C++ NK_ALIGNOF macro -/// - 2017/06/30 (1.40.1) - Fixed drawing lines smaller or equal zero -/// - 2017/06/08 (1.40.0) - Removed the breaking part of last commit. Auto layout now only -/// comes in effect if you pass in zero was row height argument -/// - 2017/06/08 (1.40.0) - BREAKING CHANGE: while not directly API breaking it will change -/// how layouting works. From now there will be an internal minimum -/// row height derived from font height. If you need a row smaller than -/// that you can directly set it by `nk_layout_set_min_row_height` and -/// reset the value back by calling `nk_layout_reset_min_row_height. -/// - 2017/06/08 (1.39.1) - Fixed property text edit handling bug caused by past `nk_widget` fix -/// - 2017/06/08 (1.39.0) - Added function to retrieve window space without calling a nk_layout_xxx function -/// - 2017/06/06 (1.38.5) - Fixed `nk_convert` return flag for command buffer -/// - 2017/05/23 (1.38.4) - Fixed activation behavior for widgets partially clipped -/// - 2017/05/10 (1.38.3) - Fixed wrong min window size mouse scaling over boundries -/// - 2017/05/09 (1.38.2) - Fixed vertical scrollbar drawing with not enough space -/// - 2017/05/09 (1.38.1) - Fixed scaler dragging behavior if window size hits minimum size -/// - 2017/05/06 (1.38.0) - Added platform double-click support -/// - 2017/04/20 (1.37.1) - Fixed key repeat found inside glfw demo backends -/// - 2017/04/20 (1.37.0) - Extended properties with selection and clipbard support -/// - 2017/04/20 (1.36.2) - Fixed #405 overlapping rows with zero padding and spacing -/// - 2017/04/09 (1.36.1) - Fixed #403 with another widget float error -/// - 2017/04/09 (1.36.0) - Added window `NK_WINDOW_NO_INPUT` and `NK_WINDOW_NOT_INTERACTIVE` flags -/// - 2017/04/09 (1.35.3) - Fixed buffer heap corruption -/// - 2017/03/25 (1.35.2) - Fixed popup overlapping for `NK_WINDOW_BACKGROUND` windows -/// - 2017/03/25 (1.35.1) - Fixed windows closing behavior -/// - 2017/03/18 (1.35.0) - Added horizontal scroll requested in #377 -/// - 2017/03/18 (1.34.3) - Fixed long window header titles -/// - 2017/03/04 (1.34.2) - Fixed text edit filtering -/// - 2017/03/04 (1.34.1) - Fixed group closable flag -/// - 2017/02/25 (1.34.0) - Added custom draw command for better language binding support -/// - 2017/01/24 (1.33.0) - Added programatic way of remove edit focus -/// - 2017/01/24 (1.32.3) - Fixed wrong define for basic type definitions for windows -/// - 2017/01/21 (1.32.2) - Fixed input capture from hidden or closed windows -/// - 2017/01/21 (1.32.1) - Fixed slider behavior and drawing -/// - 2017/01/13 (1.32.0) - Added flag to put scaler into the bottom left corner -/// - 2017/01/13 (1.31.0) - Added additional row layouting method to combine both -/// dynamic and static widgets. -/// - 2016/12/31 (1.30.0) - Extended scrollbar offset from 16-bit to 32-bit -/// - 2016/12/31 (1.29.2)- Fixed closing window bug of minimized windows -/// - 2016/12/03 (1.29.1)- Fixed wrapped text with no seperator and C89 error -/// - 2016/12/03 (1.29.0) - Changed text wrapping to process words not characters -/// - 2016/11/22 (1.28.6)- Fixed window minimized closing bug -/// - 2016/11/19 (1.28.5)- Fixed abstract combo box closing behavior -/// - 2016/11/19 (1.28.4)- Fixed tooltip flickering -/// - 2016/11/19 (1.28.3)- Fixed memory leak caused by popup repeated closing -/// - 2016/11/18 (1.28.2)- Fixed memory leak caused by popup panel allocation -/// - 2016/11/10 (1.28.1)- Fixed some warnings and C++ error -/// - 2016/11/10 (1.28.0)- Added additional `nk_button` versions which allows to directly -/// pass in a style struct to change buttons visual. -/// - 2016/11/10 (1.27.0)- Added additional 'nk_tree' versions to support external state -/// storage. Just like last the `nk_group` commit the main -/// advantage is that you optionally can minimize nuklears runtime -/// memory consumption or handle hash collisions. -/// - 2016/11/09 (1.26.0)- Added additional `nk_group` version to support external scrollbar -/// offset storage. Main advantage is that you can externalize -/// the memory management for the offset. It could also be helpful -/// if you have a hash collision in `nk_group_begin` but really -/// want the name. In addition I added `nk_list_view` which allows -/// to draw big lists inside a group without actually having to -/// commit the whole list to nuklear (issue #269). -/// - 2016/10/30 (1.25.1)- Fixed clipping rectangle bug inside `nk_draw_list` -/// - 2016/10/29 (1.25.0)- Pulled `nk_panel` memory management into nuklear and out of -/// the hands of the user. From now on users don't have to care -/// about panels unless they care about some information. If you -/// still need the panel just call `nk_window_get_panel`. -/// - 2016/10/21 (1.24.0)- Changed widget border drawing to stroked rectangle from filled -/// rectangle for less overdraw and widget background transparency. -/// - 2016/10/18 (1.23.0)- Added `nk_edit_focus` for manually edit widget focus control -/// - 2016/09/29 (1.22.7)- Fixed deduction of basic type in non `` compilation -/// - 2016/09/29 (1.22.6)- Fixed edit widget UTF-8 text cursor drawing bug -/// - 2016/09/28 (1.22.5)- Fixed edit widget UTF-8 text appending/inserting/removing -/// - 2016/09/28 (1.22.4)- Fixed drawing bug inside edit widgets which offset all text -/// text in every edit widget if one of them is scrolled. -/// - 2016/09/28 (1.22.3)- Fixed small bug in edit widgets if not active. The wrong -/// text length is passed. It should have been in bytes but -/// was passed as glyphes. -/// - 2016/09/20 (1.22.2)- Fixed color button size calculation -/// - 2016/09/20 (1.22.1)- Fixed some `nk_vsnprintf` behavior bugs and removed -/// `` again from `NK_INCLUDE_STANDARD_VARARGS`. -/// - 2016/09/18 (1.22.0)- C89 does not support vsnprintf only C99 and newer as well -/// as C++11 and newer. In addition to use vsnprintf you have -/// to include . So just defining `NK_INCLUDE_STD_VAR_ARGS` -/// is not enough. That behavior is now fixed. By default if -/// both varargs as well as stdio is selected I try to use -/// vsnprintf if not possible I will revert to vsprintf. If -/// varargs but not stdio was defined I will use my own function. -/// - 2016/09/15 (1.21.2)- Fixed panel `close` behavior for deeper panel levels -/// - 2016/09/15 (1.21.1)- Fixed C++ errors and wrong argument to `nk_panel_get_xxxx` -/// - 2016/09/13 (1.21.0) - !BREAKING! Fixed nonblocking popup behavior in menu, combo, -/// and contextual which prevented closing in y-direction if -/// popup did not reach max height. -/// In addition the height parameter was changed into vec2 -/// for width and height to have more control over the popup size. -/// - 2016/09/13 (1.20.3) - Cleaned up and extended type selection -/// - 2016/09/13 (1.20.2)- Fixed slider behavior hopefully for the last time. This time -/// all calculation are correct so no more hackery. -/// - 2016/09/13 (1.20.1)- Internal change to divide window/panel flags into panel flags and types. -/// Suprisinly spend years in C and still happened to confuse types -/// with flags. Probably something to take note. -/// - 2016/09/08 (1.20.0)- Added additional helper function to make it easier to just -/// take the produced buffers from `nk_convert` and unplug the -/// iteration process from `nk_context`. So now you can -/// just use the vertex,element and command buffer + two pointer -/// inside the command buffer retrieved by calls `nk__draw_begin` -/// and `nk__draw_end` and macro `nk_draw_foreach_bounded`. -/// - 2016/09/08 (1.19.0)- Added additional asserts to make sure every `nk_xxx_begin` call -/// for windows, popups, combobox, menu and contextual is guarded by -/// `if` condition and does not produce false drawing output. -/// - 2016/09/08 (1.18.0)- Changed confusing name for `NK_SYMBOL_RECT_FILLED`, `NK_SYMBOL_RECT` -/// to hopefully easier to understand `NK_SYMBOL_RECT_FILLED` and -/// `NK_SYMBOL_RECT_OUTLINE`. -/// - 2016/09/08 (1.17.0)- Changed confusing name for `NK_SYMBOL_CIRLCE_FILLED`, `NK_SYMBOL_CIRCLE` -/// to hopefully easier to understand `NK_SYMBOL_CIRCLE_FILLED` and -/// `NK_SYMBOL_CIRCLE_OUTLINE`. -/// - 2016/09/08 (1.16.0)- Added additional checks to select correct types if `NK_INCLUDE_FIXED_TYPES` -/// is not defined by supporting the biggest compiler GCC, clang and MSVC. -/// - 2016/09/07 (1.15.3)- Fixed `NK_INCLUDE_COMMAND_USERDATA` define to not cause an error -/// - 2016/09/04 (1.15.2)- Fixed wrong combobox height calculation -/// - 2016/09/03 (1.15.1)- Fixed gaps inside combo boxes in OpenGL -/// - 2016/09/02 (1.15.0) - Changed nuklear to not have any default vertex layout and -/// instead made it user provided. The range of types to convert -/// to is quite limited at the moment, but I would be more than -/// happy to accept PRs to add additional. -/// - 2016/08/30 (1.14.2) - Removed unused variables -/// - 2016/08/30 (1.14.1) - Fixed C++ build errors -/// - 2016/08/30 (1.14.0) - Removed mouse dragging from SDL demo since it does not work correctly -/// - 2016/08/30 (1.13.4) - Tweaked some default styling variables -/// - 2016/08/30 (1.13.3) - Hopefully fixed drawing bug in slider, in general I would -/// refrain from using slider with a big number of steps. -/// - 2016/08/30 (1.13.2) - Fixed close and minimize button which would fire even if the -/// window was in Read Only Mode. -/// - 2016/08/30 (1.13.1) - Fixed popup panel padding handling which was previously just -/// a hack for combo box and menu. -/// - 2016/08/30 (1.13.0) - Removed `NK_WINDOW_DYNAMIC` flag from public API since -/// it is bugged and causes issues in window selection. -/// - 2016/08/30 (1.12.0) - Removed scaler size. The size of the scaler is now -/// determined by the scrollbar size -/// - 2016/08/30 (1.11.2) - Fixed some drawing bugs caused by changes from 1.11 -/// - 2016/08/30 (1.11.1) - Fixed overlapping minimized window selection -/// - 2016/08/30 (1.11.0) - Removed some internal complexity and overly complex code -/// handling panel padding and panel border. -/// - 2016/08/29 (1.10.0) - Added additional height parameter to `nk_combobox_xxx` -/// - 2016/08/29 (1.10.0) - Fixed drawing bug in dynamic popups -/// - 2016/08/29 (1.10.0) - Added experimental mouse scrolling to popups, menus and comboboxes -/// - 2016/08/26 (1.10.0) - Added window name string prepresentation to account for -/// hash collisions. Currently limited to NK_WINDOW_MAX_NAME -/// which in term can be redefined if not big enough. -/// - 2016/08/26 (1.10.0) - Added stacks for temporary style/UI changes in code -/// - 2016/08/25 (1.10.0) - Changed `nk_input_is_key_pressed` and 'nk_input_is_key_released' -/// to account for key press and release happening in one frame. -/// - 2016/08/25 (1.10.0) - Added additional nk_edit flag to directly jump to the end on activate -/// - 2016/08/17 (1.09.6)- Removed invalid check for value zero in nk_propertyx -/// - 2016/08/16 (1.09.5)- Fixed ROM mode for deeper levels of popup windows parents. -/// - 2016/08/15 (1.09.4)- Editbox are now still active if enter was pressed with flag -/// `NK_EDIT_SIG_ENTER`. Main reasoning is to be able to keep -/// typing after commiting. -/// - 2016/08/15 (1.09.4)- Removed redundant code -/// - 2016/08/15 (1.09.4)- Fixed negative numbers in `nk_strtoi` and remove unused variable -/// - 2016/08/15 (1.09.3)- Fixed `NK_WINDOW_BACKGROUND` flag behavior to select a background -/// window only as selected by hovering and not by clicking. -/// - 2016/08/14 (1.09.2)- Fixed a bug in font atlas which caused wrong loading -/// of glyphes for font with multiple ranges. -/// - 2016/08/12 (1.09.1)- Added additional function to check if window is currently -/// hidden and therefore not visible. -/// - 2016/08/12 (1.09.1)- nk_window_is_closed now queries the correct flag `NK_WINDOW_CLOSED` -/// instead of the old flag `NK_WINDOW_HIDDEN` -/// - 2016/08/09 (1.09.0) - Added additional double version to nk_property and changed -/// the underlying implementation to not cast to float and instead -/// work directly on the given values. -/// - 2016/08/09 (1.08.0) - Added additional define to overwrite library internal -/// floating pointer number to string conversion for additional -/// precision. -/// - 2016/08/09 (1.08.0) - Added additional define to overwrite library internal -/// string to floating point number conversion for additional -/// precision. -/// - 2016/08/08 (1.07.2)- Fixed compiling error without define NK_INCLUDE_FIXED_TYPE -/// - 2016/08/08 (1.07.1)- Fixed possible floating point error inside `nk_widget` leading -/// to wrong wiget width calculation which results in widgets falsly -/// becomming tagged as not inside window and cannot be accessed. -/// - 2016/08/08 (1.07.0) - Nuklear now differentiates between hiding a window (NK_WINDOW_HIDDEN) and -/// closing a window (NK_WINDOW_CLOSED). A window can be hidden/shown -/// by using `nk_window_show` and closed by either clicking the close -/// icon in a window or by calling `nk_window_close`. Only closed -/// windows get removed at the end of the frame while hidden windows -/// remain. -/// - 2016/08/08 (1.06.0) - Added `nk_edit_string_zero_terminated` as a second option to -/// `nk_edit_string` which takes, edits and outputs a '\0' terminated string. -/// - 2016/08/08 (1.05.4)- Fixed scrollbar auto hiding behavior -/// - 2016/08/08 (1.05.3)- Fixed wrong panel padding selection in `nk_layout_widget_space` -/// - 2016/08/07 (1.05.2)- Fixed old bug in dynamic immediate mode layout API, calculating -/// wrong item spacing and panel width. -///- 2016/08/07 (1.05.1)- Hopefully finally fixed combobox popup drawing bug -///- 2016/08/07 (1.05.0) - Split varargs away from NK_INCLUDE_STANDARD_IO into own -/// define NK_INCLUDE_STANDARD_VARARGS to allow more fine -/// grained controlled over library includes. -/// - 2016/08/06 (1.04.5)- Changed memset calls to NK_MEMSET -/// - 2016/08/04 (1.04.4)- Fixed fast window scaling behavior -/// - 2016/08/04 (1.04.3)- Fixed window scaling, movement bug which appears if you -/// move/scale a window and another window is behind it. -/// If you are fast enough then the window behind gets activated -/// and the operation is blocked. I now require activating -/// by hovering only if mouse is not pressed. -/// - 2016/08/04 (1.04.2)- Fixed changing fonts -/// - 2016/08/03 (1.04.1)- Fixed `NK_WINDOW_BACKGROUND` behavior -/// - 2016/08/03 (1.04.0) - Added color parameter to `nk_draw_image` -/// - 2016/08/03 (1.04.0) - Added additional window padding style attributes for -/// sub windows (combo, menu, ...) -/// - 2016/08/03 (1.04.0) - Added functions to show/hide software cursor -/// - 2016/08/03 (1.04.0) - Added `NK_WINDOW_BACKGROUND` flag to force a window -/// to be always in the background of the screen -/// - 2016/08/03 (1.03.2)- Removed invalid assert macro for NK_RGB color picker -/// - 2016/08/01 (1.03.1)- Added helper macros into header include guard -/// - 2016/07/29 (1.03.0) - Moved the window/table pool into the header part to -/// simplify memory management by removing the need to -/// allocate the pool. -/// - 2016/07/29 (1.02.0) - Added auto scrollbar hiding window flag which if enabled -/// will hide the window scrollbar after NK_SCROLLBAR_HIDING_TIMEOUT -/// seconds without window interaction. To make it work -/// you have to also set a delta time inside the `nk_context`. -/// - 2016/07/25 (1.01.1) - Fixed small panel and panel border drawing bugs -/// - 2016/07/15 (1.01.0) - Added software cursor to `nk_style` and `nk_context` -/// - 2016/07/15 (1.01.0) - Added const correctness to `nk_buffer_push' data argument -/// - 2016/07/15 (1.01.0) - Removed internal font baking API and simplified -/// font atlas memory management by converting pointer -/// arrays for fonts and font configurations to lists. -/// - 2016/07/15 (1.00.0) - Changed button API to use context dependend button -/// behavior instead of passing it for every function call. -/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// -/// ## Gallery -/// ![Figure [blue]: Feature overview with blue color styling](https://cloud.githubusercontent.com/assets/8057201/13538240/acd96876-e249-11e5-9547-5ac0b19667a0.png) -/// ![Figure [red]: Feature overview with red color styling](https://cloud.githubusercontent.com/assets/8057201/13538243/b04acd4c-e249-11e5-8fd2-ad7744a5b446.png) -/// ![Figure [widgets]: Widget overview](https://cloud.githubusercontent.com/assets/8057201/11282359/3325e3c6-8eff-11e5-86cb-cf02b0596087.png) -/// ![Figure [blackwhite]: Black and white](https://cloud.githubusercontent.com/assets/8057201/11033668/59ab5d04-86e5-11e5-8091-c56f16411565.png) -/// ![Figure [filexp]: File explorer](https://cloud.githubusercontent.com/assets/8057201/10718115/02a9ba08-7b6b-11e5-950f-adacdd637739.png) -/// ![Figure [opengl]: OpenGL Editor](https://cloud.githubusercontent.com/assets/8057201/12779619/2a20d72c-ca69-11e5-95fe-4edecf820d5c.png) -/// ![Figure [nodedit]: Node Editor](https://cloud.githubusercontent.com/assets/8057201/9976995/e81ac04a-5ef7-11e5-872b-acd54fbeee03.gif) -/// ![Figure [skinning]: Using skinning in Nuklear](https://cloud.githubusercontent.com/assets/8057201/15991632/76494854-30b8-11e6-9555-a69840d0d50b.png) -/// ![Figure [bf]: Heavy modified version](https://cloud.githubusercontent.com/assets/8057201/14902576/339926a8-0d9c-11e6-9fee-a8b73af04473.png) -/// -/// ## Credits -/// Developed by Micha Mettke and every direct or indirect github contributor.

-/// -/// Embeds [stb_texedit](https://github.com/nothings/stb/blob/master/stb_textedit.h), [stb_truetype](https://github.com/nothings/stb/blob/master/stb_truetype.h) and [stb_rectpack](https://github.com/nothings/stb/blob/master/stb_rect_pack.h) by Sean Barret (public domain)
-/// Uses [stddoc.c](https://github.com/r-lyeh/stddoc.c) from r-lyeh@github.com for documentation generation

-/// Embeds ProggyClean.ttf font by Tristan Grimmer (MIT license).
-/// -/// Big thank you to Omar Cornut (ocornut@github) for his [imgui library](https://github.com/ocornut/imgui) and -/// giving me the inspiration for this library, Casey Muratori for handmade hero -/// and his original immediate mode graphical user interface idea and Sean -/// Barret for his amazing single header libraries which restored my faith -/// in libraries and brought me to create some of my own. -/// -*/ diff --git a/subprojects/nk_pugl/nuklear/package.json b/subprojects/nk_pugl/nuklear/package.json deleted file mode 100644 index edff924..0000000 --- a/subprojects/nk_pugl/nuklear/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "nuklear", - "version": "1.0.0", - "repo": "vurtun/nuklear", - "description": "A small ANSI C gui toolkit", - "keywords": ["gl", "ui", "toolkit"], - "src": ["nuklear.h"] -} diff --git a/subprojects/nk_pugl/pugl/.clang-format b/subprojects/nk_pugl/pugl/.clang-format deleted file mode 100644 index 7b30bd2..0000000 --- a/subprojects/nk_pugl/pugl/.clang-format +++ /dev/null @@ -1,28 +0,0 @@ ---- -AlignConsecutiveAssignments: true -AlignConsecutiveDeclarations: true -AlignEscapedNewlinesLeft: true -BasedOnStyle: Mozilla -BraceWrapping: - AfterNamespace: false - AfterClass: true - AfterEnum: false - AfterExternBlock: false - AfterFunction: true - AfterStruct: false - SplitEmptyFunction: false - SplitEmptyRecord: false -BreakBeforeBraces: Custom -Cpp11BracedListStyle: true -IndentCaseLabels: false -IndentPPDirectives: AfterHash -KeepEmptyLinesAtTheStartOfBlocks: false -SpacesInContainerLiterals: false -StatementMacros: - - PUGL_API - - PUGL_CONST_API - - PUGL_CONST_FUNC - - PUGL_DEPRECATED_BY - - PUGL_UNUSED - - _Pragma -... diff --git a/subprojects/nk_pugl/pugl/.clang-tidy b/subprojects/nk_pugl/pugl/.clang-tidy deleted file mode 100644 index 1e40901..0000000 --- a/subprojects/nk_pugl/pugl/.clang-tidy +++ /dev/null @@ -1,4 +0,0 @@ -Checks: > - *, -FormatStyle: file -WarningsAsErrors: '*' diff --git a/subprojects/nk_pugl/pugl/.clant.json b/subprojects/nk_pugl/pugl/.clant.json deleted file mode 100644 index 6f48901..0000000 --- a/subprojects/nk_pugl/pugl/.clant.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "version": "1.0.0", - "include_dirs": [ - "bindings/cxx/include", - "include" - ], - "exclude_patterns": [ - "glad\\.c" - ], - "mapping_files": [ - ".includes.imp" - ] -} diff --git a/subprojects/nk_pugl/pugl/.editorconfig b/subprojects/nk_pugl/pugl/.editorconfig deleted file mode 100644 index c2d35dd..0000000 --- a/subprojects/nk_pugl/pugl/.editorconfig +++ /dev/null @@ -1,19 +0,0 @@ -root = true - -[*] -charset = utf-8 -end_of_line = lf -trim_trailing_whitespace = true -insert_final_newline = true - -[*.{c,h,m,cpp,hpp,mm,glsl,frag,vert}] -indent_style = space -indent_size = 2 - -[wscript] -indent_style = space -indent_size = 4 - -[doc/**.{html,xml,css}] -indent_style = space -indent_size = 2 diff --git a/subprojects/nk_pugl/pugl/.gitattributes b/subprojects/nk_pugl/pugl/.gitattributes deleted file mode 100644 index 32967c1..0000000 --- a/subprojects/nk_pugl/pugl/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -waflib/* linguist-vendored diff --git a/subprojects/nk_pugl/pugl/.gitignore b/subprojects/nk_pugl/pugl/.gitignore deleted file mode 100644 index 41c45d2..0000000 --- a/subprojects/nk_pugl/pugl/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -build/ -__pycache__ -*.pyc diff --git a/subprojects/nk_pugl/pugl/.gitlab-ci.yml b/subprojects/nk_pugl/pugl/.gitlab-ci.yml deleted file mode 100644 index dc82cf8..0000000 --- a/subprojects/nk_pugl/pugl/.gitlab-ci.yml +++ /dev/null @@ -1,151 +0,0 @@ -stages: - - build - - deploy - -.build_template: &build_definition - stage: build - -arm32_dbg: - <<: *build_definition - image: lv2plugin/debian-arm32 - script: - - meson setup build --cross-file=/usr/share/meson/cross/arm-linux-gnueabihf.ini -Dbuildtype=debug -Ddocs=disabled -Dstrict=true -Dwerror=true - - ninja -C build - -arm32_rel: - <<: *build_definition - image: lv2plugin/debian-arm32 - script: - - meson setup build --cross-file=/usr/share/meson/cross/arm-linux-gnueabihf.ini -Dbuildtype=release -Ddocs=disabled -Dstrict=true -Dwerror=true - - ninja -C build - - -arm64_dbg: - <<: *build_definition - image: lv2plugin/debian-arm64 - script: - - meson setup build --cross-file=/usr/share/meson/cross/aarch64-linux-gnu.ini -Dbuildtype=debug -Ddocs=disabled -Dstrict=true -Dwerror=true - - ninja -C build - -arm64_rel: - <<: *build_definition - image: lv2plugin/debian-arm64 - script: - - meson setup build --cross-file=/usr/share/meson/cross/aarch64-linux-gnu.ini -Dbuildtype=release -Ddocs=disabled -Dstrict=true -Dwerror=true - - ninja -C build - - -x64_dbg: - <<: *build_definition - image: lv2plugin/debian-x64 - script: - - meson setup build -Dbuildtype=debug -Ddocs=enabled -Dstrict=true -Dwerror=true - - ninja -C build - artifacts: - paths: - - build/doc - -x64_rel: - <<: *build_definition - image: lv2plugin/debian-x64 - script: - - meson setup build -Dbuildtype=release -Ddocs=disabled -Dstrict=true -Dwerror=true - - ninja -C build - - -x64_static: - <<: *build_definition - image: lv2plugin/debian-x64 - script: - - meson setup build -Ddefault_library=static -Ddocs=disabled -Dstrict=true -Dwerror=true - - ninja -C build - - -x64_sanitize: - <<: *build_definition - image: lv2plugin/debian-x64-clang - script: - - meson setup build -Db_lundef=false -Dbuildtype=plain -Ddocs=disabled -Dstrict=true -Dwerror=true - - ninja -C build - variables: - CC: "clang" - CXX: "clang++" - CFLAGS: "-fno-sanitize-recover=all -fsanitize=address -fsanitize=undefined -fsanitize=float-divide-by-zero -fsanitize=unsigned-integer-overflow -fsanitize=implicit-conversion -fsanitize=local-bounds -fsanitize=nullability" - CXXFLAGS: "-fno-sanitize-recover=all -fsanitize=address -fsanitize=undefined -fsanitize=float-divide-by-zero -fsanitize=unsigned-integer-overflow -fsanitize=implicit-conversion -fsanitize=local-bounds -fsanitize=nullability" - LDFLAGS: "-fno-sanitize-recover=all -fsanitize=address -fsanitize=undefined -fsanitize=float-divide-by-zero -fsanitize=unsigned-integer-overflow -fsanitize=implicit-conversion -fsanitize=local-bounds -fsanitize=nullability" - - -mingw32_dbg: - <<: *build_definition - image: lv2plugin/debian-mingw32 - script: - - meson setup build --cross-file=/usr/share/meson/cross/i686-w64-mingw32.ini -Dbuildtype=debug -Ddocs=disabled -Dstrict=true -Dwerror=true - - ninja -C build - -mingw32_rel: - <<: *build_definition - image: lv2plugin/debian-mingw32 - script: - - meson setup build --cross-file=/usr/share/meson/cross/i686-w64-mingw32.ini -Dbuildtype=release -Ddocs=disabled -Dstrict=true -Dwerror=true - - ninja -C build - - -mingw64_dbg: - <<: *build_definition - image: lv2plugin/debian-mingw64 - script: - - meson setup build --cross-file=/usr/share/meson/cross/x86_64-w64-mingw32.ini -Dbuildtype=debug -Ddocs=disabled -Dstrict=true -Dwerror=true - - ninja -C build - -mingw64_rel: - <<: *build_definition - image: lv2plugin/debian-mingw64 - script: - - meson setup build --cross-file=/usr/share/meson/cross/x86_64-w64-mingw32.ini -Dbuildtype=release -Ddocs=disabled -Dstrict=true -Dwerror=true - - ninja -C build - - -mac_dbg: - <<: *build_definition - tags: [macos] - script: - - meson setup build -Dbuildtype=debug -Ddocs=disabled -Dstrict=true -Dwerror=true - - ninja -C build - -mac_rel: - <<: *build_definition - tags: [macos] - script: - - meson setup build -Dbuildtype=release -Ddocs=disabled -Dstrict=true -Dwerror=true - - ninja -C build - - -win_dbg: - <<: *build_definition - tags: [windows,meson] - script: - - meson setup build -Dbuildtype=debug -Ddocs=disabled -Dstrict=true -Dwerror=true - - ninja -C build - -win_rel: - <<: *build_definition - tags: [windows,meson] - script: - - meson setup build -Dbuildtype=release -Ddocs=disabled -Dstrict=true -Dwerror=true - - ninja -C build - -pages: - stage: deploy - script: - - mkdir public - - mkdir public/c - - mkdir public/cpp - - mv build/doc/c/singlehtml/ public/c/singlehtml/ - - mv build/doc/cpp/singlehtml/ public/cpp/singlehtml/ - dependencies: - - x64_dbg - artifacts: - paths: - - public - only: - - master diff --git a/subprojects/nk_pugl/pugl/.gitmodules b/subprojects/nk_pugl/pugl/.gitmodules deleted file mode 100644 index e69de29..0000000 diff --git a/subprojects/nk_pugl/pugl/.includes.imp b/subprojects/nk_pugl/pugl/.includes.imp deleted file mode 100644 index 74a3105..0000000 --- a/subprojects/nk_pugl/pugl/.includes.imp +++ /dev/null @@ -1,4 +0,0 @@ -[ - { "include": [ "", "private", "", "public", ] }, - { "include": [ "", "private", "", "public", ] } -] diff --git a/subprojects/nk_pugl/pugl/AUTHORS b/subprojects/nk_pugl/pugl/AUTHORS deleted file mode 100644 index 99f6dac..0000000 --- a/subprojects/nk_pugl/pugl/AUTHORS +++ /dev/null @@ -1,13 +0,0 @@ -Pugl is primarily written and maintained by David Robillard -with contributions from (in increasing chronological order): - -Ben Loftis -Robin Gareus -Erik Åldstedt Sund -Hanspeter Portner -Stefan Westerfeld -Jordan Halase -Oliver Schmidt -Zoë Sparks -Jean Pierre Cimalando -Thomas Brand diff --git a/subprojects/nk_pugl/pugl/COPYING b/subprojects/nk_pugl/pugl/COPYING deleted file mode 100644 index 63e6829..0000000 --- a/subprojects/nk_pugl/pugl/COPYING +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2011-2020 David Robillard - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/subprojects/nk_pugl/pugl/README.md b/subprojects/nk_pugl/pugl/README.md deleted file mode 100644 index 5b4f82f..0000000 --- a/subprojects/nk_pugl/pugl/README.md +++ /dev/null @@ -1,97 +0,0 @@ -Pugl -==== - -Pugl (PlUgin Graphics Library) is a minimal portable API for GUIs which is -suitable for use in plugins. It works on X11, MacOS, and Windows, and -optionally supports Vulkan, OpenGL, and Cairo graphics contexts. - -Pugl is vaguely similar to libraries like GLUT and GLFW, but with some -distinguishing features: - - * Minimal in scope, providing only a thin interface to isolate - platform-specific details from applications. - - * Zero dependencies, aside from standard system libraries. - - * Support for embedding in native windows, for example as a plugin or - component within a larger application that is not based on Pugl. - - * Simple and extensible event-based API that makes dispatching in application - or toolkit code easy with minimal boilerplate. - - * Suitable not only for continuously rendering applications like games, but - also event-driven applications that only draw when necessary. - - * Explicit context and no static data whatsoever, so that several instances - can be used within a single program at once. - - * Small, liberally licensed Free Software implementation that is suitable for - vendoring and/or static linking. Pugl can be installed as a library, or - used by simply copying the headers into a project. - -Stability ---------- - -Pugl is currently being developed towards a long-term stable API. For the time -being, however, the API may break occasionally. Please report any relevant -feedback, or file feature requests, so that we can ensure that the released API -is stable for as long as possible. - -Documentation -------------- - -Pugl is a C library that includes C++ bindings. -Each API is documented separately: - - * [C Documentation (single page)](https://lv2.gitlab.io/pugl/c/singlehtml/) - * [C Documentation (paginated)](https://lv2.gitlab.io/pugl/c/html/) - * [C++ Documentation (single page)](https://lv2.gitlab.io/pugl/cpp/singlehtml/) - * [C++ Documentation (paginated)](https://lv2.gitlab.io/pugl/cpp/html/) - -The documentation can also be built from the source by configuring with `--docs`. - -Testing -------- - -Some unit tests are included, but unfortunately manual testing is still -required. The tests and example programs are built by default. You can run -all the tests at once via ninja: - - meson setup build - cd build - ninja test - -The `examples` directory contains several programs that serve as both manual -tests and demonstrations: - - * `pugl_embed_demo` shows a view embedded in another, and also tests - requesting attention (which happens after 5 seconds), keyboard focus - (switched by pressing tab), view moving (with the arrow keys), and view - resizing (with the arrow keys while shift is held). This program uses only - very old OpenGL and should work on any system. - - * `pugl_window_demo` demonstrates multiple top-level windows. - - * `pugl_shader_demo` demonstrates using more modern OpenGL (version 3 or 4) - where dynamic loading and shaders are required. It can also be used to test - performance by passing the number of rectangles to draw on the command line. - - * `pugl_cairo_demo` demonstrates using Cairo on top of the native windowing - system (without OpenGL), and partial redrawing. - - * `pugl_print_events` is a utility that prints all received events to the - console in a human readable format. - - * `pugl_cxx_demo` is a simple cube demo that uses the C++ API. - - * `pugl_vulkan_demo` is a simple example of using Vulkan in C that simply - clears the window. - - * `pugl_vulkan_cxx_demo` is a more advanced Vulkan demo in C++ that draws many - animated rectangles like `pugl_shader_demo`. - -All example programs support several command line options to control various -behaviours, see the output of `--help` for details. Please file an issue if -any of these programs do not work as expected on your system. - - -- David Robillard diff --git a/subprojects/nk_pugl/pugl/bindings/cxx/include/.clang-tidy b/subprojects/nk_pugl/pugl/bindings/cxx/include/.clang-tidy deleted file mode 100644 index 816223d..0000000 --- a/subprojects/nk_pugl/pugl/bindings/cxx/include/.clang-tidy +++ /dev/null @@ -1,14 +0,0 @@ -Checks: > - *, - -*-uppercase-literal-suffix, - -clang-diagnostic-unused-macros, - -cppcoreguidelines-pro-bounds-pointer-arithmetic, - -cppcoreguidelines-pro-type-static-cast-downcast, - -google-runtime-references, - -hicpp-named-parameter, - -llvmlibc-*, - -modernize-use-trailing-return-type, - -readability-implicit-bool-conversion, - -readability-named-parameter, -FormatStyle: file -HeaderFilterRegex: 'pugl/.*' diff --git a/subprojects/nk_pugl/pugl/bindings/cxx/include/pugl/cairo.hpp b/subprojects/nk_pugl/pugl/bindings/cxx/include/pugl/cairo.hpp deleted file mode 100644 index 15dc5de..0000000 --- a/subprojects/nk_pugl/pugl/bindings/cxx/include/pugl/cairo.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_CAIRO_HPP -#define PUGL_CAIRO_HPP - -#include "pugl/cairo.h" -#include "pugl/pugl.h" - -namespace pugl { - -/** - @defgroup cairoxx Cairo - Cairo graphics support. - @ingroup puglxx - @{ -*/ - -/// @copydoc puglCairoBackend -inline const PuglBackend* -cairoBackend() noexcept -{ - return puglCairoBackend(); -} - -/** - @} -*/ - -} // namespace pugl - -#endif // PUGL_CAIRO_HPP diff --git a/subprojects/nk_pugl/pugl/bindings/cxx/include/pugl/gl.hpp b/subprojects/nk_pugl/pugl/bindings/cxx/include/pugl/gl.hpp deleted file mode 100644 index 023dd45..0000000 --- a/subprojects/nk_pugl/pugl/bindings/cxx/include/pugl/gl.hpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_GL_HPP -#define PUGL_GL_HPP - -#include "pugl/gl.h" -#include "pugl/pugl.h" -#include "pugl/pugl.hpp" - -namespace pugl { - -/** - @defgroup glxx OpenGL - OpenGL graphics support. - @ingroup puglxx - @{ -*/ - -/// @copydoc PuglGlFunc -using GlFunc = PuglGlFunc; - -/// @copydoc puglGetProcAddress -inline GlFunc -getProcAddress(const char* name) noexcept -{ - return puglGetProcAddress(name); -} - -/// @copydoc puglEnterContext -inline Status -enterContext(View& view) noexcept -{ - return static_cast(puglEnterContext(view.cobj())); -} - -/// @copydoc puglLeaveContext -inline Status -leaveContext(View& view) noexcept -{ - return static_cast(puglLeaveContext(view.cobj())); -} - -/// @copydoc puglGlBackend -inline const PuglBackend* -glBackend() noexcept -{ - return puglGlBackend(); -} - -/** - @} -*/ - -} // namespace pugl - -#endif // PUGL_GL_HPP diff --git a/subprojects/nk_pugl/pugl/bindings/cxx/include/pugl/pugl.hpp b/subprojects/nk_pugl/pugl/bindings/cxx/include/pugl/pugl.hpp deleted file mode 100644 index fc3bb03..0000000 --- a/subprojects/nk_pugl/pugl/bindings/cxx/include/pugl/pugl.hpp +++ /dev/null @@ -1,721 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_PUGL_HPP -#define PUGL_PUGL_HPP - -#include "pugl/pugl.h" - -#include - -#if defined(PUGL_HPP_THROW_FAILED_CONSTRUCTION) -# include -#elif defined(PUGL_HPP_ASSERT_CONSTRUCTION) -# include -#endif - -namespace pugl { - -/** - @defgroup puglxx Pugl C++ API - Pugl C++ API wrapper. - @{ -*/ - -namespace detail { - -/// Free function for a C object -template -using FreeFunc = void (*)(T*); - -/// Generic C++ wrapper for a C object -template Free> -class Wrapper -{ -public: - Wrapper(const Wrapper&) = delete; - Wrapper& operator=(const Wrapper&) = delete; - - Wrapper(Wrapper&& wrapper) noexcept - : _ptr{wrapper._ptr} - { - wrapper._ptr = nullptr; - } - - Wrapper& operator=(Wrapper&& wrapper) noexcept - { - _ptr = wrapper._ptr; - wrapper._ptr = nullptr; - return *this; - } - - ~Wrapper() noexcept { Free(_ptr); } - - T* cobj() noexcept { return _ptr; } - const T* cobj() const noexcept { return _ptr; } - -protected: - explicit Wrapper(T* ptr) noexcept - : _ptr{ptr} - {} - -private: - T* _ptr; -}; - -} // namespace detail - -using Rect = PuglRect; ///< @copydoc PuglRect - -/** - @defgroup eventsxx Events - @{ -*/ - -/** - A strongly-typed analogue of PuglEvent. - - This is bit-for-bit identical to the corresponding PuglEvent, so events are - simply cast to this type to avoid any copying overhead. - - @tparam t The `type` field of the corresponding PuglEvent. - - @tparam Base The specific struct type of the corresponding PuglEvent. -*/ -template -struct Event final : Base { - /// The type of the corresponding C event structure - using BaseEvent = Base; - - /// The `type` field of the corresponding C event structure - static constexpr const PuglEventType type = t; -}; - -using Mod = PuglMod; ///< @copydoc PuglMod -using Mods = PuglMods; ///< @copydoc PuglMods -using Key = PuglKey; ///< @copydoc PuglKey -using EventType = PuglEventType; ///< @copydoc PuglEventType -using EventFlag = PuglEventFlag; ///< @copydoc PuglEventFlag -using EventFlags = PuglEventFlags; ///< @copydoc PuglEventFlags -using CrossingMode = PuglCrossingMode; ///< @copydoc PuglCrossingMode - -/// @copydoc PuglEventCreate -using CreateEvent = Event; - -/// @copydoc PuglEventDestroy -using DestroyEvent = Event; - -/// @copydoc PuglEventConfigure -using ConfigureEvent = Event; - -/// @copydoc PuglEventMap -using MapEvent = Event; - -/// @copydoc PuglEventUnmap -using UnmapEvent = Event; - -/// @copydoc PuglEventUpdate -using UpdateEvent = Event; - -/// @copydoc PuglEventExpose -using ExposeEvent = Event; - -/// @copydoc PuglEventClose -using CloseEvent = Event; - -/// @copydoc PuglEventFocus -using FocusInEvent = Event; - -/// @copydoc PuglEventFocus -using FocusOutEvent = Event; - -/// @copydoc PuglEventKey -using KeyPressEvent = Event; - -/// @copydoc PuglEventKey -using KeyReleaseEvent = Event; - -/// @copydoc PuglEventText -using TextEvent = Event; - -/// @copydoc PuglEventCrossing -using PointerInEvent = Event; - -/// @copydoc PuglEventCrossing -using PointerOutEvent = Event; - -/// @copydoc PuglEventButton -using ButtonPressEvent = Event; - -/// @copydoc PuglEventButton -using ButtonReleaseEvent = Event; - -/// @copydoc PuglEventMotion -using MotionEvent = Event; - -/// @copydoc PuglEventScroll -using ScrollEvent = Event; - -/// @copydoc PuglEventClient -using ClientEvent = Event; - -/// @copydoc PuglEventTimer -using TimerEvent = Event; - -/// @copydoc PuglEventLoopEnter -using LoopEnterEvent = Event; - -/// @copydoc PuglEventLoopLeave -using LoopLeaveEvent = Event; - -/** - @} - @defgroup statusxx Status - @{ -*/ - -/// @copydoc PuglStatus -enum class Status { - success, ///< @copydoc PUGL_SUCCESS - failure, ///< @copydoc PUGL_FAILURE - unknownError, ///< @copydoc PUGL_UNKNOWN_ERROR - badBackend, ///< @copydoc PUGL_BAD_BACKEND - badConfiguration, ///< @copydoc PUGL_BAD_CONFIGURATION - badParameter, ///< @copydoc PUGL_BAD_PARAMETER - backendFailed, ///< @copydoc PUGL_BACKEND_FAILED - registrationFailed, ///< @copydoc PUGL_REGISTRATION_FAILED - realizeFailed, ///< @copydoc PUGL_REALIZE_FAILED - setFormatFailed, ///< @copydoc PUGL_SET_FORMAT_FAILED - createContextFailed, ///< @copydoc PUGL_CREATE_CONTEXT_FAILED - unsupportedType, ///< @copydoc PUGL_UNSUPPORTED_TYPE -}; - -static_assert(Status(PUGL_UNSUPPORTED_TYPE) == Status::unsupportedType, ""); - -/// @copydoc puglStrerror -inline const char* -strerror(const Status status) noexcept -{ - return puglStrerror(static_cast(status)); -} - -/** - @} - @defgroup worldxx World - @{ -*/ - -/// @copydoc PuglWorldType -enum class WorldType { - program, ///< @copydoc PUGL_PROGRAM - module, ///< @copydoc PUGL_MODULE -}; - -static_assert(WorldType(PUGL_MODULE) == WorldType::module, ""); - -/// @copydoc PuglWorldFlag -enum class WorldFlag { - threads = PUGL_WORLD_THREADS, ///< @copydoc PUGL_WORLD_THREADS -}; - -static_assert(WorldFlag(PUGL_WORLD_THREADS) == WorldFlag::threads, ""); - -using WorldFlags = PuglWorldFlags; ///< @copydoc PuglWorldFlags - -#if defined(PUGL_HPP_THROW_FAILED_CONSTRUCTION) - -/// An exception thrown when construction fails -class FailedConstructionError : public std::exception -{ -public: - FailedConstructionError(const char* const msg) noexcept - : _msg{msg} - {} - - virtual const char* what() const noexcept override; - -private: - const char* _msg; -}; - -# define PUGL_CHECK_CONSTRUCTION(cond, msg) \ - do { \ - if (!(cond)) { \ - throw FailedConstructionError(msg); \ - } \ - } while (0) - -#elif defined(PUGL_HPP_ASSERT_CONSTRUCTION) -# define PUGL_CHECK_CONSTRUCTION(cond, msg) assert(cond); -#else -/** - Configurable macro for handling construction failure. - - If `PUGL_HPP_THROW_FAILED_CONSTRUCTION` is defined, then this throws a - `pugl::FailedConstructionError` if construction fails. - - If `PUGL_HPP_ASSERT_CONSTRUCTION` is defined, then this asserts if - construction fails. - - Otherwise, this does nothing. -*/ -# define PUGL_CHECK_CONSTRUCTION(cond, msg) -#endif - -/// @copydoc PuglWorld -class World : public detail::Wrapper -{ -public: - World(const World&) = delete; - World& operator=(const World&) = delete; - - World(World&&) = delete; - World& operator=(World&&) = delete; - - ~World() = default; - - World(WorldType type, WorldFlag flag) - : Wrapper{puglNewWorld(static_cast(type), - static_cast(flag))} - { - PUGL_CHECK_CONSTRUCTION(cobj(), "Failed to create pugl::World"); - } - - World(WorldType type, WorldFlags flags) - : Wrapper{puglNewWorld(static_cast(type), flags)} - { - PUGL_CHECK_CONSTRUCTION(cobj(), "Failed to create pugl::World"); - } - - explicit World(WorldType type) - : World{type, WorldFlags{}} - {} - - /// @copydoc puglGetNativeWorld - void* nativeWorld() noexcept { return puglGetNativeWorld(cobj()); } - - /// @copydoc puglSetClassName - Status setClassName(const char* const name) noexcept - { - return static_cast(puglSetClassName(cobj(), name)); - } - - /// @copydoc puglGetTime - double time() const noexcept { return puglGetTime(cobj()); } - - /// @copydoc puglUpdate - Status update(const double timeout) noexcept - { - return static_cast(puglUpdate(cobj(), timeout)); - } -}; - -/** - @} - @defgroup viewxx View - @{ -*/ - -using Backend = PuglBackend; ///< @copydoc PuglBackend -using NativeView = PuglNativeView; ///< @copydoc PuglNativeView - -/// @copydoc PuglViewHint -enum class ViewHint { - useCompatProfile, ///< @copydoc PUGL_USE_COMPAT_PROFILE - useDebugContext, ///< @copydoc PUGL_USE_DEBUG_CONTEXT - contextVersionMajor, ///< @copydoc PUGL_CONTEXT_VERSION_MAJOR - contextVersionMinor, ///< @copydoc PUGL_CONTEXT_VERSION_MINOR - redBits, ///< @copydoc PUGL_RED_BITS - greenBits, ///< @copydoc PUGL_GREEN_BITS - blueBits, ///< @copydoc PUGL_BLUE_BITS - alphaBits, ///< @copydoc PUGL_ALPHA_BITS - depthBits, ///< @copydoc PUGL_DEPTH_BITS - stencilBits, ///< @copydoc PUGL_STENCIL_BITS - samples, ///< @copydoc PUGL_SAMPLES - doubleBuffer, ///< @copydoc PUGL_DOUBLE_BUFFER - swapInterval, ///< @copydoc PUGL_SWAP_INTERVAL - resizable, ///< @copydoc PUGL_RESIZABLE - ignoreKeyRepeat, ///< @copydoc PUGL_IGNORE_KEY_REPEAT - refreshRate, ///< @copydoc PUGL_REFRESH_RATE -}; - -static_assert(ViewHint(PUGL_REFRESH_RATE) == ViewHint::refreshRate, ""); - -using ViewHintValue = PuglViewHintValue; ///< @copydoc PuglViewHintValue - -/// @copydoc PuglCursor -enum class Cursor { - arrow, ///< @copydoc PUGL_CURSOR_ARROW - caret, ///< @copydoc PUGL_CURSOR_CARET - crosshair, ///< @copydoc PUGL_CURSOR_CROSSHAIR - hand, ///< @copydoc PUGL_CURSOR_HAND - no, ///< @copydoc PUGL_CURSOR_NO - leftRight, ///< @copydoc PUGL_CURSOR_LEFT_RIGHT - upDown, ///< @copydoc PUGL_CURSOR_UP_DOWN -}; - -static_assert(Cursor(PUGL_CURSOR_UP_DOWN) == Cursor::upDown, ""); - -/// @copydoc PuglView -class View : protected detail::Wrapper -{ -public: - /** - @name Setup - Methods for creating and destroying a view. - @{ - */ - - explicit View(World& world) - : Wrapper{puglNewView(world.cobj())} - , _world(world) - { - PUGL_CHECK_CONSTRUCTION(cobj(), "Failed to create pugl::View"); - } - - const World& world() const noexcept { return _world; } - World& world() noexcept { return _world; } - - /** - Set the object that will be called to handle events. - - This is a type-safe wrapper for the C functions puglSetHandle() and - puglSetEventFunc() that will automatically dispatch events to the - `onEvent` method of `handler` that takes the appropriate event type. - The handler must have such a method defined for every event type, but if - the handler is the view itself, a `using` declaration can be used to - "inherit" the default implementation to avoid having to define every - method. For example: - - @code - class MyView : public pugl::View - { - public: - explicit MyView(pugl::World& world) - : pugl::View{world} - { - setEventHandler(*this); - } - - using pugl::View::onEvent; - - pugl::Status onEvent(const pugl::ConfigureEvent& event) noexcept; - pugl::Status onEvent(const pugl::ExposeEvent& event) noexcept; - }; - @endcode - - This facility is just a convenience, applications may use the C API - directly to set a handle and event function to set up a different - approach for event handling. - */ - template - Status setEventHandler(Handler& handler) - { - puglSetHandle(cobj(), &handler); - return static_cast(puglSetEventFunc(cobj(), eventFunc)); - } - - /// @copydoc puglSetBackend - Status setBackend(const PuglBackend* backend) noexcept - { - return static_cast(puglSetBackend(cobj(), backend)); - } - - /// @copydoc puglSetViewHint - Status setHint(ViewHint hint, int value) noexcept - { - return static_cast( - puglSetViewHint(cobj(), static_cast(hint), value)); - } - - /// @copydoc puglGetViewHint - int getHint(ViewHint hint) noexcept - { - return puglGetViewHint(cobj(), static_cast(hint)); - } - - /** - @} - @name Frame - Methods for working with the position and size of a view. - @{ - */ - - /// @copydoc puglGetFrame - Rect frame() const noexcept { return puglGetFrame(cobj()); } - - /// @copydoc puglSetFrame - Status setFrame(Rect frame) noexcept - { - return static_cast(puglSetFrame(cobj(), frame)); - } - - /// @copydoc puglSetDefaultSize - Status setDefaultSize(int width, int height) noexcept - { - return static_cast(puglSetDefaultSize(cobj(), width, height)); - } - - /// @copydoc puglSetMinSize - Status setMinSize(int width, int height) noexcept - { - return static_cast(puglSetMinSize(cobj(), width, height)); - } - - /// @copydoc puglSetMaxSize - Status setMaxSize(int width, int height) noexcept - { - return static_cast(puglSetMaxSize(cobj(), width, height)); - } - - /// @copydoc puglSetAspectRatio - Status setAspectRatio(int minX, int minY, int maxX, int maxY) noexcept - { - return static_cast( - puglSetAspectRatio(cobj(), minX, minY, maxX, maxY)); - } - - /** - @} - @name Windows - Methods for working with top-level windows. - @{ - */ - - /// @copydoc puglSetWindowTitle - Status setWindowTitle(const char* title) noexcept - { - return static_cast(puglSetWindowTitle(cobj(), title)); - } - - /// @copydoc puglSetParentWindow - Status setParentWindow(NativeView parent) noexcept - { - return static_cast(puglSetParentWindow(cobj(), parent)); - } - - /// @copydoc puglSetTransientFor - Status setTransientFor(NativeView parent) noexcept - { - return static_cast(puglSetTransientFor(cobj(), parent)); - } - - /// @copydoc puglRealize - Status realize() noexcept { return static_cast(puglRealize(cobj())); } - - /// @copydoc puglShow - Status show() noexcept { return static_cast(puglShow(cobj())); } - - /// @copydoc puglHide - Status hide() noexcept { return static_cast(puglHide(cobj())); } - - /// @copydoc puglGetVisible - bool visible() const noexcept { return puglGetVisible(cobj()); } - - /// @copydoc puglGetNativeWindow - NativeView nativeWindow() noexcept { return puglGetNativeWindow(cobj()); } - - /** - @} - @name Graphics - Methods for working with the graphics context and scheduling - redisplays. - @{ - */ - - /// @copydoc puglGetContext - void* context() noexcept { return puglGetContext(cobj()); } - - /// @copydoc puglPostRedisplay - Status postRedisplay() noexcept - { - return static_cast(puglPostRedisplay(cobj())); - } - - /// @copydoc puglPostRedisplayRect - Status postRedisplayRect(const Rect rect) noexcept - { - return static_cast(puglPostRedisplayRect(cobj(), rect)); - } - - /** - @} - @name Interaction - Methods for interacting with the user and window system. - @{ - */ - - /// @copydoc puglGrabFocus - Status grabFocus() noexcept - { - return static_cast(puglGrabFocus(cobj())); - } - - /// @copydoc puglHasFocus - bool hasFocus() const noexcept { return puglHasFocus(cobj()); } - - /// @copydoc puglSetCursor - Status setCursor(const Cursor cursor) noexcept - { - return static_cast( - puglSetCursor(cobj(), static_cast(cursor))); - } - - /// @copydoc puglRequestAttention - Status requestAttention() noexcept - { - return static_cast(puglRequestAttention(cobj())); - } - - /** - Activate a repeating timer event. - - This starts a timer which will send a timer event to `view` every - `timeout` seconds. This can be used to perform some action in a view at a - regular interval with relatively low frequency. Note that the frequency - of timer events may be limited by how often update() is called. - - If the given timer already exists, it is replaced. - - @param id The identifier for this timer. This is an application-specific - ID that should be a low number, typically the value of a constant or `enum` - that starts from 0. There is a platform-specific limit to the number of - supported timers, and overhead associated with each, so applications should - create only a few timers and perform several tasks in one if necessary. - - @param timeout The period, in seconds, of this timer. This is not - guaranteed to have a resolution better than 10ms (the maximum timer - resolution on Windows) and may be rounded up if it is too short. On X11 - and MacOS, a resolution of about 1ms can usually be relied on. - - @return #PUGL_FAILURE if timers are not supported by the system, - #PUGL_UNKNOWN_ERROR if setting the timer failed. - */ - Status startTimer(const uintptr_t id, const double timeout) noexcept - { - return static_cast(puglStartTimer(cobj(), id, timeout)); - } - - /** - Stop an active timer. - - @param id The ID previously passed to startTimer(). - - @return #PUGL_FAILURE if timers are not supported by this system, - #PUGL_UNKNOWN_ERROR if stopping the timer failed. - */ - Status stopTimer(const uintptr_t id) noexcept - { - return static_cast(puglStopTimer(cobj(), id)); - } - - /** - @} - */ - - PuglView* cobj() noexcept { return Wrapper::cobj(); } - const PuglView* cobj() const noexcept { return Wrapper::cobj(); } - -private: - template - static Status dispatch(Target& target, const PuglEvent* event) - { - switch (event->type) { - case PUGL_NOTHING: - return Status::success; - case PUGL_CREATE: - return target.onEvent(static_cast(event->any)); - case PUGL_DESTROY: - return target.onEvent(static_cast(event->any)); - case PUGL_CONFIGURE: - return target.onEvent( - static_cast(event->configure)); - case PUGL_MAP: - return target.onEvent(static_cast(event->any)); - case PUGL_UNMAP: - return target.onEvent(static_cast(event->any)); - case PUGL_UPDATE: - return target.onEvent(static_cast(event->any)); - case PUGL_EXPOSE: - return target.onEvent(static_cast(event->expose)); - case PUGL_CLOSE: - return target.onEvent(static_cast(event->any)); - case PUGL_FOCUS_IN: - return target.onEvent(static_cast(event->focus)); - case PUGL_FOCUS_OUT: - return target.onEvent(static_cast(event->focus)); - case PUGL_KEY_PRESS: - return target.onEvent(static_cast(event->key)); - case PUGL_KEY_RELEASE: - return target.onEvent(static_cast(event->key)); - case PUGL_TEXT: - return target.onEvent(static_cast(event->text)); - case PUGL_POINTER_IN: - return target.onEvent( - static_cast(event->crossing)); - case PUGL_POINTER_OUT: - return target.onEvent( - static_cast(event->crossing)); - case PUGL_BUTTON_PRESS: - return target.onEvent( - static_cast(event->button)); - case PUGL_BUTTON_RELEASE: - return target.onEvent( - static_cast(event->button)); - case PUGL_MOTION: - return target.onEvent(static_cast(event->motion)); - case PUGL_SCROLL: - return target.onEvent(static_cast(event->scroll)); - case PUGL_CLIENT: - return target.onEvent(static_cast(event->client)); - case PUGL_TIMER: - return target.onEvent(static_cast(event->timer)); - case PUGL_LOOP_ENTER: - return target.onEvent(static_cast(event->any)); - case PUGL_LOOP_LEAVE: - return target.onEvent(static_cast(event->any)); - } - - return Status::failure; - } - - template - static PuglStatus eventFunc(PuglView* view, const PuglEvent* event) noexcept - { - auto* target = static_cast(puglGetHandle(view)); - -#ifdef __cpp_exceptions - try { - return static_cast(dispatch(*target, event)); - } catch (...) { - return PUGL_UNKNOWN_ERROR; - } -#else - return static_cast(pugl::dispatch(*target, event)); -#endif - } - - World& _world; -}; - -/** - @} - @} -*/ - -} // namespace pugl - -#endif // PUGL_PUGL_HPP diff --git a/subprojects/nk_pugl/pugl/bindings/cxx/include/pugl/stub.hpp b/subprojects/nk_pugl/pugl/bindings/cxx/include/pugl/stub.hpp deleted file mode 100644 index fbafcee..0000000 --- a/subprojects/nk_pugl/pugl/bindings/cxx/include/pugl/stub.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_STUB_HPP -#define PUGL_STUB_HPP - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -namespace pugl { - -/** - @defgroup stubxx Stub - Stub graphics support. - @ingroup puglxx - @{ -*/ - -/// @copydoc puglStubBackend -inline const PuglBackend* -stubBackend() noexcept -{ - return puglStubBackend(); -} - -/** - @} -*/ - -} // namespace pugl - -#endif // PUGL_STUB_HPP diff --git a/subprojects/nk_pugl/pugl/bindings/cxx/include/pugl/vulkan.hpp b/subprojects/nk_pugl/pugl/bindings/cxx/include/pugl/vulkan.hpp deleted file mode 100644 index f3dbcad..0000000 --- a/subprojects/nk_pugl/pugl/bindings/cxx/include/pugl/vulkan.hpp +++ /dev/null @@ -1,168 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Note that this header includes Vulkan headers, so if you are writing a - program or plugin that dynamically loads vulkan, you should first define - `VK_NO_PROTOTYPES` before including it. -*/ - -#ifndef PUGL_VULKAN_HPP -#define PUGL_VULKAN_HPP - -#include "pugl/pugl.h" -#include "pugl/pugl.hpp" -#include "pugl/vulkan.h" - -#include - -#include - -namespace pugl { - -/** - @defgroup vulkanxx Vulkan - Vulkan graphics support. - - Note that the Pugl C++ wrapper does not use vulkan-hpp because it is a - heavyweight dependency which not everyone uses, and its design is not very - friendly to dynamic loading in plugins anyway. However, if you do use - vulkan-hpp smart handles, it is relatively straightforward to wrap the - result of createSurface() manually. - - @ingroup puglxx - @{ -*/ - -/// @copydoc PuglVulkanLoader -class VulkanLoader final - : public detail::Wrapper -{ -public: - /** - Create a new dynamic loader for Vulkan functions. - - This dynamically loads the Vulkan library and gets the load functions - from it. - - Note that this constructor does not throw exceptions, though failure is - possible. To check if the Vulkan library failed to load, test this - loader, which is explicitly convertible to `bool`. It is safe to use a - failed loader, but the accessors will always return null. - */ - explicit VulkanLoader(World& world) noexcept - : Wrapper{puglNewVulkanLoader(world.cobj())} - {} - - /** - Return the `vkGetInstanceProcAddr` function. - - @return Null if the Vulkan library failed to load, or does not contain - this function (which is unlikely and indicates a broken system). - */ - PFN_vkGetInstanceProcAddr getInstanceProcAddrFunc() const noexcept - { - return cobj() ? puglGetInstanceProcAddrFunc(cobj()) : nullptr; - } - - /** - Return the `vkGetDeviceProcAddr` function. - - @return Null if the Vulkan library failed to load, or does not contain - this function (which is unlikely and indicates a broken system). - */ - PFN_vkGetDeviceProcAddr getDeviceProcAddrFunc() const noexcept - { - return cobj() ? puglGetDeviceProcAddrFunc(cobj()) : nullptr; - } - - /// Return true if this loader is valid to use - explicit operator bool() const noexcept { return cobj(); } -}; - -/** - A simple wrapper for an array of static C strings. - - This provides a minimal API that supports iteration, like `std::vector`, but - avoids allocation, exceptions, and a dependency on the C++ standard library. -*/ -class StaticStringArray final -{ -public: - using value_type = const char*; - using const_iterator = const char* const*; - using size_type = uint32_t; - - StaticStringArray(const char* const* strings, const uint32_t size) noexcept - : _strings{strings} - , _size{size} - {} - - const char* const* begin() const noexcept { return _strings; } - const char* const* end() const noexcept { return _strings + _size; } - const char* const* data() const noexcept { return _strings; } - uint32_t size() const noexcept { return _size; } - -private: - const char* const* _strings; - uint32_t _size; -}; - -/** - Return the Vulkan instance extensions required to draw to a PuglView. - - If successful, the returned array always contains "VK_KHR_surface", along - with whatever other platform-specific extensions are required. - - @return An array of extension name strings. -*/ -inline StaticStringArray -getInstanceExtensions() noexcept -{ - uint32_t count = 0; - const char* const* const extensions = puglGetInstanceExtensions(&count); - - return StaticStringArray{extensions, count}; -} - -/// @copydoc puglCreateSurface -inline VkResult -createSurface(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr, - View& view, - VkInstance instance, - const VkAllocationCallbacks* const allocator, - VkSurfaceKHR* const surface) noexcept -{ - const VkResult r = puglCreateSurface( - vkGetInstanceProcAddr, view.cobj(), instance, allocator, surface); - - return (!r && !surface) ? VK_ERROR_INITIALIZATION_FAILED : r; -} - -/// @copydoc puglVulkanBackend -inline const PuglBackend* -vulkanBackend() noexcept -{ - return puglVulkanBackend(); -} - -/** - @} -*/ - -} // namespace pugl - -#endif // PUGL_VULKAN_HPP diff --git a/subprojects/nk_pugl/pugl/doc/_static/meson.build b/subprojects/nk_pugl/pugl/doc/_static/meson.build deleted file mode 100644 index fc7792c..0000000 --- a/subprojects/nk_pugl/pugl/doc/_static/meson.build +++ /dev/null @@ -1,2 +0,0 @@ -configure_file(copy: true, input: '../../resources/pugl.svg', output: 'pugl.svg') - diff --git a/subprojects/nk_pugl/pugl/doc/c/Doxyfile.in b/subprojects/nk_pugl/pugl/doc/c/Doxyfile.in deleted file mode 100644 index 96bbf63..0000000 --- a/subprojects/nk_pugl/pugl/doc/c/Doxyfile.in +++ /dev/null @@ -1,28 +0,0 @@ -PROJECT_NAME = Pugl -PROJECT_BRIEF = "A minimal portable API for embeddable GUIs" - -QUIET = YES -WARN_AS_ERROR = YES -WARN_IF_UNDOCUMENTED = NO -WARN_NO_PARAMDOC = NO - -JAVADOC_AUTOBRIEF = YES - -FULL_PATH_NAMES = NO -CASE_SENSE_NAMES = YES -HIDE_IN_BODY_DOCS = YES -REFERENCES_LINK_SOURCE = NO - -GENERATE_HTML = NO -GENERATE_LATEX = NO -GENERATE_XML = YES -XML_PROGRAMLISTING = NO -SHOW_FILES = NO - -MACRO_EXPANSION = YES -PREDEFINED = PUGL_API PUGL_DISABLE_DEPRECATED PUGL_CONST_API= PUGL_CONST_FUNC= - -STRIP_FROM_PATH = @PUGL_SRCDIR@ -INPUT = @PUGL_HEADERS@ - -OUTPUT_DIRECTORY = doc/c diff --git a/subprojects/nk_pugl/pugl/doc/c/api/meson.build b/subprojects/nk_pugl/pugl/doc/c/api/meson.build deleted file mode 100644 index 5c1e30e..0000000 --- a/subprojects/nk_pugl/pugl/doc/c/api/meson.build +++ /dev/null @@ -1,5 +0,0 @@ -c_pugl_rst = custom_target( - 'C API ReST Documentation', - command: [dox_to_sphinx, '-f', '@INPUT0@', 'doc/c/api'], - input: [c_index_xml] + c_rst_files, - output: 'pugl.rst') diff --git a/subprojects/nk_pugl/pugl/doc/c/event-loop.rst b/subprojects/nk_pugl/pugl/doc/c/event-loop.rst deleted file mode 100644 index 3b9915f..0000000 --- a/subprojects/nk_pugl/pugl/doc/c/event-loop.rst +++ /dev/null @@ -1,101 +0,0 @@ -.. default-domain:: c -.. highlight:: c - -###################### -Driving the Event Loop -###################### - -Pugl does not contain any threads or other event loop "magic". -For flexibility, the event loop is driven explicitly by repeatedly calling :func:`puglUpdate`, -which processes events from the window system and dispatches them to views when necessary. - -The exact use of :func:`puglUpdate` depends on the application. -Plugins should call it with a ``timeout`` of 0 in a callback driven by the host. -This avoids blocking the main loop, -since other plugins and the host itself need to run as well. - -A program can use whatever timeout is appropriate: -event-driven applications may wait forever by using a ``timeout`` of -1, -while those that draw continuously may use a significant fraction of the frame period -(with enough time left over to render). - -********* -Redrawing -********* - -Occasional redrawing can be requested by calling :func:`puglPostRedisplay` or :func:`puglPostRedisplayRect`. -After these are called, -a :struct:`PuglEventExpose` will be dispatched on the next call to :func:`puglUpdate`. - -For continuous redrawing, -call :func:`puglPostRedisplay` while handling a :struct:`PuglEventUpdate` event. -This event is sent just before views are redrawn, -so it can be used as a hook to expand the update region right before the view is exposed. -Anything else that needs to be done every frame can be handled similarly. - -***************** -Event Dispatching -***************** - -Ideally, pending events are dispatched during a call to :func:`puglUpdate`, -directly within the scope of that call. - -Unfortunately, this is not universally true due to differences between platforms. - -MacOS -===== - -On MacOS, drawing is handled specially and not by the normal event queue mechanism. -This means that configure and expose events, -and possibly others, -may be dispatched to a view outside the scope of a :func:`puglUpdate` call. -In general, you can not rely on coherent event dispatching semantics on MacOS: -the operating system can call into application code at "random" times, -and these calls may result in Pugl events being dispatched. - -An application that follows the Pugl guidelines should work fine, -but there is one significant inconsistency you may encounter on MacOS: -posting a redisplay will not wake up a blocked :func:`puglUpdate` call. - -Windows -======= - -On Windows, the application has relatively tight control over the event loop, -so events are typically dispatched explicitly by :func:`puglUpdate`. -Drawing is handled by events, -so posting a redisplay will wake up a blocked :func:`puglUpdate` call. - -However, it is possible for the system to dispatch events at other times. -So, -it is possible for events to be dispatched outside the scope of a :func:`puglUpdate` call, -but this does not happen in normal circumstances and can largely be ignored. - -X11 -=== - -On X11, the application strictly controls event dispatching, -and there is no way for the system to call into application code at surprising times. -So, all events are dispatched in the scope of a :func:`puglUpdate` call. - -********************* -Recursive Event Loops -********************* - -On Windows and MacOS, -the event loop is stalled while the user is resizing the window or, -on Windows, -has displayed the window menu. -This means that :func:`puglUpdate` will block until the resize is finished, -or the menu is closed. - -Pugl dispatches :struct:`PuglEventLoopEnter` and :struct:`PuglEventLoopLeave` events to notify the application of this situation. -If you want to continuously redraw during resizing on these platforms, -you can schedule a timer with :func:`puglStartTimer` when the recursive loop is entered, -and post redisplays when handling the :struct:`PuglEventTimer`. -Be sure to remove the timer with :func:`puglStopTimer` when the recursive loop is finished. - -On X11, there are no recursive event loops, -and everything works as usual while the user is resizing the window. -There is nothing special about a "live resize" on X11, -and the above loop events will never be dispatched. - diff --git a/subprojects/nk_pugl/pugl/doc/c/events.rst b/subprojects/nk_pugl/pugl/doc/c/events.rst deleted file mode 100644 index bf964db..0000000 --- a/subprojects/nk_pugl/pugl/doc/c/events.rst +++ /dev/null @@ -1,84 +0,0 @@ -.. default-domain:: c -.. highlight:: c - -*************** -Handling Events -*************** - -Events are sent to a view when it has received user input, -must be drawn, or in other situations that may need to be handled such as resizing. - -Events are sent to the event handler as a :union:`PuglEvent` union. -The ``type`` field defines the type of the event and which field of the union is active. -The application must handle at least :enumerator:`PUGL_CONFIGURE ` -and :enumerator:`PUGL_EXPOSE ` to draw anything, -but there are many other :enum:`event types `. - -For example, a basic event handler might look something like this: - -.. code-block:: c - - static PuglStatus - onEvent(PuglView* view, const PuglEvent* event) - { - MyApp* app = (MyApp*)puglGetHandle(view); - - switch (event->type) { - case PUGL_CREATE: - return setupGraphics(app); - case PUGL_DESTROY: - return teardownGraphics(app); - case PUGL_CONFIGURE: - return resize(app, event->configure.width, event->configure.height); - case PUGL_EXPOSE: - return draw(app, view); - case PUGL_CLOSE: - return quit(app); - case PUGL_BUTTON_PRESS: - return onButtonPress(app, view, event->button); - default: - break; - } - - return PUGL_SUCCESS; - } - -Using the Graphics Context -========================== - -Drawing -------- - -Note that Pugl uses a different drawing model than many libraries, -particularly those designed for game-style main loops like `SDL `_ and `GLFW `_. - -In that style of code, drawing is performed imperatively in the main loop, -but with Pugl, the application must draw only while handling an expose event. -This is because Pugl supports event-driven applications that only draw the damaged region when necessary, -and handles exposure internally to provide optimized and consistent behavior across platforms. - -Cairo Context -------------- - -A Cairo context is created for each :struct:`PuglEventExpose`, -and only exists during the handling of that event. -Null is returned by :func:`puglGetContext` at any other time. - -OpenGL Context --------------- - -The OpenGL context is only active during the handling of these events: - -- :struct:`PuglEventCreate` -- :struct:`PuglEventDestroy` -- :struct:`PuglEventConfigure` -- :struct:`PuglEventExpose` - -As always, drawing is only possible during an expose. - -Vulkan Context --------------- - -With Vulkan, the graphics context is managed by the application rather than Pugl. -However, drawing must still only be performed during an expose. - diff --git a/subprojects/nk_pugl/pugl/doc/c/index.rst b/subprojects/nk_pugl/pugl/doc/c/index.rst deleted file mode 100644 index 020cf32..0000000 --- a/subprojects/nk_pugl/pugl/doc/c/index.rst +++ /dev/null @@ -1,11 +0,0 @@ -#### -Pugl -#### - -.. include:: summary.rst - -.. toctree:: - - deployment - overview - api/pugl diff --git a/subprojects/nk_pugl/pugl/doc/c/meson.build b/subprojects/nk_pugl/pugl/doc/c/meson.build deleted file mode 100644 index df9363e..0000000 --- a/subprojects/nk_pugl/pugl/doc/c/meson.build +++ /dev/null @@ -1,44 +0,0 @@ -config = configuration_data() -config.set('PUGL_VERSION', meson.project_version()) - -conf_py = configure_file(configuration: config, - input: '../conf.py.in', - output: 'conf.py') - -configure_file(copy: true, input: '../deployment.rst', output: 'deployment.rst') -configure_file(copy: true, input: '../summary.rst', output: 'summary.rst') - -c_rst_files = files( - 'index.rst', - 'overview.rst', - 'world.rst', - 'view.rst', - 'events.rst', - 'event-loop.rst', - 'shutting-down.rst' -) - -foreach f : c_rst_files - configure_file(copy: true, input: f, output: '@PLAINNAME@') -endforeach - -subdir('xml') -subdir('api') - -docs = custom_target( - 'C API Documentation (singlehtml)', - command: [sphinx_build, '-M', 'singlehtml', 'doc/c/', 'doc/c/', '-E', '-q', '-t', 'singlehtml'], - input: [c_rst_files, c_pugl_rst, c_index_xml], - output: 'singlehtml', - build_by_default: true, - install: true, - install_dir: docdir / 'pugl-0') - -docs = custom_target( - 'C API Documentation (html)', - command: [sphinx_build, '-M', 'html', 'doc/c/', 'doc/c/', '-E', '-q', '-t', 'html'], - input: [c_rst_files, c_pugl_rst, c_index_xml], - output: 'html', - build_by_default: true, - install: true, - install_dir: docdir / 'pugl-0') diff --git a/subprojects/nk_pugl/pugl/doc/c/overview.rst b/subprojects/nk_pugl/pugl/doc/c/overview.rst deleted file mode 100644 index 4bd024d..0000000 --- a/subprojects/nk_pugl/pugl/doc/c/overview.rst +++ /dev/null @@ -1,26 +0,0 @@ -.. default-domain:: c -.. highlight:: c - -######## -Overview -######## - -The Pugl API revolves around two main objects: the `world` and the `view`. -An application creates a world to manage top-level state, -then creates one or more views to display. - -The core API (excluding backend-specific components) is declared in ``pugl.h``: - -.. code-block:: c - - #include - -.. toctree:: - - world - view - events - event-loop - shutting-down - -.. _pkg-config: https://www.freedesktop.org/wiki/Software/pkg-config/ diff --git a/subprojects/nk_pugl/pugl/doc/c/shutting-down.rst b/subprojects/nk_pugl/pugl/doc/c/shutting-down.rst deleted file mode 100644 index dfb56cd..0000000 --- a/subprojects/nk_pugl/pugl/doc/c/shutting-down.rst +++ /dev/null @@ -1,20 +0,0 @@ -.. default-domain:: c -.. highlight:: c - -############# -Shutting Down -############# - -When a view is closed, -it will receive a :struct:`PuglEventClose`. -An application may also set a flag based on user input or other conditions, -which can be used to break out of the main loop and stop calling :func:`puglUpdate`. - -When the main event loop has finished running, -any views and the world need to be destroyed, in that order. -For example: - -.. code-block:: c - - puglFreeView(view); - puglFreeWorld(world); diff --git a/subprojects/nk_pugl/pugl/doc/c/view.rst b/subprojects/nk_pugl/pugl/doc/c/view.rst deleted file mode 100644 index 12f146d..0000000 --- a/subprojects/nk_pugl/pugl/doc/c/view.rst +++ /dev/null @@ -1,321 +0,0 @@ -.. default-domain:: c -.. highlight:: c - -############### -Creating a View -############### - -A view is a drawable region that receives events. -You may think of it as a window, -though it may be embedded and not represent a top-level system window. [#f1]_ - -Creating a visible view is a multi-step process. -When a new view is created with :func:`puglNewView`, -it does not yet represent a "real" system view: - -.. code-block:: c - - PuglView* view = puglNewView(world); - -********************* -Configuring the Frame -********************* - -Before display, -the necessary :doc:`frame ` and :doc:`window ` attributes should be set. -These allow the window system (or plugin host) to arrange the view properly. -For example: - -.. code-block:: c - - const double defaultWidth = 1920.0; - const double defaultHeight = 1080.0; - - puglSetWindowTitle(view, "My Window"); - puglSetDefaultSize(view, defaultWidth, defaultHeight); - puglSetMinSize(view, defaultWidth / 4.0, defaultHeight / 4.0); - puglSetAspectRatio(view, 1, 1, 16, 9); - -There are also several :enum:`hints ` for basic attributes that can be set: - -.. code-block:: c - - puglSetViewHint(view, PUGL_RESIZABLE, PUGL_TRUE); - puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, PUGL_TRUE); - -********* -Embedding -********* - -To embed the view in another window, -you will need to somehow get the :type:`native view handle ` for the parent, -then set it with :func:`puglSetParentWindow`. -If the parent is a Pugl view, -the native handle can be accessed with :func:`puglGetNativeWindow`. -For example: - -.. code-block:: c - - puglSetParentWindow(view, puglGetNativeWindow(parent)); - -************************ -Setting an Event Handler -************************ - -In order to actually do anything, a view must process events from the system. -Pugl dispatches all events to a single :type:`event handling function `, -which is set with :func:`puglSetEventFunc`: - -.. code-block:: c - - puglSetEventFunc(view, onEvent); - -See :doc:`events` for details on writing the event handler itself. - -***************** -Setting View Data -***************** - -Since the event handler is called with only a view pointer and an event, -there needs to be some way to access application data associated with the view. -Similar to :ref:`setting application data `, -this is done by setting an opaque handle on the view with :func:`puglSetHandle`, -for example: - -.. code-block:: c - - puglSetHandle(view, myViewData); - -The handle can be later retrieved, -likely in the event handler, -with :func:`puglGetHandle`: - -.. code-block:: c - - MyViewData* data = (MyViewData*)puglGetHandle(view); - -All non-constant data should be accessed via this handle, -to avoid problems associated with static mutable data. - -If data is also associated with the world, -it can be retrieved via the view using :func:`puglGetWorld`: - -.. code-block:: c - - PuglWorld* world = puglGetWorld(view); - MyApp* app = (MyApp*)puglGetWorldHandle(world); - -***************** -Setting a Backend -***************** - -Before being realized, the view must have a backend set with :func:`puglSetBackend`. - -The backend manages the graphics API that will be used for drawing. -Pugl includes backends and supporting API for -:doc:`Cairo `, :doc:`OpenGL `, and :doc:`Vulkan `. - -Using Cairo -=========== - -Cairo-specific API is declared in the ``cairo.h`` header: - -.. code-block:: c - - #include - -The Cairo backend is provided by :func:`puglCairoBackend()`: - -.. code-block:: c - - puglSetBackend(view, puglCairoBackend()); - -No additional configuration is required for Cairo. -To draw when handling an expose event, -the `Cairo context `_ can be accessed with :func:`puglGetContext`: - -.. code-block:: c - - cairo_t* cr = (cairo_t*)puglGetContext(view); - -Using OpenGL -============ - -OpenGL-specific API is declared in the ``gl.h`` header: - -.. code-block:: c - - #include - -The OpenGL backend is provided by :func:`puglGlBackend()`: - -.. code-block:: c - - puglSetBackend(view, puglGlBackend()); - -Some hints must also be set so that the context can be set up correctly. -For example, to use OpenGL 3.3 Core Profile: - -.. code-block:: c - - puglSetViewHint(view, PUGL_USE_COMPAT_PROFILE, PUGL_FALSE); - puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 3); - puglSetViewHint(view, PUGL_CONTEXT_VERSION_MINOR, 3); - -If you need to perform some setup using the OpenGL API, -there are two ways to do so. - -The OpenGL context is active when -:enumerator:`PUGL_CREATE ` and -:enumerator:`PUGL_DESTROY ` -events are dispatched, -so things like creating and destroying shaders and textures can be done then. - -Alternatively, if it is cumbersome to set up and tear down OpenGL in the event handler, -:func:`puglEnterContext` and :func:`puglLeaveContext` can be used to manually activate the OpenGL context during application setup. -Note, however, that unlike many other APIs, these functions must not be used for drawing. -It is only valid to use the OpenGL API for configuration in a manually entered context, -rendering will not work. -For example: - -.. code-block:: c - - puglEnterContext(view); - setupOpenGL(myApp); - puglLeaveContext(view); - - while (!myApp->quit) { - puglUpdate(world, 0.0); - } - - puglEnterContext(view); - teardownOpenGL(myApp); - puglLeaveContext(view); - -Using Vulkan -============ - -Vulkan-specific API is declared in the ``vulkan.h`` header. -This header includes Vulkan headers, -so if you are dynamically loading Vulkan at runtime, -you should define ``VK_NO_PROTOTYPES`` before including it. - -.. code-block:: c - - #define VK_NO_PROTOTYPES - - #include - -The Vulkan backend is provided by :func:`puglVulkanBackend()`: - -.. code-block:: c - - puglSetBackend(view, puglVulkanBackend()); - -Unlike OpenGL, almost all Vulkan configuration is done using the Vulkan API directly. -Pugl only provides a portable mechanism to load the Vulkan library and get the functions used to load the rest of the Vulkan API. - -Loading Vulkan --------------- - -For maximum compatibility, -it is best to not link to Vulkan at compile-time, -but instead load the Vulkan API at run-time. -To do so, first create a :struct:`PuglVulkanLoader`: - -.. code-block:: c - - PuglVulkanLoader* loader = puglNewVulkanLoader(world); - -The loader manages the dynamically loaded Vulkan library, -so it must be kept alive for as long as the application is using Vulkan. -You can get the function used to load Vulkan functions with :func:`puglGetInstanceProcAddrFunc`: - -.. code-block:: c - - PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = - puglGetInstanceProcAddrFunc(loader); - -This vkGetInstanceProcAddr_ function can be used to load the rest of the Vulkan API. -For example, you can use it to get the vkCreateInstance_ function, -then use that to create your Vulkan instance. -In practice, you will want to use some loader or wrapper API since there are many Vulkan functions. - -For advanced situations, -there is also :func:`puglGetDeviceProcAddrFunc` which retrieves the vkGetDeviceProcAddr_ function instead. - -The Vulkan loader is provided for convenience, -so that applications to not need to write platform-specific code to load Vulkan. -Its use it not mandatory and Pugl can be used with Vulkan loaded by some other method. - -Linking with Vulkan -------------------- - -If you do want to link to the Vulkan library at compile time, -note that the Pugl Vulkan backend does not depend on it, -so you will have to do so explicitly. - -Creating a Surface ------------------- - -The details of using Vulkan are far beyond the scope of this documentation, -but Pugl provides a portable function, :func:`puglCreateSurface`, -to get the Vulkan surface for a view. -Assuming you have somehow created your ``VkInstance``, -you can get the surface for a view using :func:`puglCreateSurface`: - -.. code-block:: c - - VkSurfaceKHR* surface = NULL; - puglCreateSurface(puglGetDeviceProcAddrFunc(loader), - view, - vulkanInstance, - NULL, - &surface); - -**************** -Showing the View -**************** - -Once the view is configured, it can be "realized" with :func:`puglRealize`. -This creates a "real" system view, for example: - -.. code-block:: c - - PuglStatus status = puglRealize(view); - if (status) { - fprintf(stderr, "Error realizing view (%s)\n", puglStrerror(status)); - } - -Note that realizing a view can fail for many reasons, -so the return code should always be checked. -This is generally the case for any function that interacts with the window system. -Most functions also return a :enum:`PuglStatus`, -but these checks are omitted for brevity in the rest of this documentation. - -A realized view is not initially visible, -but can be shown with :func:`puglShow`: - -.. code-block:: c - - puglShow(view); - -To create an initially visible view, -it is also possible to simply call :func:`puglShow` right away. -The view will be automatically realized if necessary. - -.. rubric:: Footnotes - -.. [#f1] MacOS has a strong distinction between - `views `_, - which may be nested, and - `windows `_, - which may not. - On Windows and X11, everything is a nestable window, - but top-level windows are configured differently. - -.. _vkCreateInstance: https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkCreateInstance.html - -.. _vkGetDeviceProcAddr: https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkGetDeviceProcAddr.html - -.. _vkGetInstanceProcAddr: https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkGetInstanceProcAddr.html diff --git a/subprojects/nk_pugl/pugl/doc/c/world.rst b/subprojects/nk_pugl/pugl/doc/c/world.rst deleted file mode 100644 index 83d9dbd..0000000 --- a/subprojects/nk_pugl/pugl/doc/c/world.rst +++ /dev/null @@ -1,65 +0,0 @@ -################ -Creating a World -################ - -.. default-domain:: c -.. highlight:: c - -The world is the top-level object which represents an instance of Pugl. -It handles the connection to the window system, -and manages views and the event loop. - -An application typically has a single world, -which is constructed once on startup and used to drive the main event loop. - -************ -Construction -************ - -A world must be created before any views, and it must outlive all of its views. -A world is created with :func:`puglNewWorld`, for example: - -.. code-block:: c - - PuglWorld* world = puglNewWorld(PUGL_PROGRAM, 0); - -For a plugin, specify :enumerator:`PUGL_MODULE ` instead. -In some cases, it is necessary to pass additional flags. -For example, Vulkan requires thread support: - -.. code-block:: c - - PuglWorld* world = puglNewWorld(PUGL_MODULE, PUGL_WORLD_THREADS) - -It is a good idea to set a class name for your project with :func:`puglSetClassName`. -This allows the window system to distinguish different applications and, -for example, users to set up rules to manage their windows nicely: - -.. code-block:: c - - puglSetClassName(world, "MyAwesomeProject") - -.. _setting-application-data: - -************************ -Setting Application Data -************************ - -Pugl will call an event handler in the application with only a view pointer and an event, -so there needs to be some way to access the data you use in your application. -This is done by setting an opaque handle on the world with :func:`puglSetWorldHandle`, -for example: - -.. code-block:: c - - puglSetWorldHandle(world, myApp); - -The handle can be later retrieved with :func:`puglGetWorldHandle`: - -.. code-block:: c - - MyApp* app = (MyApp*)puglGetWorldHandle(world); - -All non-constant data should be accessed via this handle, -to avoid problems associated with static mutable data. - diff --git a/subprojects/nk_pugl/pugl/doc/c/xml/meson.build b/subprojects/nk_pugl/pugl/doc/c/xml/meson.build deleted file mode 100644 index d79d59a..0000000 --- a/subprojects/nk_pugl/pugl/doc/c/xml/meson.build +++ /dev/null @@ -1,19 +0,0 @@ -doxygen = find_program('doxygen') - -c_doxygen_input = [] -foreach h : c_headers - c_doxygen_input += ['..' / h] -endforeach - -config = configuration_data() -config.set('PUGL_HEADERS', ' '.join(c_doxygen_input)) -config.set('PUGL_SRCDIR', pugl_src_root) - -c_doxyfile = configure_file(configuration: config, - input: '../Doxyfile.in', - output: 'Doxyfile') - -c_index_xml = custom_target('c-index.xml', - command: [doxygen, '@INPUT0@'], - input: [c_doxyfile] + c_header_files, - output: 'index.xml') diff --git a/subprojects/nk_pugl/pugl/doc/conf.py.in b/subprojects/nk_pugl/pugl/doc/conf.py.in deleted file mode 100644 index 3fa8ea2..0000000 --- a/subprojects/nk_pugl/pugl/doc/conf.py.in +++ /dev/null @@ -1,85 +0,0 @@ -# Project information - -project = "Pugl" -copyright = "2020, David Robillard" -author = "David Robillard" -release = "@PUGL_VERSION@" - -# General configuration - -exclude_patterns = ["xml"] -language = "en" -nitpicky = True -pygments_style = "friendly" - -# Ignore everything opaque or external for nitpicky mode -_opaque = [ - "PFN_vkGetDeviceProcAddr", - "PFN_vkGetInstanceProcAddr", - "PuglBackendImpl", - "PuglViewImpl", - "PuglVulkanLoaderImpl", - "PuglWorldImpl", - "VkAllocationCallbacks", - "VkInstance", - "VkResult", - "VkSurfaceKHR", - "size_t", - "uint32_t", - "uintptr_t", -] - -_c_nitpick_ignore = map(lambda x: ("c:identifier", x), _opaque) -_cpp_nitpick_ignore = map(lambda x: ("cpp:identifier", x), _opaque) -nitpick_ignore = list(_c_nitpick_ignore) + list(_cpp_nitpick_ignore) - -# C++ - -cpp_index_common_prefix = ["pugl::"] - -# HTML output - -html_copy_source = False -html_short_title = "Pugl" -html_static_path = ["../_static"] -html_theme = "sphinx_lv2_theme" - -if tags.has('singlehtml'): - html_sidebars = { - "**": [ - "globaltoc.html", - ] - } - - html_theme_options = { - "body_max_width": "51em", - "body_min_width": "51em", - "description": "A minimal portable API for embeddable GUIs.", - "show_footer_version": True, - "show_logo_version": False, - "logo": "pugl.svg", - "logo_name": True, - "logo_width": "8em", - "nosidebar": False, - "page_width": "80em", - "sidebar_width": "16em", - "globaltoc_maxdepth": 3, - "globaltoc_collapse": False, - } - -else: - html_theme_options = { - "body_max_width": "60em", - "body_min_width": "40em", - "description": "A minimal portable API for embeddable GUIs.", - "show_footer_version": True, - "show_logo_version": False, - "logo": "pugl.svg", - "logo_name": True, - "logo_width": "8em", - "nosidebar": True, - "page_width": "60em", - "sidebar_width": "14em", - "globaltoc_maxdepth": 1, - "globaltoc_collapse": True, - } diff --git a/subprojects/nk_pugl/pugl/doc/cpp/Doxyfile.in b/subprojects/nk_pugl/pugl/doc/cpp/Doxyfile.in deleted file mode 100644 index 889ac0b..0000000 --- a/subprojects/nk_pugl/pugl/doc/cpp/Doxyfile.in +++ /dev/null @@ -1,32 +0,0 @@ -PROJECT_NAME = Pugl -PROJECT_BRIEF = "A minimal portable API for embeddable GUIs" - -QUIET = YES -WARN_AS_ERROR = YES -WARN_IF_UNDOCUMENTED = NO -WARN_NO_PARAMDOC = NO - -JAVADOC_AUTOBRIEF = YES - -CASE_SENSE_NAMES = YES -EXCLUDE_SYMBOLS = pugl::detail -EXTRACT_LOCAL_CLASSES = NO -EXTRACT_PRIVATE = NO -HIDE_IN_BODY_DOCS = YES -HIDE_UNDOC_CLASSES = YES -HIDE_UNDOC_MEMBERS = YES -REFERENCES_LINK_SOURCE = NO - -GENERATE_HTML = NO -GENERATE_LATEX = NO -GENERATE_XML = YES -XML_PROGRAMLISTING = NO -SHOW_FILES = NO - -MACRO_EXPANSION = YES -PREDEFINED = PUGL_API PUGL_DISABLE_DEPRECATED PUGL_CONST_API= PUGL_CONST_FUNC= - -STRIP_FROM_PATH = @PUGL_SRCDIR@ -INPUT = @PUGL_HEADERS@ - -OUTPUT_DIRECTORY = doc/cpp diff --git a/subprojects/nk_pugl/pugl/doc/cpp/api/meson.build b/subprojects/nk_pugl/pugl/doc/cpp/api/meson.build deleted file mode 100644 index 4bbbec2..0000000 --- a/subprojects/nk_pugl/pugl/doc/cpp/api/meson.build +++ /dev/null @@ -1,5 +0,0 @@ -cpp_pugl_rst = custom_target( - 'C++ API ReST Documentation', - command: [dox_to_sphinx, '-l', 'cpp', '-f', '@INPUT@', 'doc/cpp/api'], - input: cpp_index_xml, - output: 'pugl.rst') diff --git a/subprojects/nk_pugl/pugl/doc/cpp/event-loop.rst b/subprojects/nk_pugl/pugl/doc/cpp/event-loop.rst deleted file mode 100644 index 1d2ac41..0000000 --- a/subprojects/nk_pugl/pugl/doc/cpp/event-loop.rst +++ /dev/null @@ -1,37 +0,0 @@ -.. default-domain:: cpp -.. highlight:: cpp -.. namespace:: pugl - -###################### -Driving the Event Loop -###################### - -Pugl does not contain any threads or other event loop "magic". -For flexibility, the event loop is driven manually by repeatedly calling :func:`World::update`, -which processes events from the window system and dispatches them to views when necessary. - -The exact use of :func:`World::update` depends on the application. -Plugins typically call it with a ``timeout`` of 0 in a callback driven by the host. -This avoids blocking the main loop, -since other plugins and the host itself need to run as well. - -A program can use whatever timeout is appropriate: -event-driven applications may wait forever by using a ``timeout`` of -1, -while those that draw continuously may use a significant fraction of the frame period -(with enough time left over to render). - -********* -Redrawing -********* - -Occasional redrawing can be requested by calling :func:`View::postRedisplay` or :func:`View::postRedisplayRect`. -After these are called, -a :type:`ExposeEvent` will be dispatched on the next call to :func:`World::update`. -Note, however, that this will not wake up a blocked :func:`World::update` call on MacOS -(which does not handle drawing via events). - -For continuous redrawing, -call :func:`View::postRedisplay` while handling a :type:`UpdateEvent`. -This event is sent just before views are redrawn, -so it can be used as a hook to expand the update region right before the view is exposed. -Anything else that needs to be done every frame can be handled similarly. diff --git a/subprojects/nk_pugl/pugl/doc/cpp/events.rst b/subprojects/nk_pugl/pugl/doc/cpp/events.rst deleted file mode 100644 index 72c396c..0000000 --- a/subprojects/nk_pugl/pugl/doc/cpp/events.rst +++ /dev/null @@ -1,43 +0,0 @@ -.. default-domain:: cpp -.. highlight:: cpp -.. namespace:: pugl - -############### -Handling Events -############### - -Events are sent to a view when it has received user input, -must be drawn, or in other situations that may need to be handled such as resizing. - -Events are sent to the ``onEvent`` method that takes the matching event type. -The application must handle at least :type:`ConfigureEvent` -and :type:`ExposeEvent` to draw anything, -but there are many other :type:`event types `. - -For example, basic event handling for our above class might look something like: - -.. code-block:: cpp - - pugl::Status - MyView::onEvent(const pugl::ConfigureEvent& event) noexcept - { - return resize(event.width, event.height); - } - - pugl::Status - MyView::onEvent(const pugl::ExposeEvent& event) noexcept - { - return drawMyAwesomeInterface(event.x, event.y, event.width, event.height); - } - -******* -Drawing -******* - -Note that Pugl uses a different drawing model than many libraries, -particularly those designed for game-style main loops like `SDL `_ and `GLFW `_. - -In that style of code, drawing is performed imperatively in the main loop, -but with Pugl, the application must draw only while handling an expose event. -This is because Pugl supports event-driven applications that only draw the damaged region when necessary, -and handles exposure internally to provide optimized and consistent behavior across platforms. diff --git a/subprojects/nk_pugl/pugl/doc/cpp/index.rst b/subprojects/nk_pugl/pugl/doc/cpp/index.rst deleted file mode 100644 index b11d028..0000000 --- a/subprojects/nk_pugl/pugl/doc/cpp/index.rst +++ /dev/null @@ -1,12 +0,0 @@ -#### -Pugl -#### - -.. include:: summary.rst - -.. toctree:: - - deployment - overview - api/pugl - api/puglxx diff --git a/subprojects/nk_pugl/pugl/doc/cpp/meson.build b/subprojects/nk_pugl/pugl/doc/cpp/meson.build deleted file mode 100644 index d8bae11..0000000 --- a/subprojects/nk_pugl/pugl/doc/cpp/meson.build +++ /dev/null @@ -1,43 +0,0 @@ -config = configuration_data() -config.set('PUGL_VERSION', meson.project_version()) - -conf_py = configure_file(configuration: config, - input: '../conf.py.in', - output: 'conf.py') - -configure_file(copy: true, input: '../deployment.rst', output: 'deployment.rst') -configure_file(copy: true, input: '../summary.rst', output: 'summary.rst') - -cpp_rst_files = files( - 'index.rst', - 'overview.rst', - 'world.rst', - 'view.rst', - 'events.rst', - 'event-loop.rst', -) - -foreach f : cpp_rst_files - configure_file(copy: true, input: f, output: '@PLAINNAME@') -endforeach - -subdir('xml') -subdir('api') - -docs = custom_target( - 'C++ API Documentation (singlehtml)', - command: [sphinx_build, '-M', 'singlehtml', 'doc/cpp/', 'doc/cpp/', '-E', '-q', '-t', 'singlehtml'], - input: [cpp_rst_files, cpp_pugl_rst, cpp_index_xml], - output: 'singlehtml', - build_by_default: true, - install: true, - install_dir: docdir / 'puglxx-0') - -docs = custom_target( - 'C++ API Documentation (html)', - command: [sphinx_build, '-M', 'html', 'doc/cpp/', 'doc/cpp/', '-E', '-q', '-t', 'html'], - input: [cpp_rst_files, cpp_pugl_rst, cpp_index_xml], - output: 'html', - build_by_default: true, - install: true, - install_dir: docdir / 'puglxx-0') diff --git a/subprojects/nk_pugl/pugl/doc/cpp/overview.rst b/subprojects/nk_pugl/pugl/doc/cpp/overview.rst deleted file mode 100644 index 1928fba..0000000 --- a/subprojects/nk_pugl/pugl/doc/cpp/overview.rst +++ /dev/null @@ -1,35 +0,0 @@ -.. default-domain:: cpp -.. highlight:: cpp -.. namespace:: pugl - -######## -Overview -######## - -Pugl is a C library, -but the bindings documented here provide a more idiomatic and type-safe API for C++. -If you would rather use C, -refer instead to the `C API documentation <../../c/singlehtml/index.html>`_. - -The C++ bindings are very lightweight and do not require virtual functions, -RTTI, -exceptions, -or linking to the C++ standard library. -They are provided by the package ``puglxx-0`` which must be used in addition to the desired platform+backend package above. - -The core API (excluding backend-specific components) is declared in ``pugl.hpp``: - -.. code-block:: cpp - - #include - -The API revolves around two main objects: the `world` and the `view`. -An application creates a world to manage top-level state, -then creates one or more views to display. - -.. toctree:: - - world - view - events - event-loop diff --git a/subprojects/nk_pugl/pugl/doc/cpp/view.rst b/subprojects/nk_pugl/pugl/doc/cpp/view.rst deleted file mode 100644 index 3f5aee8..0000000 --- a/subprojects/nk_pugl/pugl/doc/cpp/view.rst +++ /dev/null @@ -1,299 +0,0 @@ -.. default-domain:: cpp -.. highlight:: cpp -.. namespace:: pugl - -############### -Creating a View -############### - -A `view` is a drawable region that receives events. -You may think of it as a window, -though it may be embedded and not represent a top-level system window. [#f1]_ - -Pugl communicates with views by dispatching events. -For flexibility, the event handler can be a different object than the view. -This allows using :class:`View` along with a separate event handler class. -Alternatively, a view class can inherit from :class:`View` and set itself as its event handler, -for a more object-oriented style. - -This documentation will use the latter approach, -so we will define a class for our view that contains everything needed: - -.. code-block:: cpp - - class MyView : public pugl::View - { - public: - explicit MyView(pugl::World& world) - : pugl::View{world} - { - setEventHandler(*this); - } - - pugl::Status onEvent(const pugl::ConfigureEvent& event) noexcept; - pugl::Status onEvent(const pugl::ExposeEvent& event) noexcept; - - // With other handlers here as needed... - - // Fallback handler for all other events - template - pugl::Status onEvent(const pugl::Event&) noexcept - { - return pugl::Status::success; - } - - private: - // Some data... - }; - -Pugl will call an ``onEvent`` method of the event handler (the view in this case) for every event. - -Note that Pugl uses a static dispatching mechanism rather than virtual functions to minimize overhead. -It is therefore necessary for the final class to define a handler for every event type. -A terse way to do this without writing every implementation is to define a fallback handler as a template, -as in the example above. -Alternatively, you can define an explicit handler for each event that simply returns :enumerator:`Status::success`. -This way, it will be a compile error if any event is not explicitly handled. - -********************* -Configuring the Frame -********************* - -Before display, -the necessary :doc:`frame ` and :doc:`window ` attributes should be set. -These allow the window system (or plugin host) to arrange the view properly. - -Derived classes can configure themselves during construction, -but we assume here that configuration is being done outside the view. -For example: - -.. code-block:: cpp - - const double defaultWidth = 1920.0; - const double defaultHeight = 1080.0; - - view.setWindowTitle("My Window"); - view.setDefaultSize(defaultWidth, defaultHeight); - view.setMinSize(defaultWidth / 4.0, defaultHeight / 4.0); - view.setAspectRatio(1, 1, 16, 9); - -There are also several :type:`hints ` for basic attributes that can be set: - -.. code-block:: cpp - - view.setHint(pugl::ViewHint::resizable, true); - view.setHint(pugl::ViewHint::ignoreKeyRepeat, true); - -********* -Embedding -********* - -To embed the view in another window, -you will need to somehow get the :type:`native view handle ` for the parent, -then set it with :func:`View::setParentWindow`. -If the parent is a Pugl view, -the native handle can be accessed with :func:`View::nativeWindow`. -For example: - -.. code-block:: cpp - - view.setParentWindow(view, parent.getNativeWindow()); - -***************** -Setting a Backend -***************** - -Before being realized, the view must have a backend set with :func:`View::setBackend`. - -The backend manages the graphics API that will be used for drawing. -Pugl includes backends and supporting API for -:doc:`Cairo `, :doc:`OpenGL `, and :doc:`Vulkan `. - -Using Cairo -=========== - -Cairo-specific API is declared in the ``cairo.hpp`` header: - -.. code-block:: cpp - - #include - -The Cairo backend is provided by :func:`cairoBackend()`: - -.. code-block:: cpp - - view.setBackend(pugl::cairoBackend()); - -No additional configuration is required for Cairo. -To draw when handling an expose event, -the `Cairo context `_ can be accessed with :func:`View::context`: - -.. code-block:: cpp - - cairo_t* cr = static_cast(view.context()); - -Using OpenGL -============ - -OpenGL-specific API is declared in the ``gl.hpp`` header: - -.. code-block:: cpp - - #include - -The OpenGL backend is provided by :func:`glBackend()`: - -.. code-block:: cpp - - view.setBackend(pugl::glBackend()); - -Some hints must also be set so that the context can be set up correctly. -For example, to use OpenGL 3.3 Core Profile: - -.. code-block:: cpp - - view.setHint(pugl::ViewHint::useCompatProfile, false); - view.setHint(pugl::ViewHint::contextVersionMajor, 3); - view.setHint(pugl::ViewHint::contextVersionMinor, 3); - -If you need to perform some setup using the OpenGL API, -there are two ways to do so. - -The OpenGL context is active when -:type:`CreateEvent` and -:type:`DestroyEvent` -events are dispatched, -so things like creating and destroying shaders and textures can be done then. - -Alternatively, if it is cumbersome to set up and tear down OpenGL in the event handler, -:func:`enterContext` and :func:`leaveContext` can be used to manually activate the OpenGL context during application setup. -Note, however, that unlike many other APIs, these functions must not be used for drawing. -It is only valid to use the OpenGL API for configuration in a manually entered context, -rendering will not work. -For example: - -.. code-block:: cpp - - pugl::enterContext(view); - myApp.setupOpenGL(); - pugl::leaveContext(view); - - while (!myApp.quit()) { - world.update(0.0); - } - - pugl::enterContext(view); - myApp.teardownOpenGL(); - pugl::leaveContext(view); - -Using Vulkan -============ - -Vulkan-specific API is declared in the ``vulkan.hpp`` header. -This header includes Vulkan headers, -so if you are dynamically loading Vulkan at runtime, -you should define ``VK_NO_PROTOTYPES`` before including it. - -.. code-block:: cpp - - #define VK_NO_PROTOTYPES - - #include - -The Vulkan backend is provided by :func:`vulkanBackend()`: - -.. code-block:: cpp - - view.setBackend(pugl::vulkanBackend()); - -Unlike OpenGL, almost all Vulkan configuration is done using the Vulkan API directly. -Pugl only provides a portable mechanism to load the Vulkan library and get the functions used to load the rest of the Vulkan API. - -Loading Vulkan --------------- - -For maximum compatibility, -it is best to not link to Vulkan at compile-time, -but instead load the Vulkan API at run-time. -To do so, first create a :class:`VulkanLoader`: - -.. code-block:: cpp - - pugl::VulkanLoader loader{world}; - -The loader manages the dynamically loaded Vulkan library, -so it must be kept alive for as long as the application is using Vulkan. -You can get the function used to load Vulkan functions with :func:`VulkanLoader::getInstanceProcAddrFunc`: - -.. code-block:: cpp - - auto vkGetInstanceProcAddr = loader.getInstanceProcAddrFunc(); - -It is best to use this function to load everything at run time, -rather than link to the Vulkan library at run time. -You can, for example, pass this to get the ``vkCreateInstance`` function using this, -then use that to create your Vulkan instance. -In practice, you will want to use some loader or wrapper API since there are many Vulkan functions. - -It is not necessary to use :class:`VulkanLoader`, -you can, for example, use the ``DynamicLoader`` from ``vulkan.hpp`` in the Vulkan SDK instead. - -The details of using Vulkan are far beyond the scope of this documentation, -but Pugl provides a portable function, :func:`createSurface`, -to get the Vulkan surface for a view. -Assuming you have somehow created your ``VkInstance``, -you can get the surface for a view using :func:`createSurface`: - -.. code-block:: cpp - - VkSurfaceKHR* surface = nullptr; - puglCreateSurface(loader.getDeviceProcAddrFunc(), - view, - vulkanInstance, - nullptr, - &surface); - -Pugl does not provide API that uses ``vulkan.hpp`` to avoid the onerous dependency, -but if you are using it with exceptions and unique handles, -it is straightforward to wrap the surface handle yourself. - -**************** -Showing the View -**************** - -Once the view is configured, it can be "realized" with :func:`View::realize`. -This creates a "real" system view, for example: - -.. code-block:: cpp - - pugl::Status status = view.realize(); - if (status != pugl::Status::success) { - std::cerr << "Error realizing view: " << pugl::strerror(status) << "\n"; - } - -Note that realizing a view can fail for many reasons, -so the return code should always be checked. -This is generally the case for any function that interacts with the window system. -Most functions also return a :enum:`Status`, -but these checks are omitted for brevity in the rest of this documentation. - -A realized view is not initially visible, -but can be shown with :func:`View::show`: - -.. code-block:: cpp - - view.show(); - -To create an initially visible view, -it is also possible to simply call :func:`View::show()` right away. -The view will be automatically realized if necessary. - -.. rubric:: Footnotes - -.. [#f1] MacOS has a strong distinction between - `views `_, - which may be nested, and - `windows `_, - which may not. - On Windows and X11, everything is a nestable window, - but top-level windows are configured differently. diff --git a/subprojects/nk_pugl/pugl/doc/cpp/world.rst b/subprojects/nk_pugl/pugl/doc/cpp/world.rst deleted file mode 100644 index 1a3b432..0000000 --- a/subprojects/nk_pugl/pugl/doc/cpp/world.rst +++ /dev/null @@ -1,41 +0,0 @@ -.. default-domain:: cpp -.. highlight:: cpp -.. namespace:: pugl - -################ -Creating a World -################ - -The world is the top-level object which represents an instance of Pugl. -It handles the connection to the window system, -and manages views and the event loop. - -An application typically has a single world, -which is constructed once on startup and used to drive the main event loop. - -************ -Construction -************ - -A world must be created before any views, and it must outlive all of its views. -The world constructor requires an argument to specify the application type: - -.. code-block:: cpp - - pugl::World world{pugl::WorldType::program}; - -For a plugin, specify :enumerator:`WorldType::module` instead. -In some cases, it is necessary to pass additional flags. -For example, Vulkan requires thread support: - -.. code-block:: cpp - - pugl::World world{pugl::WorldType::program, pugl::WorldFlag::threads}; - -It is a good idea to set a class name for your project with :func:`World::setClassName`. -This allows the window system to distinguish different applications and, -for example, users to set up rules to manage their windows nicely: - -.. code-block:: cpp - - world.setClassName("MyAwesomeProject"); diff --git a/subprojects/nk_pugl/pugl/doc/cpp/xml/meson.build b/subprojects/nk_pugl/pugl/doc/cpp/xml/meson.build deleted file mode 100644 index 3f87f2a..0000000 --- a/subprojects/nk_pugl/pugl/doc/cpp/xml/meson.build +++ /dev/null @@ -1,21 +0,0 @@ -doxygen = find_program('doxygen') - -cpp_doxygen_input = [] -foreach h : c_headers + cpp_headers - cpp_doxygen_input += ['..' / h] -endforeach - -config = configuration_data() -config.set('PUGL_HEADERS', ' '.join(cpp_doxygen_input)) -config.set('PUGL_SRCDIR', pugl_src_root) - -cpp_doxyfile = configure_file(configuration: config, - input: '../Doxyfile.in', - output: 'Doxyfile') - -cpp_index_xml = custom_target( - 'cpp-index.xml', - command: [doxygen, '@INPUT0@'], - input: [cpp_doxyfile] + c_header_files + cpp_header_files, - output: 'index.xml') - diff --git a/subprojects/nk_pugl/pugl/doc/deployment.rst b/subprojects/nk_pugl/pugl/doc/deployment.rst deleted file mode 100644 index 4afc51a..0000000 --- a/subprojects/nk_pugl/pugl/doc/deployment.rst +++ /dev/null @@ -1,23 +0,0 @@ -##### -Usage -##### - -********************* -Building Against Pugl -********************* - -When Pugl is installed, -pkg-config_ packages are provided that link with the core platform library and desired backend: - -- ``pugl-cairo-0`` -- ``pugl-gl-0`` -- ``pugl-vulkan-0`` - -Depending on one of these packages should be all that is necessary to use Pugl, -but details on the individual libraries that are installed are available in the README. - -If you are instead including the source directly in your project, -the structure is quite simple and hopefully obvious. -It is only necessary to copy the platform and backend implementations that you need. - -.. _pkg-config: https://www.freedesktop.org/wiki/Software/pkg-config/ diff --git a/subprojects/nk_pugl/pugl/doc/meson.build b/subprojects/nk_pugl/pugl/doc/meson.build deleted file mode 100644 index 583f09d..0000000 --- a/subprojects/nk_pugl/pugl/doc/meson.build +++ /dev/null @@ -1,13 +0,0 @@ -docdir = get_option('datadir') / 'doc' - -doxygen = find_program('doxygen', required: get_option('docs')) -dox_to_sphinx = find_program('../scripts/dox_to_sphinx.py') -sphinx_build = find_program('sphinx-build', required: get_option('docs')) - -build_docs = doxygen.found() and sphinx_build.found() - -if build_docs - subdir('_static') - subdir('c') - subdir('cpp') -endif diff --git a/subprojects/nk_pugl/pugl/doc/summary.rst b/subprojects/nk_pugl/pugl/doc/summary.rst deleted file mode 100644 index f05515f..0000000 --- a/subprojects/nk_pugl/pugl/doc/summary.rst +++ /dev/null @@ -1,22 +0,0 @@ -Pugl is an API for writing portable and embeddable GUIs. -Pugl is not a toolkit or framework, -but a minimal portability layer that sets up a drawing context and delivers events. - -Compared to other libraries, -Pugl is particularly suitable for use in plugins or other loadable modules. -There is no implicit context or static data in the library, -so it may be statically linked and used multiple times in the same process. - -Pugl has a modular design that separates the core library from graphics backends. -The core library is graphics agnostic, -it implements platform support and depends only on standard system libraries. -MacOS, Windows, and X11 are currently supported as platforms. - -Graphics backends are separate so that applications only depend on the API that they use. -Pugl includes graphics backends for Cairo_, OpenGL_, and Vulkan_. -It is also possible to use some other graphics API by implementing a custom backend, -or simply accessing the native platform handle for a window. - -.. _Cairo: https://www.cairographics.org/ -.. _OpenGL: https://www.opengl.org/ -.. _Vulkan: https://www.khronos.org/vulkan/ diff --git a/subprojects/nk_pugl/pugl/examples/.clang-tidy b/subprojects/nk_pugl/pugl/examples/.clang-tidy deleted file mode 100644 index fdfa4ea..0000000 --- a/subprojects/nk_pugl/pugl/examples/.clang-tidy +++ /dev/null @@ -1,40 +0,0 @@ -Checks: > - *, - -*-non-private-member-variables-in-classes, - -*avoid-c-arrays, - -*magic-numbers, - -*uppercase-literal-suffix, - -android-cloexec-fopen, - -bugprone-macro-parentheses, - -bugprone-reserved-identifier, - -bugprone-suspicious-string-compare, - -cert-dcl37-c, - -cert-dcl51-cpp, - -cert-flp30-c, - -clang-analyzer-alpha.*, - -clang-analyzer-security.FloatLoopCounter, - -cppcoreguidelines-avoid-non-const-global-variables, - -cppcoreguidelines-macro-usage, - -cppcoreguidelines-pro-bounds-array-to-pointer-decay, - -cppcoreguidelines-pro-bounds-constant-array-index, - -cppcoreguidelines-pro-bounds-pointer-arithmetic, - -cppcoreguidelines-pro-type-reinterpret-cast, - -cppcoreguidelines-pro-type-static-cast-downcast, - -cppcoreguidelines-pro-type-vararg, - -fuchsia-default-arguments, - -fuchsia-default-arguments-calls, - -fuchsia-overloaded-operator, - -google-runtime-references, - -hicpp-multiway-paths-covered, - -hicpp-named-parameter, - -hicpp-no-array-decay, - -hicpp-signed-bitwise, - -hicpp-vararg, - -llvm-header-guard, - -llvmlibc-*, - -misc-misplaced-const, - -modernize-use-trailing-return-type, - -readability-implicit-bool-conversion, - -readability-named-parameter, -FormatStyle: file -HeaderFilterRegex: 'pugl/.*|test/.*|examples/.*' \ No newline at end of file diff --git a/subprojects/nk_pugl/pugl/examples/cube_view.h b/subprojects/nk_pugl/pugl/examples/cube_view.h deleted file mode 100644 index 71ae88d..0000000 --- a/subprojects/nk_pugl/pugl/examples/cube_view.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef EXAMPLES_CUBE_VIEW_H -#define EXAMPLES_CUBE_VIEW_H - -#define GL_SILENCE_DEPRECATION 1 - -#include "demo_utils.h" - -#include "pugl/gl.h" -#include "pugl/pugl.h" - -#include - -// clang-format off - -static const float cubeStripVertices[] = { - -1.0f, 1.0f, 1.0f, // Front top left - 1.0f, 1.0f, 1.0f, // Front top right - -1.0f, -1.0f, 1.0f, // Front bottom left - 1.0f, -1.0f, 1.0f, // Front bottom right - 1.0f, -1.0f, -1.0f, // Back bottom right - 1.0f, 1.0f, 1.0f, // Front top right - 1.0f, 1.0f, -1.0f, // Back top right - -1.0f, 1.0f, 1.0f, // Front top left - -1.0f, 1.0f, -1.0f, // Back top left - -1.0f, -1.0f, 1.0f, // Front bottom left - -1.0f, -1.0f, -1.0f, // Back bottom left - 1.0f, -1.0f, -1.0f, // Back bottom right - -1.0f, 1.0f, -1.0f, // Back top left - 1.0f, 1.0f, -1.0f // Back top right -}; - -static const float cubeFrontLineLoop[] = { - -1.0f, 1.0f, 1.0f, // Front top left - 1.0f, 1.0f, 1.0f, // Front top right - 1.0f, -1.0f, 1.0f, // Front bottom right - -1.0f, -1.0f, 1.0f, // Front bottom left -}; - -static const float cubeBackLineLoop[] = { - -1.0f, 1.0f, -1.0f, // Back top left - 1.0f, 1.0f, -1.0f, // Back top right - 1.0f, -1.0f, -1.0f, // Back bottom right - -1.0f, -1.0f, -1.0f, // Back bottom left -}; - -static const float cubeSideLines[] = { - -1.0f, 1.0f, 1.0f, // Front top left - -1.0f, 1.0f, -1.0f, // Back top left - - -1.0f, -1.0f, 1.0f, // Front bottom left - -1.0f, -1.0f, -1.0f, // Back bottom left - - 1.0f, 1.0f, 1.0f, // Front top right - 1.0f, 1.0f, -1.0f, // Back top right - - 1.0f, -1.0f, 1.0f, // Front bottom right - 1.0f, -1.0f, -1.0f, // Back bottom right -}; - -// clang-format on - -static inline void -reshapeCube(const float width, const float height) -{ - const float aspect = width / height; - - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - glClearColor(0.2f, 0.2f, 0.2f, 1.0f); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glViewport(0, 0, (int)width, (int)height); - - float projection[16]; - perspective(projection, 1.8f, aspect, 1.0f, 100.0f); - glLoadMatrixf(projection); -} - -static inline void -displayCube(PuglView* const view, - const float distance, - const float xAngle, - const float yAngle, - const bool entered) -{ - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glTranslatef(0.0f, 0.0f, distance * -1.0f); - glRotatef(xAngle, 0.0f, 1.0f, 0.0f); - glRotatef(yAngle, 1.0f, 0.0f, 0.0f); - - const float bg = entered ? 0.2f : 0.0f; - glClearColor(bg, bg, bg, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - if (puglHasFocus(view)) { - // Draw cube surfaces - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, cubeStripVertices); - glColorPointer(3, GL_FLOAT, 0, cubeStripVertices); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 14); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - - glColor3f(0.0f, 0.0f, 0.0f); - } else { - glColor3f(1.0f, 1.0f, 1.0f); - } - - // Draw cube wireframe - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, cubeFrontLineLoop); - glDrawArrays(GL_LINE_LOOP, 0, 4); - glVertexPointer(3, GL_FLOAT, 0, cubeBackLineLoop); - glDrawArrays(GL_LINE_LOOP, 0, 4); - glVertexPointer(3, GL_FLOAT, 0, cubeSideLines); - glDrawArrays(GL_LINES, 0, 8); - glDisableClientState(GL_VERTEX_ARRAY); -} - -#endif // EXAMPLES_CUBE_VIEW_H diff --git a/subprojects/nk_pugl/pugl/examples/demo_utils.h b/subprojects/nk_pugl/pugl/examples/demo_utils.h deleted file mode 100644 index 2dda756..0000000 --- a/subprojects/nk_pugl/pugl/examples/demo_utils.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - Copyright 2012-2019 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef EXAMPLES_DEMO_UTILS_H -#define EXAMPLES_DEMO_UTILS_H - -#include "pugl/pugl.h" - -#include -#include - -typedef struct { - double lastReportTime; -} PuglFpsPrinter; - -typedef float vec4[4]; -typedef vec4 mat4[4]; - -static inline void -mat4Identity(mat4 m) -{ - for (int c = 0; c < 4; ++c) { - for (int r = 0; r < 4; ++r) { - m[c][r] = c == r ? 1.0f : 0.0f; - } - } -} - -static inline void -mat4Translate(mat4 m, const float x, const float y, const float z) -{ - m[3][0] = x; - m[3][1] = y; - m[3][2] = z; -} - -static inline void -mat4Mul(mat4 m, mat4 a, mat4 b) -{ - for (int c = 0; c < 4; ++c) { - for (int r = 0; r < 4; ++r) { - m[c][r] = 0.0f; - for (int k = 0; k < 4; ++k) { - m[c][r] += a[k][r] * b[c][k]; - } - } - } -} - -static inline void -mat4Ortho(mat4 m, - const float l, - const float r, - const float b, - const float t, - const float n, - const float f) -{ - m[0][0] = 2.0f / (r - l); - m[0][1] = m[0][2] = m[0][3] = 0.0f; - - m[1][1] = 2.0f / (t - b); - m[1][0] = m[1][2] = m[1][3] = 0.0f; - - m[2][2] = -2.0f / (f - n); - m[2][0] = m[2][1] = m[2][3] = 0.0f; - - m[3][0] = -(r + l) / (r - l); - m[3][1] = -(t + b) / (t - b); - m[3][2] = -(f + n) / (f - n); - m[3][3] = 1.0f; -} - -/// Calculate a projection matrix for a given perspective -static inline void -perspective(float* m, float fov, float aspect, float zNear, float zFar) -{ - const float h = tanf(fov); - const float w = h / aspect; - const float depth = zNear - zFar; - const float q = (zFar + zNear) / depth; - const float qn = 2 * zFar * zNear / depth; - - // clang-format off - m[0] = w; m[1] = 0; m[2] = 0; m[3] = 0; - m[4] = 0; m[5] = h; m[6] = 0; m[7] = 0; - m[8] = 0; m[9] = 0; m[10] = q; m[11] = -1; - m[12] = 0; m[13] = 0; m[14] = qn; m[15] = 0; - // clang-format on -} - -static inline void -puglPrintFps(const PuglWorld* world, - PuglFpsPrinter* printer, - unsigned* const framesDrawn) -{ - const double thisTime = puglGetTime(world); - if (thisTime > printer->lastReportTime + 5) { - const double fps = *framesDrawn / (thisTime - printer->lastReportTime); - fprintf(stderr, - "FPS: %.2f (%u frames in %.0f seconds)\n", - fps, - *framesDrawn, - thisTime - printer->lastReportTime); - - printer->lastReportTime = thisTime; - *framesDrawn = 0; - } -} - -#endif // EXAMPLES_DEMO_UTILS_H diff --git a/subprojects/nk_pugl/pugl/examples/file_utils.c b/subprojects/nk_pugl/pugl/examples/file_utils.c deleted file mode 100644 index 8ecbca4..0000000 --- a/subprojects/nk_pugl/pugl/examples/file_utils.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - Copyright 2019-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#if !defined(__APPLE__) && !defined(_GNU_SOURCE) -# define _GNU_SOURCE -#endif - -#include "file_utils.h" - -#ifdef _WIN32 -# include -# include -# define F_OK 0 -#else -# include -# include -#endif - -#include -#include -#include - -char* -resourcePath(const char* const programPath, const char* const name) -{ - char* const binary = strdup(programPath); - -#ifdef _WIN32 - char programDir[_MAX_DIR]; - _splitpath(binary, programDir, NULL, NULL, NULL); - _splitpath(binary, NULL, programDir + strlen(programDir), NULL, NULL); - programDir[strlen(programDir) - 1] = '\0'; -#else - char* const programDir = dirname(binary); -#endif - - const size_t programDirLen = strlen(programDir); - const size_t nameLen = strlen(name); - const size_t totalLen = programDirLen + nameLen + 4; - - char* const programRelative = (char*)calloc(totalLen, 1); - snprintf(programRelative, totalLen, "%s/%s", programDir, name); - if (!access(programRelative, F_OK)) { - free(binary); - return programRelative; - } - - free(programRelative); - free(binary); - - const size_t sysPathLen = strlen(PUGL_DATA_DIR) + nameLen + 4; - char* const sysPath = (char*)calloc(sysPathLen, 1); - snprintf(sysPath, sysPathLen, "%s/%s", PUGL_DATA_DIR, name); - return sysPath; -} diff --git a/subprojects/nk_pugl/pugl/examples/file_utils.h b/subprojects/nk_pugl/pugl/examples/file_utils.h deleted file mode 100644 index 1530157..0000000 --- a/subprojects/nk_pugl/pugl/examples/file_utils.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - Copyright 2019-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef EXAMPLES_FILE_UTILS_H -#define EXAMPLES_FILE_UTILS_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - Return the path to a resource file. - - This takes a name like "shaders/something.glsl" and returns the actual - path that can be used to load that resource, which may be relative to the - current executable (for running in bundles or the build directory), or a - shared system directory for installs. - - The returned path must be freed with free(). -*/ -char* -resourcePath(const char* programPath, const char* name); - -#ifdef __cplusplus -} -#endif - -#endif // EXAMPLES_FILE_UTILS_H diff --git a/subprojects/nk_pugl/pugl/examples/glad/glad.c b/subprojects/nk_pugl/pugl/examples/glad/glad.c deleted file mode 100644 index 38f442c..0000000 --- a/subprojects/nk_pugl/pugl/examples/glad/glad.c +++ /dev/null @@ -1,1138 +0,0 @@ -/* - - OpenGL loader generated by glad 0.1.32 on -. - - Language/Generator: C/C++ - Specification: gl - APIs: gl=3.3 - Profile: core - Extensions: - - Loader: True - Local files: True - Omit khrplatform: False - Reproducible: True - - Commandline: - --profile="core" --api="gl=3.3" --generator="c" --spec="gl" --local-files --extensions="" - Online: - https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D3.3 -*/ - -#include -#include -#include -#include "glad.h" - -static void* get_proc(const char *namez); - -#if defined(_WIN32) || defined(__CYGWIN__) -#undef APIENTRY -#include -static HMODULE libGL; - -typedef void* (APIENTRYP PFNWGLGETPROCADDRESSPROC_PRIVATE)(const char*); -static PFNWGLGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr; - -#ifdef _MSC_VER -#ifdef __has_include - #if __has_include() - #define HAVE_WINAPIFAMILY 1 - #endif -#elif _MSC_VER >= 1700 && !_USING_V110_SDK71_ - #define HAVE_WINAPIFAMILY 1 -#endif -#endif - -#ifdef HAVE_WINAPIFAMILY - #include - #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) - #define IS_UWP 1 - #endif -#endif - -static -int open_gl(void) { -#ifndef IS_UWP - libGL = LoadLibraryW(L"opengl32.dll"); - if(libGL != NULL) { - void (* tmp)(void); - tmp = (void(*)(void)) GetProcAddress(libGL, "wglGetProcAddress"); - gladGetProcAddressPtr = (PFNWGLGETPROCADDRESSPROC_PRIVATE) tmp; - return gladGetProcAddressPtr != NULL; - } -#endif - - return 0; -} - -static -void close_gl(void) { - if(libGL != NULL) { - FreeLibrary((HMODULE) libGL); - libGL = NULL; - } -} -#else -#include -static void* libGL; - -#if !defined(__APPLE__) && !defined(__HAIKU__) -typedef void* (APIENTRYP PFNGLXGETPROCADDRESSPROC_PRIVATE)(const char*); -static PFNGLXGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr; -#endif - -static -int open_gl(void) { -#ifdef __APPLE__ - static const char *NAMES[] = { - "../Frameworks/OpenGL.framework/OpenGL", - "/Library/Frameworks/OpenGL.framework/OpenGL", - "/System/Library/Frameworks/OpenGL.framework/OpenGL", - "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL" - }; -#else - static const char *NAMES[] = {"libGL.so.1", "libGL.so"}; -#endif - - unsigned int index = 0; - for(index = 0; index < (sizeof(NAMES) / sizeof(NAMES[0])); index++) { - libGL = dlopen(NAMES[index], RTLD_NOW | RTLD_GLOBAL); - - if(libGL != NULL) { -#if defined(__APPLE__) || defined(__HAIKU__) - return 1; -#else - gladGetProcAddressPtr = (PFNGLXGETPROCADDRESSPROC_PRIVATE)dlsym(libGL, - "glXGetProcAddressARB"); - return gladGetProcAddressPtr != NULL; -#endif - } - } - - return 0; -} - -static -void close_gl(void) { - if(libGL != NULL) { - dlclose(libGL); - libGL = NULL; - } -} -#endif - -static -void* get_proc(const char *namez) { - void* result = NULL; - if(libGL == NULL) return NULL; - -#if !defined(__APPLE__) && !defined(__HAIKU__) - if(gladGetProcAddressPtr != NULL) { - result = gladGetProcAddressPtr(namez); - } -#endif - if(result == NULL) { -#if defined(_WIN32) || defined(__CYGWIN__) - result = (void*)GetProcAddress((HMODULE) libGL, namez); -#else - result = dlsym(libGL, namez); -#endif - } - - return result; -} - -int gladLoadGL(void) { - int status = 0; - - if(open_gl()) { - status = gladLoadGLLoader(&get_proc); - close_gl(); - } - - return status; -} - -struct gladGLversionStruct GLVersion = { 0, 0 }; - -#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0) -#define _GLAD_IS_SOME_NEW_VERSION 1 -#endif - -static int max_loaded_major; -static int max_loaded_minor; - -static const char *exts = NULL; -static int num_exts_i = 0; -static char **exts_i = NULL; - -static int get_exts(void) { -#ifdef _GLAD_IS_SOME_NEW_VERSION - if(max_loaded_major < 3) { -#endif - exts = (const char *)glGetString(GL_EXTENSIONS); -#ifdef _GLAD_IS_SOME_NEW_VERSION - } else { - unsigned int index; - - num_exts_i = 0; - glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i); - if (num_exts_i > 0) { - exts_i = (char **)malloc((size_t)num_exts_i * (sizeof *exts_i)); - } - - if (exts_i == NULL) { - return 0; - } - - for(index = 0; index < (unsigned)num_exts_i; index++) { - const char *gl_str_tmp = (const char*)glGetStringi(GL_EXTENSIONS, index); - size_t len = strlen(gl_str_tmp); - - char *local_str = (char*)malloc((len+1) * sizeof(char)); - if(local_str != NULL) { - memcpy(local_str, gl_str_tmp, (len+1) * sizeof(char)); - } - exts_i[index] = local_str; - } - } -#endif - return 1; -} - -static void free_exts(void) { - if (exts_i != NULL) { - int index; - for(index = 0; index < num_exts_i; index++) { - free((char *)exts_i[index]); - } - free((void *)exts_i); - exts_i = NULL; - } -} - -static int has_ext(const char *ext) { -#ifdef _GLAD_IS_SOME_NEW_VERSION - if(max_loaded_major < 3) { -#endif - const char *extensions; - const char *loc; - const char *terminator; - extensions = exts; - if(extensions == NULL || ext == NULL) { - return 0; - } - - while(1) { - loc = strstr(extensions, ext); - if(loc == NULL) { - return 0; - } - - terminator = loc + strlen(ext); - if((loc == extensions || *(loc - 1) == ' ') && - (*terminator == ' ' || *terminator == '\0')) { - return 1; - } - extensions = terminator; - } -#ifdef _GLAD_IS_SOME_NEW_VERSION - } else { - int index; - if(exts_i == NULL) return 0; - for(index = 0; index < num_exts_i; index++) { - const char *e = exts_i[index]; - - if(exts_i[index] != NULL && strcmp(e, ext) == 0) { - return 1; - } - } - } -#endif - - return 0; -} -int GLAD_GL_VERSION_1_0 = 0; -int GLAD_GL_VERSION_1_1 = 0; -int GLAD_GL_VERSION_1_2 = 0; -int GLAD_GL_VERSION_1_3 = 0; -int GLAD_GL_VERSION_1_4 = 0; -int GLAD_GL_VERSION_1_5 = 0; -int GLAD_GL_VERSION_2_0 = 0; -int GLAD_GL_VERSION_2_1 = 0; -int GLAD_GL_VERSION_3_0 = 0; -int GLAD_GL_VERSION_3_1 = 0; -int GLAD_GL_VERSION_3_2 = 0; -int GLAD_GL_VERSION_3_3 = 0; -PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL; -PFNGLATTACHSHADERPROC glad_glAttachShader = NULL; -PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender = NULL; -PFNGLBEGINQUERYPROC glad_glBeginQuery = NULL; -PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL; -PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL; -PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL; -PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL; -PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL; -PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation = NULL; -PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed = NULL; -PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL; -PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL; -PFNGLBINDSAMPLERPROC glad_glBindSampler = NULL; -PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL; -PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL; -PFNGLBLENDCOLORPROC glad_glBlendColor = NULL; -PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL; -PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL; -PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL; -PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL; -PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL; -PFNGLBUFFERDATAPROC glad_glBufferData = NULL; -PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL; -PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL; -PFNGLCLAMPCOLORPROC glad_glClampColor = NULL; -PFNGLCLEARPROC glad_glClear = NULL; -PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi = NULL; -PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv = NULL; -PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv = NULL; -PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL; -PFNGLCLEARCOLORPROC glad_glClearColor = NULL; -PFNGLCLEARDEPTHPROC glad_glClearDepth = NULL; -PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL; -PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL; -PFNGLCOLORMASKPROC glad_glColorMask = NULL; -PFNGLCOLORMASKIPROC glad_glColorMaski = NULL; -PFNGLCOLORP3UIPROC glad_glColorP3ui = NULL; -PFNGLCOLORP3UIVPROC glad_glColorP3uiv = NULL; -PFNGLCOLORP4UIPROC glad_glColorP4ui = NULL; -PFNGLCOLORP4UIVPROC glad_glColorP4uiv = NULL; -PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL; -PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D = NULL; -PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL; -PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL; -PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL; -PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL; -PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL; -PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData = NULL; -PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL; -PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL; -PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL; -PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL; -PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL; -PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL; -PFNGLCREATESHADERPROC glad_glCreateShader = NULL; -PFNGLCULLFACEPROC glad_glCullFace = NULL; -PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL; -PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL; -PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL; -PFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL; -PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL; -PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers = NULL; -PFNGLDELETESHADERPROC glad_glDeleteShader = NULL; -PFNGLDELETESYNCPROC glad_glDeleteSync = NULL; -PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL; -PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL; -PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL; -PFNGLDEPTHMASKPROC glad_glDepthMask = NULL; -PFNGLDEPTHRANGEPROC glad_glDepthRange = NULL; -PFNGLDETACHSHADERPROC glad_glDetachShader = NULL; -PFNGLDISABLEPROC glad_glDisable = NULL; -PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL; -PFNGLDISABLEIPROC glad_glDisablei = NULL; -PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL; -PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced = NULL; -PFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL; -PFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL; -PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL; -PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex = NULL; -PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced = NULL; -PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex = NULL; -PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL; -PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex = NULL; -PFNGLENABLEPROC glad_glEnable = NULL; -PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL; -PFNGLENABLEIPROC glad_glEnablei = NULL; -PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL; -PFNGLENDQUERYPROC glad_glEndQuery = NULL; -PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL; -PFNGLFENCESYNCPROC glad_glFenceSync = NULL; -PFNGLFINISHPROC glad_glFinish = NULL; -PFNGLFLUSHPROC glad_glFlush = NULL; -PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL; -PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL; -PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture = NULL; -PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D = NULL; -PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL; -PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D = NULL; -PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL; -PFNGLFRONTFACEPROC glad_glFrontFace = NULL; -PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL; -PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL; -PFNGLGENQUERIESPROC glad_glGenQueries = NULL; -PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL; -PFNGLGENSAMPLERSPROC glad_glGenSamplers = NULL; -PFNGLGENTEXTURESPROC glad_glGenTextures = NULL; -PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL; -PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL; -PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL; -PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL; -PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName = NULL; -PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv = NULL; -PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName = NULL; -PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv = NULL; -PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL; -PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL; -PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v = NULL; -PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL; -PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v = NULL; -PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL; -PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL; -PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL; -PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL; -PFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL; -PFNGLGETERRORPROC glad_glGetError = NULL; -PFNGLGETFLOATVPROC glad_glGetFloatv = NULL; -PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex = NULL; -PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL; -PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL; -PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v = NULL; -PFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL; -PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL; -PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL; -PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv = NULL; -PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL; -PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL; -PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v = NULL; -PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL; -PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v = NULL; -PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL; -PFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL; -PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL; -PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv = NULL; -PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv = NULL; -PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv = NULL; -PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv = NULL; -PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL; -PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL; -PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL; -PFNGLGETSTRINGPROC glad_glGetString = NULL; -PFNGLGETSTRINGIPROC glad_glGetStringi = NULL; -PFNGLGETSYNCIVPROC glad_glGetSynciv = NULL; -PFNGLGETTEXIMAGEPROC glad_glGetTexImage = NULL; -PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv = NULL; -PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv = NULL; -PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv = NULL; -PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv = NULL; -PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL; -PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL; -PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL; -PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex = NULL; -PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices = NULL; -PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL; -PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL; -PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL; -PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL; -PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL; -PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL; -PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL; -PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL; -PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL; -PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL; -PFNGLHINTPROC glad_glHint = NULL; -PFNGLISBUFFERPROC glad_glIsBuffer = NULL; -PFNGLISENABLEDPROC glad_glIsEnabled = NULL; -PFNGLISENABLEDIPROC glad_glIsEnabledi = NULL; -PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL; -PFNGLISPROGRAMPROC glad_glIsProgram = NULL; -PFNGLISQUERYPROC glad_glIsQuery = NULL; -PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL; -PFNGLISSAMPLERPROC glad_glIsSampler = NULL; -PFNGLISSHADERPROC glad_glIsShader = NULL; -PFNGLISSYNCPROC glad_glIsSync = NULL; -PFNGLISTEXTUREPROC glad_glIsTexture = NULL; -PFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL; -PFNGLLINEWIDTHPROC glad_glLineWidth = NULL; -PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL; -PFNGLLOGICOPPROC glad_glLogicOp = NULL; -PFNGLMAPBUFFERPROC glad_glMapBuffer = NULL; -PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL; -PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL; -PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL; -PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex = NULL; -PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui = NULL; -PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv = NULL; -PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui = NULL; -PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv = NULL; -PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui = NULL; -PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv = NULL; -PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui = NULL; -PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv = NULL; -PFNGLNORMALP3UIPROC glad_glNormalP3ui = NULL; -PFNGLNORMALP3UIVPROC glad_glNormalP3uiv = NULL; -PFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL; -PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL; -PFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL; -PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL; -PFNGLPOINTPARAMETERIPROC glad_glPointParameteri = NULL; -PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL; -PFNGLPOINTSIZEPROC glad_glPointSize = NULL; -PFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL; -PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL; -PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex = NULL; -PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex = NULL; -PFNGLQUERYCOUNTERPROC glad_glQueryCounter = NULL; -PFNGLREADBUFFERPROC glad_glReadBuffer = NULL; -PFNGLREADPIXELSPROC glad_glReadPixels = NULL; -PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL; -PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL; -PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL; -PFNGLSAMPLEMASKIPROC glad_glSampleMaski = NULL; -PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv = NULL; -PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv = NULL; -PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf = NULL; -PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv = NULL; -PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri = NULL; -PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv = NULL; -PFNGLSCISSORPROC glad_glScissor = NULL; -PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui = NULL; -PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv = NULL; -PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL; -PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL; -PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL; -PFNGLSTENCILMASKPROC glad_glStencilMask = NULL; -PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL; -PFNGLSTENCILOPPROC glad_glStencilOp = NULL; -PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL; -PFNGLTEXBUFFERPROC glad_glTexBuffer = NULL; -PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui = NULL; -PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv = NULL; -PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui = NULL; -PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv = NULL; -PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui = NULL; -PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv = NULL; -PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui = NULL; -PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv = NULL; -PFNGLTEXIMAGE1DPROC glad_glTexImage1D = NULL; -PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL; -PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample = NULL; -PFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL; -PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample = NULL; -PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv = NULL; -PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv = NULL; -PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL; -PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL; -PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL; -PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL; -PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL; -PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL; -PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL; -PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL; -PFNGLUNIFORM1FPROC glad_glUniform1f = NULL; -PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL; -PFNGLUNIFORM1IPROC glad_glUniform1i = NULL; -PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL; -PFNGLUNIFORM1UIPROC glad_glUniform1ui = NULL; -PFNGLUNIFORM1UIVPROC glad_glUniform1uiv = NULL; -PFNGLUNIFORM2FPROC glad_glUniform2f = NULL; -PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL; -PFNGLUNIFORM2IPROC glad_glUniform2i = NULL; -PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL; -PFNGLUNIFORM2UIPROC glad_glUniform2ui = NULL; -PFNGLUNIFORM2UIVPROC glad_glUniform2uiv = NULL; -PFNGLUNIFORM3FPROC glad_glUniform3f = NULL; -PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL; -PFNGLUNIFORM3IPROC glad_glUniform3i = NULL; -PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL; -PFNGLUNIFORM3UIPROC glad_glUniform3ui = NULL; -PFNGLUNIFORM3UIVPROC glad_glUniform3uiv = NULL; -PFNGLUNIFORM4FPROC glad_glUniform4f = NULL; -PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL; -PFNGLUNIFORM4IPROC glad_glUniform4i = NULL; -PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL; -PFNGLUNIFORM4UIPROC glad_glUniform4ui = NULL; -PFNGLUNIFORM4UIVPROC glad_glUniform4uiv = NULL; -PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding = NULL; -PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL; -PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL; -PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL; -PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL; -PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL; -PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL; -PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL; -PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL; -PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL; -PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL; -PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL; -PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL; -PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL; -PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL; -PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL; -PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL; -PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s = NULL; -PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv = NULL; -PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d = NULL; -PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv = NULL; -PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL; -PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL; -PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s = NULL; -PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv = NULL; -PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d = NULL; -PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv = NULL; -PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL; -PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL; -PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s = NULL; -PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv = NULL; -PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv = NULL; -PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv = NULL; -PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv = NULL; -PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub = NULL; -PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv = NULL; -PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv = NULL; -PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv = NULL; -PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv = NULL; -PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d = NULL; -PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv = NULL; -PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL; -PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL; -PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv = NULL; -PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s = NULL; -PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv = NULL; -PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv = NULL; -PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv = NULL; -PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv = NULL; -PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor = NULL; -PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i = NULL; -PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv = NULL; -PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui = NULL; -PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv = NULL; -PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i = NULL; -PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv = NULL; -PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui = NULL; -PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv = NULL; -PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i = NULL; -PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv = NULL; -PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui = NULL; -PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv = NULL; -PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv = NULL; -PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i = NULL; -PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv = NULL; -PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv = NULL; -PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv = NULL; -PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui = NULL; -PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv = NULL; -PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv = NULL; -PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL; -PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui = NULL; -PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv = NULL; -PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui = NULL; -PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv = NULL; -PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui = NULL; -PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv = NULL; -PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui = NULL; -PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv = NULL; -PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL; -PFNGLVERTEXP2UIPROC glad_glVertexP2ui = NULL; -PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv = NULL; -PFNGLVERTEXP3UIPROC glad_glVertexP3ui = NULL; -PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv = NULL; -PFNGLVERTEXP4UIPROC glad_glVertexP4ui = NULL; -PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv = NULL; -PFNGLVIEWPORTPROC glad_glViewport = NULL; -PFNGLWAITSYNCPROC glad_glWaitSync = NULL; -static void load_GL_VERSION_1_0(GLADloadproc load) { - if(!GLAD_GL_VERSION_1_0) return; - glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace"); - glad_glFrontFace = (PFNGLFRONTFACEPROC)load("glFrontFace"); - glad_glHint = (PFNGLHINTPROC)load("glHint"); - glad_glLineWidth = (PFNGLLINEWIDTHPROC)load("glLineWidth"); - glad_glPointSize = (PFNGLPOINTSIZEPROC)load("glPointSize"); - glad_glPolygonMode = (PFNGLPOLYGONMODEPROC)load("glPolygonMode"); - glad_glScissor = (PFNGLSCISSORPROC)load("glScissor"); - glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC)load("glTexParameterf"); - glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC)load("glTexParameterfv"); - glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC)load("glTexParameteri"); - glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC)load("glTexParameteriv"); - glad_glTexImage1D = (PFNGLTEXIMAGE1DPROC)load("glTexImage1D"); - glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC)load("glTexImage2D"); - glad_glDrawBuffer = (PFNGLDRAWBUFFERPROC)load("glDrawBuffer"); - glad_glClear = (PFNGLCLEARPROC)load("glClear"); - glad_glClearColor = (PFNGLCLEARCOLORPROC)load("glClearColor"); - glad_glClearStencil = (PFNGLCLEARSTENCILPROC)load("glClearStencil"); - glad_glClearDepth = (PFNGLCLEARDEPTHPROC)load("glClearDepth"); - glad_glStencilMask = (PFNGLSTENCILMASKPROC)load("glStencilMask"); - glad_glColorMask = (PFNGLCOLORMASKPROC)load("glColorMask"); - glad_glDepthMask = (PFNGLDEPTHMASKPROC)load("glDepthMask"); - glad_glDisable = (PFNGLDISABLEPROC)load("glDisable"); - glad_glEnable = (PFNGLENABLEPROC)load("glEnable"); - glad_glFinish = (PFNGLFINISHPROC)load("glFinish"); - glad_glFlush = (PFNGLFLUSHPROC)load("glFlush"); - glad_glBlendFunc = (PFNGLBLENDFUNCPROC)load("glBlendFunc"); - glad_glLogicOp = (PFNGLLOGICOPPROC)load("glLogicOp"); - glad_glStencilFunc = (PFNGLSTENCILFUNCPROC)load("glStencilFunc"); - glad_glStencilOp = (PFNGLSTENCILOPPROC)load("glStencilOp"); - glad_glDepthFunc = (PFNGLDEPTHFUNCPROC)load("glDepthFunc"); - glad_glPixelStoref = (PFNGLPIXELSTOREFPROC)load("glPixelStoref"); - glad_glPixelStorei = (PFNGLPIXELSTOREIPROC)load("glPixelStorei"); - glad_glReadBuffer = (PFNGLREADBUFFERPROC)load("glReadBuffer"); - glad_glReadPixels = (PFNGLREADPIXELSPROC)load("glReadPixels"); - glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC)load("glGetBooleanv"); - glad_glGetDoublev = (PFNGLGETDOUBLEVPROC)load("glGetDoublev"); - glad_glGetError = (PFNGLGETERRORPROC)load("glGetError"); - glad_glGetFloatv = (PFNGLGETFLOATVPROC)load("glGetFloatv"); - glad_glGetIntegerv = (PFNGLGETINTEGERVPROC)load("glGetIntegerv"); - glad_glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); - glad_glGetTexImage = (PFNGLGETTEXIMAGEPROC)load("glGetTexImage"); - glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)load("glGetTexParameterfv"); - glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)load("glGetTexParameteriv"); - glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC)load("glGetTexLevelParameterfv"); - glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC)load("glGetTexLevelParameteriv"); - glad_glIsEnabled = (PFNGLISENABLEDPROC)load("glIsEnabled"); - glad_glDepthRange = (PFNGLDEPTHRANGEPROC)load("glDepthRange"); - glad_glViewport = (PFNGLVIEWPORTPROC)load("glViewport"); -} -static void load_GL_VERSION_1_1(GLADloadproc load) { - if(!GLAD_GL_VERSION_1_1) return; - glad_glDrawArrays = (PFNGLDRAWARRAYSPROC)load("glDrawArrays"); - glad_glDrawElements = (PFNGLDRAWELEMENTSPROC)load("glDrawElements"); - glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)load("glPolygonOffset"); - glad_glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC)load("glCopyTexImage1D"); - glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)load("glCopyTexImage2D"); - glad_glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC)load("glCopyTexSubImage1D"); - glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)load("glCopyTexSubImage2D"); - glad_glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC)load("glTexSubImage1D"); - glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)load("glTexSubImage2D"); - glad_glBindTexture = (PFNGLBINDTEXTUREPROC)load("glBindTexture"); - glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC)load("glDeleteTextures"); - glad_glGenTextures = (PFNGLGENTEXTURESPROC)load("glGenTextures"); - glad_glIsTexture = (PFNGLISTEXTUREPROC)load("glIsTexture"); -} -static void load_GL_VERSION_1_2(GLADloadproc load) { - if(!GLAD_GL_VERSION_1_2) return; - glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)load("glDrawRangeElements"); - glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC)load("glTexImage3D"); - glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)load("glTexSubImage3D"); - glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)load("glCopyTexSubImage3D"); -} -static void load_GL_VERSION_1_3(GLADloadproc load) { - if(!GLAD_GL_VERSION_1_3) return; - glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC)load("glActiveTexture"); - glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)load("glSampleCoverage"); - glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)load("glCompressedTexImage3D"); - glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)load("glCompressedTexImage2D"); - glad_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)load("glCompressedTexImage1D"); - glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)load("glCompressedTexSubImage3D"); - glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)load("glCompressedTexSubImage2D"); - glad_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)load("glCompressedTexSubImage1D"); - glad_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)load("glGetCompressedTexImage"); -} -static void load_GL_VERSION_1_4(GLADloadproc load) { - if(!GLAD_GL_VERSION_1_4) return; - glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)load("glBlendFuncSeparate"); - glad_glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC)load("glMultiDrawArrays"); - glad_glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC)load("glMultiDrawElements"); - glad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC)load("glPointParameterf"); - glad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)load("glPointParameterfv"); - glad_glPointParameteri = (PFNGLPOINTPARAMETERIPROC)load("glPointParameteri"); - glad_glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC)load("glPointParameteriv"); - glad_glBlendColor = (PFNGLBLENDCOLORPROC)load("glBlendColor"); - glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC)load("glBlendEquation"); -} -static void load_GL_VERSION_1_5(GLADloadproc load) { - if(!GLAD_GL_VERSION_1_5) return; - glad_glGenQueries = (PFNGLGENQUERIESPROC)load("glGenQueries"); - glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC)load("glDeleteQueries"); - glad_glIsQuery = (PFNGLISQUERYPROC)load("glIsQuery"); - glad_glBeginQuery = (PFNGLBEGINQUERYPROC)load("glBeginQuery"); - glad_glEndQuery = (PFNGLENDQUERYPROC)load("glEndQuery"); - glad_glGetQueryiv = (PFNGLGETQUERYIVPROC)load("glGetQueryiv"); - glad_glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC)load("glGetQueryObjectiv"); - glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)load("glGetQueryObjectuiv"); - glad_glBindBuffer = (PFNGLBINDBUFFERPROC)load("glBindBuffer"); - glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)load("glDeleteBuffers"); - glad_glGenBuffers = (PFNGLGENBUFFERSPROC)load("glGenBuffers"); - glad_glIsBuffer = (PFNGLISBUFFERPROC)load("glIsBuffer"); - glad_glBufferData = (PFNGLBUFFERDATAPROC)load("glBufferData"); - glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)load("glBufferSubData"); - glad_glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC)load("glGetBufferSubData"); - glad_glMapBuffer = (PFNGLMAPBUFFERPROC)load("glMapBuffer"); - glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC)load("glUnmapBuffer"); - glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv"); - glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)load("glGetBufferPointerv"); -} -static void load_GL_VERSION_2_0(GLADloadproc load) { - if(!GLAD_GL_VERSION_2_0) return; - glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)load("glBlendEquationSeparate"); - glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC)load("glDrawBuffers"); - glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)load("glStencilOpSeparate"); - glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)load("glStencilFuncSeparate"); - glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC)load("glStencilMaskSeparate"); - glad_glAttachShader = (PFNGLATTACHSHADERPROC)load("glAttachShader"); - glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)load("glBindAttribLocation"); - glad_glCompileShader = (PFNGLCOMPILESHADERPROC)load("glCompileShader"); - glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC)load("glCreateProgram"); - glad_glCreateShader = (PFNGLCREATESHADERPROC)load("glCreateShader"); - glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC)load("glDeleteProgram"); - glad_glDeleteShader = (PFNGLDELETESHADERPROC)load("glDeleteShader"); - glad_glDetachShader = (PFNGLDETACHSHADERPROC)load("glDetachShader"); - glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)load("glDisableVertexAttribArray"); - glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)load("glEnableVertexAttribArray"); - glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)load("glGetActiveAttrib"); - glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)load("glGetActiveUniform"); - glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)load("glGetAttachedShaders"); - glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)load("glGetAttribLocation"); - glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC)load("glGetProgramiv"); - glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)load("glGetProgramInfoLog"); - glad_glGetShaderiv = (PFNGLGETSHADERIVPROC)load("glGetShaderiv"); - glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)load("glGetShaderInfoLog"); - glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC)load("glGetShaderSource"); - glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)load("glGetUniformLocation"); - glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC)load("glGetUniformfv"); - glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC)load("glGetUniformiv"); - glad_glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC)load("glGetVertexAttribdv"); - glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)load("glGetVertexAttribfv"); - glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)load("glGetVertexAttribiv"); - glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)load("glGetVertexAttribPointerv"); - glad_glIsProgram = (PFNGLISPROGRAMPROC)load("glIsProgram"); - glad_glIsShader = (PFNGLISSHADERPROC)load("glIsShader"); - glad_glLinkProgram = (PFNGLLINKPROGRAMPROC)load("glLinkProgram"); - glad_glShaderSource = (PFNGLSHADERSOURCEPROC)load("glShaderSource"); - glad_glUseProgram = (PFNGLUSEPROGRAMPROC)load("glUseProgram"); - glad_glUniform1f = (PFNGLUNIFORM1FPROC)load("glUniform1f"); - glad_glUniform2f = (PFNGLUNIFORM2FPROC)load("glUniform2f"); - glad_glUniform3f = (PFNGLUNIFORM3FPROC)load("glUniform3f"); - glad_glUniform4f = (PFNGLUNIFORM4FPROC)load("glUniform4f"); - glad_glUniform1i = (PFNGLUNIFORM1IPROC)load("glUniform1i"); - glad_glUniform2i = (PFNGLUNIFORM2IPROC)load("glUniform2i"); - glad_glUniform3i = (PFNGLUNIFORM3IPROC)load("glUniform3i"); - glad_glUniform4i = (PFNGLUNIFORM4IPROC)load("glUniform4i"); - glad_glUniform1fv = (PFNGLUNIFORM1FVPROC)load("glUniform1fv"); - glad_glUniform2fv = (PFNGLUNIFORM2FVPROC)load("glUniform2fv"); - glad_glUniform3fv = (PFNGLUNIFORM3FVPROC)load("glUniform3fv"); - glad_glUniform4fv = (PFNGLUNIFORM4FVPROC)load("glUniform4fv"); - glad_glUniform1iv = (PFNGLUNIFORM1IVPROC)load("glUniform1iv"); - glad_glUniform2iv = (PFNGLUNIFORM2IVPROC)load("glUniform2iv"); - glad_glUniform3iv = (PFNGLUNIFORM3IVPROC)load("glUniform3iv"); - glad_glUniform4iv = (PFNGLUNIFORM4IVPROC)load("glUniform4iv"); - glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)load("glUniformMatrix2fv"); - glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)load("glUniformMatrix3fv"); - glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)load("glUniformMatrix4fv"); - glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)load("glValidateProgram"); - glad_glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC)load("glVertexAttrib1d"); - glad_glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC)load("glVertexAttrib1dv"); - glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)load("glVertexAttrib1f"); - glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)load("glVertexAttrib1fv"); - glad_glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC)load("glVertexAttrib1s"); - glad_glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC)load("glVertexAttrib1sv"); - glad_glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC)load("glVertexAttrib2d"); - glad_glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC)load("glVertexAttrib2dv"); - glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC)load("glVertexAttrib2f"); - glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)load("glVertexAttrib2fv"); - glad_glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC)load("glVertexAttrib2s"); - glad_glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC)load("glVertexAttrib2sv"); - glad_glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC)load("glVertexAttrib3d"); - glad_glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC)load("glVertexAttrib3dv"); - glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC)load("glVertexAttrib3f"); - glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)load("glVertexAttrib3fv"); - glad_glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC)load("glVertexAttrib3s"); - glad_glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC)load("glVertexAttrib3sv"); - glad_glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC)load("glVertexAttrib4Nbv"); - glad_glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC)load("glVertexAttrib4Niv"); - glad_glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC)load("glVertexAttrib4Nsv"); - glad_glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC)load("glVertexAttrib4Nub"); - glad_glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC)load("glVertexAttrib4Nubv"); - glad_glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC)load("glVertexAttrib4Nuiv"); - glad_glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC)load("glVertexAttrib4Nusv"); - glad_glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC)load("glVertexAttrib4bv"); - glad_glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC)load("glVertexAttrib4d"); - glad_glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC)load("glVertexAttrib4dv"); - glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)load("glVertexAttrib4f"); - glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)load("glVertexAttrib4fv"); - glad_glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC)load("glVertexAttrib4iv"); - glad_glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC)load("glVertexAttrib4s"); - glad_glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC)load("glVertexAttrib4sv"); - glad_glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC)load("glVertexAttrib4ubv"); - glad_glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC)load("glVertexAttrib4uiv"); - glad_glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC)load("glVertexAttrib4usv"); - glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)load("glVertexAttribPointer"); -} -static void load_GL_VERSION_2_1(GLADloadproc load) { - if(!GLAD_GL_VERSION_2_1) return; - glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC)load("glUniformMatrix2x3fv"); - glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC)load("glUniformMatrix3x2fv"); - glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC)load("glUniformMatrix2x4fv"); - glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC)load("glUniformMatrix4x2fv"); - glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC)load("glUniformMatrix3x4fv"); - glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC)load("glUniformMatrix4x3fv"); -} -static void load_GL_VERSION_3_0(GLADloadproc load) { - if(!GLAD_GL_VERSION_3_0) return; - glad_glColorMaski = (PFNGLCOLORMASKIPROC)load("glColorMaski"); - glad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC)load("glGetBooleani_v"); - glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); - glad_glEnablei = (PFNGLENABLEIPROC)load("glEnablei"); - glad_glDisablei = (PFNGLDISABLEIPROC)load("glDisablei"); - glad_glIsEnabledi = (PFNGLISENABLEDIPROC)load("glIsEnabledi"); - glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC)load("glBeginTransformFeedback"); - glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC)load("glEndTransformFeedback"); - glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); - glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); - glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC)load("glTransformFeedbackVaryings"); - glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)load("glGetTransformFeedbackVarying"); - glad_glClampColor = (PFNGLCLAMPCOLORPROC)load("glClampColor"); - glad_glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC)load("glBeginConditionalRender"); - glad_glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC)load("glEndConditionalRender"); - glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)load("glVertexAttribIPointer"); - glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC)load("glGetVertexAttribIiv"); - glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC)load("glGetVertexAttribIuiv"); - glad_glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC)load("glVertexAttribI1i"); - glad_glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC)load("glVertexAttribI2i"); - glad_glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC)load("glVertexAttribI3i"); - glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC)load("glVertexAttribI4i"); - glad_glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC)load("glVertexAttribI1ui"); - glad_glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC)load("glVertexAttribI2ui"); - glad_glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC)load("glVertexAttribI3ui"); - glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC)load("glVertexAttribI4ui"); - glad_glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC)load("glVertexAttribI1iv"); - glad_glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC)load("glVertexAttribI2iv"); - glad_glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC)load("glVertexAttribI3iv"); - glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC)load("glVertexAttribI4iv"); - glad_glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC)load("glVertexAttribI1uiv"); - glad_glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC)load("glVertexAttribI2uiv"); - glad_glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC)load("glVertexAttribI3uiv"); - glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC)load("glVertexAttribI4uiv"); - glad_glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC)load("glVertexAttribI4bv"); - glad_glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC)load("glVertexAttribI4sv"); - glad_glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC)load("glVertexAttribI4ubv"); - glad_glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC)load("glVertexAttribI4usv"); - glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC)load("glGetUniformuiv"); - glad_glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC)load("glBindFragDataLocation"); - glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC)load("glGetFragDataLocation"); - glad_glUniform1ui = (PFNGLUNIFORM1UIPROC)load("glUniform1ui"); - glad_glUniform2ui = (PFNGLUNIFORM2UIPROC)load("glUniform2ui"); - glad_glUniform3ui = (PFNGLUNIFORM3UIPROC)load("glUniform3ui"); - glad_glUniform4ui = (PFNGLUNIFORM4UIPROC)load("glUniform4ui"); - glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC)load("glUniform1uiv"); - glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC)load("glUniform2uiv"); - glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC)load("glUniform3uiv"); - glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC)load("glUniform4uiv"); - glad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC)load("glTexParameterIiv"); - glad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC)load("glTexParameterIuiv"); - glad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC)load("glGetTexParameterIiv"); - glad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC)load("glGetTexParameterIuiv"); - glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC)load("glClearBufferiv"); - glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC)load("glClearBufferuiv"); - glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)load("glClearBufferfv"); - glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC)load("glClearBufferfi"); - glad_glGetStringi = (PFNGLGETSTRINGIPROC)load("glGetStringi"); - glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer"); - glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load("glBindRenderbuffer"); - glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load("glDeleteRenderbuffers"); - glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load("glGenRenderbuffers"); - glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load("glRenderbufferStorage"); - glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load("glGetRenderbufferParameteriv"); - glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load("glIsFramebuffer"); - glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load("glBindFramebuffer"); - glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load("glDeleteFramebuffers"); - glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load("glGenFramebuffers"); - glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load("glCheckFramebufferStatus"); - glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)load("glFramebufferTexture1D"); - glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load("glFramebufferTexture2D"); - glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)load("glFramebufferTexture3D"); - glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load("glFramebufferRenderbuffer"); - glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetFramebufferAttachmentParameteriv"); - glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load("glGenerateMipmap"); - glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)load("glBlitFramebuffer"); - glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glRenderbufferStorageMultisample"); - glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)load("glFramebufferTextureLayer"); - glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC)load("glMapBufferRange"); - glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC)load("glFlushMappedBufferRange"); - glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)load("glBindVertexArray"); - glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)load("glDeleteVertexArrays"); - glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)load("glGenVertexArrays"); - glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC)load("glIsVertexArray"); -} -static void load_GL_VERSION_3_1(GLADloadproc load) { - if(!GLAD_GL_VERSION_3_1) return; - glad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)load("glDrawArraysInstanced"); - glad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)load("glDrawElementsInstanced"); - glad_glTexBuffer = (PFNGLTEXBUFFERPROC)load("glTexBuffer"); - glad_glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC)load("glPrimitiveRestartIndex"); - glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC)load("glCopyBufferSubData"); - glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)load("glGetUniformIndices"); - glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)load("glGetActiveUniformsiv"); - glad_glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC)load("glGetActiveUniformName"); - glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)load("glGetUniformBlockIndex"); - glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)load("glGetActiveUniformBlockiv"); - glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)load("glGetActiveUniformBlockName"); - glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)load("glUniformBlockBinding"); - glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); - glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); - glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); -} -static void load_GL_VERSION_3_2(GLADloadproc load) { - if(!GLAD_GL_VERSION_3_2) return; - glad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC)load("glDrawElementsBaseVertex"); - glad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)load("glDrawRangeElementsBaseVertex"); - glad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)load("glDrawElementsInstancedBaseVertex"); - glad_glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)load("glMultiDrawElementsBaseVertex"); - glad_glProvokingVertex = (PFNGLPROVOKINGVERTEXPROC)load("glProvokingVertex"); - glad_glFenceSync = (PFNGLFENCESYNCPROC)load("glFenceSync"); - glad_glIsSync = (PFNGLISSYNCPROC)load("glIsSync"); - glad_glDeleteSync = (PFNGLDELETESYNCPROC)load("glDeleteSync"); - glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC)load("glClientWaitSync"); - glad_glWaitSync = (PFNGLWAITSYNCPROC)load("glWaitSync"); - glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC)load("glGetInteger64v"); - glad_glGetSynciv = (PFNGLGETSYNCIVPROC)load("glGetSynciv"); - glad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC)load("glGetInteger64i_v"); - glad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC)load("glGetBufferParameteri64v"); - glad_glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)load("glFramebufferTexture"); - glad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)load("glTexImage2DMultisample"); - glad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC)load("glTexImage3DMultisample"); - glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC)load("glGetMultisamplefv"); - glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC)load("glSampleMaski"); -} -static void load_GL_VERSION_3_3(GLADloadproc load) { - if(!GLAD_GL_VERSION_3_3) return; - glad_glBindFragDataLocationIndexed = (PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)load("glBindFragDataLocationIndexed"); - glad_glGetFragDataIndex = (PFNGLGETFRAGDATAINDEXPROC)load("glGetFragDataIndex"); - glad_glGenSamplers = (PFNGLGENSAMPLERSPROC)load("glGenSamplers"); - glad_glDeleteSamplers = (PFNGLDELETESAMPLERSPROC)load("glDeleteSamplers"); - glad_glIsSampler = (PFNGLISSAMPLERPROC)load("glIsSampler"); - glad_glBindSampler = (PFNGLBINDSAMPLERPROC)load("glBindSampler"); - glad_glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC)load("glSamplerParameteri"); - glad_glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC)load("glSamplerParameteriv"); - glad_glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC)load("glSamplerParameterf"); - glad_glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC)load("glSamplerParameterfv"); - glad_glSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC)load("glSamplerParameterIiv"); - glad_glSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC)load("glSamplerParameterIuiv"); - glad_glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC)load("glGetSamplerParameteriv"); - glad_glGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC)load("glGetSamplerParameterIiv"); - glad_glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC)load("glGetSamplerParameterfv"); - glad_glGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC)load("glGetSamplerParameterIuiv"); - glad_glQueryCounter = (PFNGLQUERYCOUNTERPROC)load("glQueryCounter"); - glad_glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC)load("glGetQueryObjecti64v"); - glad_glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC)load("glGetQueryObjectui64v"); - glad_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)load("glVertexAttribDivisor"); - glad_glVertexAttribP1ui = (PFNGLVERTEXATTRIBP1UIPROC)load("glVertexAttribP1ui"); - glad_glVertexAttribP1uiv = (PFNGLVERTEXATTRIBP1UIVPROC)load("glVertexAttribP1uiv"); - glad_glVertexAttribP2ui = (PFNGLVERTEXATTRIBP2UIPROC)load("glVertexAttribP2ui"); - glad_glVertexAttribP2uiv = (PFNGLVERTEXATTRIBP2UIVPROC)load("glVertexAttribP2uiv"); - glad_glVertexAttribP3ui = (PFNGLVERTEXATTRIBP3UIPROC)load("glVertexAttribP3ui"); - glad_glVertexAttribP3uiv = (PFNGLVERTEXATTRIBP3UIVPROC)load("glVertexAttribP3uiv"); - glad_glVertexAttribP4ui = (PFNGLVERTEXATTRIBP4UIPROC)load("glVertexAttribP4ui"); - glad_glVertexAttribP4uiv = (PFNGLVERTEXATTRIBP4UIVPROC)load("glVertexAttribP4uiv"); - glad_glVertexP2ui = (PFNGLVERTEXP2UIPROC)load("glVertexP2ui"); - glad_glVertexP2uiv = (PFNGLVERTEXP2UIVPROC)load("glVertexP2uiv"); - glad_glVertexP3ui = (PFNGLVERTEXP3UIPROC)load("glVertexP3ui"); - glad_glVertexP3uiv = (PFNGLVERTEXP3UIVPROC)load("glVertexP3uiv"); - glad_glVertexP4ui = (PFNGLVERTEXP4UIPROC)load("glVertexP4ui"); - glad_glVertexP4uiv = (PFNGLVERTEXP4UIVPROC)load("glVertexP4uiv"); - glad_glTexCoordP1ui = (PFNGLTEXCOORDP1UIPROC)load("glTexCoordP1ui"); - glad_glTexCoordP1uiv = (PFNGLTEXCOORDP1UIVPROC)load("glTexCoordP1uiv"); - glad_glTexCoordP2ui = (PFNGLTEXCOORDP2UIPROC)load("glTexCoordP2ui"); - glad_glTexCoordP2uiv = (PFNGLTEXCOORDP2UIVPROC)load("glTexCoordP2uiv"); - glad_glTexCoordP3ui = (PFNGLTEXCOORDP3UIPROC)load("glTexCoordP3ui"); - glad_glTexCoordP3uiv = (PFNGLTEXCOORDP3UIVPROC)load("glTexCoordP3uiv"); - glad_glTexCoordP4ui = (PFNGLTEXCOORDP4UIPROC)load("glTexCoordP4ui"); - glad_glTexCoordP4uiv = (PFNGLTEXCOORDP4UIVPROC)load("glTexCoordP4uiv"); - glad_glMultiTexCoordP1ui = (PFNGLMULTITEXCOORDP1UIPROC)load("glMultiTexCoordP1ui"); - glad_glMultiTexCoordP1uiv = (PFNGLMULTITEXCOORDP1UIVPROC)load("glMultiTexCoordP1uiv"); - glad_glMultiTexCoordP2ui = (PFNGLMULTITEXCOORDP2UIPROC)load("glMultiTexCoordP2ui"); - glad_glMultiTexCoordP2uiv = (PFNGLMULTITEXCOORDP2UIVPROC)load("glMultiTexCoordP2uiv"); - glad_glMultiTexCoordP3ui = (PFNGLMULTITEXCOORDP3UIPROC)load("glMultiTexCoordP3ui"); - glad_glMultiTexCoordP3uiv = (PFNGLMULTITEXCOORDP3UIVPROC)load("glMultiTexCoordP3uiv"); - glad_glMultiTexCoordP4ui = (PFNGLMULTITEXCOORDP4UIPROC)load("glMultiTexCoordP4ui"); - glad_glMultiTexCoordP4uiv = (PFNGLMULTITEXCOORDP4UIVPROC)load("glMultiTexCoordP4uiv"); - glad_glNormalP3ui = (PFNGLNORMALP3UIPROC)load("glNormalP3ui"); - glad_glNormalP3uiv = (PFNGLNORMALP3UIVPROC)load("glNormalP3uiv"); - glad_glColorP3ui = (PFNGLCOLORP3UIPROC)load("glColorP3ui"); - glad_glColorP3uiv = (PFNGLCOLORP3UIVPROC)load("glColorP3uiv"); - glad_glColorP4ui = (PFNGLCOLORP4UIPROC)load("glColorP4ui"); - glad_glColorP4uiv = (PFNGLCOLORP4UIVPROC)load("glColorP4uiv"); - glad_glSecondaryColorP3ui = (PFNGLSECONDARYCOLORP3UIPROC)load("glSecondaryColorP3ui"); - glad_glSecondaryColorP3uiv = (PFNGLSECONDARYCOLORP3UIVPROC)load("glSecondaryColorP3uiv"); -} -static int find_extensionsGL(void) { - if (!get_exts()) return 0; - (void)&has_ext; - free_exts(); - return 1; -} - -static void find_coreGL(void) { - - /* Thank you @elmindreda - * https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176 - * https://github.com/glfw/glfw/blob/master/src/context.c#L36 - */ - int i, major, minor; - - const char* version; - const char* prefixes[] = { - "OpenGL ES-CM ", - "OpenGL ES-CL ", - "OpenGL ES ", - NULL - }; - - version = (const char*) glGetString(GL_VERSION); - if (!version) return; - - for (i = 0; prefixes[i]; i++) { - const size_t length = strlen(prefixes[i]); - if (strncmp(version, prefixes[i], length) == 0) { - version += length; - break; - } - } - -/* PR #18 */ -#ifdef _MSC_VER - sscanf_s(version, "%d.%d", &major, &minor); -#else - sscanf(version, "%d.%d", &major, &minor); -#endif - - GLVersion.major = major; GLVersion.minor = minor; - max_loaded_major = major; max_loaded_minor = minor; - GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; - GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; - GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1; - GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1; - GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1; - GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1; - GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; - GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2; - GLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3; - GLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3; - GLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3; - GLAD_GL_VERSION_3_3 = (major == 3 && minor >= 3) || major > 3; - if (GLVersion.major > 3 || (GLVersion.major >= 3 && GLVersion.minor >= 3)) { - max_loaded_major = 3; - max_loaded_minor = 3; - } -} - -int gladLoadGLLoader(GLADloadproc load) { - GLVersion.major = 0; GLVersion.minor = 0; - glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); - if(glGetString == NULL) return 0; - if(glGetString(GL_VERSION) == NULL) return 0; - find_coreGL(); - load_GL_VERSION_1_0(load); - load_GL_VERSION_1_1(load); - load_GL_VERSION_1_2(load); - load_GL_VERSION_1_3(load); - load_GL_VERSION_1_4(load); - load_GL_VERSION_1_5(load); - load_GL_VERSION_2_0(load); - load_GL_VERSION_2_1(load); - load_GL_VERSION_3_0(load); - load_GL_VERSION_3_1(load); - load_GL_VERSION_3_2(load); - load_GL_VERSION_3_3(load); - - if (!find_extensionsGL()) return 0; - return GLVersion.major != 0 || GLVersion.minor != 0; -} - diff --git a/subprojects/nk_pugl/pugl/examples/glad/glad.h b/subprojects/nk_pugl/pugl/examples/glad/glad.h deleted file mode 100644 index 9efb229..0000000 --- a/subprojects/nk_pugl/pugl/examples/glad/glad.h +++ /dev/null @@ -1,2127 +0,0 @@ -/* - - OpenGL loader generated by glad 0.1.32 on -. - - Language/Generator: C/C++ - Specification: gl - APIs: gl=3.3 - Profile: core - Extensions: - - Loader: True - Local files: True - Omit khrplatform: False - Reproducible: True - - Commandline: - --profile="core" --api="gl=3.3" --generator="c" --spec="gl" --local-files --extensions="" - Online: - https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D3.3 -*/ - - -#ifndef __glad_h_ -#define __glad_h_ - -#ifdef __gl_h_ -#error OpenGL header already included, remove this include, glad already provides it -#endif -#define __gl_h_ - -#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) -#define APIENTRY __stdcall -#endif - -#ifndef APIENTRY -#define APIENTRY -#endif -#ifndef APIENTRYP -#define APIENTRYP APIENTRY * -#endif - -#ifndef GLAPIENTRY -#define GLAPIENTRY APIENTRY -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -struct gladGLversionStruct { - int major; - int minor; -}; - -typedef void* (* GLADloadproc)(const char *name); - -#ifndef GLAPI -# if defined(GLAD_GLAPI_EXPORT) -# if defined(_WIN32) || defined(__CYGWIN__) -# if defined(GLAD_GLAPI_EXPORT_BUILD) -# if defined(__GNUC__) -# define GLAPI __attribute__ ((dllexport)) extern -# else -# define GLAPI __declspec(dllexport) extern -# endif -# else -# if defined(__GNUC__) -# define GLAPI __attribute__ ((dllimport)) extern -# else -# define GLAPI __declspec(dllimport) extern -# endif -# endif -# elif defined(__GNUC__) && defined(GLAD_GLAPI_EXPORT_BUILD) -# define GLAPI __attribute__ ((visibility ("default"))) extern -# else -# define GLAPI extern -# endif -# else -# define GLAPI extern -# endif -#endif - -GLAPI struct gladGLversionStruct GLVersion; - -GLAPI int gladLoadGL(void); - -GLAPI int gladLoadGLLoader(GLADloadproc); - -#include "khrplatform.h" -typedef unsigned int GLenum; -typedef unsigned char GLboolean; -typedef unsigned int GLbitfield; -typedef void GLvoid; -typedef khronos_int8_t GLbyte; -typedef khronos_uint8_t GLubyte; -typedef khronos_int16_t GLshort; -typedef khronos_uint16_t GLushort; -typedef int GLint; -typedef unsigned int GLuint; -typedef khronos_int32_t GLclampx; -typedef int GLsizei; -typedef khronos_float_t GLfloat; -typedef khronos_float_t GLclampf; -typedef double GLdouble; -typedef double GLclampd; -typedef void *GLeglClientBufferEXT; -typedef void *GLeglImageOES; -typedef char GLchar; -typedef char GLcharARB; -#ifdef __APPLE__ -typedef void *GLhandleARB; -#else -typedef unsigned int GLhandleARB; -#endif -typedef khronos_uint16_t GLhalf; -typedef khronos_uint16_t GLhalfARB; -typedef khronos_int32_t GLfixed; -typedef khronos_intptr_t GLintptr; -typedef khronos_intptr_t GLintptrARB; -typedef khronos_ssize_t GLsizeiptr; -typedef khronos_ssize_t GLsizeiptrARB; -typedef khronos_int64_t GLint64; -typedef khronos_int64_t GLint64EXT; -typedef khronos_uint64_t GLuint64; -typedef khronos_uint64_t GLuint64EXT; -typedef struct __GLsync *GLsync; -typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); -typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); -typedef void (APIENTRY *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); -typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); -typedef unsigned short GLhalfNV; -typedef GLintptr GLvdpauSurfaceNV; -typedef void (APIENTRY *GLVULKANPROCNV)(void); -#define GL_DEPTH_BUFFER_BIT 0x00000100 -#define GL_STENCIL_BUFFER_BIT 0x00000400 -#define GL_COLOR_BUFFER_BIT 0x00004000 -#define GL_FALSE 0 -#define GL_TRUE 1 -#define GL_POINTS 0x0000 -#define GL_LINES 0x0001 -#define GL_LINE_LOOP 0x0002 -#define GL_LINE_STRIP 0x0003 -#define GL_TRIANGLES 0x0004 -#define GL_TRIANGLE_STRIP 0x0005 -#define GL_TRIANGLE_FAN 0x0006 -#define GL_NEVER 0x0200 -#define GL_LESS 0x0201 -#define GL_EQUAL 0x0202 -#define GL_LEQUAL 0x0203 -#define GL_GREATER 0x0204 -#define GL_NOTEQUAL 0x0205 -#define GL_GEQUAL 0x0206 -#define GL_ALWAYS 0x0207 -#define GL_ZERO 0 -#define GL_ONE 1 -#define GL_SRC_COLOR 0x0300 -#define GL_ONE_MINUS_SRC_COLOR 0x0301 -#define GL_SRC_ALPHA 0x0302 -#define GL_ONE_MINUS_SRC_ALPHA 0x0303 -#define GL_DST_ALPHA 0x0304 -#define GL_ONE_MINUS_DST_ALPHA 0x0305 -#define GL_DST_COLOR 0x0306 -#define GL_ONE_MINUS_DST_COLOR 0x0307 -#define GL_SRC_ALPHA_SATURATE 0x0308 -#define GL_NONE 0 -#define GL_FRONT_LEFT 0x0400 -#define GL_FRONT_RIGHT 0x0401 -#define GL_BACK_LEFT 0x0402 -#define GL_BACK_RIGHT 0x0403 -#define GL_FRONT 0x0404 -#define GL_BACK 0x0405 -#define GL_LEFT 0x0406 -#define GL_RIGHT 0x0407 -#define GL_FRONT_AND_BACK 0x0408 -#define GL_NO_ERROR 0 -#define GL_INVALID_ENUM 0x0500 -#define GL_INVALID_VALUE 0x0501 -#define GL_INVALID_OPERATION 0x0502 -#define GL_OUT_OF_MEMORY 0x0505 -#define GL_CW 0x0900 -#define GL_CCW 0x0901 -#define GL_POINT_SIZE 0x0B11 -#define GL_POINT_SIZE_RANGE 0x0B12 -#define GL_POINT_SIZE_GRANULARITY 0x0B13 -#define GL_LINE_SMOOTH 0x0B20 -#define GL_LINE_WIDTH 0x0B21 -#define GL_LINE_WIDTH_RANGE 0x0B22 -#define GL_LINE_WIDTH_GRANULARITY 0x0B23 -#define GL_POLYGON_MODE 0x0B40 -#define GL_POLYGON_SMOOTH 0x0B41 -#define GL_CULL_FACE 0x0B44 -#define GL_CULL_FACE_MODE 0x0B45 -#define GL_FRONT_FACE 0x0B46 -#define GL_DEPTH_RANGE 0x0B70 -#define GL_DEPTH_TEST 0x0B71 -#define GL_DEPTH_WRITEMASK 0x0B72 -#define GL_DEPTH_CLEAR_VALUE 0x0B73 -#define GL_DEPTH_FUNC 0x0B74 -#define GL_STENCIL_TEST 0x0B90 -#define GL_STENCIL_CLEAR_VALUE 0x0B91 -#define GL_STENCIL_FUNC 0x0B92 -#define GL_STENCIL_VALUE_MASK 0x0B93 -#define GL_STENCIL_FAIL 0x0B94 -#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 -#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 -#define GL_STENCIL_REF 0x0B97 -#define GL_STENCIL_WRITEMASK 0x0B98 -#define GL_VIEWPORT 0x0BA2 -#define GL_DITHER 0x0BD0 -#define GL_BLEND_DST 0x0BE0 -#define GL_BLEND_SRC 0x0BE1 -#define GL_BLEND 0x0BE2 -#define GL_LOGIC_OP_MODE 0x0BF0 -#define GL_DRAW_BUFFER 0x0C01 -#define GL_READ_BUFFER 0x0C02 -#define GL_SCISSOR_BOX 0x0C10 -#define GL_SCISSOR_TEST 0x0C11 -#define GL_COLOR_CLEAR_VALUE 0x0C22 -#define GL_COLOR_WRITEMASK 0x0C23 -#define GL_DOUBLEBUFFER 0x0C32 -#define GL_STEREO 0x0C33 -#define GL_LINE_SMOOTH_HINT 0x0C52 -#define GL_POLYGON_SMOOTH_HINT 0x0C53 -#define GL_UNPACK_SWAP_BYTES 0x0CF0 -#define GL_UNPACK_LSB_FIRST 0x0CF1 -#define GL_UNPACK_ROW_LENGTH 0x0CF2 -#define GL_UNPACK_SKIP_ROWS 0x0CF3 -#define GL_UNPACK_SKIP_PIXELS 0x0CF4 -#define GL_UNPACK_ALIGNMENT 0x0CF5 -#define GL_PACK_SWAP_BYTES 0x0D00 -#define GL_PACK_LSB_FIRST 0x0D01 -#define GL_PACK_ROW_LENGTH 0x0D02 -#define GL_PACK_SKIP_ROWS 0x0D03 -#define GL_PACK_SKIP_PIXELS 0x0D04 -#define GL_PACK_ALIGNMENT 0x0D05 -#define GL_MAX_TEXTURE_SIZE 0x0D33 -#define GL_MAX_VIEWPORT_DIMS 0x0D3A -#define GL_SUBPIXEL_BITS 0x0D50 -#define GL_TEXTURE_1D 0x0DE0 -#define GL_TEXTURE_2D 0x0DE1 -#define GL_TEXTURE_WIDTH 0x1000 -#define GL_TEXTURE_HEIGHT 0x1001 -#define GL_TEXTURE_BORDER_COLOR 0x1004 -#define GL_DONT_CARE 0x1100 -#define GL_FASTEST 0x1101 -#define GL_NICEST 0x1102 -#define GL_BYTE 0x1400 -#define GL_UNSIGNED_BYTE 0x1401 -#define GL_SHORT 0x1402 -#define GL_UNSIGNED_SHORT 0x1403 -#define GL_INT 0x1404 -#define GL_UNSIGNED_INT 0x1405 -#define GL_FLOAT 0x1406 -#define GL_CLEAR 0x1500 -#define GL_AND 0x1501 -#define GL_AND_REVERSE 0x1502 -#define GL_COPY 0x1503 -#define GL_AND_INVERTED 0x1504 -#define GL_NOOP 0x1505 -#define GL_XOR 0x1506 -#define GL_OR 0x1507 -#define GL_NOR 0x1508 -#define GL_EQUIV 0x1509 -#define GL_INVERT 0x150A -#define GL_OR_REVERSE 0x150B -#define GL_COPY_INVERTED 0x150C -#define GL_OR_INVERTED 0x150D -#define GL_NAND 0x150E -#define GL_SET 0x150F -#define GL_TEXTURE 0x1702 -#define GL_COLOR 0x1800 -#define GL_DEPTH 0x1801 -#define GL_STENCIL 0x1802 -#define GL_STENCIL_INDEX 0x1901 -#define GL_DEPTH_COMPONENT 0x1902 -#define GL_RED 0x1903 -#define GL_GREEN 0x1904 -#define GL_BLUE 0x1905 -#define GL_ALPHA 0x1906 -#define GL_RGB 0x1907 -#define GL_RGBA 0x1908 -#define GL_POINT 0x1B00 -#define GL_LINE 0x1B01 -#define GL_FILL 0x1B02 -#define GL_KEEP 0x1E00 -#define GL_REPLACE 0x1E01 -#define GL_INCR 0x1E02 -#define GL_DECR 0x1E03 -#define GL_VENDOR 0x1F00 -#define GL_RENDERER 0x1F01 -#define GL_VERSION 0x1F02 -#define GL_EXTENSIONS 0x1F03 -#define GL_NEAREST 0x2600 -#define GL_LINEAR 0x2601 -#define GL_NEAREST_MIPMAP_NEAREST 0x2700 -#define GL_LINEAR_MIPMAP_NEAREST 0x2701 -#define GL_NEAREST_MIPMAP_LINEAR 0x2702 -#define GL_LINEAR_MIPMAP_LINEAR 0x2703 -#define GL_TEXTURE_MAG_FILTER 0x2800 -#define GL_TEXTURE_MIN_FILTER 0x2801 -#define GL_TEXTURE_WRAP_S 0x2802 -#define GL_TEXTURE_WRAP_T 0x2803 -#define GL_REPEAT 0x2901 -#define GL_COLOR_LOGIC_OP 0x0BF2 -#define GL_POLYGON_OFFSET_UNITS 0x2A00 -#define GL_POLYGON_OFFSET_POINT 0x2A01 -#define GL_POLYGON_OFFSET_LINE 0x2A02 -#define GL_POLYGON_OFFSET_FILL 0x8037 -#define GL_POLYGON_OFFSET_FACTOR 0x8038 -#define GL_TEXTURE_BINDING_1D 0x8068 -#define GL_TEXTURE_BINDING_2D 0x8069 -#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 -#define GL_TEXTURE_RED_SIZE 0x805C -#define GL_TEXTURE_GREEN_SIZE 0x805D -#define GL_TEXTURE_BLUE_SIZE 0x805E -#define GL_TEXTURE_ALPHA_SIZE 0x805F -#define GL_DOUBLE 0x140A -#define GL_PROXY_TEXTURE_1D 0x8063 -#define GL_PROXY_TEXTURE_2D 0x8064 -#define GL_R3_G3_B2 0x2A10 -#define GL_RGB4 0x804F -#define GL_RGB5 0x8050 -#define GL_RGB8 0x8051 -#define GL_RGB10 0x8052 -#define GL_RGB12 0x8053 -#define GL_RGB16 0x8054 -#define GL_RGBA2 0x8055 -#define GL_RGBA4 0x8056 -#define GL_RGB5_A1 0x8057 -#define GL_RGBA8 0x8058 -#define GL_RGB10_A2 0x8059 -#define GL_RGBA12 0x805A -#define GL_RGBA16 0x805B -#define GL_UNSIGNED_BYTE_3_3_2 0x8032 -#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 -#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 -#define GL_UNSIGNED_INT_8_8_8_8 0x8035 -#define GL_UNSIGNED_INT_10_10_10_2 0x8036 -#define GL_TEXTURE_BINDING_3D 0x806A -#define GL_PACK_SKIP_IMAGES 0x806B -#define GL_PACK_IMAGE_HEIGHT 0x806C -#define GL_UNPACK_SKIP_IMAGES 0x806D -#define GL_UNPACK_IMAGE_HEIGHT 0x806E -#define GL_TEXTURE_3D 0x806F -#define GL_PROXY_TEXTURE_3D 0x8070 -#define GL_TEXTURE_DEPTH 0x8071 -#define GL_TEXTURE_WRAP_R 0x8072 -#define GL_MAX_3D_TEXTURE_SIZE 0x8073 -#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 -#define GL_UNSIGNED_SHORT_5_6_5 0x8363 -#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 -#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 -#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 -#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 -#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 -#define GL_BGR 0x80E0 -#define GL_BGRA 0x80E1 -#define GL_MAX_ELEMENTS_VERTICES 0x80E8 -#define GL_MAX_ELEMENTS_INDICES 0x80E9 -#define GL_CLAMP_TO_EDGE 0x812F -#define GL_TEXTURE_MIN_LOD 0x813A -#define GL_TEXTURE_MAX_LOD 0x813B -#define GL_TEXTURE_BASE_LEVEL 0x813C -#define GL_TEXTURE_MAX_LEVEL 0x813D -#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 -#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 -#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 -#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 -#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E -#define GL_TEXTURE0 0x84C0 -#define GL_TEXTURE1 0x84C1 -#define GL_TEXTURE2 0x84C2 -#define GL_TEXTURE3 0x84C3 -#define GL_TEXTURE4 0x84C4 -#define GL_TEXTURE5 0x84C5 -#define GL_TEXTURE6 0x84C6 -#define GL_TEXTURE7 0x84C7 -#define GL_TEXTURE8 0x84C8 -#define GL_TEXTURE9 0x84C9 -#define GL_TEXTURE10 0x84CA -#define GL_TEXTURE11 0x84CB -#define GL_TEXTURE12 0x84CC -#define GL_TEXTURE13 0x84CD -#define GL_TEXTURE14 0x84CE -#define GL_TEXTURE15 0x84CF -#define GL_TEXTURE16 0x84D0 -#define GL_TEXTURE17 0x84D1 -#define GL_TEXTURE18 0x84D2 -#define GL_TEXTURE19 0x84D3 -#define GL_TEXTURE20 0x84D4 -#define GL_TEXTURE21 0x84D5 -#define GL_TEXTURE22 0x84D6 -#define GL_TEXTURE23 0x84D7 -#define GL_TEXTURE24 0x84D8 -#define GL_TEXTURE25 0x84D9 -#define GL_TEXTURE26 0x84DA -#define GL_TEXTURE27 0x84DB -#define GL_TEXTURE28 0x84DC -#define GL_TEXTURE29 0x84DD -#define GL_TEXTURE30 0x84DE -#define GL_TEXTURE31 0x84DF -#define GL_ACTIVE_TEXTURE 0x84E0 -#define GL_MULTISAMPLE 0x809D -#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE 0x809F -#define GL_SAMPLE_COVERAGE 0x80A0 -#define GL_SAMPLE_BUFFERS 0x80A8 -#define GL_SAMPLES 0x80A9 -#define GL_SAMPLE_COVERAGE_VALUE 0x80AA -#define GL_SAMPLE_COVERAGE_INVERT 0x80AB -#define GL_TEXTURE_CUBE_MAP 0x8513 -#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A -#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B -#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C -#define GL_COMPRESSED_RGB 0x84ED -#define GL_COMPRESSED_RGBA 0x84EE -#define GL_TEXTURE_COMPRESSION_HINT 0x84EF -#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 -#define GL_TEXTURE_COMPRESSED 0x86A1 -#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 -#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 -#define GL_CLAMP_TO_BORDER 0x812D -#define GL_BLEND_DST_RGB 0x80C8 -#define GL_BLEND_SRC_RGB 0x80C9 -#define GL_BLEND_DST_ALPHA 0x80CA -#define GL_BLEND_SRC_ALPHA 0x80CB -#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 -#define GL_DEPTH_COMPONENT16 0x81A5 -#define GL_DEPTH_COMPONENT24 0x81A6 -#define GL_DEPTH_COMPONENT32 0x81A7 -#define GL_MIRRORED_REPEAT 0x8370 -#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD -#define GL_TEXTURE_LOD_BIAS 0x8501 -#define GL_INCR_WRAP 0x8507 -#define GL_DECR_WRAP 0x8508 -#define GL_TEXTURE_DEPTH_SIZE 0x884A -#define GL_TEXTURE_COMPARE_MODE 0x884C -#define GL_TEXTURE_COMPARE_FUNC 0x884D -#define GL_BLEND_COLOR 0x8005 -#define GL_BLEND_EQUATION 0x8009 -#define GL_CONSTANT_COLOR 0x8001 -#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 -#define GL_CONSTANT_ALPHA 0x8003 -#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 -#define GL_FUNC_ADD 0x8006 -#define GL_FUNC_REVERSE_SUBTRACT 0x800B -#define GL_FUNC_SUBTRACT 0x800A -#define GL_MIN 0x8007 -#define GL_MAX 0x8008 -#define GL_BUFFER_SIZE 0x8764 -#define GL_BUFFER_USAGE 0x8765 -#define GL_QUERY_COUNTER_BITS 0x8864 -#define GL_CURRENT_QUERY 0x8865 -#define GL_QUERY_RESULT 0x8866 -#define GL_QUERY_RESULT_AVAILABLE 0x8867 -#define GL_ARRAY_BUFFER 0x8892 -#define GL_ELEMENT_ARRAY_BUFFER 0x8893 -#define GL_ARRAY_BUFFER_BINDING 0x8894 -#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 -#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F -#define GL_READ_ONLY 0x88B8 -#define GL_WRITE_ONLY 0x88B9 -#define GL_READ_WRITE 0x88BA -#define GL_BUFFER_ACCESS 0x88BB -#define GL_BUFFER_MAPPED 0x88BC -#define GL_BUFFER_MAP_POINTER 0x88BD -#define GL_STREAM_DRAW 0x88E0 -#define GL_STREAM_READ 0x88E1 -#define GL_STREAM_COPY 0x88E2 -#define GL_STATIC_DRAW 0x88E4 -#define GL_STATIC_READ 0x88E5 -#define GL_STATIC_COPY 0x88E6 -#define GL_DYNAMIC_DRAW 0x88E8 -#define GL_DYNAMIC_READ 0x88E9 -#define GL_DYNAMIC_COPY 0x88EA -#define GL_SAMPLES_PASSED 0x8914 -#define GL_SRC1_ALPHA 0x8589 -#define GL_BLEND_EQUATION_RGB 0x8009 -#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 -#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 -#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 -#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 -#define GL_CURRENT_VERTEX_ATTRIB 0x8626 -#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 -#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 -#define GL_STENCIL_BACK_FUNC 0x8800 -#define GL_STENCIL_BACK_FAIL 0x8801 -#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 -#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 -#define GL_MAX_DRAW_BUFFERS 0x8824 -#define GL_DRAW_BUFFER0 0x8825 -#define GL_DRAW_BUFFER1 0x8826 -#define GL_DRAW_BUFFER2 0x8827 -#define GL_DRAW_BUFFER3 0x8828 -#define GL_DRAW_BUFFER4 0x8829 -#define GL_DRAW_BUFFER5 0x882A -#define GL_DRAW_BUFFER6 0x882B -#define GL_DRAW_BUFFER7 0x882C -#define GL_DRAW_BUFFER8 0x882D -#define GL_DRAW_BUFFER9 0x882E -#define GL_DRAW_BUFFER10 0x882F -#define GL_DRAW_BUFFER11 0x8830 -#define GL_DRAW_BUFFER12 0x8831 -#define GL_DRAW_BUFFER13 0x8832 -#define GL_DRAW_BUFFER14 0x8833 -#define GL_DRAW_BUFFER15 0x8834 -#define GL_BLEND_EQUATION_ALPHA 0x883D -#define GL_MAX_VERTEX_ATTRIBS 0x8869 -#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A -#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 -#define GL_FRAGMENT_SHADER 0x8B30 -#define GL_VERTEX_SHADER 0x8B31 -#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 -#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A -#define GL_MAX_VARYING_FLOATS 0x8B4B -#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C -#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D -#define GL_SHADER_TYPE 0x8B4F -#define GL_FLOAT_VEC2 0x8B50 -#define GL_FLOAT_VEC3 0x8B51 -#define GL_FLOAT_VEC4 0x8B52 -#define GL_INT_VEC2 0x8B53 -#define GL_INT_VEC3 0x8B54 -#define GL_INT_VEC4 0x8B55 -#define GL_BOOL 0x8B56 -#define GL_BOOL_VEC2 0x8B57 -#define GL_BOOL_VEC3 0x8B58 -#define GL_BOOL_VEC4 0x8B59 -#define GL_FLOAT_MAT2 0x8B5A -#define GL_FLOAT_MAT3 0x8B5B -#define GL_FLOAT_MAT4 0x8B5C -#define GL_SAMPLER_1D 0x8B5D -#define GL_SAMPLER_2D 0x8B5E -#define GL_SAMPLER_3D 0x8B5F -#define GL_SAMPLER_CUBE 0x8B60 -#define GL_SAMPLER_1D_SHADOW 0x8B61 -#define GL_SAMPLER_2D_SHADOW 0x8B62 -#define GL_DELETE_STATUS 0x8B80 -#define GL_COMPILE_STATUS 0x8B81 -#define GL_LINK_STATUS 0x8B82 -#define GL_VALIDATE_STATUS 0x8B83 -#define GL_INFO_LOG_LENGTH 0x8B84 -#define GL_ATTACHED_SHADERS 0x8B85 -#define GL_ACTIVE_UNIFORMS 0x8B86 -#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 -#define GL_SHADER_SOURCE_LENGTH 0x8B88 -#define GL_ACTIVE_ATTRIBUTES 0x8B89 -#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A -#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B -#define GL_SHADING_LANGUAGE_VERSION 0x8B8C -#define GL_CURRENT_PROGRAM 0x8B8D -#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 -#define GL_LOWER_LEFT 0x8CA1 -#define GL_UPPER_LEFT 0x8CA2 -#define GL_STENCIL_BACK_REF 0x8CA3 -#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 -#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 -#define GL_PIXEL_PACK_BUFFER 0x88EB -#define GL_PIXEL_UNPACK_BUFFER 0x88EC -#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED -#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF -#define GL_FLOAT_MAT2x3 0x8B65 -#define GL_FLOAT_MAT2x4 0x8B66 -#define GL_FLOAT_MAT3x2 0x8B67 -#define GL_FLOAT_MAT3x4 0x8B68 -#define GL_FLOAT_MAT4x2 0x8B69 -#define GL_FLOAT_MAT4x3 0x8B6A -#define GL_SRGB 0x8C40 -#define GL_SRGB8 0x8C41 -#define GL_SRGB_ALPHA 0x8C42 -#define GL_SRGB8_ALPHA8 0x8C43 -#define GL_COMPRESSED_SRGB 0x8C48 -#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 -#define GL_COMPARE_REF_TO_TEXTURE 0x884E -#define GL_CLIP_DISTANCE0 0x3000 -#define GL_CLIP_DISTANCE1 0x3001 -#define GL_CLIP_DISTANCE2 0x3002 -#define GL_CLIP_DISTANCE3 0x3003 -#define GL_CLIP_DISTANCE4 0x3004 -#define GL_CLIP_DISTANCE5 0x3005 -#define GL_CLIP_DISTANCE6 0x3006 -#define GL_CLIP_DISTANCE7 0x3007 -#define GL_MAX_CLIP_DISTANCES 0x0D32 -#define GL_MAJOR_VERSION 0x821B -#define GL_MINOR_VERSION 0x821C -#define GL_NUM_EXTENSIONS 0x821D -#define GL_CONTEXT_FLAGS 0x821E -#define GL_COMPRESSED_RED 0x8225 -#define GL_COMPRESSED_RG 0x8226 -#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 -#define GL_RGBA32F 0x8814 -#define GL_RGB32F 0x8815 -#define GL_RGBA16F 0x881A -#define GL_RGB16F 0x881B -#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD -#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF -#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 -#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 -#define GL_CLAMP_READ_COLOR 0x891C -#define GL_FIXED_ONLY 0x891D -#define GL_MAX_VARYING_COMPONENTS 0x8B4B -#define GL_TEXTURE_1D_ARRAY 0x8C18 -#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 -#define GL_TEXTURE_2D_ARRAY 0x8C1A -#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B -#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C -#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D -#define GL_R11F_G11F_B10F 0x8C3A -#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B -#define GL_RGB9_E5 0x8C3D -#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E -#define GL_TEXTURE_SHARED_SIZE 0x8C3F -#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 -#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 -#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 -#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 -#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 -#define GL_PRIMITIVES_GENERATED 0x8C87 -#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 -#define GL_RASTERIZER_DISCARD 0x8C89 -#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A -#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B -#define GL_INTERLEAVED_ATTRIBS 0x8C8C -#define GL_SEPARATE_ATTRIBS 0x8C8D -#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E -#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F -#define GL_RGBA32UI 0x8D70 -#define GL_RGB32UI 0x8D71 -#define GL_RGBA16UI 0x8D76 -#define GL_RGB16UI 0x8D77 -#define GL_RGBA8UI 0x8D7C -#define GL_RGB8UI 0x8D7D -#define GL_RGBA32I 0x8D82 -#define GL_RGB32I 0x8D83 -#define GL_RGBA16I 0x8D88 -#define GL_RGB16I 0x8D89 -#define GL_RGBA8I 0x8D8E -#define GL_RGB8I 0x8D8F -#define GL_RED_INTEGER 0x8D94 -#define GL_GREEN_INTEGER 0x8D95 -#define GL_BLUE_INTEGER 0x8D96 -#define GL_RGB_INTEGER 0x8D98 -#define GL_RGBA_INTEGER 0x8D99 -#define GL_BGR_INTEGER 0x8D9A -#define GL_BGRA_INTEGER 0x8D9B -#define GL_SAMPLER_1D_ARRAY 0x8DC0 -#define GL_SAMPLER_2D_ARRAY 0x8DC1 -#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 -#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 -#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 -#define GL_UNSIGNED_INT_VEC2 0x8DC6 -#define GL_UNSIGNED_INT_VEC3 0x8DC7 -#define GL_UNSIGNED_INT_VEC4 0x8DC8 -#define GL_INT_SAMPLER_1D 0x8DC9 -#define GL_INT_SAMPLER_2D 0x8DCA -#define GL_INT_SAMPLER_3D 0x8DCB -#define GL_INT_SAMPLER_CUBE 0x8DCC -#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE -#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF -#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 -#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 -#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 -#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 -#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 -#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 -#define GL_QUERY_WAIT 0x8E13 -#define GL_QUERY_NO_WAIT 0x8E14 -#define GL_QUERY_BY_REGION_WAIT 0x8E15 -#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 -#define GL_BUFFER_ACCESS_FLAGS 0x911F -#define GL_BUFFER_MAP_LENGTH 0x9120 -#define GL_BUFFER_MAP_OFFSET 0x9121 -#define GL_DEPTH_COMPONENT32F 0x8CAC -#define GL_DEPTH32F_STENCIL8 0x8CAD -#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD -#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 -#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 -#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 -#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 -#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 -#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 -#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 -#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 -#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 -#define GL_FRAMEBUFFER_DEFAULT 0x8218 -#define GL_FRAMEBUFFER_UNDEFINED 0x8219 -#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A -#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 -#define GL_DEPTH_STENCIL 0x84F9 -#define GL_UNSIGNED_INT_24_8 0x84FA -#define GL_DEPTH24_STENCIL8 0x88F0 -#define GL_TEXTURE_STENCIL_SIZE 0x88F1 -#define GL_TEXTURE_RED_TYPE 0x8C10 -#define GL_TEXTURE_GREEN_TYPE 0x8C11 -#define GL_TEXTURE_BLUE_TYPE 0x8C12 -#define GL_TEXTURE_ALPHA_TYPE 0x8C13 -#define GL_TEXTURE_DEPTH_TYPE 0x8C16 -#define GL_UNSIGNED_NORMALIZED 0x8C17 -#define GL_FRAMEBUFFER_BINDING 0x8CA6 -#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 -#define GL_RENDERBUFFER_BINDING 0x8CA7 -#define GL_READ_FRAMEBUFFER 0x8CA8 -#define GL_DRAW_FRAMEBUFFER 0x8CA9 -#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA -#define GL_RENDERBUFFER_SAMPLES 0x8CAB -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 -#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 -#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 -#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 -#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB -#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC -#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD -#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF -#define GL_COLOR_ATTACHMENT0 0x8CE0 -#define GL_COLOR_ATTACHMENT1 0x8CE1 -#define GL_COLOR_ATTACHMENT2 0x8CE2 -#define GL_COLOR_ATTACHMENT3 0x8CE3 -#define GL_COLOR_ATTACHMENT4 0x8CE4 -#define GL_COLOR_ATTACHMENT5 0x8CE5 -#define GL_COLOR_ATTACHMENT6 0x8CE6 -#define GL_COLOR_ATTACHMENT7 0x8CE7 -#define GL_COLOR_ATTACHMENT8 0x8CE8 -#define GL_COLOR_ATTACHMENT9 0x8CE9 -#define GL_COLOR_ATTACHMENT10 0x8CEA -#define GL_COLOR_ATTACHMENT11 0x8CEB -#define GL_COLOR_ATTACHMENT12 0x8CEC -#define GL_COLOR_ATTACHMENT13 0x8CED -#define GL_COLOR_ATTACHMENT14 0x8CEE -#define GL_COLOR_ATTACHMENT15 0x8CEF -#define GL_COLOR_ATTACHMENT16 0x8CF0 -#define GL_COLOR_ATTACHMENT17 0x8CF1 -#define GL_COLOR_ATTACHMENT18 0x8CF2 -#define GL_COLOR_ATTACHMENT19 0x8CF3 -#define GL_COLOR_ATTACHMENT20 0x8CF4 -#define GL_COLOR_ATTACHMENT21 0x8CF5 -#define GL_COLOR_ATTACHMENT22 0x8CF6 -#define GL_COLOR_ATTACHMENT23 0x8CF7 -#define GL_COLOR_ATTACHMENT24 0x8CF8 -#define GL_COLOR_ATTACHMENT25 0x8CF9 -#define GL_COLOR_ATTACHMENT26 0x8CFA -#define GL_COLOR_ATTACHMENT27 0x8CFB -#define GL_COLOR_ATTACHMENT28 0x8CFC -#define GL_COLOR_ATTACHMENT29 0x8CFD -#define GL_COLOR_ATTACHMENT30 0x8CFE -#define GL_COLOR_ATTACHMENT31 0x8CFF -#define GL_DEPTH_ATTACHMENT 0x8D00 -#define GL_STENCIL_ATTACHMENT 0x8D20 -#define GL_FRAMEBUFFER 0x8D40 -#define GL_RENDERBUFFER 0x8D41 -#define GL_RENDERBUFFER_WIDTH 0x8D42 -#define GL_RENDERBUFFER_HEIGHT 0x8D43 -#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 -#define GL_STENCIL_INDEX1 0x8D46 -#define GL_STENCIL_INDEX4 0x8D47 -#define GL_STENCIL_INDEX8 0x8D48 -#define GL_STENCIL_INDEX16 0x8D49 -#define GL_RENDERBUFFER_RED_SIZE 0x8D50 -#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 -#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 -#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 -#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 -#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 -#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 -#define GL_MAX_SAMPLES 0x8D57 -#define GL_FRAMEBUFFER_SRGB 0x8DB9 -#define GL_HALF_FLOAT 0x140B -#define GL_MAP_READ_BIT 0x0001 -#define GL_MAP_WRITE_BIT 0x0002 -#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 -#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 -#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 -#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 -#define GL_COMPRESSED_RED_RGTC1 0x8DBB -#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC -#define GL_COMPRESSED_RG_RGTC2 0x8DBD -#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE -#define GL_RG 0x8227 -#define GL_RG_INTEGER 0x8228 -#define GL_R8 0x8229 -#define GL_R16 0x822A -#define GL_RG8 0x822B -#define GL_RG16 0x822C -#define GL_R16F 0x822D -#define GL_R32F 0x822E -#define GL_RG16F 0x822F -#define GL_RG32F 0x8230 -#define GL_R8I 0x8231 -#define GL_R8UI 0x8232 -#define GL_R16I 0x8233 -#define GL_R16UI 0x8234 -#define GL_R32I 0x8235 -#define GL_R32UI 0x8236 -#define GL_RG8I 0x8237 -#define GL_RG8UI 0x8238 -#define GL_RG16I 0x8239 -#define GL_RG16UI 0x823A -#define GL_RG32I 0x823B -#define GL_RG32UI 0x823C -#define GL_VERTEX_ARRAY_BINDING 0x85B5 -#define GL_SAMPLER_2D_RECT 0x8B63 -#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 -#define GL_SAMPLER_BUFFER 0x8DC2 -#define GL_INT_SAMPLER_2D_RECT 0x8DCD -#define GL_INT_SAMPLER_BUFFER 0x8DD0 -#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 -#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 -#define GL_TEXTURE_BUFFER 0x8C2A -#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B -#define GL_TEXTURE_BINDING_BUFFER 0x8C2C -#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D -#define GL_TEXTURE_RECTANGLE 0x84F5 -#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 -#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 -#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 -#define GL_R8_SNORM 0x8F94 -#define GL_RG8_SNORM 0x8F95 -#define GL_RGB8_SNORM 0x8F96 -#define GL_RGBA8_SNORM 0x8F97 -#define GL_R16_SNORM 0x8F98 -#define GL_RG16_SNORM 0x8F99 -#define GL_RGB16_SNORM 0x8F9A -#define GL_RGBA16_SNORM 0x8F9B -#define GL_SIGNED_NORMALIZED 0x8F9C -#define GL_PRIMITIVE_RESTART 0x8F9D -#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E -#define GL_COPY_READ_BUFFER 0x8F36 -#define GL_COPY_WRITE_BUFFER 0x8F37 -#define GL_UNIFORM_BUFFER 0x8A11 -#define GL_UNIFORM_BUFFER_BINDING 0x8A28 -#define GL_UNIFORM_BUFFER_START 0x8A29 -#define GL_UNIFORM_BUFFER_SIZE 0x8A2A -#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B -#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C -#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D -#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E -#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F -#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 -#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 -#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 -#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 -#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 -#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 -#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 -#define GL_UNIFORM_TYPE 0x8A37 -#define GL_UNIFORM_SIZE 0x8A38 -#define GL_UNIFORM_NAME_LENGTH 0x8A39 -#define GL_UNIFORM_BLOCK_INDEX 0x8A3A -#define GL_UNIFORM_OFFSET 0x8A3B -#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C -#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D -#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E -#define GL_UNIFORM_BLOCK_BINDING 0x8A3F -#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 -#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 -#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 -#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 -#define GL_INVALID_INDEX 0xFFFFFFFF -#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 -#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 -#define GL_LINES_ADJACENCY 0x000A -#define GL_LINE_STRIP_ADJACENCY 0x000B -#define GL_TRIANGLES_ADJACENCY 0x000C -#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D -#define GL_PROGRAM_POINT_SIZE 0x8642 -#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 -#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 -#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 -#define GL_GEOMETRY_SHADER 0x8DD9 -#define GL_GEOMETRY_VERTICES_OUT 0x8916 -#define GL_GEOMETRY_INPUT_TYPE 0x8917 -#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 -#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF -#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 -#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 -#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 -#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 -#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 -#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 -#define GL_CONTEXT_PROFILE_MASK 0x9126 -#define GL_DEPTH_CLAMP 0x864F -#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C -#define GL_FIRST_VERTEX_CONVENTION 0x8E4D -#define GL_LAST_VERTEX_CONVENTION 0x8E4E -#define GL_PROVOKING_VERTEX 0x8E4F -#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F -#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 -#define GL_OBJECT_TYPE 0x9112 -#define GL_SYNC_CONDITION 0x9113 -#define GL_SYNC_STATUS 0x9114 -#define GL_SYNC_FLAGS 0x9115 -#define GL_SYNC_FENCE 0x9116 -#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 -#define GL_UNSIGNALED 0x9118 -#define GL_SIGNALED 0x9119 -#define GL_ALREADY_SIGNALED 0x911A -#define GL_TIMEOUT_EXPIRED 0x911B -#define GL_CONDITION_SATISFIED 0x911C -#define GL_WAIT_FAILED 0x911D -#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF -#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 -#define GL_SAMPLE_POSITION 0x8E50 -#define GL_SAMPLE_MASK 0x8E51 -#define GL_SAMPLE_MASK_VALUE 0x8E52 -#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 -#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 -#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 -#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 -#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 -#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 -#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 -#define GL_TEXTURE_SAMPLES 0x9106 -#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 -#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 -#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 -#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A -#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B -#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C -#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D -#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E -#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F -#define GL_MAX_INTEGER_SAMPLES 0x9110 -#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE -#define GL_SRC1_COLOR 0x88F9 -#define GL_ONE_MINUS_SRC1_COLOR 0x88FA -#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB -#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC -#define GL_ANY_SAMPLES_PASSED 0x8C2F -#define GL_SAMPLER_BINDING 0x8919 -#define GL_RGB10_A2UI 0x906F -#define GL_TEXTURE_SWIZZLE_R 0x8E42 -#define GL_TEXTURE_SWIZZLE_G 0x8E43 -#define GL_TEXTURE_SWIZZLE_B 0x8E44 -#define GL_TEXTURE_SWIZZLE_A 0x8E45 -#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 -#define GL_TIME_ELAPSED 0x88BF -#define GL_TIMESTAMP 0x8E28 -#define GL_INT_2_10_10_10_REV 0x8D9F -#ifndef GL_VERSION_1_0 -#define GL_VERSION_1_0 1 -GLAPI int GLAD_GL_VERSION_1_0; -typedef void (APIENTRYP PFNGLCULLFACEPROC)(GLenum mode); -GLAPI PFNGLCULLFACEPROC glad_glCullFace; -#define glCullFace glad_glCullFace -typedef void (APIENTRYP PFNGLFRONTFACEPROC)(GLenum mode); -GLAPI PFNGLFRONTFACEPROC glad_glFrontFace; -#define glFrontFace glad_glFrontFace -typedef void (APIENTRYP PFNGLHINTPROC)(GLenum target, GLenum mode); -GLAPI PFNGLHINTPROC glad_glHint; -#define glHint glad_glHint -typedef void (APIENTRYP PFNGLLINEWIDTHPROC)(GLfloat width); -GLAPI PFNGLLINEWIDTHPROC glad_glLineWidth; -#define glLineWidth glad_glLineWidth -typedef void (APIENTRYP PFNGLPOINTSIZEPROC)(GLfloat size); -GLAPI PFNGLPOINTSIZEPROC glad_glPointSize; -#define glPointSize glad_glPointSize -typedef void (APIENTRYP PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode); -GLAPI PFNGLPOLYGONMODEPROC glad_glPolygonMode; -#define glPolygonMode glad_glPolygonMode -typedef void (APIENTRYP PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI PFNGLSCISSORPROC glad_glScissor; -#define glScissor glad_glScissor -typedef void (APIENTRYP PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); -GLAPI PFNGLTEXPARAMETERFPROC glad_glTexParameterf; -#define glTexParameterf glad_glTexParameterf -typedef void (APIENTRYP PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat *params); -GLAPI PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; -#define glTexParameterfv glad_glTexParameterfv -typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); -GLAPI PFNGLTEXPARAMETERIPROC glad_glTexParameteri; -#define glTexParameteri glad_glTexParameteri -typedef void (APIENTRYP PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint *params); -GLAPI PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; -#define glTexParameteriv glad_glTexParameteriv -typedef void (APIENTRYP PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI PFNGLTEXIMAGE1DPROC glad_glTexImage1D; -#define glTexImage1D glad_glTexImage1D -typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI PFNGLTEXIMAGE2DPROC glad_glTexImage2D; -#define glTexImage2D glad_glTexImage2D -typedef void (APIENTRYP PFNGLDRAWBUFFERPROC)(GLenum buf); -GLAPI PFNGLDRAWBUFFERPROC glad_glDrawBuffer; -#define glDrawBuffer glad_glDrawBuffer -typedef void (APIENTRYP PFNGLCLEARPROC)(GLbitfield mask); -GLAPI PFNGLCLEARPROC glad_glClear; -#define glClear glad_glClear -typedef void (APIENTRYP PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -GLAPI PFNGLCLEARCOLORPROC glad_glClearColor; -#define glClearColor glad_glClearColor -typedef void (APIENTRYP PFNGLCLEARSTENCILPROC)(GLint s); -GLAPI PFNGLCLEARSTENCILPROC glad_glClearStencil; -#define glClearStencil glad_glClearStencil -typedef void (APIENTRYP PFNGLCLEARDEPTHPROC)(GLdouble depth); -GLAPI PFNGLCLEARDEPTHPROC glad_glClearDepth; -#define glClearDepth glad_glClearDepth -typedef void (APIENTRYP PFNGLSTENCILMASKPROC)(GLuint mask); -GLAPI PFNGLSTENCILMASKPROC glad_glStencilMask; -#define glStencilMask glad_glStencilMask -typedef void (APIENTRYP PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); -GLAPI PFNGLCOLORMASKPROC glad_glColorMask; -#define glColorMask glad_glColorMask -typedef void (APIENTRYP PFNGLDEPTHMASKPROC)(GLboolean flag); -GLAPI PFNGLDEPTHMASKPROC glad_glDepthMask; -#define glDepthMask glad_glDepthMask -typedef void (APIENTRYP PFNGLDISABLEPROC)(GLenum cap); -GLAPI PFNGLDISABLEPROC glad_glDisable; -#define glDisable glad_glDisable -typedef void (APIENTRYP PFNGLENABLEPROC)(GLenum cap); -GLAPI PFNGLENABLEPROC glad_glEnable; -#define glEnable glad_glEnable -typedef void (APIENTRYP PFNGLFINISHPROC)(void); -GLAPI PFNGLFINISHPROC glad_glFinish; -#define glFinish glad_glFinish -typedef void (APIENTRYP PFNGLFLUSHPROC)(void); -GLAPI PFNGLFLUSHPROC glad_glFlush; -#define glFlush glad_glFlush -typedef void (APIENTRYP PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); -GLAPI PFNGLBLENDFUNCPROC glad_glBlendFunc; -#define glBlendFunc glad_glBlendFunc -typedef void (APIENTRYP PFNGLLOGICOPPROC)(GLenum opcode); -GLAPI PFNGLLOGICOPPROC glad_glLogicOp; -#define glLogicOp glad_glLogicOp -typedef void (APIENTRYP PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); -GLAPI PFNGLSTENCILFUNCPROC glad_glStencilFunc; -#define glStencilFunc glad_glStencilFunc -typedef void (APIENTRYP PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); -GLAPI PFNGLSTENCILOPPROC glad_glStencilOp; -#define glStencilOp glad_glStencilOp -typedef void (APIENTRYP PFNGLDEPTHFUNCPROC)(GLenum func); -GLAPI PFNGLDEPTHFUNCPROC glad_glDepthFunc; -#define glDepthFunc glad_glDepthFunc -typedef void (APIENTRYP PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param); -GLAPI PFNGLPIXELSTOREFPROC glad_glPixelStoref; -#define glPixelStoref glad_glPixelStoref -typedef void (APIENTRYP PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param); -GLAPI PFNGLPIXELSTOREIPROC glad_glPixelStorei; -#define glPixelStorei glad_glPixelStorei -typedef void (APIENTRYP PFNGLREADBUFFERPROC)(GLenum src); -GLAPI PFNGLREADBUFFERPROC glad_glReadBuffer; -#define glReadBuffer glad_glReadBuffer -typedef void (APIENTRYP PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); -GLAPI PFNGLREADPIXELSPROC glad_glReadPixels; -#define glReadPixels glad_glReadPixels -typedef void (APIENTRYP PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean *data); -GLAPI PFNGLGETBOOLEANVPROC glad_glGetBooleanv; -#define glGetBooleanv glad_glGetBooleanv -typedef void (APIENTRYP PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble *data); -GLAPI PFNGLGETDOUBLEVPROC glad_glGetDoublev; -#define glGetDoublev glad_glGetDoublev -typedef GLenum (APIENTRYP PFNGLGETERRORPROC)(void); -GLAPI PFNGLGETERRORPROC glad_glGetError; -#define glGetError glad_glGetError -typedef void (APIENTRYP PFNGLGETFLOATVPROC)(GLenum pname, GLfloat *data); -GLAPI PFNGLGETFLOATVPROC glad_glGetFloatv; -#define glGetFloatv glad_glGetFloatv -typedef void (APIENTRYP PFNGLGETINTEGERVPROC)(GLenum pname, GLint *data); -GLAPI PFNGLGETINTEGERVPROC glad_glGetIntegerv; -#define glGetIntegerv glad_glGetIntegerv -typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGPROC)(GLenum name); -GLAPI PFNGLGETSTRINGPROC glad_glGetString; -#define glGetString glad_glGetString -typedef void (APIENTRYP PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void *pixels); -GLAPI PFNGLGETTEXIMAGEPROC glad_glGetTexImage; -#define glGetTexImage glad_glGetTexImage -typedef void (APIENTRYP PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat *params); -GLAPI PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; -#define glGetTexParameterfv glad_glGetTexParameterfv -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); -GLAPI PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; -#define glGetTexParameteriv glad_glGetTexParameteriv -typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat *params); -GLAPI PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv; -#define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv -typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint *params); -GLAPI PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv; -#define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv -typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC)(GLenum cap); -GLAPI PFNGLISENABLEDPROC glad_glIsEnabled; -#define glIsEnabled glad_glIsEnabled -typedef void (APIENTRYP PFNGLDEPTHRANGEPROC)(GLdouble n, GLdouble f); -GLAPI PFNGLDEPTHRANGEPROC glad_glDepthRange; -#define glDepthRange glad_glDepthRange -typedef void (APIENTRYP PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI PFNGLVIEWPORTPROC glad_glViewport; -#define glViewport glad_glViewport -#endif -#ifndef GL_VERSION_1_1 -#define GL_VERSION_1_1 1 -GLAPI int GLAD_GL_VERSION_1_1; -typedef void (APIENTRYP PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); -GLAPI PFNGLDRAWARRAYSPROC glad_glDrawArrays; -#define glDrawArrays glad_glDrawArrays -typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices); -GLAPI PFNGLDRAWELEMENTSPROC glad_glDrawElements; -#define glDrawElements glad_glDrawElements -typedef void (APIENTRYP PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); -GLAPI PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; -#define glPolygonOffset glad_glPolygonOffset -typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); -GLAPI PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D; -#define glCopyTexImage1D glad_glCopyTexImage1D -typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -GLAPI PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; -#define glCopyTexImage2D glad_glCopyTexImage2D -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -GLAPI PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D; -#define glCopyTexSubImage1D glad_glCopyTexSubImage1D -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; -#define glCopyTexSubImage2D glad_glCopyTexSubImage2D -typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); -GLAPI PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D; -#define glTexSubImage1D glad_glTexSubImage1D -typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); -GLAPI PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; -#define glTexSubImage2D glad_glTexSubImage2D -typedef void (APIENTRYP PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture); -GLAPI PFNGLBINDTEXTUREPROC glad_glBindTexture; -#define glBindTexture glad_glBindTexture -typedef void (APIENTRYP PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint *textures); -GLAPI PFNGLDELETETEXTURESPROC glad_glDeleteTextures; -#define glDeleteTextures glad_glDeleteTextures -typedef void (APIENTRYP PFNGLGENTEXTURESPROC)(GLsizei n, GLuint *textures); -GLAPI PFNGLGENTEXTURESPROC glad_glGenTextures; -#define glGenTextures glad_glGenTextures -typedef GLboolean (APIENTRYP PFNGLISTEXTUREPROC)(GLuint texture); -GLAPI PFNGLISTEXTUREPROC glad_glIsTexture; -#define glIsTexture glad_glIsTexture -#endif -#ifndef GL_VERSION_1_2 -#define GL_VERSION_1_2 1 -GLAPI int GLAD_GL_VERSION_1_2; -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); -GLAPI PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements; -#define glDrawRangeElements glad_glDrawRangeElements -typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); -GLAPI PFNGLTEXIMAGE3DPROC glad_glTexImage3D; -#define glTexImage3D glad_glTexImage3D -typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); -GLAPI PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D; -#define glTexSubImage3D glad_glTexSubImage3D -typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D; -#define glCopyTexSubImage3D glad_glCopyTexSubImage3D -#endif -#ifndef GL_VERSION_1_3 -#define GL_VERSION_1_3 1 -GLAPI int GLAD_GL_VERSION_1_3; -typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC)(GLenum texture); -GLAPI PFNGLACTIVETEXTUREPROC glad_glActiveTexture; -#define glActiveTexture glad_glActiveTexture -typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert); -GLAPI PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; -#define glSampleCoverage glad_glSampleCoverage -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); -GLAPI PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D; -#define glCompressedTexImage3D glad_glCompressedTexImage3D -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); -GLAPI PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; -#define glCompressedTexImage2D glad_glCompressedTexImage2D -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); -GLAPI PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D; -#define glCompressedTexImage1D glad_glCompressedTexImage1D -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); -GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D; -#define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); -GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; -#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); -GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D; -#define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D -typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void *img); -GLAPI PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage; -#define glGetCompressedTexImage glad_glGetCompressedTexImage -#endif -#ifndef GL_VERSION_1_4 -#define GL_VERSION_1_4 1 -GLAPI int GLAD_GL_VERSION_1_4; -typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -GLAPI PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; -#define glBlendFuncSeparate glad_glBlendFuncSeparate -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); -GLAPI PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays; -#define glMultiDrawArrays glad_glMultiDrawArrays -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); -GLAPI PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements; -#define glMultiDrawElements glad_glMultiDrawElements -typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param); -GLAPI PFNGLPOINTPARAMETERFPROC glad_glPointParameterf; -#define glPointParameterf glad_glPointParameterf -typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat *params); -GLAPI PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv; -#define glPointParameterfv glad_glPointParameterfv -typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param); -GLAPI PFNGLPOINTPARAMETERIPROC glad_glPointParameteri; -#define glPointParameteri glad_glPointParameteri -typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint *params); -GLAPI PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv; -#define glPointParameteriv glad_glPointParameteriv -typedef void (APIENTRYP PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -GLAPI PFNGLBLENDCOLORPROC glad_glBlendColor; -#define glBlendColor glad_glBlendColor -typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC)(GLenum mode); -GLAPI PFNGLBLENDEQUATIONPROC glad_glBlendEquation; -#define glBlendEquation glad_glBlendEquation -#endif -#ifndef GL_VERSION_1_5 -#define GL_VERSION_1_5 1 -GLAPI int GLAD_GL_VERSION_1_5; -typedef void (APIENTRYP PFNGLGENQUERIESPROC)(GLsizei n, GLuint *ids); -GLAPI PFNGLGENQUERIESPROC glad_glGenQueries; -#define glGenQueries glad_glGenQueries -typedef void (APIENTRYP PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint *ids); -GLAPI PFNGLDELETEQUERIESPROC glad_glDeleteQueries; -#define glDeleteQueries glad_glDeleteQueries -typedef GLboolean (APIENTRYP PFNGLISQUERYPROC)(GLuint id); -GLAPI PFNGLISQUERYPROC glad_glIsQuery; -#define glIsQuery glad_glIsQuery -typedef void (APIENTRYP PFNGLBEGINQUERYPROC)(GLenum target, GLuint id); -GLAPI PFNGLBEGINQUERYPROC glad_glBeginQuery; -#define glBeginQuery glad_glBeginQuery -typedef void (APIENTRYP PFNGLENDQUERYPROC)(GLenum target); -GLAPI PFNGLENDQUERYPROC glad_glEndQuery; -#define glEndQuery glad_glEndQuery -typedef void (APIENTRYP PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint *params); -GLAPI PFNGLGETQUERYIVPROC glad_glGetQueryiv; -#define glGetQueryiv glad_glGetQueryiv -typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint *params); -GLAPI PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv; -#define glGetQueryObjectiv glad_glGetQueryObjectiv -typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint *params); -GLAPI PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv; -#define glGetQueryObjectuiv glad_glGetQueryObjectuiv -typedef void (APIENTRYP PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer); -GLAPI PFNGLBINDBUFFERPROC glad_glBindBuffer; -#define glBindBuffer glad_glBindBuffer -typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint *buffers); -GLAPI PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; -#define glDeleteBuffers glad_glDeleteBuffers -typedef void (APIENTRYP PFNGLGENBUFFERSPROC)(GLsizei n, GLuint *buffers); -GLAPI PFNGLGENBUFFERSPROC glad_glGenBuffers; -#define glGenBuffers glad_glGenBuffers -typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC)(GLuint buffer); -GLAPI PFNGLISBUFFERPROC glad_glIsBuffer; -#define glIsBuffer glad_glIsBuffer -typedef void (APIENTRYP PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void *data, GLenum usage); -GLAPI PFNGLBUFFERDATAPROC glad_glBufferData; -#define glBufferData glad_glBufferData -typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void *data); -GLAPI PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; -#define glBufferSubData glad_glBufferSubData -typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void *data); -GLAPI PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData; -#define glGetBufferSubData glad_glGetBufferSubData -typedef void * (APIENTRYP PFNGLMAPBUFFERPROC)(GLenum target, GLenum access); -GLAPI PFNGLMAPBUFFERPROC glad_glMapBuffer; -#define glMapBuffer glad_glMapBuffer -typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC)(GLenum target); -GLAPI PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer; -#define glUnmapBuffer glad_glUnmapBuffer -typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); -GLAPI PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; -#define glGetBufferParameteriv glad_glGetBufferParameteriv -typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void **params); -GLAPI PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; -#define glGetBufferPointerv glad_glGetBufferPointerv -#endif -#ifndef GL_VERSION_2_0 -#define GL_VERSION_2_0 1 -GLAPI int GLAD_GL_VERSION_2_0; -typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); -GLAPI PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; -#define glBlendEquationSeparate glad_glBlendEquationSeparate -typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum *bufs); -GLAPI PFNGLDRAWBUFFERSPROC glad_glDrawBuffers; -#define glDrawBuffers glad_glDrawBuffers -typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); -GLAPI PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; -#define glStencilOpSeparate glad_glStencilOpSeparate -typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask); -GLAPI PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; -#define glStencilFuncSeparate glad_glStencilFuncSeparate -typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); -GLAPI PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; -#define glStencilMaskSeparate glad_glStencilMaskSeparate -typedef void (APIENTRYP PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader); -GLAPI PFNGLATTACHSHADERPROC glad_glAttachShader; -#define glAttachShader glad_glAttachShader -typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar *name); -GLAPI PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; -#define glBindAttribLocation glad_glBindAttribLocation -typedef void (APIENTRYP PFNGLCOMPILESHADERPROC)(GLuint shader); -GLAPI PFNGLCOMPILESHADERPROC glad_glCompileShader; -#define glCompileShader glad_glCompileShader -typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC)(void); -GLAPI PFNGLCREATEPROGRAMPROC glad_glCreateProgram; -#define glCreateProgram glad_glCreateProgram -typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC)(GLenum type); -GLAPI PFNGLCREATESHADERPROC glad_glCreateShader; -#define glCreateShader glad_glCreateShader -typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC)(GLuint program); -GLAPI PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; -#define glDeleteProgram glad_glDeleteProgram -typedef void (APIENTRYP PFNGLDELETESHADERPROC)(GLuint shader); -GLAPI PFNGLDELETESHADERPROC glad_glDeleteShader; -#define glDeleteShader glad_glDeleteShader -typedef void (APIENTRYP PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader); -GLAPI PFNGLDETACHSHADERPROC glad_glDetachShader; -#define glDetachShader glad_glDetachShader -typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); -GLAPI PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; -#define glDisableVertexAttribArray glad_glDisableVertexAttribArray -typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); -GLAPI PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; -#define glEnableVertexAttribArray glad_glEnableVertexAttribArray -typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -GLAPI PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; -#define glGetActiveAttrib glad_glGetActiveAttrib -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -GLAPI PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; -#define glGetActiveUniform glad_glGetActiveUniform -typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); -GLAPI PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; -#define glGetAttachedShaders glad_glGetAttachedShaders -typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar *name); -GLAPI PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; -#define glGetAttribLocation glad_glGetAttribLocation -typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint *params); -GLAPI PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; -#define glGetProgramiv glad_glGetProgramiv -typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -GLAPI PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; -#define glGetProgramInfoLog glad_glGetProgramInfoLog -typedef void (APIENTRYP PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint *params); -GLAPI PFNGLGETSHADERIVPROC glad_glGetShaderiv; -#define glGetShaderiv glad_glGetShaderiv -typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -GLAPI PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; -#define glGetShaderInfoLog glad_glGetShaderInfoLog -typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); -GLAPI PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; -#define glGetShaderSource glad_glGetShaderSource -typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar *name); -GLAPI PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; -#define glGetUniformLocation glad_glGetUniformLocation -typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat *params); -GLAPI PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; -#define glGetUniformfv glad_glGetUniformfv -typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint *params); -GLAPI PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; -#define glGetUniformiv glad_glGetUniformiv -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble *params); -GLAPI PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv; -#define glGetVertexAttribdv glad_glGetVertexAttribdv -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat *params); -GLAPI PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; -#define glGetVertexAttribfv glad_glGetVertexAttribfv -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint *params); -GLAPI PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; -#define glGetVertexAttribiv glad_glGetVertexAttribiv -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void **pointer); -GLAPI PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; -#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv -typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC)(GLuint program); -GLAPI PFNGLISPROGRAMPROC glad_glIsProgram; -#define glIsProgram glad_glIsProgram -typedef GLboolean (APIENTRYP PFNGLISSHADERPROC)(GLuint shader); -GLAPI PFNGLISSHADERPROC glad_glIsShader; -#define glIsShader glad_glIsShader -typedef void (APIENTRYP PFNGLLINKPROGRAMPROC)(GLuint program); -GLAPI PFNGLLINKPROGRAMPROC glad_glLinkProgram; -#define glLinkProgram glad_glLinkProgram -typedef void (APIENTRYP PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); -GLAPI PFNGLSHADERSOURCEPROC glad_glShaderSource; -#define glShaderSource glad_glShaderSource -typedef void (APIENTRYP PFNGLUSEPROGRAMPROC)(GLuint program); -GLAPI PFNGLUSEPROGRAMPROC glad_glUseProgram; -#define glUseProgram glad_glUseProgram -typedef void (APIENTRYP PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0); -GLAPI PFNGLUNIFORM1FPROC glad_glUniform1f; -#define glUniform1f glad_glUniform1f -typedef void (APIENTRYP PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); -GLAPI PFNGLUNIFORM2FPROC glad_glUniform2f; -#define glUniform2f glad_glUniform2f -typedef void (APIENTRYP PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -GLAPI PFNGLUNIFORM3FPROC glad_glUniform3f; -#define glUniform3f glad_glUniform3f -typedef void (APIENTRYP PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -GLAPI PFNGLUNIFORM4FPROC glad_glUniform4f; -#define glUniform4f glad_glUniform4f -typedef void (APIENTRYP PFNGLUNIFORM1IPROC)(GLint location, GLint v0); -GLAPI PFNGLUNIFORM1IPROC glad_glUniform1i; -#define glUniform1i glad_glUniform1i -typedef void (APIENTRYP PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); -GLAPI PFNGLUNIFORM2IPROC glad_glUniform2i; -#define glUniform2i glad_glUniform2i -typedef void (APIENTRYP PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); -GLAPI PFNGLUNIFORM3IPROC glad_glUniform3i; -#define glUniform3i glad_glUniform3i -typedef void (APIENTRYP PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -GLAPI PFNGLUNIFORM4IPROC glad_glUniform4i; -#define glUniform4i glad_glUniform4i -typedef void (APIENTRYP PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat *value); -GLAPI PFNGLUNIFORM1FVPROC glad_glUniform1fv; -#define glUniform1fv glad_glUniform1fv -typedef void (APIENTRYP PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat *value); -GLAPI PFNGLUNIFORM2FVPROC glad_glUniform2fv; -#define glUniform2fv glad_glUniform2fv -typedef void (APIENTRYP PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat *value); -GLAPI PFNGLUNIFORM3FVPROC glad_glUniform3fv; -#define glUniform3fv glad_glUniform3fv -typedef void (APIENTRYP PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat *value); -GLAPI PFNGLUNIFORM4FVPROC glad_glUniform4fv; -#define glUniform4fv glad_glUniform4fv -typedef void (APIENTRYP PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint *value); -GLAPI PFNGLUNIFORM1IVPROC glad_glUniform1iv; -#define glUniform1iv glad_glUniform1iv -typedef void (APIENTRYP PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint *value); -GLAPI PFNGLUNIFORM2IVPROC glad_glUniform2iv; -#define glUniform2iv glad_glUniform2iv -typedef void (APIENTRYP PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint *value); -GLAPI PFNGLUNIFORM3IVPROC glad_glUniform3iv; -#define glUniform3iv glad_glUniform3iv -typedef void (APIENTRYP PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint *value); -GLAPI PFNGLUNIFORM4IVPROC glad_glUniform4iv; -#define glUniform4iv glad_glUniform4iv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; -#define glUniformMatrix2fv glad_glUniformMatrix2fv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; -#define glUniformMatrix3fv glad_glUniformMatrix3fv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; -#define glUniformMatrix4fv glad_glUniformMatrix4fv -typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC)(GLuint program); -GLAPI PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; -#define glValidateProgram glad_glValidateProgram -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x); -GLAPI PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d; -#define glVertexAttrib1d glad_glVertexAttrib1d -typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble *v); -GLAPI PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv; -#define glVertexAttrib1dv glad_glVertexAttrib1dv -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); -GLAPI PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; -#define glVertexAttrib1f glad_glVertexAttrib1f -typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat *v); -GLAPI PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; -#define glVertexAttrib1fv glad_glVertexAttrib1fv -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x); -GLAPI PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s; -#define glVertexAttrib1s glad_glVertexAttrib1s -typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort *v); -GLAPI PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv; -#define glVertexAttrib1sv glad_glVertexAttrib1sv -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y); -GLAPI PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d; -#define glVertexAttrib2d glad_glVertexAttrib2d -typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble *v); -GLAPI PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv; -#define glVertexAttrib2dv glad_glVertexAttrib2dv -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); -GLAPI PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; -#define glVertexAttrib2f glad_glVertexAttrib2f -typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat *v); -GLAPI PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; -#define glVertexAttrib2fv glad_glVertexAttrib2fv -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y); -GLAPI PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s; -#define glVertexAttrib2s glad_glVertexAttrib2s -typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort *v); -GLAPI PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv; -#define glVertexAttrib2sv glad_glVertexAttrib2sv -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); -GLAPI PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d; -#define glVertexAttrib3d glad_glVertexAttrib3d -typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble *v); -GLAPI PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv; -#define glVertexAttrib3dv glad_glVertexAttrib3dv -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); -GLAPI PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; -#define glVertexAttrib3f glad_glVertexAttrib3f -typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat *v); -GLAPI PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; -#define glVertexAttrib3fv glad_glVertexAttrib3fv -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z); -GLAPI PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s; -#define glVertexAttrib3s glad_glVertexAttrib3s -typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort *v); -GLAPI PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv; -#define glVertexAttrib3sv glad_glVertexAttrib3sv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte *v); -GLAPI PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv; -#define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint *v); -GLAPI PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv; -#define glVertexAttrib4Niv glad_glVertexAttrib4Niv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort *v); -GLAPI PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv; -#define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -GLAPI PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub; -#define glVertexAttrib4Nub glad_glVertexAttrib4Nub -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte *v); -GLAPI PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv; -#define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint *v); -GLAPI PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv; -#define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort *v); -GLAPI PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv; -#define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte *v); -GLAPI PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv; -#define glVertexAttrib4bv glad_glVertexAttrib4bv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -GLAPI PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d; -#define glVertexAttrib4d glad_glVertexAttrib4d -typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble *v); -GLAPI PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv; -#define glVertexAttrib4dv glad_glVertexAttrib4dv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -GLAPI PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; -#define glVertexAttrib4f glad_glVertexAttrib4f -typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat *v); -GLAPI PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; -#define glVertexAttrib4fv glad_glVertexAttrib4fv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint *v); -GLAPI PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv; -#define glVertexAttrib4iv glad_glVertexAttrib4iv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -GLAPI PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s; -#define glVertexAttrib4s glad_glVertexAttrib4s -typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort *v); -GLAPI PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv; -#define glVertexAttrib4sv glad_glVertexAttrib4sv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte *v); -GLAPI PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv; -#define glVertexAttrib4ubv glad_glVertexAttrib4ubv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint *v); -GLAPI PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv; -#define glVertexAttrib4uiv glad_glVertexAttrib4uiv -typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort *v); -GLAPI PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv; -#define glVertexAttrib4usv glad_glVertexAttrib4usv -typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); -GLAPI PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; -#define glVertexAttribPointer glad_glVertexAttribPointer -#endif -#ifndef GL_VERSION_2_1 -#define GL_VERSION_2_1 1 -GLAPI int GLAD_GL_VERSION_2_1; -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv; -#define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv; -#define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv; -#define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv; -#define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv; -#define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv -typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -GLAPI PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv; -#define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv -#endif -#ifndef GL_VERSION_3_0 -#define GL_VERSION_3_0 1 -GLAPI int GLAD_GL_VERSION_3_0; -typedef void (APIENTRYP PFNGLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); -GLAPI PFNGLCOLORMASKIPROC glad_glColorMaski; -#define glColorMaski glad_glColorMaski -typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean *data); -GLAPI PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v; -#define glGetBooleani_v glad_glGetBooleani_v -typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint *data); -GLAPI PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v; -#define glGetIntegeri_v glad_glGetIntegeri_v -typedef void (APIENTRYP PFNGLENABLEIPROC)(GLenum target, GLuint index); -GLAPI PFNGLENABLEIPROC glad_glEnablei; -#define glEnablei glad_glEnablei -typedef void (APIENTRYP PFNGLDISABLEIPROC)(GLenum target, GLuint index); -GLAPI PFNGLDISABLEIPROC glad_glDisablei; -#define glDisablei glad_glDisablei -typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC)(GLenum target, GLuint index); -GLAPI PFNGLISENABLEDIPROC glad_glIsEnabledi; -#define glIsEnabledi glad_glIsEnabledi -typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode); -GLAPI PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback; -#define glBeginTransformFeedback glad_glBeginTransformFeedback -typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC)(void); -GLAPI PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback; -#define glEndTransformFeedback glad_glEndTransformFeedback -typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -GLAPI PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange; -#define glBindBufferRange glad_glBindBufferRange -typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer); -GLAPI PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase; -#define glBindBufferBase glad_glBindBufferBase -typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); -GLAPI PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings; -#define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings -typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -GLAPI PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying; -#define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying -typedef void (APIENTRYP PFNGLCLAMPCOLORPROC)(GLenum target, GLenum clamp); -GLAPI PFNGLCLAMPCOLORPROC glad_glClampColor; -#define glClampColor glad_glClampColor -typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode); -GLAPI PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender; -#define glBeginConditionalRender glad_glBeginConditionalRender -typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC)(void); -GLAPI PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender; -#define glEndConditionalRender glad_glEndConditionalRender -typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); -GLAPI PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer; -#define glVertexAttribIPointer glad_glVertexAttribIPointer -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint *params); -GLAPI PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv; -#define glGetVertexAttribIiv glad_glGetVertexAttribIiv -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint *params); -GLAPI PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv; -#define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC)(GLuint index, GLint x); -GLAPI PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i; -#define glVertexAttribI1i glad_glVertexAttribI1i -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y); -GLAPI PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i; -#define glVertexAttribI2i glad_glVertexAttribI2i -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z); -GLAPI PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i; -#define glVertexAttribI3i glad_glVertexAttribI3i -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w); -GLAPI PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i; -#define glVertexAttribI4i glad_glVertexAttribI4i -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x); -GLAPI PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui; -#define glVertexAttribI1ui glad_glVertexAttribI1ui -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y); -GLAPI PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui; -#define glVertexAttribI2ui glad_glVertexAttribI2ui -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z); -GLAPI PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui; -#define glVertexAttribI3ui glad_glVertexAttribI3ui -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -GLAPI PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui; -#define glVertexAttribI4ui glad_glVertexAttribI4ui -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint *v); -GLAPI PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv; -#define glVertexAttribI1iv glad_glVertexAttribI1iv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint *v); -GLAPI PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv; -#define glVertexAttribI2iv glad_glVertexAttribI2iv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint *v); -GLAPI PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv; -#define glVertexAttribI3iv glad_glVertexAttribI3iv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint *v); -GLAPI PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv; -#define glVertexAttribI4iv glad_glVertexAttribI4iv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint *v); -GLAPI PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv; -#define glVertexAttribI1uiv glad_glVertexAttribI1uiv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint *v); -GLAPI PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv; -#define glVertexAttribI2uiv glad_glVertexAttribI2uiv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint *v); -GLAPI PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv; -#define glVertexAttribI3uiv glad_glVertexAttribI3uiv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint *v); -GLAPI PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv; -#define glVertexAttribI4uiv glad_glVertexAttribI4uiv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte *v); -GLAPI PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv; -#define glVertexAttribI4bv glad_glVertexAttribI4bv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort *v); -GLAPI PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv; -#define glVertexAttribI4sv glad_glVertexAttribI4sv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte *v); -GLAPI PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv; -#define glVertexAttribI4ubv glad_glVertexAttribI4ubv -typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort *v); -GLAPI PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv; -#define glVertexAttribI4usv glad_glVertexAttribI4usv -typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint *params); -GLAPI PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv; -#define glGetUniformuiv glad_glGetUniformuiv -typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, const GLchar *name); -GLAPI PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation; -#define glBindFragDataLocation glad_glBindFragDataLocation -typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar *name); -GLAPI PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation; -#define glGetFragDataLocation glad_glGetFragDataLocation -typedef void (APIENTRYP PFNGLUNIFORM1UIPROC)(GLint location, GLuint v0); -GLAPI PFNGLUNIFORM1UIPROC glad_glUniform1ui; -#define glUniform1ui glad_glUniform1ui -typedef void (APIENTRYP PFNGLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1); -GLAPI PFNGLUNIFORM2UIPROC glad_glUniform2ui; -#define glUniform2ui glad_glUniform2ui -typedef void (APIENTRYP PFNGLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2); -GLAPI PFNGLUNIFORM3UIPROC glad_glUniform3ui; -#define glUniform3ui glad_glUniform3ui -typedef void (APIENTRYP PFNGLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -GLAPI PFNGLUNIFORM4UIPROC glad_glUniform4ui; -#define glUniform4ui glad_glUniform4ui -typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint *value); -GLAPI PFNGLUNIFORM1UIVPROC glad_glUniform1uiv; -#define glUniform1uiv glad_glUniform1uiv -typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint *value); -GLAPI PFNGLUNIFORM2UIVPROC glad_glUniform2uiv; -#define glUniform2uiv glad_glUniform2uiv -typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint *value); -GLAPI PFNGLUNIFORM3UIVPROC glad_glUniform3uiv; -#define glUniform3uiv glad_glUniform3uiv -typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint *value); -GLAPI PFNGLUNIFORM4UIVPROC glad_glUniform4uiv; -#define glUniform4uiv glad_glUniform4uiv -typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint *params); -GLAPI PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv; -#define glTexParameterIiv glad_glTexParameterIiv -typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, const GLuint *params); -GLAPI PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv; -#define glTexParameterIuiv glad_glTexParameterIuiv -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint *params); -GLAPI PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv; -#define glGetTexParameterIiv glad_glGetTexParameterIiv -typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint *params); -GLAPI PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv; -#define glGetTexParameterIuiv glad_glGetTexParameterIuiv -typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, const GLint *value); -GLAPI PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv; -#define glClearBufferiv glad_glClearBufferiv -typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, const GLuint *value); -GLAPI PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv; -#define glClearBufferuiv glad_glClearBufferuiv -typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, const GLfloat *value); -GLAPI PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv; -#define glClearBufferfv glad_glClearBufferfv -typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); -GLAPI PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi; -#define glClearBufferfi glad_glClearBufferfi -typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGIPROC)(GLenum name, GLuint index); -GLAPI PFNGLGETSTRINGIPROC glad_glGetStringi; -#define glGetStringi glad_glGetStringi -typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer); -GLAPI PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; -#define glIsRenderbuffer glad_glIsRenderbuffer -typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); -GLAPI PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; -#define glBindRenderbuffer glad_glBindRenderbuffer -typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint *renderbuffers); -GLAPI PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; -#define glDeleteRenderbuffers glad_glDeleteRenderbuffers -typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint *renderbuffers); -GLAPI PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; -#define glGenRenderbuffers glad_glGenRenderbuffers -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; -#define glRenderbufferStorage glad_glRenderbufferStorage -typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); -GLAPI PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; -#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv -typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer); -GLAPI PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; -#define glIsFramebuffer glad_glIsFramebuffer -typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); -GLAPI PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; -#define glBindFramebuffer glad_glBindFramebuffer -typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint *framebuffers); -GLAPI PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; -#define glDeleteFramebuffers glad_glDeleteFramebuffers -typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint *framebuffers); -GLAPI PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; -#define glGenFramebuffers glad_glGenFramebuffers -typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); -GLAPI PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; -#define glCheckFramebufferStatus glad_glCheckFramebufferStatus -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D; -#define glFramebufferTexture1D glad_glFramebufferTexture1D -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLAPI PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; -#define glFramebufferTexture2D glad_glFramebufferTexture2D -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -GLAPI PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D; -#define glFramebufferTexture3D glad_glFramebufferTexture3D -typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -GLAPI PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; -#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer -typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint *params); -GLAPI PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; -#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv -typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC)(GLenum target); -GLAPI PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; -#define glGenerateMipmap glad_glGenerateMipmap -typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -GLAPI PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer; -#define glBlitFramebuffer glad_glBlitFramebuffer -typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -GLAPI PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample; -#define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -GLAPI PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer; -#define glFramebufferTextureLayer glad_glFramebufferTextureLayer -typedef void * (APIENTRYP PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); -GLAPI PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange; -#define glMapBufferRange glad_glMapBufferRange -typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length); -GLAPI PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange; -#define glFlushMappedBufferRange glad_glFlushMappedBufferRange -typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC)(GLuint array); -GLAPI PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray; -#define glBindVertexArray glad_glBindVertexArray -typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint *arrays); -GLAPI PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays; -#define glDeleteVertexArrays glad_glDeleteVertexArrays -typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint *arrays); -GLAPI PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays; -#define glGenVertexArrays glad_glGenVertexArrays -typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC)(GLuint array); -GLAPI PFNGLISVERTEXARRAYPROC glad_glIsVertexArray; -#define glIsVertexArray glad_glIsVertexArray -#endif -#ifndef GL_VERSION_3_1 -#define GL_VERSION_3_1 1 -GLAPI int GLAD_GL_VERSION_3_1; -typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount); -GLAPI PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced; -#define glDrawArraysInstanced glad_glDrawArraysInstanced -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); -GLAPI PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced; -#define glDrawElementsInstanced glad_glDrawElementsInstanced -typedef void (APIENTRYP PFNGLTEXBUFFERPROC)(GLenum target, GLenum internalformat, GLuint buffer); -GLAPI PFNGLTEXBUFFERPROC glad_glTexBuffer; -#define glTexBuffer glad_glTexBuffer -typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint index); -GLAPI PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex; -#define glPrimitiveRestartIndex glad_glPrimitiveRestartIndex -typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -GLAPI PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData; -#define glCopyBufferSubData glad_glCopyBufferSubData -typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC)(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); -GLAPI PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices; -#define glGetUniformIndices glad_glGetUniformIndices -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC)(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); -GLAPI PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv; -#define glGetActiveUniformsiv glad_glGetActiveUniformsiv -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC)(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); -GLAPI PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName; -#define glGetActiveUniformName glad_glGetActiveUniformName -typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC)(GLuint program, const GLchar *uniformBlockName); -GLAPI PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex; -#define glGetUniformBlockIndex glad_glGetUniformBlockIndex -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); -GLAPI PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv; -#define glGetActiveUniformBlockiv glad_glGetActiveUniformBlockiv -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); -GLAPI PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName; -#define glGetActiveUniformBlockName glad_glGetActiveUniformBlockName -typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); -GLAPI PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding; -#define glUniformBlockBinding glad_glUniformBlockBinding -#endif -#ifndef GL_VERSION_3_2 -#define GL_VERSION_3_2 1 -GLAPI int GLAD_GL_VERSION_3_2; -typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); -GLAPI PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex; -#define glDrawElementsBaseVertex glad_glDrawElementsBaseVertex -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); -GLAPI PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex; -#define glDrawRangeElementsBaseVertex glad_glDrawRangeElementsBaseVertex -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); -GLAPI PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex; -#define glDrawElementsInstancedBaseVertex glad_glDrawElementsInstancedBaseVertex -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); -GLAPI PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex; -#define glMultiDrawElementsBaseVertex glad_glMultiDrawElementsBaseVertex -typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC)(GLenum mode); -GLAPI PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex; -#define glProvokingVertex glad_glProvokingVertex -typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags); -GLAPI PFNGLFENCESYNCPROC glad_glFenceSync; -#define glFenceSync glad_glFenceSync -typedef GLboolean (APIENTRYP PFNGLISSYNCPROC)(GLsync sync); -GLAPI PFNGLISSYNCPROC glad_glIsSync; -#define glIsSync glad_glIsSync -typedef void (APIENTRYP PFNGLDELETESYNCPROC)(GLsync sync); -GLAPI PFNGLDELETESYNCPROC glad_glDeleteSync; -#define glDeleteSync glad_glDeleteSync -typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); -GLAPI PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync; -#define glClientWaitSync glad_glClientWaitSync -typedef void (APIENTRYP PFNGLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); -GLAPI PFNGLWAITSYNCPROC glad_glWaitSync; -#define glWaitSync glad_glWaitSync -typedef void (APIENTRYP PFNGLGETINTEGER64VPROC)(GLenum pname, GLint64 *data); -GLAPI PFNGLGETINTEGER64VPROC glad_glGetInteger64v; -#define glGetInteger64v glad_glGetInteger64v -typedef void (APIENTRYP PFNGLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); -GLAPI PFNGLGETSYNCIVPROC glad_glGetSynciv; -#define glGetSynciv glad_glGetSynciv -typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC)(GLenum target, GLuint index, GLint64 *data); -GLAPI PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v; -#define glGetInteger64i_v glad_glGetInteger64i_v -typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC)(GLenum target, GLenum pname, GLint64 *params); -GLAPI PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v; -#define glGetBufferParameteri64v glad_glGetBufferParameteri64v -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level); -GLAPI PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture; -#define glFramebufferTexture glad_glFramebufferTexture -typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -GLAPI PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample; -#define glTexImage2DMultisample glad_glTexImage2DMultisample -typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -GLAPI PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample; -#define glTexImage3DMultisample glad_glTexImage3DMultisample -typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat *val); -GLAPI PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv; -#define glGetMultisamplefv glad_glGetMultisamplefv -typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask); -GLAPI PFNGLSAMPLEMASKIPROC glad_glSampleMaski; -#define glSampleMaski glad_glSampleMaski -#endif -#ifndef GL_VERSION_3_3 -#define GL_VERSION_3_3 1 -GLAPI int GLAD_GL_VERSION_3_3; -typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)(GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); -GLAPI PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed; -#define glBindFragDataLocationIndexed glad_glBindFragDataLocationIndexed -typedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC)(GLuint program, const GLchar *name); -GLAPI PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex; -#define glGetFragDataIndex glad_glGetFragDataIndex -typedef void (APIENTRYP PFNGLGENSAMPLERSPROC)(GLsizei count, GLuint *samplers); -GLAPI PFNGLGENSAMPLERSPROC glad_glGenSamplers; -#define glGenSamplers glad_glGenSamplers -typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC)(GLsizei count, const GLuint *samplers); -GLAPI PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers; -#define glDeleteSamplers glad_glDeleteSamplers -typedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC)(GLuint sampler); -GLAPI PFNGLISSAMPLERPROC glad_glIsSampler; -#define glIsSampler glad_glIsSampler -typedef void (APIENTRYP PFNGLBINDSAMPLERPROC)(GLuint unit, GLuint sampler); -GLAPI PFNGLBINDSAMPLERPROC glad_glBindSampler; -#define glBindSampler glad_glBindSampler -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC)(GLuint sampler, GLenum pname, GLint param); -GLAPI PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri; -#define glSamplerParameteri glad_glSamplerParameteri -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, const GLint *param); -GLAPI PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv; -#define glSamplerParameteriv glad_glSamplerParameteriv -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC)(GLuint sampler, GLenum pname, GLfloat param); -GLAPI PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf; -#define glSamplerParameterf glad_glSamplerParameterf -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, const GLfloat *param); -GLAPI PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv; -#define glSamplerParameterfv glad_glSamplerParameterfv -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, const GLint *param); -GLAPI PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv; -#define glSamplerParameterIiv glad_glSamplerParameterIiv -typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, const GLuint *param); -GLAPI PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv; -#define glSamplerParameterIuiv glad_glSamplerParameterIuiv -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, GLint *params); -GLAPI PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv; -#define glGetSamplerParameteriv glad_glGetSamplerParameteriv -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, GLint *params); -GLAPI PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv; -#define glGetSamplerParameterIiv glad_glGetSamplerParameterIiv -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, GLfloat *params); -GLAPI PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv; -#define glGetSamplerParameterfv glad_glGetSamplerParameterfv -typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, GLuint *params); -GLAPI PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv; -#define glGetSamplerParameterIuiv glad_glGetSamplerParameterIuiv -typedef void (APIENTRYP PFNGLQUERYCOUNTERPROC)(GLuint id, GLenum target); -GLAPI PFNGLQUERYCOUNTERPROC glad_glQueryCounter; -#define glQueryCounter glad_glQueryCounter -typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC)(GLuint id, GLenum pname, GLint64 *params); -GLAPI PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v; -#define glGetQueryObjecti64v glad_glGetQueryObjecti64v -typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC)(GLuint id, GLenum pname, GLuint64 *params); -GLAPI PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v; -#define glGetQueryObjectui64v glad_glGetQueryObjectui64v -typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC)(GLuint index, GLuint divisor); -GLAPI PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor; -#define glVertexAttribDivisor glad_glVertexAttribDivisor -typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui; -#define glVertexAttribP1ui glad_glVertexAttribP1ui -typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -GLAPI PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv; -#define glVertexAttribP1uiv glad_glVertexAttribP1uiv -typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui; -#define glVertexAttribP2ui glad_glVertexAttribP2ui -typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -GLAPI PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv; -#define glVertexAttribP2uiv glad_glVertexAttribP2uiv -typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui; -#define glVertexAttribP3ui glad_glVertexAttribP3ui -typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -GLAPI PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv; -#define glVertexAttribP3uiv glad_glVertexAttribP3uiv -typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); -GLAPI PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui; -#define glVertexAttribP4ui glad_glVertexAttribP4ui -typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value); -GLAPI PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv; -#define glVertexAttribP4uiv glad_glVertexAttribP4uiv -typedef void (APIENTRYP PFNGLVERTEXP2UIPROC)(GLenum type, GLuint value); -GLAPI PFNGLVERTEXP2UIPROC glad_glVertexP2ui; -#define glVertexP2ui glad_glVertexP2ui -typedef void (APIENTRYP PFNGLVERTEXP2UIVPROC)(GLenum type, const GLuint *value); -GLAPI PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv; -#define glVertexP2uiv glad_glVertexP2uiv -typedef void (APIENTRYP PFNGLVERTEXP3UIPROC)(GLenum type, GLuint value); -GLAPI PFNGLVERTEXP3UIPROC glad_glVertexP3ui; -#define glVertexP3ui glad_glVertexP3ui -typedef void (APIENTRYP PFNGLVERTEXP3UIVPROC)(GLenum type, const GLuint *value); -GLAPI PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv; -#define glVertexP3uiv glad_glVertexP3uiv -typedef void (APIENTRYP PFNGLVERTEXP4UIPROC)(GLenum type, GLuint value); -GLAPI PFNGLVERTEXP4UIPROC glad_glVertexP4ui; -#define glVertexP4ui glad_glVertexP4ui -typedef void (APIENTRYP PFNGLVERTEXP4UIVPROC)(GLenum type, const GLuint *value); -GLAPI PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv; -#define glVertexP4uiv glad_glVertexP4uiv -typedef void (APIENTRYP PFNGLTEXCOORDP1UIPROC)(GLenum type, GLuint coords); -GLAPI PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui; -#define glTexCoordP1ui glad_glTexCoordP1ui -typedef void (APIENTRYP PFNGLTEXCOORDP1UIVPROC)(GLenum type, const GLuint *coords); -GLAPI PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv; -#define glTexCoordP1uiv glad_glTexCoordP1uiv -typedef void (APIENTRYP PFNGLTEXCOORDP2UIPROC)(GLenum type, GLuint coords); -GLAPI PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui; -#define glTexCoordP2ui glad_glTexCoordP2ui -typedef void (APIENTRYP PFNGLTEXCOORDP2UIVPROC)(GLenum type, const GLuint *coords); -GLAPI PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv; -#define glTexCoordP2uiv glad_glTexCoordP2uiv -typedef void (APIENTRYP PFNGLTEXCOORDP3UIPROC)(GLenum type, GLuint coords); -GLAPI PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui; -#define glTexCoordP3ui glad_glTexCoordP3ui -typedef void (APIENTRYP PFNGLTEXCOORDP3UIVPROC)(GLenum type, const GLuint *coords); -GLAPI PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv; -#define glTexCoordP3uiv glad_glTexCoordP3uiv -typedef void (APIENTRYP PFNGLTEXCOORDP4UIPROC)(GLenum type, GLuint coords); -GLAPI PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui; -#define glTexCoordP4ui glad_glTexCoordP4ui -typedef void (APIENTRYP PFNGLTEXCOORDP4UIVPROC)(GLenum type, const GLuint *coords); -GLAPI PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv; -#define glTexCoordP4uiv glad_glTexCoordP4uiv -typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIPROC)(GLenum texture, GLenum type, GLuint coords); -GLAPI PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui; -#define glMultiTexCoordP1ui glad_glMultiTexCoordP1ui -typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIVPROC)(GLenum texture, GLenum type, const GLuint *coords); -GLAPI PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv; -#define glMultiTexCoordP1uiv glad_glMultiTexCoordP1uiv -typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIPROC)(GLenum texture, GLenum type, GLuint coords); -GLAPI PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui; -#define glMultiTexCoordP2ui glad_glMultiTexCoordP2ui -typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIVPROC)(GLenum texture, GLenum type, const GLuint *coords); -GLAPI PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv; -#define glMultiTexCoordP2uiv glad_glMultiTexCoordP2uiv -typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIPROC)(GLenum texture, GLenum type, GLuint coords); -GLAPI PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui; -#define glMultiTexCoordP3ui glad_glMultiTexCoordP3ui -typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIVPROC)(GLenum texture, GLenum type, const GLuint *coords); -GLAPI PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv; -#define glMultiTexCoordP3uiv glad_glMultiTexCoordP3uiv -typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIPROC)(GLenum texture, GLenum type, GLuint coords); -GLAPI PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui; -#define glMultiTexCoordP4ui glad_glMultiTexCoordP4ui -typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIVPROC)(GLenum texture, GLenum type, const GLuint *coords); -GLAPI PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv; -#define glMultiTexCoordP4uiv glad_glMultiTexCoordP4uiv -typedef void (APIENTRYP PFNGLNORMALP3UIPROC)(GLenum type, GLuint coords); -GLAPI PFNGLNORMALP3UIPROC glad_glNormalP3ui; -#define glNormalP3ui glad_glNormalP3ui -typedef void (APIENTRYP PFNGLNORMALP3UIVPROC)(GLenum type, const GLuint *coords); -GLAPI PFNGLNORMALP3UIVPROC glad_glNormalP3uiv; -#define glNormalP3uiv glad_glNormalP3uiv -typedef void (APIENTRYP PFNGLCOLORP3UIPROC)(GLenum type, GLuint color); -GLAPI PFNGLCOLORP3UIPROC glad_glColorP3ui; -#define glColorP3ui glad_glColorP3ui -typedef void (APIENTRYP PFNGLCOLORP3UIVPROC)(GLenum type, const GLuint *color); -GLAPI PFNGLCOLORP3UIVPROC glad_glColorP3uiv; -#define glColorP3uiv glad_glColorP3uiv -typedef void (APIENTRYP PFNGLCOLORP4UIPROC)(GLenum type, GLuint color); -GLAPI PFNGLCOLORP4UIPROC glad_glColorP4ui; -#define glColorP4ui glad_glColorP4ui -typedef void (APIENTRYP PFNGLCOLORP4UIVPROC)(GLenum type, const GLuint *color); -GLAPI PFNGLCOLORP4UIVPROC glad_glColorP4uiv; -#define glColorP4uiv glad_glColorP4uiv -typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIPROC)(GLenum type, GLuint color); -GLAPI PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui; -#define glSecondaryColorP3ui glad_glSecondaryColorP3ui -typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC)(GLenum type, const GLuint *color); -GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv; -#define glSecondaryColorP3uiv glad_glSecondaryColorP3uiv -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/subprojects/nk_pugl/pugl/examples/glad/khrplatform.h b/subprojects/nk_pugl/pugl/examples/glad/khrplatform.h deleted file mode 100644 index 5b55ea2..0000000 --- a/subprojects/nk_pugl/pugl/examples/glad/khrplatform.h +++ /dev/null @@ -1,290 +0,0 @@ -#ifndef __khrplatform_h_ -#define __khrplatform_h_ - -/* -** Copyright (c) 2008-2018 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -*/ - -/* Khronos platform-specific types and definitions. - * - * The master copy of khrplatform.h is maintained in the Khronos EGL - * Registry repository at https://github.com/KhronosGroup/EGL-Registry - * The last semantic modification to khrplatform.h was at commit ID: - * 67a3e0864c2d75ea5287b9f3d2eb74a745936692 - * - * Adopters may modify this file to suit their platform. Adopters are - * encouraged to submit platform specific modifications to the Khronos - * group so that they can be included in future versions of this file. - * Please submit changes by filing pull requests or issues on - * the EGL Registry repository linked above. - * - * - * See the Implementer's Guidelines for information about where this file - * should be located on your system and for more details of its use: - * http://www.khronos.org/registry/implementers_guide.pdf - * - * This file should be included as - * #include - * by Khronos client API header files that use its types and defines. - * - * The types in khrplatform.h should only be used to define API-specific types. - * - * Types defined in khrplatform.h: - * khronos_int8_t signed 8 bit - * khronos_uint8_t unsigned 8 bit - * khronos_int16_t signed 16 bit - * khronos_uint16_t unsigned 16 bit - * khronos_int32_t signed 32 bit - * khronos_uint32_t unsigned 32 bit - * khronos_int64_t signed 64 bit - * khronos_uint64_t unsigned 64 bit - * khronos_intptr_t signed same number of bits as a pointer - * khronos_uintptr_t unsigned same number of bits as a pointer - * khronos_ssize_t signed size - * khronos_usize_t unsigned size - * khronos_float_t signed 32 bit floating point - * khronos_time_ns_t unsigned 64 bit time in nanoseconds - * khronos_utime_nanoseconds_t unsigned time interval or absolute time in - * nanoseconds - * khronos_stime_nanoseconds_t signed time interval in nanoseconds - * khronos_boolean_enum_t enumerated boolean type. This should - * only be used as a base type when a client API's boolean type is - * an enum. Client APIs which use an integer or other type for - * booleans cannot use this as the base type for their boolean. - * - * Tokens defined in khrplatform.h: - * - * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. - * - * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. - * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. - * - * Calling convention macros defined in this file: - * KHRONOS_APICALL - * KHRONOS_APIENTRY - * KHRONOS_APIATTRIBUTES - * - * These may be used in function prototypes as: - * - * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( - * int arg1, - * int arg2) KHRONOS_APIATTRIBUTES; - */ - -#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC) -# define KHRONOS_STATIC 1 -#endif - -/*------------------------------------------------------------------------- - * Definition of KHRONOS_APICALL - *------------------------------------------------------------------------- - * This precedes the return type of the function in the function prototype. - */ -#if defined(KHRONOS_STATIC) - /* If the preprocessor constant KHRONOS_STATIC is defined, make the - * header compatible with static linking. */ -# define KHRONOS_APICALL -#elif defined(_WIN32) -# define KHRONOS_APICALL __declspec(dllimport) -#elif defined (__SYMBIAN32__) -# define KHRONOS_APICALL IMPORT_C -#elif defined(__ANDROID__) -# define KHRONOS_APICALL __attribute__((visibility("default"))) -#else -# define KHRONOS_APICALL -#endif - -/*------------------------------------------------------------------------- - * Definition of KHRONOS_APIENTRY - *------------------------------------------------------------------------- - * This follows the return type of the function and precedes the function - * name in the function prototype. - */ -#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(KHRONOS_STATIC) - /* Win32 but not WinCE */ -# define KHRONOS_APIENTRY __stdcall -#else -# define KHRONOS_APIENTRY -#endif - -/*------------------------------------------------------------------------- - * Definition of KHRONOS_APIATTRIBUTES - *------------------------------------------------------------------------- - * This follows the closing parenthesis of the function prototype arguments. - */ -#if defined (__ARMCC_2__) -#define KHRONOS_APIATTRIBUTES __softfp -#else -#define KHRONOS_APIATTRIBUTES -#endif - -/*------------------------------------------------------------------------- - * basic type definitions - *-----------------------------------------------------------------------*/ -#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) - - -/* - * Using - */ -#include -typedef int32_t khronos_int32_t; -typedef uint32_t khronos_uint32_t; -typedef int64_t khronos_int64_t; -typedef uint64_t khronos_uint64_t; -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#elif defined(__VMS ) || defined(__sgi) - -/* - * Using - */ -#include -typedef int32_t khronos_int32_t; -typedef uint32_t khronos_uint32_t; -typedef int64_t khronos_int64_t; -typedef uint64_t khronos_uint64_t; -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) - -/* - * Win32 - */ -typedef __int32 khronos_int32_t; -typedef unsigned __int32 khronos_uint32_t; -typedef __int64 khronos_int64_t; -typedef unsigned __int64 khronos_uint64_t; -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#elif defined(__sun__) || defined(__digital__) - -/* - * Sun or Digital - */ -typedef int khronos_int32_t; -typedef unsigned int khronos_uint32_t; -#if defined(__arch64__) || defined(_LP64) -typedef long int khronos_int64_t; -typedef unsigned long int khronos_uint64_t; -#else -typedef long long int khronos_int64_t; -typedef unsigned long long int khronos_uint64_t; -#endif /* __arch64__ */ -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#elif 0 - -/* - * Hypothetical platform with no float or int64 support - */ -typedef int khronos_int32_t; -typedef unsigned int khronos_uint32_t; -#define KHRONOS_SUPPORT_INT64 0 -#define KHRONOS_SUPPORT_FLOAT 0 - -#else - -/* - * Generic fallback - */ -#include -typedef int32_t khronos_int32_t; -typedef uint32_t khronos_uint32_t; -typedef int64_t khronos_int64_t; -typedef uint64_t khronos_uint64_t; -#define KHRONOS_SUPPORT_INT64 1 -#define KHRONOS_SUPPORT_FLOAT 1 - -#endif - - -/* - * Types that are (so far) the same on all platforms - */ -typedef signed char khronos_int8_t; -typedef unsigned char khronos_uint8_t; -typedef signed short int khronos_int16_t; -typedef unsigned short int khronos_uint16_t; - -/* - * Types that differ between LLP64 and LP64 architectures - in LLP64, - * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears - * to be the only LLP64 architecture in current use. - */ -#ifdef _WIN64 -typedef signed long long int khronos_intptr_t; -typedef unsigned long long int khronos_uintptr_t; -typedef signed long long int khronos_ssize_t; -typedef unsigned long long int khronos_usize_t; -#else -typedef signed long int khronos_intptr_t; -typedef unsigned long int khronos_uintptr_t; -typedef signed long int khronos_ssize_t; -typedef unsigned long int khronos_usize_t; -#endif - -#if KHRONOS_SUPPORT_FLOAT -/* - * Float type - */ -typedef float khronos_float_t; -#endif - -#if KHRONOS_SUPPORT_INT64 -/* Time types - * - * These types can be used to represent a time interval in nanoseconds or - * an absolute Unadjusted System Time. Unadjusted System Time is the number - * of nanoseconds since some arbitrary system event (e.g. since the last - * time the system booted). The Unadjusted System Time is an unsigned - * 64 bit value that wraps back to 0 every 584 years. Time intervals - * may be either signed or unsigned. - */ -typedef khronos_uint64_t khronos_utime_nanoseconds_t; -typedef khronos_int64_t khronos_stime_nanoseconds_t; -#endif - -/* - * Dummy value used to pad enum types to 32 bits. - */ -#ifndef KHRONOS_MAX_ENUM -#define KHRONOS_MAX_ENUM 0x7FFFFFFF -#endif - -/* - * Enumerated boolean type - * - * Values other than zero should be considered to be true. Therefore - * comparisons should not be made against KHRONOS_TRUE. - */ -typedef enum { - KHRONOS_FALSE = 0, - KHRONOS_TRUE = 1, - KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM -} khronos_boolean_enum_t; - -#endif /* __khrplatform_h_ */ diff --git a/subprojects/nk_pugl/pugl/examples/meson.build b/subprojects/nk_pugl/pugl/examples/meson.build deleted file mode 100644 index d455faf..0000000 --- a/subprojects/nk_pugl/pugl/examples/meson.build +++ /dev/null @@ -1,80 +0,0 @@ -data_dir = get_option('prefix') / get_option('datadir') / 'pugl-0' -example_args = ['-DPUGL_DATA_DIR="@0@"'.format(data_dir)] - -gl_examples = [ - 'pugl_cxx_demo.cpp', - 'pugl_embed_demo.c', - 'pugl_print_events.c', - 'pugl_shader_demo.c', - 'pugl_window_demo.c', -] - -cairo_examples = [ - 'pugl_cairo_demo.c' -] - -vulkan_examples = [ - 'pugl_vulkan_cxx_demo.cpp', - 'pugl_vulkan_demo.c', -] - -includes = [ - '.', - '..', - '../bindings/cxx/include', - '../include', -] - -subdir('shaders') - -# Build GL examples -if opengl_dep.found() - foreach example : gl_examples - source = [example] - target = example.split('.')[0] - dependencies = [gl_backend_dep] - - if target == 'pugl_shader_demo' - source += ['file_utils.c', 'glad/glad.c'] - dependencies += [dl_dep] - elif target == 'pugl_print_events' - dependencies += [stub_backend_dep] - endif - - executable(target, source, - include_directories: include_directories(includes), - c_args: example_args, - cpp_args: example_args, - dependencies: dependencies) - endforeach -endif - -# Build Cairo examples -if cairo_dep.found() - foreach example : cairo_examples - target = example.split('.')[0] - executable(target, example, - include_directories: include_directories(includes), - c_args: example_args, - dependencies: [pugl_dep, cairo_backend_dep]) - endforeach -endif - -# Build Vulkan examples -if vulkan_dep.found() - foreach example : vulkan_examples - source = [example] - target = example.split('.')[0] - dependencies = [dl_dep, vulkan_backend_dep] - - if target == 'pugl_vulkan_cxx_demo' - source += ['file_utils.c'] - endif - - executable(target, source, - include_directories: include_directories(includes), - c_args: example_args, - cpp_args: example_args, - dependencies: dependencies) - endforeach -endif diff --git a/subprojects/nk_pugl/pugl/examples/pugl_cairo_demo.c b/subprojects/nk_pugl/pugl/examples/pugl_cairo_demo.c deleted file mode 100644 index 67bc13c..0000000 --- a/subprojects/nk_pugl/pugl/examples/pugl_cairo_demo.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "demo_utils.h" -#include "test/test_utils.h" - -#include "pugl/cairo.h" -#include "pugl/pugl.h" - -#include - -#include -#include -#include -#include - -typedef struct { - PuglWorld* world; - PuglTestOptions opts; - unsigned framesDrawn; - int quit; - bool entered; - bool mouseDown; -} PuglTestApp; - -typedef struct { - int x; - int y; - int w; - int h; - const char* label; -} Button; - -static const Button buttons[] = {{128, 128, 64, 64, "1"}, - {384, 128, 64, 64, "2"}, - {128, 384, 64, 64, "3"}, - {384, 384, 64, 64, "4"}, - {0, 0, 0, 0, NULL}}; - -static void -roundedBox(cairo_t* cr, double x, double y, double w, double h) -{ - static const double radius = 10; - static const double degrees = 3.14159265 / 180.0; - - cairo_new_sub_path(cr); - cairo_arc(cr, x + w - radius, y + radius, radius, -90 * degrees, 0 * degrees); - - cairo_arc( - cr, x + w - radius, y + h - radius, radius, 0 * degrees, 90 * degrees); - - cairo_arc( - cr, x + radius, y + h - radius, radius, 90 * degrees, 180 * degrees); - - cairo_arc(cr, x + radius, y + radius, radius, 180 * degrees, 270 * degrees); - cairo_close_path(cr); -} - -static void -buttonDraw(PuglTestApp* app, cairo_t* cr, const Button* but, const double time) -{ - cairo_save(cr); - cairo_translate(cr, but->x, but->y); - cairo_rotate(cr, sin(time) * 3.141592); - - // Draw base - if (app->mouseDown) { - cairo_set_source_rgba(cr, 0.4, 0.9, 0.1, 1); - } else { - cairo_set_source_rgba(cr, 0.3, 0.5, 0.1, 1); - } - roundedBox(cr, 0, 0, but->w, but->h); - cairo_fill_preserve(cr); - - // Draw border - cairo_set_source_rgba(cr, 0.4, 0.9, 0.1, 1); - cairo_set_line_width(cr, 4.0); - cairo_stroke(cr); - - // Draw label - cairo_text_extents_t extents; - cairo_set_font_size(cr, 32.0); - cairo_text_extents(cr, but->label, &extents); - cairo_move_to(cr, - (but->w / 2.0) - extents.width / 2, - (but->h / 2.0) + extents.height / 2); - cairo_set_source_rgba(cr, 0, 0, 0, 1); - cairo_show_text(cr, but->label); - - cairo_restore(cr); -} - -static void -postButtonRedisplay(PuglView* view) -{ - const PuglRect frame = puglGetFrame(view); - const double width = frame.width; - const double height = frame.height; - const double scaleX = (width - (512 / width)) / 512.0; - const double scaleY = (height - (512 / height)) / 512.0; - - for (const Button* b = buttons; b->label; ++b) { - const double span = sqrt(b->w * b->w + b->h * b->h); - const PuglRect rect = {(b->x - span) * scaleX, - (b->y - span) * scaleY, - span * 2.0 * scaleX, - span * 2.0 * scaleY}; - - puglPostRedisplayRect(view, rect); - } -} - -static void -onDisplay(PuglTestApp* app, PuglView* view, const PuglEventExpose* event) -{ - cairo_t* cr = (cairo_t*)puglGetContext(view); - - cairo_rectangle(cr, event->x, event->y, event->width, event->height); - cairo_clip_preserve(cr); - - // Draw background - const PuglRect frame = puglGetFrame(view); - const double width = frame.width; - const double height = frame.height; - if (app->entered) { - cairo_set_source_rgb(cr, 0.1, 0.1, 0.1); - } else { - cairo_set_source_rgb(cr, 0, 0, 0); - } - cairo_fill(cr); - - // Scale to view size - const double scaleX = (width - (512 / width)) / 512.0; - const double scaleY = (height - (512 / height)) / 512.0; - cairo_scale(cr, scaleX, scaleY); - - // Draw button - for (const Button* b = buttons; b->label; ++b) { - buttonDraw( - app, cr, b, app->opts.continuous ? puglGetTime(app->world) : 0.0); - } - - ++app->framesDrawn; -} - -static void -onClose(PuglView* view) -{ - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - - app->quit = 1; -} - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - - printEvent(event, "Event: ", app->opts.verbose); - - switch (event->type) { - case PUGL_KEY_PRESS: - if (event->key.key == 'q' || event->key.key == PUGL_KEY_ESCAPE) { - app->quit = 1; - } - break; - case PUGL_BUTTON_PRESS: - app->mouseDown = true; - postButtonRedisplay(view); - break; - case PUGL_BUTTON_RELEASE: - app->mouseDown = false; - postButtonRedisplay(view); - break; - case PUGL_POINTER_IN: - app->entered = true; - puglPostRedisplay(view); - break; - case PUGL_POINTER_OUT: - app->entered = false; - puglPostRedisplay(view); - break; - case PUGL_UPDATE: - if (app->opts.continuous) { - puglPostRedisplay(view); - } - break; - case PUGL_EXPOSE: - onDisplay(app, view, &event->expose); - break; - case PUGL_CLOSE: - onClose(view); - break; - default: - break; - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - PuglTestApp app; - memset(&app, 0, sizeof(app)); - - app.opts = puglParseTestOptions(&argc, &argv); - if (app.opts.help) { - puglPrintTestUsage("pugl_test", ""); - return 1; - } - - app.world = puglNewWorld(PUGL_PROGRAM, 0); - puglSetClassName(app.world, "PuglCairoTest"); - - PuglView* view = puglNewView(app.world); - - puglSetWindowTitle(view, "Pugl Cairo Demo"); - puglSetDefaultSize(view, 512, 512); - puglSetMinSize(view, 256, 256); - puglSetMaxSize(view, 2048, 2048); - puglSetViewHint(view, PUGL_RESIZABLE, app.opts.resizable); - puglSetHandle(view, &app); - puglSetBackend(view, puglCairoBackend()); - puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, app.opts.ignoreKeyRepeat); - puglSetEventFunc(view, onEvent); - - PuglStatus st = puglRealize(view); - if (st) { - return logError("Failed to create window (%s)\n", puglStrerror(st)); - } - - puglShow(view); - - PuglFpsPrinter fpsPrinter = {puglGetTime(app.world)}; - const double timeout = app.opts.continuous ? (1 / 60.0) : -1.0; - while (!app.quit) { - puglUpdate(app.world, timeout); - - if (app.opts.continuous) { - puglPrintFps(app.world, &fpsPrinter, &app.framesDrawn); - } - } - - puglFreeView(view); - puglFreeWorld(app.world); - return 0; -} diff --git a/subprojects/nk_pugl/pugl/examples/pugl_cursor_demo.c b/subprojects/nk_pugl/pugl/examples/pugl_cursor_demo.c deleted file mode 100644 index 97e3b9f..0000000 --- a/subprojects/nk_pugl/pugl/examples/pugl_cursor_demo.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "test/test_utils.h" - -#include "pugl/gl.h" -#include "pugl/pugl.h" - -#include - -static const int N_CURSORS = 7; -static const int N_ROWS = 2; -static const int N_COLS = 4; - -typedef struct { - PuglWorld* world; - PuglTestOptions opts; - bool quit; -} PuglTestApp; - -static void -onConfigure(const double width, const double height) -{ - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - glClearColor(0.2f, 0.2f, 0.2f, 1.0f); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glViewport(0, 0, (int)width, (int)height); -} - -static void -onExpose(void) -{ - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glColor3f(0.6f, 0.6f, 0.6f); - - for (int row = 1; row < N_ROWS; ++row) { - const float y = (float)row * (2.0f / (float)N_ROWS) - 1.0f; - glBegin(GL_LINES); - glVertex2f(-1.0f, y); - glVertex2f(1.0f, y); - glEnd(); - } - - for (int col = 1; col < N_COLS; ++col) { - const float x = (float)col * (2.0f / (float)N_COLS) - 1.0f; - glBegin(GL_LINES); - glVertex2f(x, -1.0f); - glVertex2f(x, 1.0f); - glEnd(); - } -} - -static void -onMotion(PuglView* view, double x, double y) -{ - const PuglRect frame = puglGetFrame(view); - int row = (int)(y * N_ROWS / frame.height); - int col = (int)(x * N_COLS / frame.width); - - row = (row < 0) ? 0 : (row >= N_ROWS) ? (N_ROWS - 1) : row; - col = (col < 0) ? 0 : (col >= N_COLS) ? (N_COLS - 1) : col; - - const PuglCursor cursor = (PuglCursor)((row * N_COLS + col) % N_CURSORS); - puglSetCursor(view, cursor); -} - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - - printEvent(event, "Event: ", app->opts.verbose); - - switch (event->type) { - case PUGL_CONFIGURE: - onConfigure(event->configure.width, event->configure.height); - break; - case PUGL_KEY_PRESS: - if (event->key.key == 'q' || event->key.key == PUGL_KEY_ESCAPE) { - app->quit = 1; - } - break; - case PUGL_MOTION: - onMotion(view, event->motion.x, event->motion.y); - break; - case PUGL_EXPOSE: - onExpose(); - break; - case PUGL_POINTER_OUT: - puglSetCursor(view, PUGL_CURSOR_ARROW); - break; - case PUGL_CLOSE: - app->quit = 1; - break; - default: - break; - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - PuglTestApp app = {0}; - - app.opts = puglParseTestOptions(&argc, &argv); - if (app.opts.help) { - puglPrintTestUsage(argv[0], ""); - return 1; - } - - app.world = puglNewWorld(PUGL_PROGRAM, 0); - - puglSetWorldHandle(app.world, &app); - puglSetClassName(app.world, "Pugl Test"); - - PuglView* view = puglNewView(app.world); - - puglSetWindowTitle(view, "Pugl Window Demo"); - puglSetDefaultSize(view, 512, 256); - puglSetMinSize(view, 128, 64); - puglSetMaxSize(view, 512, 256); - puglSetBackend(view, puglGlBackend()); - - puglSetViewHint(view, PUGL_USE_DEBUG_CONTEXT, app.opts.errorChecking); - puglSetViewHint(view, PUGL_RESIZABLE, app.opts.resizable); - puglSetViewHint(view, PUGL_SAMPLES, app.opts.samples); - puglSetViewHint(view, PUGL_DOUBLE_BUFFER, app.opts.doubleBuffer); - puglSetViewHint(view, PUGL_SWAP_INTERVAL, app.opts.sync); - puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, app.opts.ignoreKeyRepeat); - puglSetHandle(view, &app); - puglSetEventFunc(view, onEvent); - - const PuglStatus st = puglRealize(view); - if (st) { - return logError("Failed to create window (%s)\n", puglStrerror(st)); - } - - puglShow(view); - - while (!app.quit) { - puglUpdate(app.world, -1.0); - } - - puglFreeView(view); - puglFreeWorld(app.world); - - return 0; -} diff --git a/subprojects/nk_pugl/pugl/examples/pugl_cxx_demo.cpp b/subprojects/nk_pugl/pugl/examples/pugl_cxx_demo.cpp deleted file mode 100644 index d663a3f..0000000 --- a/subprojects/nk_pugl/pugl/examples/pugl_cxx_demo.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "cube_view.h" -#include "demo_utils.h" -#include "test/test_utils.h" - -#include "pugl/gl.hpp" -#include "pugl/pugl.h" -#include "pugl/pugl.hpp" - -#include - -class CubeView : public pugl::View -{ -public: - explicit CubeView(pugl::World& world) - : pugl::View{world} - { - setEventHandler(*this); - } - - template - pugl::Status onEvent(const pugl::Event&) noexcept - { - return pugl::Status::success; - } - - static pugl::Status onEvent(const pugl::ConfigureEvent& event) noexcept; - pugl::Status onEvent(const pugl::UpdateEvent& event) noexcept; - pugl::Status onEvent(const pugl::ExposeEvent& event) noexcept; - pugl::Status onEvent(const pugl::KeyPressEvent& event) noexcept; - pugl::Status onEvent(const pugl::CloseEvent& event) noexcept; - - bool quit() const { return _quit; } - -private: - double _xAngle{0.0}; - double _yAngle{0.0}; - double _lastDrawTime{0.0}; - bool _quit{false}; -}; - -pugl::Status -CubeView::onEvent(const pugl::ConfigureEvent& event) noexcept -{ - reshapeCube(static_cast(event.width), - static_cast(event.height)); - - return pugl::Status::success; -} - -pugl::Status -CubeView::onEvent(const pugl::UpdateEvent&) noexcept -{ - return postRedisplay(); -} - -pugl::Status -CubeView::onEvent(const pugl::ExposeEvent&) noexcept -{ - const double thisTime = world().time(); - const double dTime = thisTime - _lastDrawTime; - const double dAngle = dTime * 100.0; - - _xAngle = fmod(_xAngle + dAngle, 360.0); - _yAngle = fmod(_yAngle + dAngle, 360.0); - displayCube(cobj(), - 8.0f, - static_cast(_xAngle), - static_cast(_yAngle), - false); - - _lastDrawTime = thisTime; - - return pugl::Status::success; -} - -pugl::Status -CubeView::onEvent(const pugl::KeyPressEvent& event) noexcept -{ - if (event.key == PUGL_KEY_ESCAPE || event.key == 'q') { - _quit = true; - } - - return pugl::Status::success; -} - -pugl::Status -CubeView::onEvent(const pugl::CloseEvent&) noexcept -{ - _quit = true; - - return pugl::Status::success; -} - -int -main(int argc, char** argv) -{ - const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); - if (opts.help) { - puglPrintTestUsage("pugl_cxx_demo", ""); - return 1; - } - - pugl::World world{pugl::WorldType::program}; - CubeView view{world}; - PuglFpsPrinter fpsPrinter{}; - - world.setClassName("PuglCppTest"); - - view.setWindowTitle("Pugl C++ Test"); - view.setDefaultSize(512, 512); - view.setMinSize(64, 64); - view.setMaxSize(256, 256); - view.setAspectRatio(1, 1, 16, 9); - view.setBackend(pugl::glBackend()); - view.setHint(pugl::ViewHint::resizable, opts.resizable); - view.setHint(pugl::ViewHint::samples, opts.samples); - view.setHint(pugl::ViewHint::doubleBuffer, opts.doubleBuffer); - view.setHint(pugl::ViewHint::swapInterval, opts.sync); - view.setHint(pugl::ViewHint::ignoreKeyRepeat, opts.ignoreKeyRepeat); - view.realize(); - view.show(); - - unsigned framesDrawn = 0; - while (!view.quit()) { - world.update(0.0); - - ++framesDrawn; - puglPrintFps(world.cobj(), &fpsPrinter, &framesDrawn); - } - - return 0; -} diff --git a/subprojects/nk_pugl/pugl/examples/pugl_embed_demo.c b/subprojects/nk_pugl/pugl/examples/pugl_embed_demo.c deleted file mode 100644 index 0e12ddb..0000000 --- a/subprojects/nk_pugl/pugl/examples/pugl_embed_demo.c +++ /dev/null @@ -1,354 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "cube_view.h" -#include "demo_utils.h" -#include "test/test_utils.h" - -#include "pugl/gl.h" -#include "pugl/pugl.h" - -#include -#include -#include -#include -#include - -static const int borderWidth = 64; -static const uintptr_t reverseTimerId = 1u; - -typedef struct { - PuglWorld* world; - PuglView* parent; - PuglView* child; - double xAngle; - double yAngle; - double lastMouseX; - double lastMouseY; - double lastDrawTime; - float dist; - int quit; - bool continuous; - bool mouseEntered; - bool verbose; - bool reversing; -} PuglTestApp; - -// clang-format off -static const float backgroundVertices[] = { - -1.0f, 1.0f, -1.0f, // Top left - 1.0f, 1.0f, -1.0f, // Top right - -1.0f, -1.0f, -1.0f, // Bottom left - 1.0f, -1.0f, -1.0f, // Bottom right -}; -// clang-format on - -static PuglRect -getChildFrame(const PuglRect parentFrame) -{ - const PuglRect childFrame = {borderWidth, - borderWidth, - parentFrame.width - 2 * borderWidth, - parentFrame.height - 2 * borderWidth}; - - return childFrame; -} - -static void -onDisplay(PuglView* view) -{ - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - - const double thisTime = puglGetTime(app->world); - if (app->continuous) { - const double dTime = - (thisTime - app->lastDrawTime) * (app->reversing ? -1.0 : 1.0); - - app->xAngle = fmod(app->xAngle + dTime * 100.0, 360.0); - app->yAngle = fmod(app->yAngle + dTime * 100.0, 360.0); - } - - displayCube( - view, app->dist, (float)app->xAngle, (float)app->yAngle, app->mouseEntered); - - app->lastDrawTime = thisTime; -} - -static void -swapFocus(PuglTestApp* app) -{ - if (puglHasFocus(app->parent)) { - puglGrabFocus(app->child); - } else { - puglGrabFocus(app->parent); - } - - if (!app->continuous) { - puglPostRedisplay(app->parent); - puglPostRedisplay(app->child); - } -} - -static void -onKeyPress(PuglView* view, const PuglEventKey* event, const char* prefix) -{ - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - PuglRect frame = puglGetFrame(view); - - if (event->key == '\t') { - swapFocus(app); - } else if (event->key == 'q' || event->key == PUGL_KEY_ESCAPE) { - app->quit = 1; - } else if (event->state & PUGL_MOD_CTRL && event->key == 'c') { - puglSetClipboard(view, NULL, "Pugl test", strlen("Pugl test") + 1); - fprintf(stderr, "%sCopy \"Pugl test\"\n", prefix); - } else if (event->state & PUGL_MOD_CTRL && event->key == 'v') { - const char* type = NULL; - size_t len = 0; - const char* text = (const char*)puglGetClipboard(view, &type, &len); - fprintf(stderr, "%sPaste \"%s\"\n", prefix, text); - } else if (event->state & PUGL_MOD_SHIFT) { - if (event->key == PUGL_KEY_UP) { - frame.height += 10; - } else if (event->key == PUGL_KEY_DOWN) { - frame.height -= 10; - } else if (event->key == PUGL_KEY_LEFT) { - frame.width -= 10; - } else if (event->key == PUGL_KEY_RIGHT) { - frame.width += 10; - } else { - return; - } - puglSetFrame(view, frame); - } else { - if (event->key == PUGL_KEY_UP) { - frame.y -= 10; - } else if (event->key == PUGL_KEY_DOWN) { - frame.y += 10; - } else if (event->key == PUGL_KEY_LEFT) { - frame.x -= 10; - } else if (event->key == PUGL_KEY_RIGHT) { - frame.x += 10; - } else { - return; - } - puglSetFrame(view, frame); - } -} - -static PuglStatus -onParentEvent(PuglView* view, const PuglEvent* event) -{ - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - const PuglRect parentFrame = puglGetFrame(view); - - printEvent(event, "Parent: ", app->verbose); - - switch (event->type) { - case PUGL_CONFIGURE: - reshapeCube((float)event->configure.width, (float)event->configure.height); - - puglSetFrame(app->child, getChildFrame(parentFrame)); - break; - case PUGL_UPDATE: - if (app->continuous) { - puglPostRedisplay(view); - } - break; - case PUGL_EXPOSE: - if (puglHasFocus(app->parent)) { - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, backgroundVertices); - glColorPointer(3, GL_FLOAT, 0, backgroundVertices); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - } else { - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - break; - case PUGL_KEY_PRESS: - onKeyPress(view, &event->key, "Parent: "); - break; - case PUGL_MOTION: - break; - case PUGL_CLOSE: - app->quit = 1; - break; - default: - break; - } - - return PUGL_SUCCESS; -} - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - - printEvent(event, "Child: ", app->verbose); - - switch (event->type) { - case PUGL_CONFIGURE: - reshapeCube((float)event->configure.width, (float)event->configure.height); - break; - case PUGL_UPDATE: - if (app->continuous) { - puglPostRedisplay(view); - } - break; - case PUGL_EXPOSE: - onDisplay(view); - break; - case PUGL_CLOSE: - app->quit = 1; - break; - case PUGL_KEY_PRESS: - onKeyPress(view, &event->key, "Child: "); - break; - case PUGL_MOTION: - app->xAngle -= event->motion.x - app->lastMouseX; - app->yAngle += event->motion.y - app->lastMouseY; - app->lastMouseX = event->motion.x; - app->lastMouseY = event->motion.y; - if (!app->continuous) { - puglPostRedisplay(view); - puglPostRedisplay(app->parent); - } - break; - case PUGL_SCROLL: - app->dist = fmaxf(10.0f, app->dist + (float)event->scroll.dy); - if (!app->continuous) { - puglPostRedisplay(view); - } - break; - case PUGL_POINTER_IN: - app->mouseEntered = true; - break; - case PUGL_POINTER_OUT: - app->mouseEntered = false; - break; - case PUGL_TIMER: - app->reversing = !app->reversing; - break; - default: - break; - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - PuglTestApp app = {0}; - - app.dist = 10; - - const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); - if (opts.help) { - puglPrintTestUsage("pugl_test", ""); - return 1; - } - - app.continuous = opts.continuous; - app.verbose = opts.verbose; - - app.world = puglNewWorld(PUGL_PROGRAM, 0); - app.parent = puglNewView(app.world); - app.child = puglNewView(app.world); - - puglSetClassName(app.world, "Pugl Test"); - - const PuglRect parentFrame = {0, 0, 512, 512}; - puglSetDefaultSize(app.parent, 512, 512); - puglSetMinSize(app.parent, borderWidth * 3, borderWidth * 3); - puglSetMaxSize(app.parent, 1024, 1024); - puglSetAspectRatio(app.parent, 1, 1, 16, 9); - puglSetBackend(app.parent, puglGlBackend()); - - puglSetViewHint(app.parent, PUGL_USE_DEBUG_CONTEXT, opts.errorChecking); - puglSetViewHint(app.parent, PUGL_RESIZABLE, opts.resizable); - puglSetViewHint(app.parent, PUGL_SAMPLES, opts.samples); - puglSetViewHint(app.parent, PUGL_DOUBLE_BUFFER, opts.doubleBuffer); - puglSetViewHint(app.parent, PUGL_SWAP_INTERVAL, opts.sync); - puglSetViewHint(app.parent, PUGL_IGNORE_KEY_REPEAT, opts.ignoreKeyRepeat); - puglSetHandle(app.parent, &app); - puglSetEventFunc(app.parent, onParentEvent); - - PuglStatus st = PUGL_SUCCESS; - const uint8_t title[] = { - 'P', 'u', 'g', 'l', ' ', 'P', 'r', 0xC3, 0xBC, 'f', 'u', 'n', 'g', 0}; - - puglSetWindowTitle(app.parent, (const char*)title); - - if ((st = puglRealize(app.parent))) { - return logError("Failed to create parent window (%s)\n", puglStrerror(st)); - } - - puglSetFrame(app.child, getChildFrame(parentFrame)); - puglSetParentWindow(app.child, puglGetNativeWindow(app.parent)); - - puglSetViewHint(app.child, PUGL_USE_DEBUG_CONTEXT, opts.errorChecking); - puglSetViewHint(app.child, PUGL_SAMPLES, opts.samples); - puglSetViewHint(app.child, PUGL_DOUBLE_BUFFER, opts.doubleBuffer); - puglSetViewHint(app.child, PUGL_SWAP_INTERVAL, opts.sync); - puglSetBackend(app.child, puglGlBackend()); - puglSetViewHint(app.child, PUGL_IGNORE_KEY_REPEAT, opts.ignoreKeyRepeat); - puglSetHandle(app.child, &app); - puglSetEventFunc(app.child, onEvent); - - if ((st = puglRealize(app.child))) { - return logError("Failed to create child window (%s)\n", puglStrerror(st)); - } - - puglShow(app.parent); - puglShow(app.child); - - puglStartTimer(app.child, reverseTimerId, 3.6); - - PuglFpsPrinter fpsPrinter = {puglGetTime(app.world)}; - unsigned framesDrawn = 0; - bool requestedAttention = false; - while (!app.quit) { - const double thisTime = puglGetTime(app.world); - - puglUpdate(app.world, app.continuous ? 0.0 : -1.0); - ++framesDrawn; - - if (!requestedAttention && thisTime > 5.0) { - puglRequestAttention(app.parent); - requestedAttention = true; - } - - if (app.continuous) { - puglPrintFps(app.world, &fpsPrinter, &framesDrawn); - } - } - - puglFreeView(app.child); - puglFreeView(app.parent); - puglFreeWorld(app.world); - - return 0; -} diff --git a/subprojects/nk_pugl/pugl/examples/pugl_print_events.c b/subprojects/nk_pugl/pugl/examples/pugl_print_events.c deleted file mode 100644 index dfa217e..0000000 --- a/subprojects/nk_pugl/pugl/examples/pugl_print_events.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "test/test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -#include -#include - -typedef struct { - PuglWorld* world; - PuglView* view; - int quit; -} PuglPrintEventsApp; - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglPrintEventsApp* app = (PuglPrintEventsApp*)puglGetHandle(view); - - printEvent(event, "Event: ", true); - - switch (event->type) { - case PUGL_CLOSE: - app->quit = 1; - break; - default: - break; - } - - return PUGL_SUCCESS; -} - -int -main(void) -{ - PuglPrintEventsApp app = {NULL, NULL, 0}; - - app.world = puglNewWorld(PUGL_PROGRAM, 0); - app.view = puglNewView(app.world); - - puglSetClassName(app.world, "Pugl Print Events"); - puglSetWindowTitle(app.view, "Pugl Event Printer"); - puglSetDefaultSize(app.view, 512, 512); - puglSetBackend(app.view, puglStubBackend()); - puglSetHandle(app.view, &app); - puglSetEventFunc(app.view, onEvent); - - PuglStatus st = puglRealize(app.view); - if (st) { - return logError("Failed to create window (%s)\n", puglStrerror(st)); - } - - puglShow(app.view); - - while (!app.quit) { - puglUpdate(app.world, -1.0); - } - - puglFreeView(app.view); - puglFreeWorld(app.world); - - return 0; -} diff --git a/subprojects/nk_pugl/pugl/examples/pugl_shader_demo.c b/subprojects/nk_pugl/pugl/examples/pugl_shader_demo.c deleted file mode 100644 index aa5c38e..0000000 --- a/subprojects/nk_pugl/pugl/examples/pugl_shader_demo.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - An example of drawing with OpenGL 3/4. - - This is an example of using OpenGL for pixel-perfect 2D drawing. It uses - pixel coordinates for positions and sizes so that things work roughly like a - typical 2D graphics API. - - The program draws a bunch of rectangles with borders, using instancing. - Each rectangle has origin, size, and fill color attributes, which are shared - for all four vertices. On each frame, a single buffer with all the - rectangle data is sent to the GPU, and everything is drawn with a single - draw call. - - This is not particularly realistic or optimal, but serves as a decent rough - benchmark for how much simple geometry you can draw. The number of - rectangles can be given on the command line. For reference, it begins to - struggle to maintain 60 FPS on my machine (1950x + Vega64) with more than - about 100000 rectangles. -*/ - -#include "demo_utils.h" -#include "file_utils.h" -#include "rects.h" -#include "shader_utils.h" -#include "test/test_utils.h" - -#include "glad/glad.h" - -#include "pugl/gl.h" -#include "pugl/pugl.h" - -#include -#include -#include -#include -#include -#include - -static const int defaultWidth = 512; -static const int defaultHeight = 512; -static const uintptr_t resizeTimerId = 1u; - -typedef struct { - mat4 projection; -} RectUniforms; - -typedef struct { - const char* programPath; - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - size_t numRects; - Rect* rects; - Program drawRect; - GLuint vao; - GLuint vbo; - GLuint instanceVbo; - GLuint ibo; - double lastDrawDuration; - double lastFrameEndTime; - unsigned framesDrawn; - int glMajorVersion; - int glMinorVersion; - int quit; -} PuglTestApp; - -static PuglStatus -setupGl(PuglTestApp* app); - -static void -teardownGl(PuglTestApp* app); - -static void -onConfigure(PuglView* view, double width, double height) -{ - (void)view; - - glEnable(GL_BLEND); - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); - glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glViewport(0, 0, (int)width, (int)height); -} - -static void -onExpose(PuglView* view) -{ - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - const PuglRect frame = puglGetFrame(view); - const float width = (float)frame.width; - const float height = (float)frame.height; - const double time = puglGetTime(puglGetWorld(view)); - - // Construct projection matrix for 2D window surface (in pixels) - mat4 proj; - mat4Ortho( - proj, 0.0f, (float)frame.width, 0.0f, (float)frame.height, -1.0f, 1.0f); - - // Clear and bind everything that is the same for every rect - glClear(GL_COLOR_BUFFER_BIT); - glUseProgram(app->drawRect.program); - glBindVertexArray(app->vao); - - for (size_t i = 0; i < app->numRects; ++i) { - moveRect(&app->rects[i], i, app->numRects, width, height, time); - } - - glBufferData(GL_UNIFORM_BUFFER, sizeof(proj), &proj, GL_STREAM_DRAW); - - glBufferSubData( - GL_ARRAY_BUFFER, 0, (GLsizeiptr)(app->numRects * sizeof(Rect)), app->rects); - - glDrawElementsInstanced( - GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, NULL, (GLsizei)(app->numRects * 4)); - - ++app->framesDrawn; - - app->lastFrameEndTime = puglGetTime(puglGetWorld(view)); - app->lastDrawDuration = app->lastFrameEndTime - time; -} - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - - printEvent(event, "Event: ", app->opts.verbose); - - switch (event->type) { - case PUGL_CREATE: - setupGl(app); - break; - case PUGL_DESTROY: - teardownGl(app); - break; - case PUGL_CONFIGURE: - onConfigure(view, event->configure.width, event->configure.height); - break; - case PUGL_UPDATE: - puglPostRedisplay(view); - break; - case PUGL_EXPOSE: - onExpose(view); - break; - case PUGL_CLOSE: - app->quit = 1; - break; - case PUGL_LOOP_ENTER: - puglStartTimer(view, - resizeTimerId, - 1.0 / (double)puglGetViewHint(view, PUGL_REFRESH_RATE)); - break; - case PUGL_LOOP_LEAVE: - puglStopTimer(view, resizeTimerId); - break; - case PUGL_KEY_PRESS: - if (event->key.key == 'q' || event->key.key == PUGL_KEY_ESCAPE) { - app->quit = 1; - } - break; - case PUGL_TIMER: - if (event->timer.id == resizeTimerId) { - puglPostRedisplay(view); - } - break; - default: - break; - } - - return PUGL_SUCCESS; -} - -static Rect* -makeRects(const size_t numRects) -{ - Rect* rects = (Rect*)calloc(numRects, sizeof(Rect)); - for (size_t i = 0; i < numRects; ++i) { - rects[i] = makeRect(i, (float)defaultWidth); - } - - return rects; -} - -static char* -loadShader(const char* const programPath, const char* const name) -{ - char* const path = resourcePath(programPath, name); - fprintf(stderr, "Loading shader %s\n", path); - - FILE* const file = fopen(path, "r"); - if (!file) { - logError("Failed to open '%s'\n", path); - return NULL; - } - - free(path); - fseek(file, 0, SEEK_END); - const size_t fileSize = (size_t)ftell(file); - - fseek(file, 0, SEEK_SET); - char* source = (char*)calloc(1, fileSize + 1u); - - fread(source, 1, fileSize, file); - fclose(file); - - return source; -} - -static int -parseOptions(PuglTestApp* app, int argc, char** argv) -{ - char* endptr = NULL; - - // Parse command line options - app->numRects = 1024; - app->opts = puglParseTestOptions(&argc, &argv); - if (app->opts.help) { - return 1; - } - - // Parse number of rectangles argument, if given - if (argc >= 1) { - app->numRects = (size_t)strtol(argv[0], &endptr, 10); - if (endptr != argv[0] + strlen(argv[0])) { - logError("Invalid number of rectangles: %s\n", argv[0]); - return 1; - } - } - - // Parse OpenGL major version argument, if given - if (argc >= 2) { - app->glMajorVersion = (int)strtol(argv[1], &endptr, 10); - if (endptr != argv[1] + strlen(argv[1])) { - logError("Invalid GL major version: %s\n", argv[1]); - return 1; - } - - if (app->glMajorVersion == 4) { - app->glMinorVersion = 2; - } else if (app->glMajorVersion != 3) { - logError("Unsupported GL major version %d\n", app->glMajorVersion); - return 1; - } - } - - return 0; -} - -static void -setupPugl(PuglTestApp* app) -{ - // Create world, view, and rect data - app->world = puglNewWorld(PUGL_PROGRAM, 0); - app->view = puglNewView(app->world); - app->rects = makeRects(app->numRects); - - // Set up world and view - puglSetClassName(app->world, "PuglGL3Demo"); - puglSetWindowTitle(app->view, "Pugl OpenGL 3"); - puglSetDefaultSize(app->view, defaultWidth, defaultHeight); - puglSetMinSize(app->view, defaultWidth / 4, defaultHeight / 4); - puglSetMaxSize(app->view, defaultWidth * 4, defaultHeight * 4); - puglSetAspectRatio(app->view, 1, 1, 16, 9); - puglSetBackend(app->view, puglGlBackend()); - puglSetViewHint(app->view, PUGL_USE_COMPAT_PROFILE, PUGL_FALSE); - puglSetViewHint(app->view, PUGL_USE_DEBUG_CONTEXT, app->opts.errorChecking); - puglSetViewHint(app->view, PUGL_CONTEXT_VERSION_MAJOR, app->glMajorVersion); - puglSetViewHint(app->view, PUGL_CONTEXT_VERSION_MINOR, app->glMinorVersion); - puglSetViewHint(app->view, PUGL_RESIZABLE, app->opts.resizable); - puglSetViewHint(app->view, PUGL_SAMPLES, app->opts.samples); - puglSetViewHint(app->view, PUGL_DOUBLE_BUFFER, app->opts.doubleBuffer); - puglSetViewHint(app->view, PUGL_SWAP_INTERVAL, app->opts.sync); - puglSetViewHint(app->view, PUGL_IGNORE_KEY_REPEAT, PUGL_TRUE); - puglSetHandle(app->view, app); - puglSetEventFunc(app->view, onEvent); -} - -static PuglStatus -setupGl(PuglTestApp* app) -{ - // Load GL functions via GLAD - if (!gladLoadGLLoader((GLADloadproc)&puglGetProcAddress)) { - logError("Failed to load GL\n"); - return PUGL_FAILURE; - } - - const char* const headerFile = - (app->glMajorVersion == 3 ? "shaders/header_330.glsl" - : "shaders/header_420.glsl"); - - // Load shader sources - char* const headerSource = loadShader(app->programPath, headerFile); - - char* const vertexSource = loadShader(app->programPath, "shaders/rect.vert"); - - char* const fragmentSource = - loadShader(app->programPath, "shaders/rect.frag"); - - if (!vertexSource || !fragmentSource) { - logError("Failed to load shader sources\n"); - return PUGL_FAILURE; - } - - // Compile rectangle shaders and program - app->drawRect = compileProgram(headerSource, vertexSource, fragmentSource); - free(fragmentSource); - free(vertexSource); - free(headerSource); - if (!app->drawRect.program) { - return PUGL_FAILURE; - } - - // Get location of rectangle shader uniform block - const GLuint globalsIndex = - glGetUniformBlockIndex(app->drawRect.program, "UniformBufferObject"); - - // Generate/bind a uniform buffer for setting rectangle properties - GLuint uboHandle = 0; - glGenBuffers(1, &uboHandle); - glBindBuffer(GL_UNIFORM_BUFFER, uboHandle); - glBindBufferBase(GL_UNIFORM_BUFFER, globalsIndex, uboHandle); - - // Generate/bind a VAO to track state - glGenVertexArrays(1, &app->vao); - glBindVertexArray(app->vao); - - // Generate/bind a VBO to store vertex position data - glGenBuffers(1, &app->vbo); - glBindBuffer(GL_ARRAY_BUFFER, app->vbo); - glBufferData( - GL_ARRAY_BUFFER, sizeof(rectVertices), rectVertices, GL_STATIC_DRAW); - - // Attribute 0 is position, 2 floats from the VBO - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), NULL); - - // Generate/bind a VBO to store instance attribute data - glGenBuffers(1, &app->instanceVbo); - glBindBuffer(GL_ARRAY_BUFFER, app->instanceVbo); - glBufferData(GL_ARRAY_BUFFER, - (GLsizeiptr)(app->numRects * sizeof(Rect)), - app->rects, - GL_STREAM_DRAW); - - // Attribute 1 is Rect::position - glEnableVertexAttribArray(1); - glVertexAttribDivisor(1, 4); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Rect), NULL); - - // Attribute 2 is Rect::size - glEnableVertexAttribArray(2); - glVertexAttribDivisor(2, 4); - glVertexAttribPointer( - 2, 2, GL_FLOAT, GL_FALSE, sizeof(Rect), (const void*)offsetof(Rect, size)); - - // Attribute 3 is Rect::fillColor - glEnableVertexAttribArray(3); - glVertexAttribDivisor(3, 4); - glVertexAttribPointer(3, - 4, - GL_FLOAT, - GL_FALSE, - sizeof(Rect), - (const void*)offsetof(Rect, fillColor)); - - // Set up the IBO to index into the VBO - glGenBuffers(1, &app->ibo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, app->ibo); - glBufferData( - GL_ELEMENT_ARRAY_BUFFER, sizeof(rectIndices), rectIndices, GL_STATIC_DRAW); - - return PUGL_SUCCESS; -} - -static void -teardownGl(PuglTestApp* app) -{ - glDeleteBuffers(1, &app->ibo); - glDeleteBuffers(1, &app->vbo); - glDeleteBuffers(1, &app->instanceVbo); - glDeleteVertexArrays(1, &app->vao); - deleteProgram(app->drawRect); -} - -int -main(int argc, char** argv) -{ - PuglTestApp app = {0}; - - app.programPath = argv[0]; - app.glMajorVersion = 3; - app.glMinorVersion = 3; - - // Parse command line options - if (parseOptions(&app, argc, argv)) { - puglPrintTestUsage("pugl_shader_demo", "[NUM_RECTS] [GL_MAJOR]"); - return 1; - } - - // Create and configure world and view - setupPugl(&app); - - // Create window (which will send a PUGL_CREATE event) - const PuglStatus st = puglRealize(app.view); - if (st) { - return logError("Failed to create window (%s)\n", puglStrerror(st)); - } - - // Show window - printViewHints(app.view); - puglShow(app.view); - - // Calculate ideal frame duration to drive the main loop at a good rate - const int refreshRate = puglGetViewHint(app.view, PUGL_REFRESH_RATE); - const double frameDuration = 1.0 / (double)refreshRate; - - // Grind away, drawing continuously - const double startTime = puglGetTime(app.world); - PuglFpsPrinter fpsPrinter = {startTime}; - while (!app.quit) { - /* To minimize input latency and get smooth performance during window - resizing, we want to poll for events as long as possible before - starting to draw the next frame. This ensures that as many events - are consumed as possible before starting to draw, or, equivalently, - that the next rendered frame represents the latest events possible. - This is particularly important for mouse input and "live" window - resizing, where many events tend to pile up within a frame. - - To do this, we keep track of the time when the last frame was - finished drawing, and how long it took to expose (and assume this is - relatively stable). Then, we can calculate how much time there is - from now until the time when we should start drawing to not miss the - deadline, and use that as the timeout for puglUpdate(). - */ - - const double now = puglGetTime(app.world); - const double nextFrameEndTime = app.lastFrameEndTime + frameDuration; - const double nextExposeTime = nextFrameEndTime - app.lastDrawDuration; - const double timeUntilNext = nextExposeTime - now; - const double timeout = app.opts.sync ? timeUntilNext : 0.0; - - puglUpdate(app.world, fmax(0.0, timeout)); - puglPrintFps(app.world, &fpsPrinter, &app.framesDrawn); - } - - // Destroy window (which will send a PUGL_DESTROY event) - puglFreeView(app.view); - - // Free everything else - puglFreeWorld(app.world); - free(app.rects); - - return 0; -} diff --git a/subprojects/nk_pugl/pugl/examples/pugl_vulkan_cxx_demo.cpp b/subprojects/nk_pugl/pugl/examples/pugl_vulkan_cxx_demo.cpp deleted file mode 100644 index d92e652..0000000 --- a/subprojects/nk_pugl/pugl/examples/pugl_vulkan_cxx_demo.cpp +++ /dev/null @@ -1,1826 +0,0 @@ -/* - Copyright 2019-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - An example of drawing with Vulkan. - - This is an example of using Vulkan for pixel-perfect 2D drawing. It uses - the same data and shaders as pugl_shader_demo.c and attempts to draw the - same thing, except using Vulkan. - - Since Vulkan is a complicated and very verbose API, this example is - unfortunately much larger than the others. You should not use this as a - resource to learn Vulkan, but it provides a decent demo of using Vulkan with - Pugl that works nicely on all supported platforms. -*/ - -#include "demo_utils.h" -#include "file_utils.h" -#include "rects.h" -#include "test/test_utils.h" - -#include "sybok.hpp" - -#include "pugl/pugl.h" -#include "pugl/pugl.hpp" -#include "pugl/vulkan.hpp" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace { - -constexpr uintptr_t resizeTimerId = 1u; - -struct PhysicalDeviceSelection { - sk::PhysicalDevice physicalDevice; - uint32_t graphicsFamilyIndex; -}; - -/// Basic Vulkan context associated with the window -struct VulkanContext { - VkResult init(pugl::VulkanLoader& loader, const PuglTestOptions& opts); - - sk::VulkanApi vk; - sk::Instance instance; - sk::DebugReportCallbackEXT debugCallback; -}; - -/// Basic setup of graphics device -struct GraphicsDevice { - VkResult init(const pugl::VulkanLoader& loader, - const VulkanContext& context, - pugl::View& view, - const PuglTestOptions& opts); - - sk::SurfaceKHR surface; - sk::PhysicalDevice physicalDevice{}; - uint32_t graphicsIndex{}; - VkSurfaceFormatKHR surfaceFormat{}; - VkPresentModeKHR presentMode{}; - VkPresentModeKHR resizePresentMode{}; - sk::Device device{}; - sk::Queue graphicsQueue{}; - sk::CommandPool commandPool{}; -}; - -/// Buffer allocated on the GPU -struct Buffer { - VkResult init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - VkDeviceSize size, - VkBufferUsageFlags usage, - VkMemoryPropertyFlags properties); - - sk::Buffer buffer; - sk::DeviceMemory deviceMemory; -}; - -/// A set of frames that can be rendered concurrently -struct Swapchain { - VkResult init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - VkSurfaceCapabilitiesKHR capabilities, - VkExtent2D extent, - VkSwapchainKHR oldSwapchain, - bool resizing); - - VkSurfaceCapabilitiesKHR capabilities{}; - VkExtent2D extent{}; - sk::SwapchainKHR swapchain{}; - std::vector imageViews{}; -}; - -/// A pass that renders to a target -struct RenderPass { - VkResult init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const Swapchain& swapchain); - - sk::RenderPass renderPass; - std::vector framebuffers; - sk::CommandBuffers> commandBuffers; -}; - -/// Uniform buffer for constant data used in shaders -struct UniformBufferObject { - mat4 projection; -}; - -/// Rectangle data that does not depend on renderer configuration -struct RectData { - VkResult init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - size_t nRects); - - sk::DescriptorSetLayout descriptorSetLayout{}; - Buffer uniformBuffer{}; - sk::MappedMemory uniformData{}; - Buffer modelBuffer{}; - Buffer instanceBuffer{}; - sk::MappedMemory vertexData{}; - size_t numRects{}; -}; - -/// Shader modules for drawing rectangles -struct RectShaders { - VkResult init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const std::string& programPath); - - sk::ShaderModule vert{}; - sk::ShaderModule frag{}; -}; - -/// A pipeline to render rectangles with our shaders -struct RectPipeline { - VkResult init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const RectData& rectData, - const RectShaders& shaders, - const Swapchain& swapchain, - const RenderPass& renderPass); - - sk::DescriptorPool descriptorPool{}; - sk::DescriptorSets> descriptorSets{}; - sk::PipelineLayout pipelineLayout{}; - std::array pipelines{}; - uint32_t numImages{}; -}; - -/// Synchronization primitives used to coordinate drawing frames -struct RenderSync { - VkResult init(const sk::VulkanApi& vk, - const sk::Device& device, - uint32_t numImages); - - std::vector imageAvailable{}; - std::vector renderFinished{}; - std::vector inFlight{}; - size_t currentFrame{}; -}; - -/// Renderer that owns the above and everything required to draw -struct Renderer { - VkResult init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const RectData& rectData, - const RectShaders& rectShaders, - VkExtent2D extent, - bool resizing); - - VkResult recreate(const sk::VulkanApi& vk, - const sk::SurfaceKHR& surface, - const GraphicsDevice& gpu, - const RectData& rectData, - const RectShaders& rectShaders, - VkExtent2D extent, - bool resizing); - - Swapchain swapchain; - RenderPass renderPass; - RectPipeline rectPipeline; - RenderSync sync; -}; - -VkResult -selectSurfaceFormat(const sk::VulkanApi& vk, - const sk::PhysicalDevice& physicalDevice, - const sk::SurfaceKHR& surface, - VkSurfaceFormatKHR& surfaceFormat) -{ - std::vector formats; - if (VkResult r = vk.getPhysicalDeviceSurfaceFormatsKHR( - physicalDevice, surface, formats)) { - return r; - } - - for (const auto& format : formats) { - if (format.format == VK_FORMAT_B8G8R8A8_UNORM && - format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - surfaceFormat = format; - return VK_SUCCESS; - } - } - - return VK_ERROR_FORMAT_NOT_SUPPORTED; -} - -VkResult -selectPresentMode(const sk::VulkanApi& vk, - const sk::PhysicalDevice& physicalDevice, - const sk::SurfaceKHR& surface, - const bool multiBuffer, - const bool sync, - VkPresentModeKHR& presentMode) -{ - // Map command line options to mode priorities - static constexpr VkPresentModeKHR priorities[][2][4] = { - { - // No double buffer, no sync - {VK_PRESENT_MODE_IMMEDIATE_KHR, - VK_PRESENT_MODE_MAILBOX_KHR, - VK_PRESENT_MODE_FIFO_RELAXED_KHR, - VK_PRESENT_MODE_FIFO_KHR}, - - // No double buffer, sync (nonsense, map to FIFO relaxed) - {VK_PRESENT_MODE_FIFO_RELAXED_KHR, - VK_PRESENT_MODE_FIFO_KHR, - VK_PRESENT_MODE_MAILBOX_KHR, - VK_PRESENT_MODE_IMMEDIATE_KHR}, - }, - { - // Double buffer, no sync - { - VK_PRESENT_MODE_MAILBOX_KHR, - VK_PRESENT_MODE_IMMEDIATE_KHR, - VK_PRESENT_MODE_FIFO_RELAXED_KHR, - VK_PRESENT_MODE_FIFO_KHR, - }, - - // Double buffer, sync - {VK_PRESENT_MODE_FIFO_KHR, - VK_PRESENT_MODE_FIFO_RELAXED_KHR, - VK_PRESENT_MODE_MAILBOX_KHR, - VK_PRESENT_MODE_IMMEDIATE_KHR}, - }, - }; - - std::vector modes; - if (VkResult r = vk.getPhysicalDeviceSurfacePresentModesKHR( - physicalDevice, surface, modes)) { - return r; - } - - const auto& tryModes = priorities[bool(multiBuffer)][bool(sync)]; - for (const auto m : tryModes) { - if (std::find(modes.begin(), modes.end(), m) != modes.end()) { - presentMode = m; - return VK_SUCCESS; - } - } - - return VK_ERROR_INCOMPATIBLE_DRIVER; -} - -VkResult -openDevice(const sk::VulkanApi& vk, - const sk::PhysicalDevice& physicalDevice, - const uint32_t graphicsFamilyIndex, - sk::Device& device) -{ - const float graphicsQueuePriority = 1.0f; - const char* const swapchainName = "VK_KHR_swapchain"; - - const VkDeviceQueueCreateInfo queueCreateInfo{ - VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, - nullptr, - 0u, - graphicsFamilyIndex, - SK_COUNTED(1u, &graphicsQueuePriority), - }; - - const VkDeviceCreateInfo createInfo{VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - nullptr, - 0u, - SK_COUNTED(1u, &queueCreateInfo), - SK_COUNTED(0u, nullptr), // Deprecated - SK_COUNTED(1u, &swapchainName), - nullptr}; - - return vk.createDevice(physicalDevice, createInfo, device); -} - -/// Return whether the physical device supports the extensions we require -VkResult -deviceSupportsRequiredExtensions(const sk::VulkanApi& vk, - const sk::PhysicalDevice& device, - bool& supported) -{ - VkResult r = VK_SUCCESS; - - std::vector props; - if ((r = vk.enumerateDeviceExtensionProperties(device, props))) { - return r; - } - - supported = std::any_of( - props.begin(), props.end(), [&](const VkExtensionProperties& e) { - return !strcmp(e.extensionName, "VK_KHR_swapchain"); - }); - - return VK_SUCCESS; -} - -/// Return the index of the graphics queue, if there is one -VkResult -findGraphicsQueue(const sk::VulkanApi& vk, - const sk::SurfaceKHR& surface, - const sk::PhysicalDevice& device, - uint32_t& queueIndex) -{ - VkResult r = VK_SUCCESS; - - std::vector queueProps; - if ((r = vk.getPhysicalDeviceQueueFamilyProperties(device, queueProps))) { - return r; - } - - for (uint32_t q = 0u; q < queueProps.size(); ++q) { - if (queueProps[q].queueFlags & VK_QUEUE_GRAPHICS_BIT) { - bool supported = false; - if ((r = vk.getPhysicalDeviceSurfaceSupportKHR( - device, q, surface, supported))) { - return r; - } - - if (supported) { - queueIndex = q; - return VK_SUCCESS; - } - } - } - - return VK_ERROR_FEATURE_NOT_PRESENT; -} - -/// Select a physical graphics device to use (simply the first found) -VkResult -selectPhysicalDevice(const sk::VulkanApi& vk, - const sk::Instance& instance, - const sk::SurfaceKHR& surface, - PhysicalDeviceSelection& selection) -{ - VkResult r = VK_SUCCESS; - - std::vector devices; - if ((r = vk.enumeratePhysicalDevices(instance, devices))) { - return r; - } - - for (const auto& device : devices) { - auto supported = false; - if ((r = deviceSupportsRequiredExtensions(vk, device, supported))) { - return r; - } - - if (supported) { - auto queueIndex = 0u; - if ((r = findGraphicsQueue(vk, surface, device, queueIndex))) { - return r; - } - - selection = PhysicalDeviceSelection{device, queueIndex}; - return VK_SUCCESS; - } - } - - return VK_ERROR_INCOMPATIBLE_DISPLAY_KHR; -} - -VkResult -GraphicsDevice::init(const pugl::VulkanLoader& loader, - const VulkanContext& context, - pugl::View& view, - const PuglTestOptions& opts) -{ - const auto& vk = context.vk; - VkResult r = VK_SUCCESS; - - // Create a Vulkan surface for the window using the Pugl API - VkSurfaceKHR surfaceHandle = {}; - if ((r = pugl::createSurface(loader.getInstanceProcAddrFunc(), - view, - context.instance, - nullptr, - &surfaceHandle))) { - return r; - } - - // Wrap surface in a safe RAII handle - surface = - sk::SurfaceKHR{surfaceHandle, {context.instance, vk.vkDestroySurfaceKHR}}; - - PhysicalDeviceSelection physicalDeviceSelection = {}; - // Select a physical device to use - if ((r = selectPhysicalDevice( - vk, context.instance, surface, physicalDeviceSelection))) { - return r; - } - - physicalDevice = physicalDeviceSelection.physicalDevice; - graphicsIndex = physicalDeviceSelection.graphicsFamilyIndex; - - if ((r = selectSurfaceFormat(vk, physicalDevice, surface, surfaceFormat)) || - (r = selectPresentMode(vk, - physicalDevice, - surface, - opts.doubleBuffer, - opts.sync, - presentMode)) || - (r = selectPresentMode( - vk, physicalDevice, surface, true, false, resizePresentMode)) || - (r = openDevice(vk, physicalDevice, graphicsIndex, device))) { - return r; - } - - const VkCommandPoolCreateInfo commandPoolInfo{ - VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, nullptr, {}, graphicsIndex}; - - if ((r = vk.createCommandPool(device, commandPoolInfo, commandPool))) { - return r; - } - - graphicsQueue = vk.getDeviceQueue(device, graphicsIndex, 0); - return VK_SUCCESS; -} - -uint32_t -findMemoryType(const sk::VulkanApi& vk, - const sk::PhysicalDevice& physicalDevice, - const uint32_t typeFilter, - const VkMemoryPropertyFlags& properties) -{ - VkPhysicalDeviceMemoryProperties memProperties = - vk.getPhysicalDeviceMemoryProperties(physicalDevice); - - for (uint32_t i = 0; i < memProperties.memoryTypeCount; ++i) { - if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & - properties) == properties) { - return i; - } - } - - return UINT32_MAX; -} - -VkResult -Buffer::init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const VkDeviceSize size, - const VkBufferUsageFlags usage, - const VkMemoryPropertyFlags properties) -{ - const VkBufferCreateInfo bufferInfo{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - nullptr, - {}, - size, - usage, - VK_SHARING_MODE_EXCLUSIVE, - SK_COUNTED(0, nullptr)}; - - const auto& device = gpu.device; - - VkResult r = VK_SUCCESS; - if ((r = vk.createBuffer(device, bufferInfo, buffer))) { - return r; - } - - const auto requirements = vk.getBufferMemoryRequirements(device, buffer); - const auto memoryTypeIndex = findMemoryType( - vk, gpu.physicalDevice, requirements.memoryTypeBits, properties); - - if (memoryTypeIndex == UINT32_MAX) { - return VK_ERROR_FEATURE_NOT_PRESENT; - } - - const VkMemoryAllocateInfo allocInfo{VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - nullptr, - requirements.size, - memoryTypeIndex}; - - if ((r = vk.allocateMemory(device, allocInfo, deviceMemory)) || - (r = vk.bindBufferMemory(device, buffer, deviceMemory, 0))) { - return r; - } - - return VK_SUCCESS; -} - -VkResult -Swapchain::init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const VkSurfaceCapabilitiesKHR surfaceCapabilities, - const VkExtent2D surfaceExtent, - VkSwapchainKHR oldSwapchain, - bool resizing) -{ - capabilities = surfaceCapabilities; - extent = surfaceExtent; - - const auto minNumImages = - (!capabilities.maxImageCount || capabilities.maxImageCount >= 3u) - ? 3u - : capabilities.maxImageCount; - - const VkSwapchainCreateInfoKHR swapchainCreateInfo{ - VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, - nullptr, - {}, - gpu.surface, - minNumImages, - gpu.surfaceFormat.format, - gpu.surfaceFormat.colorSpace, - surfaceExtent, - 1, - (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT), - VK_SHARING_MODE_EXCLUSIVE, - SK_COUNTED(0, nullptr), - capabilities.currentTransform, - VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, - resizing ? gpu.resizePresentMode : gpu.presentMode, - VK_TRUE, - oldSwapchain}; - - VkResult r = VK_SUCCESS; - std::vector images; - if ((r = vk.createSwapchainKHR(gpu.device, swapchainCreateInfo, swapchain)) || - (r = vk.getSwapchainImagesKHR(gpu.device, swapchain, images))) { - return r; - } - - imageViews = std::vector(images.size()); - for (size_t i = 0; i < images.size(); ++i) { - const VkImageViewCreateInfo imageViewCreateInfo{ - VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - nullptr, - {}, - images[i], - VK_IMAGE_VIEW_TYPE_2D, - gpu.surfaceFormat.format, - {}, - {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}}; - - if ((r = vk.createImageView( - gpu.device, imageViewCreateInfo, imageViews[i]))) { - return r; - } - } - - return VK_SUCCESS; -} - -VkResult -RenderPass::init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const Swapchain& swapchain) -{ - const auto numImages = static_cast(swapchain.imageViews.size()); - - assert(numImages > 0); - - // Create command buffers - const VkCommandBufferAllocateInfo commandBufferAllocateInfo{ - VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - nullptr, - gpu.commandPool, - VK_COMMAND_BUFFER_LEVEL_PRIMARY, - numImages}; - - VkResult r = VK_SUCCESS; - if ((r = vk.allocateCommandBuffers( - gpu.device, commandBufferAllocateInfo, commandBuffers))) { - return r; - } - - static constexpr VkAttachmentReference colorAttachmentRef{ - 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - - static constexpr VkSubpassDescription subpass{ - {}, - VK_PIPELINE_BIND_POINT_GRAPHICS, - SK_COUNTED(0, nullptr), - SK_COUNTED(1, &colorAttachmentRef, nullptr, nullptr), - SK_COUNTED(0u, nullptr)}; - - static constexpr VkSubpassDependency dependency{ - VK_SUBPASS_EXTERNAL, - 0, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT), - {}, - {}}; - - const VkAttachmentDescription colorAttachment{ - {}, - gpu.surfaceFormat.format, - VK_SAMPLE_COUNT_1_BIT, - VK_ATTACHMENT_LOAD_OP_CLEAR, - VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - }; - - const VkRenderPassCreateInfo renderPassCreateInfo{ - VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - nullptr, - {}, - SK_COUNTED(1, &colorAttachment), - SK_COUNTED(1, &subpass), - SK_COUNTED(1, &dependency)}; - - if ((r = vk.createRenderPass(gpu.device, renderPassCreateInfo, renderPass))) { - return r; - } - - // Create framebuffers - framebuffers = std::vector(numImages); - for (uint32_t i = 0; i < numImages; ++i) { - const VkFramebufferCreateInfo framebufferCreateInfo{ - VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, - nullptr, - {}, - renderPass, - SK_COUNTED(1, &swapchain.imageViews[i].get()), - swapchain.extent.width, - swapchain.extent.height, - 1}; - - if ((r = vk.createFramebuffer( - gpu.device, framebufferCreateInfo, framebuffers[i]))) { - return r; - } - } - - return VK_SUCCESS; -} - -std::vector -readFile(const char* const programPath, const std::string& filename) -{ - std::unique_ptr path{ - resourcePath(programPath, filename.c_str()), &free}; - - std::cerr << "Loading shader: " << path.get() << std::endl; - - std::unique_ptr file{fopen(path.get(), "rb"), - &fclose}; - - if (!file) { - std::cerr << "Failed to open file '" << filename << "'\n"; - return {}; - } - - fseek(file.get(), 0, SEEK_END); - const auto fileSize = static_cast(ftell(file.get())); - fseek(file.get(), 0, SEEK_SET); - - const auto numWords = fileSize / sizeof(uint32_t); - std::vector buffer(numWords); - - fread(buffer.data(), sizeof(uint32_t), numWords, file.get()); - - return buffer; -} - -VkResult -createShaderModule(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const std::vector& code, - sk::ShaderModule& shaderModule) -{ - const VkShaderModuleCreateInfo createInfo{ - VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - nullptr, - {}, - code.size() * sizeof(uint32_t), - code.data()}; - - return vk.createShaderModule(gpu.device, createInfo, shaderModule); -} - -VkResult -RectShaders::init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const std::string& programPath) -{ - auto vertShaderCode = readFile(programPath.c_str(), "shaders/rect.vert.spv"); - - auto fragShaderCode = readFile(programPath.c_str(), "shaders/rect.frag.spv"); - - if (vertShaderCode.empty() || fragShaderCode.empty()) { - return VK_ERROR_INITIALIZATION_FAILED; - } - - VkResult r = VK_SUCCESS; - if ((r = createShaderModule(vk, gpu, vertShaderCode, vert)) || - (r = createShaderModule(vk, gpu, fragShaderCode, frag))) { - return r; - } - - return VK_SUCCESS; -} - -VkResult -RectPipeline::init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const RectData& rectData, - const RectShaders& shaders, - const Swapchain& swapchain, - const RenderPass& renderPass) -{ - const auto oldNumImages = numImages; - VkResult r = VK_SUCCESS; - - numImages = static_cast(swapchain.imageViews.size()); - pipelines = {}; - pipelineLayout = {}; - descriptorSets = {}; - - if (numImages != oldNumImages) { - // Create layout descriptor pool - - const VkDescriptorPoolSize poolSize{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - numImages}; - - const VkDescriptorPoolCreateInfo descriptorPoolCreateInfo{ - VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, - nullptr, - VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, - numImages, - 1u, - &poolSize}; - if ((r = vk.createDescriptorPool( - gpu.device, descriptorPoolCreateInfo, descriptorPool))) { - return r; - } - } - - const std::vector layouts( - numImages, rectData.descriptorSetLayout.get()); - - const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo{ - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, - nullptr, - descriptorPool, - numImages, - layouts.data()}; - if ((r = vk.allocateDescriptorSets( - gpu.device, descriptorSetAllocateInfo, descriptorSets))) { - return r; - } - - const VkDescriptorBufferInfo bufferInfo{ - rectData.uniformBuffer.buffer, 0, sizeof(UniformBufferObject)}; - - const std::array descriptorWrites{ - {{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - nullptr, - descriptorSets[0], - 0, - 0, - 1, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - nullptr, - &bufferInfo, - nullptr}}}; - - const std::array descriptorCopies{}; - - vk.updateDescriptorSets(gpu.device, descriptorWrites, descriptorCopies); - - static constexpr std::array - vertexAttributeDescriptions{ - {// Model - {0u, 0u, VK_FORMAT_R32G32_SFLOAT, 0}, - - // Rect instance attributes - {1u, 1u, VK_FORMAT_R32G32_SFLOAT, offsetof(Rect, pos)}, - {2u, 1u, VK_FORMAT_R32G32_SFLOAT, offsetof(Rect, size)}, - {3u, 1u, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(Rect, fillColor)}}}; - - static constexpr std::array - vertexBindingDescriptions{ - VkVertexInputBindingDescription{ - 0, sizeof(vec2), VK_VERTEX_INPUT_RATE_VERTEX}, - VkVertexInputBindingDescription{ - 1u, sizeof(Rect), VK_VERTEX_INPUT_RATE_INSTANCE}}; - - static constexpr VkPipelineInputAssemblyStateCreateInfo inputAssembly{ - VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, - nullptr, - {}, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, - false}; - - static constexpr VkPipelineRasterizationStateCreateInfo rasterizer{ - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, - nullptr, - {}, - 0, - 0, - VK_POLYGON_MODE_FILL, - VK_CULL_MODE_BACK_BIT, - VK_FRONT_FACE_CLOCKWISE, - 0, - 0, - 0, - 0, - 1.0f}; - - static constexpr VkPipelineMultisampleStateCreateInfo multisampling{ - VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, - nullptr, - {}, - VK_SAMPLE_COUNT_1_BIT, - false, - 0.0f, - nullptr, - false, - false}; - - static constexpr VkPipelineColorBlendAttachmentState colorBlendAttachment{ - true, - VK_BLEND_FACTOR_SRC_ALPHA, - VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - VK_BLEND_OP_ADD, - VK_BLEND_FACTOR_ONE, - VK_BLEND_FACTOR_ZERO, - VK_BLEND_OP_ADD, - (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | - VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT)}; - - const VkPipelineShaderStageCreateInfo shaderStages[] = { - {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - nullptr, - {}, - VK_SHADER_STAGE_VERTEX_BIT, - shaders.vert.get(), - "main", - nullptr}, - {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - nullptr, - {}, - VK_SHADER_STAGE_FRAGMENT_BIT, - shaders.frag.get(), - "main", - nullptr}}; - - const VkPipelineVertexInputStateCreateInfo vertexInputInfo{ - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - nullptr, - {}, - SK_COUNTED(static_cast(vertexBindingDescriptions.size()), - vertexBindingDescriptions.data()), - SK_COUNTED(static_cast(vertexAttributeDescriptions.size()), - vertexAttributeDescriptions.data())}; - - const VkViewport viewport{0.0f, - 0.0f, - float(swapchain.extent.width), - float(swapchain.extent.height), - 0.0f, - 1.0f}; - - const VkRect2D scissor{{0, 0}, swapchain.extent}; - - const VkPipelineViewportStateCreateInfo viewportState{ - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, - nullptr, - {}, - SK_COUNTED(1, &viewport), - SK_COUNTED(1, &scissor)}; - - const VkPipelineColorBlendStateCreateInfo colorBlending{ - VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, - nullptr, - {}, - false, - VK_LOGIC_OP_COPY, - SK_COUNTED(1, &colorBlendAttachment), - {1.0f, 0.0f, 0.0f, 0.0f}}; - - const VkPipelineLayoutCreateInfo layoutInfo{ - VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - nullptr, - {}, - SK_COUNTED(1, &rectData.descriptorSetLayout.get()), - SK_COUNTED(0, nullptr)}; - - if ((r = vk.createPipelineLayout(gpu.device, layoutInfo, pipelineLayout))) { - return r; - } - - const std::array pipelineInfos{ - {{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, - nullptr, - {}, - SK_COUNTED(2, shaderStages), - &vertexInputInfo, - &inputAssembly, - nullptr, - &viewportState, - &rasterizer, - &multisampling, - nullptr, - &colorBlending, - nullptr, - pipelineLayout, - renderPass.renderPass, - 0u, - {}, - 0}}}; - - if ((r = vk.createGraphicsPipelines( - gpu.device, {}, pipelineInfos, pipelines))) { - return r; - } - - return VK_SUCCESS; -} - -VkResult -RectData::init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const size_t nRects) -{ - numRects = nRects; - - static constexpr VkDescriptorSetLayoutBinding uboLayoutBinding{ - 0, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - 1, - VK_SHADER_STAGE_VERTEX_BIT, - nullptr}; - - const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo{ - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - nullptr, - {}, - 1, - &uboLayoutBinding}; - - VkResult r = VK_SUCCESS; - if ((r = vk.createDescriptorSetLayout( - gpu.device, descriptorSetLayoutInfo, descriptorSetLayout)) || - (r = uniformBuffer.init(vk, - gpu, - sizeof(UniformBufferObject), - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) || - (r = vk.mapMemory(gpu.device, - uniformBuffer.deviceMemory, - 0, - sizeof(UniformBufferObject), - {}, - uniformData))) { - return r; - } - - const VkBufferUsageFlags usageFlags = - (VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | - VK_BUFFER_USAGE_TRANSFER_DST_BIT); - - const VkMemoryPropertyFlags propertyFlags = - (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - - if ((r = modelBuffer.init( - vk, gpu, sizeof(rectVertices), usageFlags, propertyFlags))) { - return r; - } - - { - // Copy model vertices (directly, we do this only once) - sk::MappedMemory modelData; - if ((r = vk.mapMemory(gpu.device, - modelBuffer.deviceMemory, - 0, - static_cast(sizeof(rectVertices)), - {}, - modelData))) { - return r; - } - - memcpy(modelData.get(), rectVertices, sizeof(rectVertices)); - } - - if ((r = instanceBuffer.init( - vk, gpu, sizeof(Rect) * numRects, usageFlags, propertyFlags))) { - return r; - } - - // Map attribute vertices (we will update them every frame) - const auto rectsSize = static_cast(sizeof(Rect) * numRects); - if ((r = vk.mapMemory(gpu.device, - instanceBuffer.deviceMemory, - 0, - rectsSize, - {}, - vertexData))) { - return r; - } - - return VK_SUCCESS; -} - -VkResult -RenderSync::init(const sk::VulkanApi& vk, - const sk::Device& device, - const uint32_t numImages) -{ - const auto maxInFlight = std::max(1u, numImages - 1u); - VkResult r = VK_SUCCESS; - - imageAvailable = std::vector(numImages); - renderFinished = std::vector(numImages); - for (uint32_t i = 0; i < numImages; ++i) { - static constexpr VkSemaphoreCreateInfo semaphoreInfo{ - VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, {}}; - - if ((r = vk.createSemaphore(device, semaphoreInfo, imageAvailable[i])) || - (r = vk.createSemaphore(device, semaphoreInfo, renderFinished[i]))) { - return r; - } - } - - inFlight = std::vector(maxInFlight); - for (uint32_t i = 0; i < maxInFlight; ++i) { - static constexpr VkFenceCreateInfo fenceInfo{ - VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, - nullptr, - VK_FENCE_CREATE_SIGNALED_BIT}; - - if ((r = vk.createFence(device, fenceInfo, inFlight[i]))) { - return r; - } - } - - return VK_SUCCESS; -} - -VkResult -Renderer::init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const RectData& rectData, - const RectShaders& rectShaders, - const VkExtent2D extent, - bool resizing) -{ - VkResult r = VK_SUCCESS; - VkSurfaceCapabilitiesKHR capabilities = {}; - - if ((r = vk.getPhysicalDeviceSurfaceCapabilitiesKHR( - gpu.physicalDevice, gpu.surface, capabilities)) || - (r = swapchain.init(vk, gpu, capabilities, extent, {}, resizing)) || - (r = renderPass.init(vk, gpu, swapchain)) || - (r = rectPipeline.init( - vk, gpu, rectData, rectShaders, swapchain, renderPass))) { - return r; - } - - const auto numFrames = static_cast(swapchain.imageViews.size()); - return sync.init(vk, gpu.device, numFrames); -} - -VkResult -Renderer::recreate(const sk::VulkanApi& vk, - const sk::SurfaceKHR& surface, - const GraphicsDevice& gpu, - const RectData& rectData, - const RectShaders& rectShaders, - const VkExtent2D extent, - bool resizing) -{ - VkResult r = VK_SUCCESS; - const auto oldNumImages = swapchain.imageViews.size(); - - VkSurfaceCapabilitiesKHR capabilities = {}; - if ((r = vk.getPhysicalDeviceSurfaceCapabilitiesKHR( - gpu.physicalDevice, surface, capabilities)) || - (r = swapchain.init( - vk, gpu, capabilities, extent, swapchain.swapchain, resizing)) || - (r = renderPass.init(vk, gpu, swapchain)) || - (r = rectPipeline.init( - vk, gpu, rectData, rectShaders, swapchain, renderPass))) { - return r; - } - - const auto numFrames = static_cast(swapchain.imageViews.size()); - if (swapchain.imageViews.size() != oldNumImages) { - return sync.init(vk, gpu.device, numFrames); - } - - return VK_SUCCESS; -} - -VKAPI_ATTR -VkBool32 VKAPI_CALL -debugCallback(VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT, - uint64_t, - size_t, - int32_t, - const char* layerPrefix, - const char* msg, - void*) -{ - std::cerr << sk::string(static_cast(flags)) << ": " - << layerPrefix << ": " << msg << std::endl; - - return VK_FALSE; -} - -bool -hasExtension(const char* name, - const std::vector& properties) -{ - for (const auto& p : properties) { - if (!strcmp(p.extensionName, name)) { - return true; - } - } - - return false; -} - -bool -hasLayer(const char* name, const std::vector& properties) -{ - for (const auto& p : properties) { - if (!strcmp(p.layerName, name)) { - return true; - } - } - - return false; -} - -template -void -logInfo(const char* heading, const Value& value) -{ - std::cout << std::setw(26) << std::left << (std::string(heading) + ":") - << value << std::endl; -} - -VkResult -createInstance(sk::VulkanInitApi& initApi, - const PuglTestOptions& opts, - sk::Instance& instance) -{ - VkResult r = VK_SUCCESS; - - std::vector layerProps; - std::vector extProps; - if ((r = initApi.enumerateInstanceLayerProperties(layerProps)) || - (r = initApi.enumerateInstanceExtensionProperties(extProps))) { - return r; - } - - const auto puglExtensions = pugl::getInstanceExtensions(); - auto extensions = - std::vector(puglExtensions.begin(), puglExtensions.end()); - - // Add extra extensions we want to use if they are supported - if (hasExtension("VK_EXT_debug_report", extProps)) { - extensions.push_back("VK_EXT_debug_report"); - } - - // Add validation layers if error checking is enabled - std::vector layers; - if (opts.errorChecking) { - for (const char* l : {"VK_LAYER_KHRONOS_validation", - "VK_LAYER_LUNARG_standard_validation"}) { - if (hasLayer(l, layerProps)) { - layers.push_back(l); - } - } - } - - for (const auto& e : extensions) { - logInfo("Using instance extension", e); - } - - for (const auto& l : layers) { - logInfo("Using instance layer", l); - } - - static constexpr VkApplicationInfo appInfo{ - VK_STRUCTURE_TYPE_APPLICATION_INFO, - nullptr, - "Pugl Vulkan Demo", - 0, - nullptr, - 0, - VK_MAKE_VERSION(1, 0, 0), - }; - - const VkInstanceCreateInfo createInfo{ - VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, - nullptr, - VkInstanceCreateFlags{}, - &appInfo, - SK_COUNTED(uint32_t(layers.size()), layers.data()), - SK_COUNTED(uint32_t(extensions.size()), extensions.data())}; - - return initApi.createInstance(createInfo, instance); -} - -VkResult -getDebugReportCallback(sk::VulkanApi& api, - sk::Instance& instance, - const bool verbose, - sk::DebugReportCallbackEXT& callback) -{ - if (api.vkCreateDebugReportCallbackEXT) { - VkDebugReportFlagsEXT flags = (VK_DEBUG_REPORT_WARNING_BIT_EXT | - VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | - VK_DEBUG_REPORT_ERROR_BIT_EXT); - - if (verbose) { - flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT; - flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT; - } - - const VkDebugReportCallbackCreateInfoEXT createInfo{ - VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT, - nullptr, - flags, - debugCallback, - nullptr}; - - return api.createDebugReportCallbackEXT(instance, createInfo, callback); - } - - return VK_ERROR_FEATURE_NOT_PRESENT; -} - -void -recordCommandBuffer(sk::CommandScope& cmd, - const Swapchain& swapchain, - const RenderPass& renderPass, - const RectPipeline& rectPipeline, - const RectData& rectData, - const size_t imageIndex) -{ - const VkClearColorValue clearColorValue{{0.0f, 0.0f, 0.0f, 1.0f}}; - const VkClearValue clearValue{clearColorValue}; - - const VkRenderPassBeginInfo renderPassBegin{ - VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - nullptr, - renderPass.renderPass, - renderPass.framebuffers[imageIndex], - VkRect2D{{0, 0}, swapchain.extent}, - SK_COUNTED(1, &clearValue)}; - - auto pass = cmd.beginRenderPass(renderPassBegin, VK_SUBPASS_CONTENTS_INLINE); - - pass.bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, rectPipeline.pipelines[0]); - - const std::array offsets{0}; - pass.bindVertexBuffers( - 0u, SK_COUNTED(1u, &rectData.modelBuffer.buffer.get(), offsets.data())); - - pass.bindVertexBuffers( - 1u, SK_COUNTED(1u, &rectData.instanceBuffer.buffer.get(), offsets.data())); - - pass.bindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, - rectPipeline.pipelineLayout, - 0u, - SK_COUNTED(1u, rectPipeline.descriptorSets.get()), - 0u, - nullptr); - - pass.draw(4u, static_cast(rectData.numRects), 0u, 0u); -} - -VkResult -recordCommandBuffers(const sk::VulkanApi& vk, - const Swapchain& swapchain, - const RenderPass& renderPass, - const RectPipeline& rectPipeline, - const RectData& rectData) -{ - VkResult r = VK_SUCCESS; - - for (size_t i = 0; i < swapchain.imageViews.size(); ++i) { - const VkCommandBufferBeginInfo beginInfo{ - VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, - nullptr, - VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, - nullptr}; - - auto* const commandBuffer = renderPass.commandBuffers[i]; - auto cmd = vk.beginCommandBuffer(commandBuffer, beginInfo); - if (!cmd) { - return cmd.error(); - } - - recordCommandBuffer(cmd, swapchain, renderPass, rectPipeline, rectData, i); - - if ((r = cmd.end())) { - return r; - } - } - - return VK_SUCCESS; -} - -class PuglVulkanDemo; - -class View : public pugl::View -{ -public: - View(pugl::World& world, PuglVulkanDemo& app) - : pugl::View{world} - , _app{app} - { - setEventHandler(*this); - } - - template - pugl::Status onEvent(const pugl::Event&) noexcept - { - return pugl::Status::success; - } - - pugl::Status onEvent(const pugl::ConfigureEvent& event); - pugl::Status onEvent(const pugl::UpdateEvent& event); - pugl::Status onEvent(const pugl::ExposeEvent& event); - pugl::Status onEvent(const pugl::LoopEnterEvent& event); - pugl::Status onEvent(const pugl::TimerEvent& event); - pugl::Status onEvent(const pugl::LoopLeaveEvent& event); - pugl::Status onEvent(const pugl::KeyPressEvent& event); - pugl::Status onEvent(const pugl::CloseEvent& event); - -private: - PuglVulkanDemo& _app; -}; - -class PuglVulkanDemo -{ -public: - PuglVulkanDemo(const char* executablePath, - const PuglTestOptions& o, - size_t numRects); - - const char* programPath; - PuglTestOptions opts; - pugl::World world; - pugl::VulkanLoader loader; - View view; - VulkanContext vulkan; - GraphicsDevice gpu; - Renderer renderer; - RectData rectData; - RectShaders rectShaders; - uint32_t framesDrawn{0}; - VkExtent2D extent{512u, 512u}; - std::vector rects; - bool resizing{false}; - bool quit{false}; -}; - -std::vector -makeRects(const size_t numRects, const uint32_t windowWidth) -{ - std::vector rects(numRects); - for (size_t i = 0; i < numRects; ++i) { - rects[i] = makeRect(i, static_cast(windowWidth)); - } - - return rects; -} - -PuglVulkanDemo::PuglVulkanDemo(const char* const executablePath, - const PuglTestOptions& o, - const size_t numRects) - : programPath{executablePath} - , opts{o} - , world{pugl::WorldType::program, pugl::WorldFlag::threads} - , loader{world} - , view{world, *this} - , rects{makeRects(numRects, extent.width)} -{} - -VkResult -recreateRenderer(PuglVulkanDemo& app, - const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const VkExtent2D extent, - const RectData& rectData, - const RectShaders& rectShaders) -{ - VkResult r = VK_SUCCESS; - VkSurfaceCapabilitiesKHR capabilities = {}; - if ((r = vk.getPhysicalDeviceSurfaceCapabilitiesKHR( - gpu.physicalDevice, gpu.surface, capabilities))) { - return r; - } - - // There is a known race issue here, so we clamp and hope for the best - const VkExtent2D clampedExtent{ - std::min(capabilities.maxImageExtent.width, - std::max(capabilities.minImageExtent.width, extent.width)), - std::min(capabilities.maxImageExtent.height, - std::max(capabilities.minImageExtent.height, extent.height))}; - - if ((r = vk.deviceWaitIdle(gpu.device)) || - (r = app.renderer.recreate(vk, - gpu.surface, - gpu, - rectData, - rectShaders, - clampedExtent, - app.resizing))) { - return r; - } - - // Reset current (initially signaled) fence because we already waited - vk.resetFence(gpu.device, - app.renderer.sync.inFlight[app.renderer.sync.currentFrame]); - - // Record new command buffers - return recordCommandBuffers(vk, - app.renderer.swapchain, - app.renderer.renderPass, - app.renderer.rectPipeline, - rectData); -} - -pugl::Status -View::onEvent(const pugl::ConfigureEvent& event) -{ - // We just record the size here and lazily resize the surface when exposed - _app.extent = {static_cast(event.width), - static_cast(event.height)}; - - return pugl::Status::success; -} - -pugl::Status -View::onEvent(const pugl::UpdateEvent&) -{ - return postRedisplay(); -} - -VkResult -beginFrame(PuglVulkanDemo& app, const sk::Device& device, uint32_t& imageIndex) -{ - const auto& vk = app.vulkan.vk; - - VkResult r = VK_SUCCESS; - - // Wait until we can start rendering the next frame - if ((r = vk.waitForFence( - device, app.renderer.sync.inFlight[app.renderer.sync.currentFrame])) || - (r = vk.resetFence( - device, app.renderer.sync.inFlight[app.renderer.sync.currentFrame]))) { - return r; - } - - // Rebuild the renderer first if the window size has changed - if (app.extent.width != app.renderer.swapchain.extent.width || - app.extent.height != app.renderer.swapchain.extent.height) { - if ((r = recreateRenderer( - app, vk, app.gpu, app.extent, app.rectData, app.rectShaders))) { - return r; - } - } - - // Acquire the next image to render, rebuilding if necessary - while ((r = vk.acquireNextImageKHR( - device, - app.renderer.swapchain.swapchain, - UINT64_MAX, - app.renderer.sync.imageAvailable[app.renderer.sync.currentFrame], - {}, - &imageIndex))) { - switch (r) { - case VK_SUBOPTIMAL_KHR: - case VK_ERROR_OUT_OF_DATE_KHR: - if ((r = recreateRenderer(app, - vk, - app.gpu, - app.renderer.swapchain.extent, - app.rectData, - app.rectShaders))) { - return r; - } - continue; - default: - return r; - } - } - - return VK_SUCCESS; -} - -void -update(PuglVulkanDemo& app, const double time) -{ - // Animate rectangles - for (size_t i = 0; i < app.rects.size(); ++i) { - moveRect(&app.rects[i], - i, - app.rects.size(), - static_cast(app.extent.width), - static_cast(app.extent.height), - time); - } - - // Update vertex buffer - memcpy(app.rectData.vertexData.get(), - app.rects.data(), - sizeof(Rect) * app.rects.size()); - - // Update uniform buffer - UniformBufferObject ubo = {{}}; - mat4Ortho(ubo.projection, - 0.0f, - float(app.renderer.swapchain.extent.width), - 0.0f, - float(app.renderer.swapchain.extent.height), - -1.0f, - 1.0f); - - memcpy(app.rectData.uniformData.get(), &ubo, sizeof(ubo)); -} - -VkResult -endFrame(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const Renderer& renderer, - const uint32_t imageIndex) -{ - const auto currentFrame = renderer.sync.currentFrame; - VkResult r = VK_SUCCESS; - - static constexpr VkPipelineStageFlags waitStage = - VK_PIPELINE_STAGE_TRANSFER_BIT; - - const VkSubmitInfo submitInfo{ - VK_STRUCTURE_TYPE_SUBMIT_INFO, - nullptr, - SK_COUNTED(1, &renderer.sync.imageAvailable[currentFrame].get()), - &waitStage, - SK_COUNTED(1, &renderer.renderPass.commandBuffers[imageIndex]), - SK_COUNTED(1, &renderer.sync.renderFinished[imageIndex].get())}; - - if ((r = vk.queueSubmit(gpu.graphicsQueue, - submitInfo, - renderer.sync.inFlight[currentFrame]))) { - return r; - } - - const VkPresentInfoKHR presentInfo{ - VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, - nullptr, - SK_COUNTED(1, &renderer.sync.renderFinished[imageIndex].get()), - SK_COUNTED(1, &renderer.swapchain.swapchain.get(), &imageIndex), - nullptr}; - - switch ((r = vk.queuePresentKHR(gpu.graphicsQueue, presentInfo))) { - case VK_SUCCESS: // Sucessfully presented - case VK_SUBOPTIMAL_KHR: // Probably a resize race, ignore - case VK_ERROR_OUT_OF_DATE_KHR: // Probably a resize race, ignore - break; - default: - return r; - } - - return VK_SUCCESS; -} - -pugl::Status -View::onEvent(const pugl::ExposeEvent&) -{ - const auto& vk = _app.vulkan.vk; - const auto& gpu = _app.gpu; - - // Acquire the next image, waiting and/or rebuilding if necessary - auto nextImageIndex = 0u; - if (beginFrame(_app, gpu.device, nextImageIndex)) { - return pugl::Status::unknownError; - } - - // Ready to go, update the data to the current time - update(_app, world().time()); - - // Submit the frame to the queue and present it - endFrame(vk, gpu, _app.renderer, nextImageIndex); - - ++_app.framesDrawn; - ++_app.renderer.sync.currentFrame; - _app.renderer.sync.currentFrame %= _app.renderer.sync.inFlight.size(); - - return pugl::Status::success; -} - -pugl::Status -View::onEvent(const pugl::LoopEnterEvent&) -{ - _app.resizing = true; - startTimer(resizeTimerId, - 1.0 / static_cast(getHint(pugl::ViewHint::refreshRate))); - - return pugl::Status::success; -} - -pugl::Status -View::onEvent(const pugl::TimerEvent&) -{ - return postRedisplay(); -} - -pugl::Status -View::onEvent(const pugl::LoopLeaveEvent&) -{ - stopTimer(resizeTimerId); - - // Trigger a swapchain recreation with the normal present mode - _app.renderer.swapchain.extent = {}; - _app.resizing = false; - - return pugl::Status::success; -} - -pugl::Status -View::onEvent(const pugl::KeyPressEvent& event) -{ - if (event.key == PUGL_KEY_ESCAPE || event.key == 'q') { - _app.quit = true; - } - - return pugl::Status::success; -} - -pugl::Status -View::onEvent(const pugl::CloseEvent&) -{ - _app.quit = true; - - return pugl::Status::success; -} - -VkResult -VulkanContext::init(pugl::VulkanLoader& loader, const PuglTestOptions& opts) -{ - VkResult r = VK_SUCCESS; - - sk::VulkanInitApi initApi{}; - - // Load Vulkan API and set up the fundamentals - if ((r = initApi.init(loader.getInstanceProcAddrFunc())) || - (r = createInstance(initApi, opts, instance)) || - (r = vk.init(initApi, instance)) || - (r = getDebugReportCallback(vk, instance, opts.verbose, debugCallback))) { - return r; - } - - return VK_SUCCESS; -} - -int -run(const char* const programPath, - const PuglTestOptions opts, - const size_t numRects) -{ - PuglVulkanDemo app{programPath, opts, numRects}; - - VkResult r = VK_SUCCESS; - const auto width = static_cast(app.extent.width); - const auto height = static_cast(app.extent.height); - - // Realize window so we can set up Vulkan - app.world.setClassName("PuglVulkanDemo"); - app.view.setWindowTitle("Pugl Vulkan Demo"); - app.view.setAspectRatio(1, 1, 16, 9); - app.view.setDefaultSize(width, height); - app.view.setMinSize(width / 4, height / 4); - app.view.setMaxSize(width * 4, height * 4); - app.view.setBackend(pugl::vulkanBackend()); - app.view.setHint(pugl::ViewHint::resizable, opts.resizable); - const pugl::Status st = app.view.realize(); - if (st != pugl::Status::success) { - return logError("Failed to create window (%s)\n", pugl::strerror(st)); - } - - if (!app.loader) { - return logError("Failed to load Vulkan library\n"); - } - - // Load Vulkan for the view - if ((r = app.vulkan.init(app.loader, opts))) { - return logError("Failed to set up Vulkan API (%s)\n", sk::string(r)); - } - - const auto& vk = app.vulkan.vk; - - // Set up the graphics device - if ((r = app.gpu.init(app.loader, app.vulkan, app.view, opts))) { - return logError("Failed to set up device (%s)\n", sk::string(r)); - } - - logInfo("Present mode", sk::string(app.gpu.presentMode)); - logInfo("Resize present mode", sk::string(app.gpu.resizePresentMode)); - - // Set up the rectangle data we will render every frame - if ((r = app.rectData.init(vk, app.gpu, app.rects.size()))) { - return logError("Failed to allocate render data (%s)\n", sk::string(r)); - } - - // Load shader modules - if ((r = app.rectShaders.init(vk, app.gpu, app.programPath))) { - return logError("Failed to load shaders (%s)\n", sk::string(r)); - } - - if ((r = app.renderer.init(app.vulkan.vk, - app.gpu, - app.rectData, - app.rectShaders, - app.extent, - false))) { - return logError("Failed to create renderer (%s)\n", sk::string(r)); - } - - logInfo("Swapchain frames", - std::to_string(app.renderer.swapchain.imageViews.size())); - logInfo("Frames in flight", - std::to_string(app.renderer.sync.inFlight.size())); - - recordCommandBuffers(app.vulkan.vk, - app.renderer.swapchain, - app.renderer.renderPass, - app.renderer.rectPipeline, - app.rectData); - - const int refreshRate = app.view.getHint(pugl::ViewHint::refreshRate); - const double frameDuration = 1.0 / static_cast(refreshRate); - const double timeout = app.opts.sync ? frameDuration : 0.0; - - PuglFpsPrinter fpsPrinter = {app.world.time()}; - app.view.show(); - while (!app.quit) { - app.world.update(timeout); - puglPrintFps(app.world.cobj(), &fpsPrinter, &app.framesDrawn); - } - - if ((r = app.vulkan.vk.deviceWaitIdle(app.gpu.device))) { - return logError("Failed to wait for device idle (%s)\n", sk::string(r)); - } - - return 0; -} - -} // namespace - -int -main(int argc, char** argv) -{ - // Parse command line options - const char* const programPath = argv[0]; - const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); - if (opts.help) { - puglPrintTestUsage(programPath, ""); - return 0; - } - - // Parse number of rectangles argument, if given - int64_t numRects = 1000; - if (argc >= 1) { - char* endptr = nullptr; - numRects = strtol(argv[0], &endptr, 10); - if (endptr != argv[0] + strlen(argv[0]) || numRects < 1) { - logError("Invalid number of rectangles: %s\n", argv[0]); - return 1; - } - } - - // Run application - return run(programPath, opts, static_cast(numRects)); -} diff --git a/subprojects/nk_pugl/pugl/examples/pugl_vulkan_demo.c b/subprojects/nk_pugl/pugl/examples/pugl_vulkan_demo.c deleted file mode 100644 index 0dfbadd..0000000 --- a/subprojects/nk_pugl/pugl/examples/pugl_vulkan_demo.c +++ /dev/null @@ -1,1127 +0,0 @@ -/* - Copyright 2019-2020 David Robillard - Copyright 2019 Jordan Halase - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - A simple example of drawing with Vulkan. - - For a more advanced demo that actually draws something interesting, see - pugl_vulkan_cxx_demo.cpp. -*/ - -#include "demo_utils.h" -#include "test/test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/vulkan.h" - -#include -#include - -#include -#include -#include -#include -#include - -#define CLAMP(x, l, h) ((x) <= (l) ? (l) : (x) >= (h) ? (h) : (x)) - -// Vulkan allocation callbacks which can be used for debugging -#define ALLOC_VK NULL - -// Helper macro for allocating arrays by type, with C++ compatible cast -#define AALLOC(size, Type) ((Type*)calloc(size, sizeof(Type))) - -// Helper macro for counted array arguments to make clang-format behave -#define COUNTED(count, ...) count, __VA_ARGS__ - -/// Dynamically loaded Vulkan API functions -typedef struct { - PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; - PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; -} InstanceAPI; - -/// Vulkan swapchain and everything that depends on it -typedef struct { - VkSwapchainKHR rawSwapchain; - uint32_t nImages; - VkExtent2D extent; - VkImage* images; - VkImageView* imageViews; - VkFence* fences; - VkCommandBuffer* commandBuffers; -} Swapchain; - -/// Synchronization semaphores -typedef struct { - VkSemaphore presentComplete; - VkSemaphore renderFinished; -} Sync; - -/// Vulkan state, purely Vulkan functions can depend on only this -typedef struct { - InstanceAPI api; - VkInstance instance; - VkDebugReportCallbackEXT debugCallback; - VkSurfaceKHR surface; - VkSurfaceFormatKHR surfaceFormat; - VkPresentModeKHR presentMode; - VkPhysicalDeviceProperties deviceProperties; - VkPhysicalDevice physicalDevice; - uint32_t graphicsIndex; - VkDevice device; - VkQueue graphicsQueue; - VkCommandPool commandPool; - Swapchain* swapchain; - Sync sync; -} VulkanState; - -/// Complete application -typedef struct { - PuglTestOptions opts; - PuglWorld* world; - PuglView* view; - VulkanState vk; - uint32_t framesDrawn; - uint32_t width; - uint32_t height; - bool quit; -} VulkanApp; - -static VKAPI_ATTR VkBool32 VKAPI_CALL -debugCallback(VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT objType, - uint64_t obj, - size_t location, - int32_t code, - const char* layerPrefix, - const char* msg, - void* userData) -{ - (void)userData; - (void)objType; - (void)obj; - (void)location; - (void)code; - - if (flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) { - fprintf(stderr, "note: "); - } else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { - fprintf(stderr, "warning: "); - } else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) { - fprintf(stderr, "performance warning: "); - } else if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { - fprintf(stderr, "error: "); - } else if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) { - fprintf(stderr, "debug: "); - } - - fprintf(stderr, "%s: ", layerPrefix); - fprintf(stderr, "%s\n", msg); - return VK_FALSE; -} - -static bool -hasExtension(const char* const name, - const VkExtensionProperties* const properties, - const uint32_t count) -{ - for (uint32_t i = 0; i < count; ++i) { - if (!strcmp(properties[i].extensionName, name)) { - return true; - } - } - - return false; -} - -static bool -hasLayer(const char* const name, - const VkLayerProperties* const properties, - const uint32_t count) -{ - for (uint32_t i = 0; i < count; ++i) { - if (!strcmp(properties[i].layerName, name)) { - return true; - } - } - - return false; -} - -static void -pushString(const char*** const array, - uint32_t* const count, - const char* const string) -{ - *array = (const char**)realloc(*array, (*count + 1) * sizeof(const char*)); - (*array)[*count] = string; - ++*count; -} - -static VkResult -createInstance(VulkanApp* const app) -{ - const VkApplicationInfo appInfo = { - VK_STRUCTURE_TYPE_APPLICATION_INFO, - NULL, - "Pugl Vulkan Test", - VK_MAKE_VERSION(0, 1, 0), - "Pugl Vulkan Test Engine", - VK_MAKE_VERSION(0, 1, 0), - VK_MAKE_VERSION(1, 0, 0), - }; - - // Get the number of supported extensions and layers - VkResult vr = VK_SUCCESS; - uint32_t nExtProps = 0; - uint32_t nLayerProps = 0; - if ((vr = vkEnumerateInstanceLayerProperties(&nLayerProps, NULL)) || - (vr = vkEnumerateInstanceExtensionProperties(NULL, &nExtProps, NULL))) { - return vr; - } - - // Get properties of supported extensions - VkExtensionProperties* extProps = AALLOC(nExtProps, VkExtensionProperties); - vkEnumerateInstanceExtensionProperties(NULL, &nExtProps, extProps); - - uint32_t nExtensions = 0; - const char** extensions = NULL; - - // Add extensions required by pugl - uint32_t nPuglExts = 0; - const char* const* puglExts = puglGetInstanceExtensions(&nPuglExts); - for (uint32_t i = 0; i < nPuglExts; ++i) { - pushString(&extensions, &nExtensions, puglExts[i]); - } - - // Add extra extensions we want to use if they are supported - if (hasExtension("VK_EXT_debug_report", extProps, nExtProps)) { - pushString(&extensions, &nExtensions, "VK_EXT_debug_report"); - } - - // Get properties of supported layers - VkLayerProperties* layerProps = AALLOC(nLayerProps, VkLayerProperties); - vkEnumerateInstanceLayerProperties(&nLayerProps, layerProps); - - // Add validation layers if error checking is enabled - uint32_t nLayers = 0; - const char** layers = NULL; - if (app->opts.errorChecking) { - const char* debugLayers[] = {"VK_LAYER_KHRONOS_validation", - "VK_LAYER_LUNARG_standard_validation", - NULL}; - - for (const char** l = debugLayers; *l; ++l) { - if (hasLayer(*l, layerProps, nLayerProps)) { - pushString(&layers, &nLayers, *l); - } - } - } - - for (uint32_t i = 0; i < nExtensions; ++i) { - printf("Using instance extension: %s\n", extensions[i]); - } - - for (uint32_t i = 0; i < nLayers; ++i) { - printf("Using instance layer: %s\n", layers[i]); - } - - const VkInstanceCreateInfo createInfo = { - VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, - NULL, - 0, - &appInfo, - COUNTED(nLayers, layers), - COUNTED(nExtensions, extensions), - }; - - if ((vr = vkCreateInstance(&createInfo, ALLOC_VK, &app->vk.instance))) { - logError("Could not create Vulkan Instance: %d\n", vr); - } - - free(layers); - free(extensions); - free(layerProps); - free(extProps); - - return vr; -} - -static VkResult -enableDebugging(VulkanState* const vk) -{ - vk->api.vkCreateDebugReportCallbackEXT = - (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr( - vk->instance, "vkCreateDebugReportCallbackEXT"); - - vk->api.vkDestroyDebugReportCallbackEXT = - (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr( - vk->instance, "vkDestroyDebugReportCallbackEXT"); - - if (vk->api.vkCreateDebugReportCallbackEXT) { - const VkDebugReportCallbackCreateInfoEXT info = { - VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, - NULL, - VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT, - debugCallback, - NULL, - }; - - VkResult vr = VK_SUCCESS; - if ((vr = vk->api.vkCreateDebugReportCallbackEXT( - vk->instance, &info, ALLOC_VK, &vk->debugCallback))) { - logError("Could not create debug reporter: %d\n", vr); - return vr; - } - } - - return VK_SUCCESS; -} - -static VkResult -getGraphicsQueueIndex(VkSurfaceKHR surface, - VkPhysicalDevice device, - uint32_t* graphicsIndex) -{ - VkResult r = VK_SUCCESS; - - uint32_t nProps = 0; - vkGetPhysicalDeviceQueueFamilyProperties(device, &nProps, NULL); - - VkQueueFamilyProperties* props = AALLOC(nProps, VkQueueFamilyProperties); - vkGetPhysicalDeviceQueueFamilyProperties(device, &nProps, props); - - for (uint32_t q = 0; q < nProps; ++q) { - if (props[q].queueFlags & VK_QUEUE_GRAPHICS_BIT) { - VkBool32 supported = false; - if ((r = vkGetPhysicalDeviceSurfaceSupportKHR( - device, q, surface, &supported))) { - free(props); - return r; - } - - if (supported) { - *graphicsIndex = q; - free(props); - return VK_SUCCESS; - } - } - } - - free(props); - return VK_ERROR_FEATURE_NOT_PRESENT; -} - -static bool -supportsRequiredExtensions(const VkPhysicalDevice device) -{ - uint32_t nExtProps = 0; - vkEnumerateDeviceExtensionProperties(device, NULL, &nExtProps, NULL); - - VkExtensionProperties* extProps = AALLOC(nExtProps, VkExtensionProperties); - vkEnumerateDeviceExtensionProperties(device, NULL, &nExtProps, extProps); - - for (uint32_t i = 0; i < nExtProps; ++i) { - if (!strcmp(extProps[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) { - free(extProps); - return true; - } - } - - free(extProps); - return false; -} - -static bool -isDeviceSuitable(const VulkanState* const vk, - const VkPhysicalDevice device, - uint32_t* const graphicsIndex) -{ - if (!supportsRequiredExtensions(device) || - getGraphicsQueueIndex(vk->surface, device, graphicsIndex)) { - return false; - } - - return true; -} - -/** - Selects a physical graphics device. - - This doesn't try to be clever, and just selects the first suitable device. -*/ -static VkResult -selectPhysicalDevice(VulkanState* const vk) -{ - VkResult vr = VK_SUCCESS; - if (!vk->surface) { - logError("Cannot select a physical device without a surface\n"); - return VK_ERROR_SURFACE_LOST_KHR; - } - - uint32_t nDevices = 0; - if ((vr = vkEnumeratePhysicalDevices(vk->instance, &nDevices, NULL))) { - logError("Failed to get count of physical devices: %d\n", vr); - return vr; - } - - if (!nDevices) { - logError("No physical devices found\n"); - return VK_ERROR_DEVICE_LOST; - } - - VkPhysicalDevice* devices = AALLOC(nDevices, VkPhysicalDevice); - if ((vr = vkEnumeratePhysicalDevices(vk->instance, &nDevices, devices))) { - logError("Failed to enumerate physical devices: %d\n", vr); - free(devices); - return vr; - } - - uint32_t i = 0; - for (i = 0; i < nDevices; ++i) { - VkPhysicalDeviceProperties deviceProps = {0}; - vkGetPhysicalDeviceProperties(devices[i], &deviceProps); - - uint32_t graphicsIndex = 0; - if (isDeviceSuitable(vk, devices[i], &graphicsIndex)) { - printf("Using device %u/%u: \"%s\"\n", - i + 1, - nDevices, - deviceProps.deviceName); - vk->deviceProperties = deviceProps; - vk->physicalDevice = devices[i]; - vk->graphicsIndex = graphicsIndex; - printf("Using graphics queue family: %u\n", vk->graphicsIndex); - break; - } - - printf("Device \"%s\" not suitable\n", deviceProps.deviceName); - } - - if (i >= nDevices) { - logError("No suitable devices found\n"); - vr = VK_ERROR_DEVICE_LOST; - } - - free(devices); - return vr; -} - -/// Opens the logical device and sets up the queue and command pool -static VkResult -openDevice(VulkanState* const vk) -{ - if (vk->device) { - logError("Renderer already has an opened device\n"); - return VK_NOT_READY; - } - - const float graphicsQueuePriority = 1.0f; - const char* const swapchainName = VK_KHR_SWAPCHAIN_EXTENSION_NAME; - - const VkDeviceQueueCreateInfo queueCreateInfo = { - VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, - NULL, - 0, - vk->graphicsIndex, - COUNTED(1, &graphicsQueuePriority), - }; - - const VkDeviceCreateInfo createInfo = { - VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - NULL, - 0, - COUNTED(1, &queueCreateInfo), - COUNTED(0, NULL), - COUNTED(1, &swapchainName), - NULL, - }; - - VkDevice device = NULL; - VkResult vr = VK_SUCCESS; - if ((vr = - vkCreateDevice(vk->physicalDevice, &createInfo, ALLOC_VK, &device))) { - logError("Could not open device \"%s\": %d\n", - vk->deviceProperties.deviceName, - vr); - return vr; - } - - vk->device = device; - vkGetDeviceQueue(vk->device, vk->graphicsIndex, 0, &vk->graphicsQueue); - - const VkCommandPoolCreateInfo commandInfo = { - VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, - NULL, - 0, - vk->graphicsIndex, - }; - - if ((vr = vkCreateCommandPool( - vk->device, &commandInfo, ALLOC_VK, &vk->commandPool))) { - logError("Could not create command pool: %d\n", vr); - return vr; - } - - return VK_SUCCESS; -} - -static const char* -presentModeString(const VkPresentModeKHR presentMode) -{ - switch (presentMode) { - case VK_PRESENT_MODE_IMMEDIATE_KHR: - return "Immediate"; - case VK_PRESENT_MODE_MAILBOX_KHR: - return "Mailbox"; - case VK_PRESENT_MODE_FIFO_KHR: - return "FIFO"; - case VK_PRESENT_MODE_FIFO_RELAXED_KHR: - return "FIFO relaxed"; - default: - return "Other"; - } -} - -static bool -hasPresentMode(const VkPresentModeKHR mode, - const VkPresentModeKHR* const presentModes, - const uint32_t nPresentModes) -{ - for (uint32_t i = 0; i < nPresentModes; ++i) { - if (presentModes[i] == mode) { - return true; - } - } - - return false; -} - -/// Configure the surface for the currently opened device -static VkResult -configureSurface(VulkanState* const vk) -{ - uint32_t nFormats = 0; - vkGetPhysicalDeviceSurfaceFormatsKHR( - vk->physicalDevice, vk->surface, &nFormats, NULL); - if (!nFormats) { - logError("No surface formats available\n"); - return VK_ERROR_FORMAT_NOT_SUPPORTED; - } - - VkSurfaceFormatKHR* surfaceFormats = AALLOC(nFormats, VkSurfaceFormatKHR); - vkGetPhysicalDeviceSurfaceFormatsKHR( - vk->physicalDevice, vk->surface, &nFormats, surfaceFormats); - - const VkSurfaceFormatKHR want = {VK_FORMAT_B8G8R8A8_UNORM, - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}; - - uint32_t formatIndex = 0; - for (formatIndex = 0; formatIndex < nFormats; ++formatIndex) { - if (surfaceFormats[formatIndex].format == want.format && - surfaceFormats[formatIndex].colorSpace == want.colorSpace) { - vk->surfaceFormat = want; - break; - } - } - free(surfaceFormats); - if (formatIndex >= nFormats) { - logError("Could not find a suitable surface format\n"); - return VK_ERROR_FORMAT_NOT_SUPPORTED; - } - - uint32_t nPresentModes = 0; - vkGetPhysicalDeviceSurfacePresentModesKHR( - vk->physicalDevice, vk->surface, &nPresentModes, NULL); - if (!nPresentModes) { - logError("No present modes available\n"); - return VK_ERROR_FORMAT_NOT_SUPPORTED; - } - - VkPresentModeKHR* presentModes = AALLOC(nPresentModes, VkPresentModeKHR); - vkGetPhysicalDeviceSurfacePresentModesKHR( - vk->physicalDevice, vk->surface, &nPresentModes, presentModes); - - const VkPresentModeKHR tryModes[] = { - VK_PRESENT_MODE_MAILBOX_KHR, - VK_PRESENT_MODE_FIFO_RELAXED_KHR, - VK_PRESENT_MODE_FIFO_KHR, - VK_PRESENT_MODE_IMMEDIATE_KHR, - }; - - VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; - for (uint32_t i = 0; i < sizeof(tryModes) / sizeof(VkPresentModeKHR); ++i) { - if (hasPresentMode(tryModes[i], presentModes, nPresentModes)) { - presentMode = tryModes[i]; - break; - } - } - - free(presentModes); - vk->presentMode = presentMode; - printf("Using present mode: \"%s\" (%u)\n", - presentModeString(presentMode), - presentMode); - - return VK_SUCCESS; -} - -static VkResult -createRawSwapchain(VulkanState* const vk, - const uint32_t width, - const uint32_t height) -{ - VkSurfaceCapabilitiesKHR surfaceCapabilities; - VkResult vr = VK_SUCCESS; - if ((vr = vkGetPhysicalDeviceSurfaceCapabilitiesKHR( - vk->physicalDevice, vk->surface, &surfaceCapabilities))) { - logError("Could not get surface capabilities: %d\n", vr); - return vr; - } - - /* There is a known race condition with window/surface sizes, so we clamp - to what Vulkan reports and hope for the best. */ - - vk->swapchain->extent.width = CLAMP(width, - surfaceCapabilities.minImageExtent.width, - surfaceCapabilities.maxImageExtent.width); - - vk->swapchain->extent.height = - CLAMP(height, - surfaceCapabilities.minImageExtent.height, - surfaceCapabilities.maxImageExtent.height); - - vk->swapchain->nImages = surfaceCapabilities.minImageCount; - - const VkSwapchainCreateInfoKHR createInfo = { - VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, - NULL, - 0, - vk->surface, - vk->swapchain->nImages, - vk->surfaceFormat.format, - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, - vk->swapchain->extent, - 1, - (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT), - VK_SHARING_MODE_EXCLUSIVE, - COUNTED(0, NULL), - surfaceCapabilities.currentTransform, - VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, - vk->presentMode, - VK_TRUE, - 0, - }; - - if ((vr = vkCreateSwapchainKHR( - vk->device, &createInfo, ALLOC_VK, &vk->swapchain->rawSwapchain))) { - logError("Could not create swapchain: %d\n", vr); - return vr; - } - - return VK_SUCCESS; -} - -static VkResult -recordCommandBuffers(VulkanState* const vk) -{ - const VkClearColorValue clearValue = {{ - 0xA4 / (float)0x100, // R - 0x1E / (float)0x100, // G - 0x22 / (float)0x100, // B - 0xFF / (float)0x100, // A - }}; - - const VkImageSubresourceRange range = { - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - 1, - 0, - 1, - }; - - const VkCommandBufferBeginInfo beginInfo = { - VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, - NULL, - VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, - NULL, - }; - - for (uint32_t i = 0; i < vk->swapchain->nImages; ++i) { - const VkImageMemoryBarrier toClearBarrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - NULL, - VK_ACCESS_MEMORY_READ_BIT, - VK_ACCESS_TRANSFER_WRITE_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - vk->graphicsIndex, - vk->graphicsIndex, - vk->swapchain->images[i], - range, - }; - - const VkImageMemoryBarrier toPresentBarrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - NULL, - VK_ACCESS_TRANSFER_WRITE_BIT, - VK_ACCESS_MEMORY_READ_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - vk->graphicsIndex, - vk->graphicsIndex, - vk->swapchain->images[i], - range, - }; - - vkBeginCommandBuffer(vk->swapchain->commandBuffers[i], &beginInfo); - - vkCmdPipelineBarrier(vk->swapchain->commandBuffers[i], - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - 0, - COUNTED(0, NULL), - COUNTED(0, NULL), - COUNTED(1, &toClearBarrier)); - - vkCmdClearColorImage(vk->swapchain->commandBuffers[i], - vk->swapchain->images[i], - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - &clearValue, - COUNTED(1, &range)); - - vkCmdPipelineBarrier(vk->swapchain->commandBuffers[i], - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, - 0, - COUNTED(0, NULL), - COUNTED(0, NULL), - COUNTED(1, &toPresentBarrier)); - - vkEndCommandBuffer(vk->swapchain->commandBuffers[i]); - } - - return VK_SUCCESS; -} - -static VkResult -createSwapchain(VulkanState* const vk, - const uint32_t width, - const uint32_t height) -{ - VkResult vr = VK_SUCCESS; - - vk->swapchain = AALLOC(1, Swapchain); - if ((vr = createRawSwapchain(vk, width, height))) { - return vr; - } - - if ((vr = vkGetSwapchainImagesKHR(vk->device, - vk->swapchain->rawSwapchain, - &vk->swapchain->nImages, - NULL))) { - logError("Failed to query swapchain images: %d\n", vr); - return vr; - } - - vk->swapchain->images = AALLOC(vk->swapchain->nImages, VkImage); - if ((vr = vkGetSwapchainImagesKHR(vk->device, - vk->swapchain->rawSwapchain, - &vk->swapchain->nImages, - vk->swapchain->images))) { - logError("Failed to get swapchain images: %d\n", vr); - return vr; - } - - const VkCommandBufferAllocateInfo allocInfo = { - VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - NULL, - vk->commandPool, - VK_COMMAND_BUFFER_LEVEL_PRIMARY, - vk->swapchain->nImages, - }; - - vk->swapchain->commandBuffers = - AALLOC(vk->swapchain->nImages, VkCommandBuffer); - - if ((vr = vkAllocateCommandBuffers( - vk->device, &allocInfo, vk->swapchain->commandBuffers))) { - logError("Could not allocate command buffers: %d\n", vr); - return vr; - } - - const VkFenceCreateInfo fenceInfo = { - VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, - NULL, - VK_FENCE_CREATE_SIGNALED_BIT, - }; - vk->swapchain->fences = AALLOC(vk->swapchain->nImages, VkFence); - - for (uint32_t i = 0; i < vk->swapchain->nImages; ++i) { - if ((vr = vkCreateFence( - vk->device, &fenceInfo, ALLOC_VK, &vk->swapchain->fences[i]))) { - logError("Could not create render finished fence: %d\n", vr); - return vr; - } - } - - if ((vr = recordCommandBuffers(vk))) { - logError("Failed to record command buffers\n"); - return vr; - } - - return VK_SUCCESS; -} - -static void -destroySwapchain(VulkanState* const vk, Swapchain* const swapchain) -{ - if (!swapchain) { - return; - } - - for (uint32_t i = 0; i < swapchain->nImages; ++i) { - if (swapchain->fences[i]) { - vkDestroyFence(vk->device, swapchain->fences[i], ALLOC_VK); - } - - if (swapchain->imageViews && swapchain->imageViews[i]) { - vkDestroyImageView(vk->device, swapchain->imageViews[i], ALLOC_VK); - } - } - - free(swapchain->fences); - swapchain->fences = NULL; - free(swapchain->imageViews); - swapchain->imageViews = NULL; - - if (swapchain->images) { - free(swapchain->images); - swapchain->images = NULL; - } - - if (swapchain->commandBuffers) { - vkFreeCommandBuffers(vk->device, - vk->commandPool, - swapchain->nImages, - swapchain->commandBuffers); - free(swapchain->commandBuffers); - } - - if (swapchain->rawSwapchain) { - vkDestroySwapchainKHR(vk->device, swapchain->rawSwapchain, ALLOC_VK); - } - - free(swapchain); -} - -static VkResult -createSyncObjects(VulkanState* const vk) -{ - const VkSemaphoreCreateInfo info = { - VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, - NULL, - 0, - }; - - vkCreateSemaphore(vk->device, &info, ALLOC_VK, &vk->sync.presentComplete); - vkCreateSemaphore(vk->device, &info, ALLOC_VK, &vk->sync.renderFinished); - return VK_SUCCESS; -} - -static void -destroySyncObjects(VulkanState* const vk) -{ - if (vk->sync.renderFinished) { - vkDestroySemaphore(vk->device, vk->sync.renderFinished, ALLOC_VK); - vk->sync.renderFinished = VK_NULL_HANDLE; - } - if (vk->sync.presentComplete) { - vkDestroySemaphore(vk->device, vk->sync.presentComplete, ALLOC_VK); - vk->sync.presentComplete = VK_NULL_HANDLE; - } -} - -static void -closeDevice(VulkanState* const vk) -{ - if (vk->device) { - vkDeviceWaitIdle(vk->device); - destroySyncObjects(vk); - destroySwapchain(vk, vk->swapchain); - if (vk->commandPool) { - vkDestroyCommandPool(vk->device, vk->commandPool, ALLOC_VK); - vk->commandPool = VK_NULL_HANDLE; - } - vk->graphicsQueue = VK_NULL_HANDLE; - vkDestroyDevice(vk->device, ALLOC_VK); - vk->device = VK_NULL_HANDLE; - } -} - -static void -destroyWorld(VulkanApp* const app) -{ - VulkanState* vk = &app->vk; - - if (vk) { - closeDevice(vk); - - if (app->view) { - puglHide(app->view); - puglFreeView(app->view); - app->view = NULL; - } - if (vk->debugCallback && vk->api.vkDestroyDebugReportCallbackEXT) { - vk->api.vkDestroyDebugReportCallbackEXT( - vk->instance, vk->debugCallback, ALLOC_VK); - vk->debugCallback = VK_NULL_HANDLE; - } - if (vk->surface) { - vkDestroySurfaceKHR(vk->instance, vk->surface, ALLOC_VK); - vk->surface = VK_NULL_HANDLE; - } - if (vk->instance) { - fflush(stderr); - vkDestroyInstance(vk->instance, ALLOC_VK); - vk->instance = VK_NULL_HANDLE; - } - if (app->world) { - puglFreeWorld(app->world); - app->world = NULL; - } - } -} - -static PuglStatus -onConfigure(PuglView* const view, const double width, const double height) -{ - VulkanApp* const app = (VulkanApp*)puglGetHandle(view); - - // We just record the size here and lazily resize the surface when exposed - app->width = (uint32_t)width; - app->height = (uint32_t)height; - - return PUGL_SUCCESS; -} - -static PuglStatus -recreateSwapchain(VulkanState* const vk, - const uint32_t width, - const uint32_t height) -{ - vkDeviceWaitIdle(vk->device); - destroySwapchain(vk, vk->swapchain); - - if (createSwapchain(vk, width, height)) { - logError("Failed to recreate swapchain\n"); - return PUGL_UNKNOWN_ERROR; - } - - return PUGL_SUCCESS; -} - -static PuglStatus -onExpose(PuglView* const view) -{ - VulkanApp* app = (VulkanApp*)puglGetHandle(view); - VulkanState* vk = &app->vk; - uint32_t imageIndex = 0; - VkResult result = VK_SUCCESS; - - // Recreate swapchain if the window size has changed - const Swapchain* swapchain = vk->swapchain; - if (swapchain->extent.width != app->width || - swapchain->extent.height != app->height) { - recreateSwapchain(vk, app->width, app->height); - } - - // Acquire the next image to render, rebuilding if necessary - while ((result = vkAcquireNextImageKHR(vk->device, - vk->swapchain->rawSwapchain, - UINT64_MAX, - vk->sync.presentComplete, - VK_NULL_HANDLE, - &imageIndex))) { - switch (result) { - case VK_SUCCESS: - break; - case VK_SUBOPTIMAL_KHR: - case VK_ERROR_OUT_OF_DATE_KHR: - recreateSwapchain(vk, app->width, app->height); - continue; - default: - logError("Could not acquire swapchain image: %d\n", result); - return PUGL_UNKNOWN_ERROR; - } - } - - // Wait until we can start rendering this frame - vkWaitForFences(vk->device, - COUNTED(1, &vk->swapchain->fences[imageIndex]), - VK_TRUE, - UINT64_MAX); - vkResetFences(vk->device, 1, &vk->swapchain->fences[imageIndex]); - - const VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - - // Submit command buffer to render this frame - const VkSubmitInfo submitInfo = { - VK_STRUCTURE_TYPE_SUBMIT_INFO, - NULL, - COUNTED(1, &vk->sync.presentComplete), - &waitStage, - COUNTED(1, &vk->swapchain->commandBuffers[imageIndex]), - COUNTED(1, &vk->sync.renderFinished)}; - if ((result = vkQueueSubmit(vk->graphicsQueue, - 1, - &submitInfo, - vk->swapchain->fences[imageIndex]))) { - logError("Could not submit to queue: %d\n", result); - return PUGL_FAILURE; - } - - // Present this frame - const VkPresentInfoKHR presentInfo = { - VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, - NULL, - COUNTED(1, &vk->sync.renderFinished), - COUNTED(1, &vk->swapchain->rawSwapchain, &imageIndex, NULL), - }; - if ((result = vkQueuePresentKHR(vk->graphicsQueue, &presentInfo))) { - logError("Could not present image: %d\n", result); - } - - if (app->opts.continuous) { - ++app->framesDrawn; - } - - return PUGL_SUCCESS; -} - -static PuglStatus -onEvent(PuglView* const view, const PuglEvent* const e) -{ - VulkanApp* const app = (VulkanApp*)puglGetHandle(view); - - printEvent(e, "Event: ", app->opts.verbose); - - switch (e->type) { - case PUGL_EXPOSE: - return onExpose(view); - case PUGL_CONFIGURE: - return onConfigure(view, e->configure.width, e->configure.height); - case PUGL_CLOSE: - app->quit = 1; - break; - case PUGL_KEY_PRESS: - switch (e->key.key) { - case PUGL_KEY_ESCAPE: - case 'q': - app->quit = 1; - break; - } - break; - default: - break; - } - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - VulkanApp app = {0}; - VulkanState* vk = &app.vk; - const uint32_t defaultWidth = 640; - const uint32_t defaultHeight = 360; - const PuglRect frame = {0, 0, defaultWidth, defaultHeight}; - - // Parse command line options - app.opts = puglParseTestOptions(&argc, &argv); - if (app.opts.help) { - puglPrintTestUsage(argv[0], ""); - return 0; - } - - // Create world and view - if (!(app.world = puglNewWorld(PUGL_PROGRAM, PUGL_WORLD_THREADS))) { - return logError("Failed to create world\n"); - } - - if (!(app.view = puglNewView(app.world))) { - puglFreeWorld(app.world); - return logError("Failed to create Pugl World and View\n"); - } - - // Create Vulkan instance - if (createInstance(&app)) { - puglFreeWorld(app.world); - return logError("Failed to create instance\n"); - } - - // Create window - puglSetWindowTitle(app.view, "Pugl Vulkan"); - puglSetFrame(app.view, frame); - puglSetHandle(app.view, &app); - puglSetBackend(app.view, puglVulkanBackend()); - puglSetViewHint(app.view, PUGL_RESIZABLE, app.opts.resizable); - puglSetEventFunc(app.view, onEvent); - const PuglStatus st = puglRealize(app.view); - if (st) { - puglFreeWorld(app.world); - puglFreeView(app.view); - return logError("Failed to create window (%s)\n", puglStrerror(st)); - } - - // Create Vulkan surface for Window - PuglVulkanLoader* loader = puglNewVulkanLoader(app.world); - if (puglCreateSurface(puglGetInstanceProcAddrFunc(loader), - app.view, - vk->instance, - ALLOC_VK, - &vk->surface)) { - return logError("Failed to create surface\n"); - } - - // Set up Vulkan - VkResult vr = VK_SUCCESS; - if ((vr = enableDebugging(vk)) || // - (vr = selectPhysicalDevice(vk)) || // - (vr = openDevice(vk)) || // - (vr = configureSurface(vk)) || // - (vr = createSwapchain(vk, defaultWidth, defaultHeight)) || // - (vr = createSyncObjects(vk))) { - destroyWorld(&app); - return logError("Failed to set up graphics (%d)\n", vr); - } - - printf("Swapchain images: %u\n", app.vk.swapchain->nImages); - - PuglFpsPrinter fpsPrinter = {puglGetTime(app.world)}; - puglShow(app.view); - while (!app.quit) { - puglUpdate(app.world, -1.0); - - if (app.opts.continuous) { - puglPrintFps(app.world, &fpsPrinter, &app.framesDrawn); - } - } - - destroyWorld(&app); - return 0; -} diff --git a/subprojects/nk_pugl/pugl/examples/pugl_window_demo.c b/subprojects/nk_pugl/pugl/examples/pugl_window_demo.c deleted file mode 100644 index f7d5b2c..0000000 --- a/subprojects/nk_pugl/pugl/examples/pugl_window_demo.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - A demonstration of using multiple top-level windows. -*/ - -#include "cube_view.h" -#include "demo_utils.h" -#include "test/test_utils.h" - -#include "pugl/gl.h" -#include "pugl/pugl.h" - -#include -#include -#include - -typedef struct { - PuglView* view; - double xAngle; - double yAngle; - double lastMouseX; - double lastMouseY; - double lastDrawTime; - float dist; - bool entered; -} CubeView; - -typedef struct { - PuglWorld* world; - CubeView cubes[2]; - int quit; - bool continuous; - bool verbose; -} PuglTestApp; - -static const double pad = 64.0; - -static void -onDisplay(PuglView* view) -{ - PuglWorld* world = puglGetWorld(view); - PuglTestApp* app = (PuglTestApp*)puglGetWorldHandle(world); - CubeView* cube = (CubeView*)puglGetHandle(view); - - const double thisTime = puglGetTime(app->world); - if (app->continuous) { - const double dTime = thisTime - cube->lastDrawTime; - - cube->xAngle = fmod(cube->xAngle + dTime * 100.0, 360.0); - cube->yAngle = fmod(cube->yAngle + dTime * 100.0, 360.0); - } - - displayCube( - view, cube->dist, (float)cube->xAngle, (float)cube->yAngle, cube->entered); - - cube->lastDrawTime = thisTime; -} - -static void -onKeyPress(PuglView* view, const PuglEventKey* event) -{ - PuglWorld* world = puglGetWorld(view); - PuglTestApp* app = (PuglTestApp*)puglGetWorldHandle(world); - PuglRect frame = puglGetFrame(view); - - if (event->key == 'q' || event->key == PUGL_KEY_ESCAPE) { - app->quit = 1; - } else if (event->state & PUGL_MOD_SHIFT) { - if (event->key == PUGL_KEY_UP) { - frame.height += 10; - } else if (event->key == PUGL_KEY_DOWN) { - frame.height -= 10; - } else if (event->key == PUGL_KEY_LEFT) { - frame.width -= 10; - } else if (event->key == PUGL_KEY_RIGHT) { - frame.width += 10; - } else { - return; - } - puglSetFrame(view, frame); - } else { - if (event->key == PUGL_KEY_UP) { - frame.y -= 10; - } else if (event->key == PUGL_KEY_DOWN) { - frame.y += 10; - } else if (event->key == PUGL_KEY_LEFT) { - frame.x -= 10; - } else if (event->key == PUGL_KEY_RIGHT) { - frame.x += 10; - } else { - return; - } - puglSetFrame(view, frame); - } -} - -static void -redisplayView(PuglTestApp* app, PuglView* view) -{ - if (!app->continuous) { - puglPostRedisplay(view); - } -} - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglWorld* world = puglGetWorld(view); - PuglTestApp* app = (PuglTestApp*)puglGetWorldHandle(world); - CubeView* cube = (CubeView*)puglGetHandle(view); - - const char* const prefix = cube == &app->cubes[0] ? "View 1: " : "View 2: "; - printEvent(event, prefix, app->verbose); - - switch (event->type) { - case PUGL_CONFIGURE: - reshapeCube((float)event->configure.width, (float)event->configure.height); - break; - case PUGL_UPDATE: - if (app->continuous) { - puglPostRedisplay(view); - } - break; - case PUGL_EXPOSE: - onDisplay(view); - break; - case PUGL_CLOSE: - app->quit = 1; - break; - case PUGL_KEY_PRESS: - onKeyPress(view, &event->key); - break; - case PUGL_MOTION: - cube->xAngle -= event->motion.x - cube->lastMouseX; - cube->yAngle += event->motion.y - cube->lastMouseY; - cube->lastMouseX = event->motion.x; - cube->lastMouseY = event->motion.y; - redisplayView(app, view); - break; - case PUGL_SCROLL: - cube->dist = fmaxf(10.0f, cube->dist + (float)event->scroll.dy); - redisplayView(app, view); - break; - case PUGL_POINTER_IN: - cube->entered = true; - redisplayView(app, view); - break; - case PUGL_POINTER_OUT: - cube->entered = false; - redisplayView(app, view); - break; - case PUGL_FOCUS_IN: - case PUGL_FOCUS_OUT: - redisplayView(app, view); - break; - default: - break; - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - PuglTestApp app = {0}; - - const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); - if (opts.help) { - puglPrintTestUsage(argv[0], ""); - return 1; - } - - app.continuous = opts.continuous; - app.verbose = opts.verbose; - - app.world = puglNewWorld(PUGL_PROGRAM, 0); - app.cubes[0].view = puglNewView(app.world); - app.cubes[1].view = puglNewView(app.world); - - puglSetWorldHandle(app.world, &app); - puglSetClassName(app.world, "Pugl Test"); - - PuglStatus st = PUGL_SUCCESS; - for (unsigned i = 0; i < 2; ++i) { - CubeView* cube = &app.cubes[i]; - PuglView* view = cube->view; - const PuglRect frame = { - pad + (128.0 + pad) * i, pad + (128.0 + pad) * i, 512.0, 512.0}; - - cube->dist = 10; - - puglSetWindowTitle(view, "Pugl Window Demo"); - puglSetFrame(view, frame); - puglSetDefaultSize(view, 512, 512); - puglSetMinSize(view, 128, 128); - puglSetMaxSize(view, 2048, 2048); - puglSetBackend(view, puglGlBackend()); - - puglSetViewHint(view, PUGL_USE_DEBUG_CONTEXT, opts.errorChecking); - puglSetViewHint(view, PUGL_RESIZABLE, opts.resizable); - puglSetViewHint(view, PUGL_SAMPLES, opts.samples); - puglSetViewHint(view, PUGL_DOUBLE_BUFFER, opts.doubleBuffer); - puglSetViewHint(view, PUGL_SWAP_INTERVAL, opts.sync); - puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, opts.ignoreKeyRepeat); - puglSetHandle(view, cube); - puglSetEventFunc(view, onEvent); - - if (i == 1) { - puglSetTransientFor(app.cubes[1].view, - puglGetNativeWindow(app.cubes[0].view)); - } - - if ((st = puglRealize(view))) { - return logError("Failed to create window (%s)\n", puglStrerror(st)); - } - - puglShow(view); - } - - PuglFpsPrinter fpsPrinter = {puglGetTime(app.world)}; - unsigned framesDrawn = 0; - while (!app.quit) { - puglUpdate(app.world, app.continuous ? 0.0 : -1.0); - ++framesDrawn; - - if (app.continuous) { - puglPrintFps(app.world, &fpsPrinter, &framesDrawn); - } - } - - for (size_t i = 0; i < 2; ++i) { - puglFreeView(app.cubes[i].view); - } - - puglFreeWorld(app.world); - - return 0; -} diff --git a/subprojects/nk_pugl/pugl/examples/rects.h b/subprojects/nk_pugl/pugl/examples/rects.h deleted file mode 100644 index b99d9f0..0000000 --- a/subprojects/nk_pugl/pugl/examples/rects.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - Copyright 2019-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef EXAMPLES_RECTS_H -#define EXAMPLES_RECTS_H - -#include -#include - -typedef float vec2[2]; - -typedef struct { - float pos[2]; - float size[2]; - float fillColor[4]; -} Rect; - -static const vec2 rectVertices[] = { - {0.0f, 0.0f}, // TL - {1.0f, 0.0f}, // TR - {0.0f, 1.0f}, // BL - {1.0f, 1.0f} // BR -}; - -static const unsigned rectIndices[4] = {0, 1, 2, 3}; - -/// Make a new rectangle with the given index (each is slightly different) -static inline Rect -makeRect(const size_t index, const float frameWidth) -{ - static const float alpha = 0.3f; - const float minSize = frameWidth / 64.0f; - const float maxSize = frameWidth / 6.0f; - const float s = (sinf((float)index) / 2.0f + 0.5f); - const float c = (cosf((float)index) / 2.0f + 0.5f); - - const Rect rect = { - {0.0f, 0.0f}, // Position is set later during expose - {minSize + s * maxSize, minSize + c * maxSize}, - {0.0f, s / 2.0f + 0.25f, c / 2.0f + 0.25f, alpha}, - }; - - return rect; -} - -/// Move `rect` with the given index around in an arbitrary way that looks cool -static inline void -moveRect(Rect* const rect, - const size_t index, - const size_t numRects, - const float frameWidth, - const float frameHeight, - const double time) -{ - const float normal = (float)index / (float)numRects; - const float offset[2] = {normal * 128.0f, normal * 128.0f}; - - rect->pos[0] = (frameWidth - rect->size[0] + offset[0]) * - (sinf((float)time * rect->size[0] / 64.0f + normal) + 1.0f) / - 2.0f; - rect->pos[1] = (frameHeight - rect->size[1] + offset[1]) * - (cosf((float)time * rect->size[1] / 64.0f + normal) + 1.0f) / - 2.0f; -} - -#endif // EXAMPLES_RECTS_H diff --git a/subprojects/nk_pugl/pugl/examples/shader_utils.h b/subprojects/nk_pugl/pugl/examples/shader_utils.h deleted file mode 100644 index 2575f47..0000000 --- a/subprojects/nk_pugl/pugl/examples/shader_utils.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - Copyright 2019-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef EXAMPLES_SHADER_UTILS_H -#define EXAMPLES_SHADER_UTILS_H - -#include "glad/glad.h" - -#include -#include -#include - -typedef struct { - GLuint vertexShader; - GLuint fragmentShader; - GLuint program; -} Program; - -static GLuint -compileShader(const char* header, const char* source, const GLenum type) -{ - const GLchar* sources[] = {header, source}; - const GLint lengths[] = {(GLint)strlen(header), (GLint)strlen(source)}; - GLuint shader = glCreateShader(type); - glShaderSource(shader, 2, sources, lengths); - glCompileShader(shader); - - int status = 0; - glGetShaderiv(shader, GL_COMPILE_STATUS, &status); - if (status == GL_FALSE) { - GLint length = 0; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); - - char* log = (char*)calloc(1, (size_t)length); - glGetShaderInfoLog(shader, length, &length, log); - fprintf(stderr, "error: Failed to compile shader (%s)\n", log); - free(log); - - return 0; - } - - return shader; -} - -static void -deleteProgram(Program program) -{ - glDeleteShader(program.vertexShader); - glDeleteShader(program.fragmentShader); - glDeleteProgram(program.program); -} - -static Program -compileProgram(const char* headerSource, - const char* vertexSource, - const char* fragmentSource) -{ - static const Program nullProgram = {0, 0, 0}; - - Program program = { - compileShader(headerSource, vertexSource, GL_VERTEX_SHADER), - compileShader(headerSource, fragmentSource, GL_FRAGMENT_SHADER), - glCreateProgram(), - }; - - if (!program.vertexShader || !program.fragmentShader || !program.program) { - deleteProgram(program); - return nullProgram; - } - - glAttachShader(program.program, program.vertexShader); - glAttachShader(program.program, program.fragmentShader); - glLinkProgram(program.program); - - GLint status = 0; - glGetProgramiv(program.program, GL_LINK_STATUS, &status); - if (status == GL_FALSE) { - GLint length = 0; - glGetProgramiv(program.program, GL_INFO_LOG_LENGTH, &length); - - char* log = (char*)calloc(1, (size_t)length); - glGetProgramInfoLog(program.program, length, &length, &log[0]); - fprintf(stderr, "error: Failed to link program (%s)\n", log); - free(log); - - deleteProgram(program); - return nullProgram; - } - - return program; -} - -#endif // EXAMPLES_SHADER_UTILS_H diff --git a/subprojects/nk_pugl/pugl/examples/shaders/header_330.glsl b/subprojects/nk_pugl/pugl/examples/shaders/header_330.glsl deleted file mode 100644 index 59d5f6f..0000000 --- a/subprojects/nk_pugl/pugl/examples/shaders/header_330.glsl +++ /dev/null @@ -1,4 +0,0 @@ -#version 330 core - -#define INTER(qualifiers) -#define UBO(qualifiers) layout(std140) diff --git a/subprojects/nk_pugl/pugl/examples/shaders/header_420.glsl b/subprojects/nk_pugl/pugl/examples/shaders/header_420.glsl deleted file mode 100644 index 2beaad0..0000000 --- a/subprojects/nk_pugl/pugl/examples/shaders/header_420.glsl +++ /dev/null @@ -1,4 +0,0 @@ -#version 420 core - -#define INTER(qualifiers) layout(qualifiers) -#define UBO(qualifiers) layout(std140, qualifiers) diff --git a/subprojects/nk_pugl/pugl/examples/shaders/meson.build b/subprojects/nk_pugl/pugl/examples/shaders/meson.build deleted file mode 100644 index e47be9d..0000000 --- a/subprojects/nk_pugl/pugl/examples/shaders/meson.build +++ /dev/null @@ -1,35 +0,0 @@ -shader_files = [ - 'header_330.glsl', - 'header_420.glsl', - 'rect.frag', - 'rect.vert', -] - -# Copy shader sources for GL examples -foreach shader_file : shader_files - configure_file(copy: true, input: shader_file, output: shader_file) -endforeach - -# Build SPV shader binaries for Vulkan examples -if vulkan_dep.found() - cat = find_program('../../scripts/cat.py') - glslang = find_program('glslangValidator') - - shaders = ['rect.vert', 'rect.frag'] - foreach shader : shaders - source = shader.split('.')[0] + '.vulkan.' + shader.split('.')[1] - shader_input = custom_target(source, - output: source, - input: ['header_420.glsl', shader], - command: [cat, '@INPUT@'], - build_by_default: true, - capture: true) - - mytarget = custom_target(shader, - output: shader + '.spv', - input: shader_input, - command: [glslang, '-V', '-o', '@OUTPUT@', '@INPUT@'], - build_by_default: true, - install: false) - endforeach -endif diff --git a/subprojects/nk_pugl/pugl/examples/shaders/rect.frag b/subprojects/nk_pugl/pugl/examples/shaders/rect.frag deleted file mode 100644 index 33bfbb2..0000000 --- a/subprojects/nk_pugl/pugl/examples/shaders/rect.frag +++ /dev/null @@ -1,33 +0,0 @@ -/* The fragment shader uses the UV coordinates to calculate whether it is in - the T, R, B, or L border. These are then mixed with the border color, and - their inverse is mixed with the fill color, to calculate the fragment color. - For example, if we are in the top border, then T=1, so the border mix factor - TRBL=1, and the fill mix factor (1-TRBL) is 0. - - The use of pixel units here is handy because the border width can be - specified precisely in pixels to draw sharp lines. The border width is just - hardcoded, but could be made a uniform or vertex attribute easily enough. */ - -INTER(location = 0) noperspective in vec2 f_uv; -INTER(location = 1) noperspective in vec2 f_size; -INTER(location = 2) noperspective in vec4 f_fillColor; - -layout(location = 0) out vec4 FragColor; - -void -main() -{ - const float borderWidth = 2.0; - - vec4 borderColor = f_fillColor + vec4(0.0, 0.4, 0.4, 0.0); - float t = step(borderWidth, f_uv[1]); - float r = step(borderWidth, f_size.x - f_uv[0]); - float b = step(borderWidth, f_size.y - f_uv[1]); - float l = step(borderWidth, f_uv[0]); - float fillMix = t * r * b * l; - float borderMix = 1.0 - fillMix; - vec4 fill = fillMix * f_fillColor; - vec4 border = borderMix * borderColor; - - FragColor = fill + border; -} diff --git a/subprojects/nk_pugl/pugl/examples/shaders/rect.vert b/subprojects/nk_pugl/pugl/examples/shaders/rect.vert deleted file mode 100644 index 2c7b5f1..0000000 --- a/subprojects/nk_pugl/pugl/examples/shaders/rect.vert +++ /dev/null @@ -1,36 +0,0 @@ -/* The vertex shader is trivial, but forwards scaled UV coordinates (in pixels) - to the fragment shader for drawing the border. */ - -UBO(binding = 0) uniform UniformBufferObject -{ - mat4 projection; -} -ubo; - -layout(location = 0) in vec2 v_position; -layout(location = 1) in vec2 v_origin; -layout(location = 2) in vec2 v_size; -layout(location = 3) in vec4 v_fillColor; - -INTER(location = 0) noperspective out vec2 f_uv; -INTER(location = 1) noperspective out vec2 f_size; -INTER(location = 2) noperspective out vec4 f_fillColor; - -void -main() -{ - // clang-format off - mat4 m = mat4(v_size[0], 0.0, 0.0, 0.0, - 0.0, v_size[1], 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - v_origin[0], v_origin[1], 0.0, 1.0); - // clang-format on - - mat4 MVP = ubo.projection * m; - - f_uv = v_position * v_size; - f_size = v_size; - f_fillColor = v_fillColor; - - gl_Position = MVP * vec4(v_position, 0.0, 1.0); -} diff --git a/subprojects/nk_pugl/pugl/examples/sybok.hpp b/subprojects/nk_pugl/pugl/examples/sybok.hpp deleted file mode 100644 index 7740824..0000000 --- a/subprojects/nk_pugl/pugl/examples/sybok.hpp +++ /dev/null @@ -1,2325 +0,0 @@ -/* - Copyright 2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/** - @file sybok.hpp - @brief A minimal C++ wrapper for the Vulkan API. - - This is a manually-written minimal wrapper for Vulkan. It makes working - with Vulkan a little easier in C++, but takes a different approach than - vulkan.hpp. In particular: - - - Works nicely with dynamic loading. Since the API itself is an object, it - is simple to ensure the dynamically loaded API (or a consistent API in - general) is used everywhere. Passing a dispatch parameter to every - function as in vulkan.hpp makes dynamic loading extremely painful (not to - mention ugly), and mistakes tend to become link time errors. This is, in - my opinion, a glaring design flaw, and the real reason why this wrapper - reluctantly exists. - - - Explicit separation of the initial API that does not require an instance - to load, from the rest of the API that does. - - - Opinionated use of scoped handles everywhere. - - - Remains close to the C API so that code can be easily ported. This means - that the pattern of return codes with output parameters is preserved, - except with smart handles that make leaks impossible. While less pretty, - this does not require exceptions. - - - No exceptions or RTTI required. - - - A safe scoped API for commands that encodes the semantics of the Vulkan - API. For example, it is statically impossible to call render scope - commands while not in a render scope. - - - A reasonable amount of relatively readable code. - - On the other hand, there are far fewer niceties, and the C API is used - directly as much as possible, particularly for structs (although they are - taken by const reference so they can be written inline). There is only - support for a minimal portable subset of Vulkan 1.1 with a few portable KHR - extensions. - - In short, if the above sounds appealing, or you want a minimal wrapper that - can be extended if necessary to suit your application, you might find this - useful. If you want a fully-featured wrapper for Vulkan and don't care - about linker dependencies, you probably won't. -*/ - -#ifndef SYBOK_HPP -#define SYBOK_HPP - -#ifdef VULKAN_CORE_H_ -# error "sybok.hpp must be included before or instead of vulkan headers" -#endif - -#ifdef __GNUC__ -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wswitch-enum" -#endif - -#define VK_NO_PROTOTYPES - -// On 64-bit platforms, all handles are "dispatchable" pointers -#if defined(__LP64__) || defined(_WIN64) || \ - (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || \ - defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || \ - defined(__powerpc64__) - -# define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) \ - typedef struct object##_T* object; // NOLINT(bugprone-macro-parentheses) - -// On 32-bit platforms, some "non-dispatchable" handles are 64 bit integers -#else - -/// Trivial wrapper class for a 64-bit integer handle for type safety -template -struct NonDispatchableHandle { - explicit operator uint64_t() const noexcept { return handle; } - explicit operator bool() const noexcept { return handle; } - - uint64_t handle; -}; - -# define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) \ - using object = NonDispatchableHandle; - -#endif - -#include // IWYU pragma: export - -#include -#include -#include -#include -#include -#include - -#if __cplusplus >= 201703L -# define SYBOK_NODISCARD [[nodiscard]] -#elif defined(__GNUC__) -# define SYBOK_NODISCARD [[gnu::warn_unused_result]] -#else -# define SYBOK_NODISCARD -#endif - -/// Helper macro to make array arguments format nicely -#define SK_COUNTED(count, ...) count, __VA_ARGS__ - -namespace sk { - -class CommandScope; -class RenderCommandScope; - -inline const char* -string(const VkResult result) -{ - switch (result) { - case VK_SUCCESS: - return "Success"; - case VK_NOT_READY: - return "Not Ready"; - case VK_TIMEOUT: - return "Timeout"; - case VK_EVENT_SET: - return "Event set"; - case VK_EVENT_RESET: - return "Event reset"; - case VK_INCOMPLETE: - return "Incomplete"; - case VK_ERROR_OUT_OF_HOST_MEMORY: - return "Out of host memory"; - case VK_ERROR_OUT_OF_DEVICE_MEMORY: - return "Out of device memory"; - case VK_ERROR_INITIALIZATION_FAILED: - return "Initialization failed"; - case VK_ERROR_DEVICE_LOST: - return "Device lost"; - case VK_ERROR_MEMORY_MAP_FAILED: - return "Memory map failed"; - case VK_ERROR_LAYER_NOT_PRESENT: - return "Layer not present"; - case VK_ERROR_EXTENSION_NOT_PRESENT: - return "Extension not present"; - case VK_ERROR_FEATURE_NOT_PRESENT: - return "Feature not present"; - case VK_ERROR_INCOMPATIBLE_DRIVER: - return "Incompatible driver"; - case VK_ERROR_TOO_MANY_OBJECTS: - return "Too many objects"; - case VK_ERROR_FORMAT_NOT_SUPPORTED: - return "Format not supported"; - case VK_ERROR_FRAGMENTED_POOL: - return "Fragmented pool"; - case VK_ERROR_OUT_OF_POOL_MEMORY: // Vulkan 1.1 - return "Out of pool memory"; - case VK_ERROR_INVALID_EXTERNAL_HANDLE: // Vulkan 1.1 - return "Invalid external handle"; - case VK_ERROR_SURFACE_LOST_KHR: // VK_KHR_surface - return "Surface lost"; - case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: // VK_KHR_surface - return "Native window in use"; - case VK_SUBOPTIMAL_KHR: // VK_KHR_swapchain - return "Suboptimal"; - case VK_ERROR_OUT_OF_DATE_KHR: // VK_KHR_swapchain - return "Out of date"; - case VK_ERROR_VALIDATION_FAILED_EXT: // VK_EXT_debug_report - return "Validation failed"; - default: - break; - } - - return "Unknown error"; -} - -inline const char* -string(const VkPresentModeKHR presentMode) -{ - switch (presentMode) { - case VK_PRESENT_MODE_IMMEDIATE_KHR: - return "Immediate"; - case VK_PRESENT_MODE_MAILBOX_KHR: - return "Mailbox"; - case VK_PRESENT_MODE_FIFO_KHR: - return "FIFO"; - case VK_PRESENT_MODE_FIFO_RELAXED_KHR: - return "Relaxed FIFO"; - default: - break; - } - - return "Unknown present mode"; -} - -inline const char* -string(const VkDebugReportFlagBitsEXT flag) -{ - switch (flag) { - case VK_DEBUG_REPORT_INFORMATION_BIT_EXT: - return "Information"; - case VK_DEBUG_REPORT_WARNING_BIT_EXT: - return "Warning"; - case VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT: - return "Performance Warning"; - case VK_DEBUG_REPORT_ERROR_BIT_EXT: - return "Error"; - case VK_DEBUG_REPORT_DEBUG_BIT_EXT: - return "Debug"; - default: - break; - } - - return "Unknown report"; -} - -template -class GlobalDeleter -{ -public: - using DestroyFunc = void (*)(T, const VkAllocationCallbacks*); - - GlobalDeleter() = default; - ~GlobalDeleter() = default; - - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - GlobalDeleter(DestroyFunc destroyFunc) noexcept - : _destroyFunc{destroyFunc} - {} - - GlobalDeleter(const GlobalDeleter&) = delete; - GlobalDeleter& operator=(const GlobalDeleter&) = delete; - - GlobalDeleter(GlobalDeleter&& other) noexcept - { - std::swap(_destroyFunc, other._destroyFunc); - } - - GlobalDeleter& operator=(GlobalDeleter&& other) noexcept - { - std::swap(_destroyFunc, other._destroyFunc); - return *this; - } - - void operator()(T handle) noexcept - { - if (_destroyFunc && handle) { - _destroyFunc(handle, nullptr); - } - } - -private: - DestroyFunc _destroyFunc{}; -}; - -template -class DependantDeleter -{ -public: - using DestroyFunc = void (*)(Parent, T, const VkAllocationCallbacks*); - - DependantDeleter() = default; - ~DependantDeleter() = default; - - DependantDeleter(Parent parent, DestroyFunc destroyFunc) noexcept - : _parent{parent} - , _destroyFunc{destroyFunc} - {} - - DependantDeleter(const DependantDeleter&) = delete; - DependantDeleter& operator=(const DependantDeleter&) = delete; - - DependantDeleter(DependantDeleter&& other) noexcept { swap(other); } - - DependantDeleter& operator=(DependantDeleter&& other) noexcept - { - swap(other); - return *this; - } - - void operator()(T handle) noexcept - { - if (_parent && _destroyFunc && handle) { - _destroyFunc(_parent, handle, nullptr); - } - } - -private: - void swap(DependantDeleter& other) noexcept - { - std::swap(_parent, other._parent); - std::swap(_destroyFunc, other._destroyFunc); - } - - Parent _parent{}; - DestroyFunc _destroyFunc{}; -}; - -template -class PoolDeleter -{ -public: - using FreeFunc = FreeFuncResult (*)(VkDevice, Pool, uint32_t, const T*); - - PoolDeleter() noexcept = default; - ~PoolDeleter() noexcept = default; - - PoolDeleter(VkDevice device, - Pool pool, - uint32_t count, - FreeFunc freeFunc) noexcept - : _device{device} - , _pool{pool} - , _count{count} - , _freeFunc{freeFunc} - {} - - PoolDeleter(const PoolDeleter&) = delete; - PoolDeleter& operator=(const PoolDeleter&) = delete; - - PoolDeleter(PoolDeleter&& other) noexcept { swap(other); } - - PoolDeleter& operator=(PoolDeleter&& other) noexcept - { - swap(other); - return *this; - } - - void operator()(T* handle) noexcept - { - if (_device && _pool && handle) { - _freeFunc(_device, _pool, _count, handle); - } - } - -private: - void swap(PoolDeleter& other) noexcept - { - std::swap(_device, other._device); - std::swap(_pool, other._pool); - std::swap(_count, other._count); - std::swap(_freeFunc, other._freeFunc); - } - - VkDevice _device{}; - Pool _pool{}; - uint32_t _count{}; - FreeFunc _freeFunc{}; -}; - -template -class UniqueDispatchableHandle -{ -public: - using Deleter = TDeleter; - using Handle = T; - - static_assert(std::is_pointer::value, ""); - - UniqueDispatchableHandle() = default; - - UniqueDispatchableHandle(Handle handle, Deleter deleter) noexcept - : _handle{handle} - , _deleter{std::move(deleter)} - {} - - ~UniqueDispatchableHandle() noexcept - { - if (_handle) { - _deleter(_handle); - } - } - - UniqueDispatchableHandle(const UniqueDispatchableHandle&) noexcept = delete; - UniqueDispatchableHandle& operator =( - const UniqueDispatchableHandle&) noexcept = delete; - - UniqueDispatchableHandle(UniqueDispatchableHandle&& other) noexcept - { - swap(other); - } - - UniqueDispatchableHandle& operator=(UniqueDispatchableHandle&& other) noexcept - { - swap(other); - return *this; - } - - const Handle& get() const noexcept { return _handle; } - - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - operator Handle() const noexcept { return _handle; } - -private: - void swap(UniqueDispatchableHandle& other) noexcept - { - std::swap(_handle, other._handle); - std::swap(_deleter, other._deleter); - } - - Handle _handle{}; - Deleter _deleter{}; -}; - -#if defined(__LP64__) || defined(_WIN64) || \ - (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || \ - defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || \ - defined(__powerpc64__) - -template -using UniqueNonDispatchableHandle = UniqueDispatchableHandle; - -#else - -template -class UniqueNonDispatchableHandle -{ -public: - using Deleter = TDeleter; - using Handle = T; - - UniqueNonDispatchableHandle() = default; - - UniqueNonDispatchableHandle(T handle, Deleter deleter) noexcept - : _handle{handle} - , _deleter{std::move(deleter)} - { - assert(handle); - } - - ~UniqueNonDispatchableHandle() noexcept - { - if (_handle) { - _deleter(_handle); - } - } - - UniqueNonDispatchableHandle(const UniqueNonDispatchableHandle&) noexcept = - delete; - UniqueNonDispatchableHandle& operator =( - const UniqueNonDispatchableHandle&) noexcept = delete; - - UniqueNonDispatchableHandle(UniqueNonDispatchableHandle&& other) noexcept - { - swap(other); - } - - UniqueNonDispatchableHandle& operator=( - UniqueNonDispatchableHandle&& other) noexcept - { - swap(other); - return *this; - } - - const Handle& get() const noexcept { return _handle; } - - operator Handle() const noexcept { return _handle; } - -private: - void swap(UniqueNonDispatchableHandle& other) noexcept - { - std::swap(_handle, other._handle); - std::swap(_deleter, other._deleter); - } - - T _handle{}; - Deleter _deleter{}; -}; - -#endif - -template -class UniqueArrayHandle -{ -public: - using T = typename Vector::value_type; - - UniqueArrayHandle() = default; - - UniqueArrayHandle(uint32_t size, Vector&& array, Deleter deleter) noexcept - : _array{std::move(array)} - , _deleter{std::move(deleter)} - , _size{size} - { - assert(!_array.empty()); - } - - ~UniqueArrayHandle() noexcept - { - if (!_array.empty()) { - _deleter(_array.data()); - } - } - - UniqueArrayHandle(const UniqueArrayHandle&) noexcept = delete; - UniqueArrayHandle& operator=(const UniqueArrayHandle&) noexcept = delete; - - UniqueArrayHandle(UniqueArrayHandle&& other) noexcept { swap(other); } - - UniqueArrayHandle& operator=(UniqueArrayHandle&& other) noexcept - { - swap(other); - return *this; - } - - const T& operator[](const size_t index) const noexcept - { - return _array[index]; - } - - T& operator[](const size_t index) noexcept { return _array[index]; } - - const T* get() const noexcept { return _array.data(); } - T* get() noexcept { return _array.data(); } - -private: - void swap(UniqueArrayHandle& other) noexcept - { - std::swap(_array, other._array); - std::swap(_deleter, other._deleter); - std::swap(_size, other._size); - } - - Vector _array{}; - Deleter _deleter{}; - uint32_t _size{}; -}; - -template -class OptionalParameter -{ -public: - using Handle = typename T::Handle; - - // NOLINTNEXTLINE(hicpp-explicit-conversions, google-explicit-constructor) - OptionalParameter(const T& value) noexcept - : _handle{value.get()} - {} - - OptionalParameter() noexcept = default; - ~OptionalParameter() noexcept = default; - - OptionalParameter(const OptionalParameter&) = delete; - OptionalParameter& operator=(const OptionalParameter&) = delete; - - OptionalParameter(OptionalParameter&&) = delete; - OptionalParameter& operator=(OptionalParameter&&) = delete; - - Handle get() const noexcept { return _handle; } - -private: - Handle _handle{}; -}; - -template -using GlobalObject = UniqueDispatchableHandle>; - -template -using InstanceChild = - UniqueNonDispatchableHandle>; - -template -using DispatchableDeviceChild = - UniqueDispatchableHandle>; - -template -using NonDispatchableDeviceChild = - UniqueNonDispatchableHandle>; - -template -using PoolChild = UniqueArrayHandle< - Vector, - PoolDeleter>; - -using Device = GlobalObject; -using Instance = GlobalObject; - -using PhysicalDevice = VkPhysicalDevice; // Weak handle, no destroy function -using Queue = VkQueue; // Weak handle, no destroy function - -using Buffer = NonDispatchableDeviceChild; -using BufferView = NonDispatchableDeviceChild; -using CommandBuffer = DispatchableDeviceChild; -using CommandPool = NonDispatchableDeviceChild; -using DescriptorPool = NonDispatchableDeviceChild; -using DescriptorSetLayout = NonDispatchableDeviceChild; -using DeviceMemory = NonDispatchableDeviceChild; -using Event = NonDispatchableDeviceChild; -using Fence = NonDispatchableDeviceChild; -using Framebuffer = NonDispatchableDeviceChild; -using Image = NonDispatchableDeviceChild; -using ImageView = NonDispatchableDeviceChild; -using Pipeline = NonDispatchableDeviceChild; -using PipelineCache = NonDispatchableDeviceChild; -using PipelineLayout = NonDispatchableDeviceChild; -using QueryPool = NonDispatchableDeviceChild; -using RenderPass = NonDispatchableDeviceChild; -using Sampler = NonDispatchableDeviceChild; -using Semaphore = NonDispatchableDeviceChild; -using ShaderModule = NonDispatchableDeviceChild; - -template -using CommandBuffers = PoolChild; - -template -using DescriptorSets = - PoolChild; - -// VK_KHR_swapchain -using SwapchainKHR = NonDispatchableDeviceChild; - -// VK_KHR_surface -using SurfaceKHR = InstanceChild; - -// VK_EXT_debug_report -using DebugReportCallbackEXT = InstanceChild; - -template -struct IndexSequence {}; - -template -struct IndexSequenceHelper - : public IndexSequenceHelper {}; - -template -struct IndexSequenceHelper<0U, Next...> { - using type = IndexSequence; -}; - -template -using makeIndexSequence = typename IndexSequenceHelper::type; - -template -std::array -make_handle_array_h(Parent parent, - DestroyFunc destroyFunc, - std::array handles, - IndexSequence) noexcept -{ - return {T{handles[Is], {parent, destroyFunc}}...}; -} - -template -std::array -make_handle_array(Parent parent, - DestroyFunc destroyFunc, - std::array handles) noexcept -{ - return make_handle_array_h( - parent, destroyFunc, handles, makeIndexSequence()); -} - -namespace detail { - -template -inline VkResult -wrapVectorAccessor(Vector& vector, Func func, Args... args) noexcept -{ - uint32_t count = 0u; - VkResult r = func(args..., &count, nullptr); - if (r > VK_INCOMPLETE) { - vector.clear(); - return r; - } - - vector = Vector(count); - if ((r = func(args..., &count, vector.data()))) { - vector.clear(); - return r; - } - - return VK_SUCCESS; -} - -} // namespace detail - -class VulkanApi; - -struct MappedMemory { - MappedMemory() noexcept = default; - - MappedMemory(const VulkanApi& api, - VkDevice device, - VkDeviceMemory memory, - void* data) noexcept - : _api{&api} - , _device{device} - , _memory{memory} - , _data{data} - {} - - MappedMemory(const MappedMemory&) = delete; - MappedMemory& operator=(const MappedMemory&) = delete; - - MappedMemory(MappedMemory&& mappedMemory) noexcept - : _api{mappedMemory._api} - , _device{mappedMemory._device} - , _memory{mappedMemory._memory} - , _data{mappedMemory._data} - { - mappedMemory._device = {}; - mappedMemory._memory = {}; - mappedMemory._data = {}; - } - - MappedMemory& operator=(MappedMemory&& mappedMemory) noexcept - { - std::swap(_api, mappedMemory._api); - std::swap(_device, mappedMemory._device); - std::swap(_memory, mappedMemory._memory); - std::swap(_data, mappedMemory._data); - return *this; - } - - ~MappedMemory() noexcept; - - const void* get() const noexcept { return _data; } - void* get() noexcept { return _data; } - -private: - const VulkanApi* _api{}; - VkDevice _device{}; - VkDeviceMemory _memory{}; - void* _data{}; -}; - -class VulkanInitApi -{ -public: - template - VkResult init(PFN_vkGetInstanceProcAddr pGetInstanceProcAddr, - NotFoundFunc notFound) noexcept - { -#define SK_INIT(name) \ - do { \ - if (!(name = PFN_##name(getInstanceProcAddr(NULL, #name)))) { \ - notFound(#name); \ - } \ - } while (0) - - vkGetInstanceProcAddr = pGetInstanceProcAddr; - SK_INIT(vkCreateInstance); - vkDestroyInstance = {}; // Loaded after we create an instance - SK_INIT(vkEnumerateInstanceExtensionProperties); - SK_INIT(vkEnumerateInstanceLayerProperties); - - if (!vkCreateInstance || !vkEnumerateInstanceExtensionProperties || - !vkEnumerateInstanceLayerProperties) { - return VK_ERROR_INITIALIZATION_FAILED; - } - - return VK_SUCCESS; -#undef SK_INIT - } - - VkResult init(PFN_vkGetInstanceProcAddr pGetInstanceProcAddr) noexcept - { - return init(pGetInstanceProcAddr, [](const char*) {}); - } - - PFN_vkVoidFunction getInstanceProcAddr(VkInstance instance, - const char* const name) const noexcept - { - return vkGetInstanceProcAddr(instance, name); - } - - VkResult createInstance(const VkInstanceCreateInfo& createInfo, - Instance& instance) noexcept - { - VkInstance h = {}; - if (const VkResult r = vkCreateInstance(&createInfo, nullptr, &h)) { - return r; - } - - if (!h) { - // Shouldn't actually happen, but this lets the compiler know that - return VK_ERROR_INITIALIZATION_FAILED; - } - - if (!vkDestroyInstance) { - vkDestroyInstance = PFN_vkDestroyInstance( - getInstanceProcAddr(instance, "vkDestroyInstance")); - } - - instance = {h, {vkDestroyInstance}}; - return VK_SUCCESS; - } - - template - VkResult enumerateInstanceExtensionProperties( - Vector& properties) const noexcept - { - return detail::wrapVectorAccessor( - properties, vkEnumerateInstanceExtensionProperties, nullptr); - } - - template - VkResult enumerateInstanceExtensionProperties( - const char* const layerName, - Vector& properties) const noexcept - { - return detail::wrapVectorAccessor( - properties, vkEnumerateInstanceExtensionProperties, layerName); - } - - template - VkResult enumerateInstanceLayerProperties(Vector& properties) const noexcept - { - return detail::wrapVectorAccessor( - properties, vkEnumerateInstanceLayerProperties); - } - -private: - PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr{}; - -#define SK_FUNC(name) \ - PFN_##name name {} - - SK_FUNC(vkCreateInstance); - SK_FUNC(vkDestroyInstance); - SK_FUNC(vkEnumerateInstanceExtensionProperties); - SK_FUNC(vkEnumerateInstanceLayerProperties); - -#undef SK_FUNC -}; - -class VulkanApi -{ -public: - template - VkResult init(const VulkanInitApi& initApi, - const Instance& instance, - NotFoundFunc notFound) noexcept - { - VkResult r = VK_SUCCESS; - - const auto notFoundWrapper = [&r, notFound](const char* name) { - r = VK_INCOMPLETE; - notFound(name); - }; - -#define SK_INIT(name) \ - do { \ - if (!(name = PFN_##name(initApi.getInstanceProcAddr(instance, #name)))) { \ - notFoundWrapper(#name); \ - } \ - } while (0) - - SK_INIT(vkAllocateCommandBuffers); - SK_INIT(vkAllocateDescriptorSets); - SK_INIT(vkAllocateMemory); - SK_INIT(vkBeginCommandBuffer); - SK_INIT(vkBindBufferMemory); - SK_INIT(vkBindImageMemory); - SK_INIT(vkCmdBeginQuery); - SK_INIT(vkCmdBeginRenderPass); - SK_INIT(vkCmdBindDescriptorSets); - SK_INIT(vkCmdBindIndexBuffer); - SK_INIT(vkCmdBindPipeline); - SK_INIT(vkCmdBindVertexBuffers); - SK_INIT(vkCmdBlitImage); - SK_INIT(vkCmdClearAttachments); - SK_INIT(vkCmdClearColorImage); - SK_INIT(vkCmdClearDepthStencilImage); - SK_INIT(vkCmdCopyBuffer); - SK_INIT(vkCmdCopyBufferToImage); - SK_INIT(vkCmdCopyImage); - SK_INIT(vkCmdCopyImageToBuffer); - SK_INIT(vkCmdCopyQueryPoolResults); - SK_INIT(vkCmdDispatch); - SK_INIT(vkCmdDispatchIndirect); - SK_INIT(vkCmdDraw); - SK_INIT(vkCmdDrawIndexed); - SK_INIT(vkCmdDrawIndexedIndirect); - SK_INIT(vkCmdDrawIndirect); - SK_INIT(vkCmdEndQuery); - SK_INIT(vkCmdEndRenderPass); - SK_INIT(vkCmdExecuteCommands); - SK_INIT(vkCmdFillBuffer); - SK_INIT(vkCmdNextSubpass); - SK_INIT(vkCmdPipelineBarrier); - SK_INIT(vkCmdPushConstants); - SK_INIT(vkCmdResetEvent); - SK_INIT(vkCmdResetQueryPool); - SK_INIT(vkCmdResolveImage); - SK_INIT(vkCmdSetBlendConstants); - SK_INIT(vkCmdSetDepthBias); - SK_INIT(vkCmdSetDepthBounds); - SK_INIT(vkCmdSetEvent); - SK_INIT(vkCmdSetLineWidth); - SK_INIT(vkCmdSetScissor); - SK_INIT(vkCmdSetStencilCompareMask); - SK_INIT(vkCmdSetStencilReference); - SK_INIT(vkCmdSetStencilWriteMask); - SK_INIT(vkCmdSetViewport); - SK_INIT(vkCmdUpdateBuffer); - SK_INIT(vkCmdWaitEvents); - SK_INIT(vkCmdWriteTimestamp); - SK_INIT(vkCreateBuffer); - SK_INIT(vkCreateBufferView); - SK_INIT(vkCreateCommandPool); - SK_INIT(vkCreateComputePipelines); - SK_INIT(vkCreateDescriptorPool); - SK_INIT(vkCreateDescriptorSetLayout); - SK_INIT(vkCreateDevice); - SK_INIT(vkCreateEvent); - SK_INIT(vkCreateFence); - SK_INIT(vkCreateFramebuffer); - SK_INIT(vkCreateGraphicsPipelines); - SK_INIT(vkCreateImage); - SK_INIT(vkCreateImageView); - SK_INIT(vkCreateInstance); - SK_INIT(vkCreatePipelineCache); - SK_INIT(vkCreatePipelineLayout); - SK_INIT(vkCreateQueryPool); - SK_INIT(vkCreateRenderPass); - SK_INIT(vkCreateSampler); - SK_INIT(vkCreateSemaphore); - SK_INIT(vkCreateShaderModule); - SK_INIT(vkDestroyBuffer); - SK_INIT(vkDestroyBufferView); - SK_INIT(vkDestroyCommandPool); - SK_INIT(vkDestroyDescriptorPool); - SK_INIT(vkDestroyDescriptorSetLayout); - SK_INIT(vkDestroyDevice); - SK_INIT(vkDestroyEvent); - SK_INIT(vkDestroyFence); - SK_INIT(vkDestroyFramebuffer); - SK_INIT(vkDestroyImage); - SK_INIT(vkDestroyImageView); - SK_INIT(vkDestroyPipeline); - SK_INIT(vkDestroyPipelineCache); - SK_INIT(vkDestroyPipelineLayout); - SK_INIT(vkDestroyQueryPool); - SK_INIT(vkDestroyRenderPass); - SK_INIT(vkDestroySampler); - SK_INIT(vkDestroySemaphore); - SK_INIT(vkDestroyShaderModule); - SK_INIT(vkDeviceWaitIdle); - SK_INIT(vkEndCommandBuffer); - SK_INIT(vkEnumerateDeviceExtensionProperties); - SK_INIT(vkEnumerateDeviceLayerProperties); - SK_INIT(vkEnumeratePhysicalDevices); - SK_INIT(vkFlushMappedMemoryRanges); - SK_INIT(vkFreeCommandBuffers); - SK_INIT(vkFreeDescriptorSets); - SK_INIT(vkFreeMemory); - SK_INIT(vkGetBufferMemoryRequirements); - SK_INIT(vkGetDeviceMemoryCommitment); - SK_INIT(vkGetDeviceProcAddr); - SK_INIT(vkGetDeviceQueue); - SK_INIT(vkGetEventStatus); - SK_INIT(vkGetFenceStatus); - SK_INIT(vkGetImageMemoryRequirements); - SK_INIT(vkGetImageSparseMemoryRequirements); - SK_INIT(vkGetImageSubresourceLayout); - SK_INIT(vkGetInstanceProcAddr); - SK_INIT(vkGetPhysicalDeviceFeatures); - SK_INIT(vkGetPhysicalDeviceFormatProperties); - SK_INIT(vkGetPhysicalDeviceImageFormatProperties); - SK_INIT(vkGetPhysicalDeviceMemoryProperties); - SK_INIT(vkGetPhysicalDeviceProperties); - SK_INIT(vkGetPhysicalDeviceQueueFamilyProperties); - SK_INIT(vkGetPhysicalDeviceSparseImageFormatProperties); - SK_INIT(vkGetPipelineCacheData); - SK_INIT(vkGetQueryPoolResults); - SK_INIT(vkGetRenderAreaGranularity); - SK_INIT(vkInvalidateMappedMemoryRanges); - SK_INIT(vkMapMemory); - SK_INIT(vkMergePipelineCaches); - SK_INIT(vkQueueBindSparse); - SK_INIT(vkQueueSubmit); - SK_INIT(vkQueueWaitIdle); - SK_INIT(vkResetCommandBuffer); - SK_INIT(vkResetCommandPool); - SK_INIT(vkResetDescriptorPool); - SK_INIT(vkResetEvent); - SK_INIT(vkResetFences); - SK_INIT(vkSetEvent); - SK_INIT(vkUnmapMemory); - SK_INIT(vkUpdateDescriptorSets); - SK_INIT(vkWaitForFences); - - // VK_EXT_debug_report - SK_INIT(vkCreateDebugReportCallbackEXT); - SK_INIT(vkDebugReportMessageEXT); - SK_INIT(vkDestroyDebugReportCallbackEXT); - - // VK_KHR_surface - SK_INIT(vkDestroySurfaceKHR); - SK_INIT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); - SK_INIT(vkGetPhysicalDeviceSurfaceFormatsKHR); - SK_INIT(vkGetPhysicalDeviceSurfacePresentModesKHR); - SK_INIT(vkGetPhysicalDeviceSurfaceSupportKHR); - - // VK_KHR_swapchain - SK_INIT(vkAcquireNextImageKHR); - SK_INIT(vkCreateSwapchainKHR); - SK_INIT(vkDestroySwapchainKHR); - SK_INIT(vkGetDeviceGroupPresentCapabilitiesKHR); - SK_INIT(vkGetDeviceGroupSurfacePresentModesKHR); - SK_INIT(vkGetPhysicalDevicePresentRectanglesKHR); - SK_INIT(vkGetSwapchainImagesKHR); - SK_INIT(vkQueuePresentKHR); - -#undef SK_INIT - - return r; - } - - VkResult init(const VulkanInitApi& initApi, const Instance& instance) noexcept - { - return init(initApi, instance, [](const char*) {}); - } - - template - VkResult allocateCommandBuffers( - const Device& device, - const VkCommandBufferAllocateInfo& allocateInfo, - CommandBuffers& commandBuffers) const noexcept - { - VkCommandBufferVector rawCommandBuffers = - VkCommandBufferVector(allocateInfo.commandBufferCount); - - if (const VkResult r = vkAllocateCommandBuffers( - device, &allocateInfo, rawCommandBuffers.data())) { - return r; - } - - commandBuffers = CommandBuffers{ - allocateInfo.commandBufferCount, - std::move(rawCommandBuffers), - PoolDeleter{ - device, - allocateInfo.commandPool, - allocateInfo.commandBufferCount, - vkFreeCommandBuffers}}; - return VK_SUCCESS; - } - - template - VkResult allocateDescriptorSets( - const Device& device, - const VkDescriptorSetAllocateInfo& allocateInfo, - DescriptorSets& descriptorSets) const noexcept - { - auto descriptorSetVector = - VkDescriptorSetVector(allocateInfo.descriptorSetCount); - - if (const VkResult r = vkAllocateDescriptorSets( - device, &allocateInfo, descriptorSetVector.data())) { - return r; - } - - descriptorSets = DescriptorSets{ - allocateInfo.descriptorSetCount, - std::move(descriptorSetVector), - PoolDeleter{ - device, - allocateInfo.descriptorPool, - allocateInfo.descriptorSetCount, - vkFreeDescriptorSets}}; - return VK_SUCCESS; - } - - VkResult bindBufferMemory(const Device& device, - const Buffer& buffer, - const DeviceMemory& memory, - VkDeviceSize memoryOffset) const noexcept - { - return vkBindBufferMemory - ? vkBindBufferMemory(device, buffer, memory, memoryOffset) - : VK_ERROR_FEATURE_NOT_PRESENT; - } - - VkResult createBuffer(const Device& device, - const VkBufferCreateInfo& createInfo, - Buffer& buffer) const noexcept - { - VkBuffer h = {}; - const VkResult r = vkCreateBuffer(device, &createInfo, nullptr, &h); - return wrapResult(r, h, {device, vkDestroyBuffer}, buffer); - } - - VkResult createBufferView(const Device& device, - const VkBufferViewCreateInfo& createInfo, - BufferView& bufferView) const noexcept - { - VkBufferView h = {}; - const VkResult r = vkCreateBufferView(device, &createInfo, nullptr, &h); - return wrapResult(r, h, {device, vkDestroyBufferView}, bufferView); - } - - VkResult createCommandPool(const Device& device, - const VkCommandPoolCreateInfo& createInfo, - CommandPool& commandPool) const noexcept - { - VkCommandPool h = {}; - const VkResult r = vkCreateCommandPool(device, &createInfo, nullptr, &h); - return wrapResult(r, h, {device, vkDestroyCommandPool}, commandPool); - } - - VkResult createDescriptorPool(const Device& device, - const VkDescriptorPoolCreateInfo& createInfo, - DescriptorPool& descriptorPool) const noexcept - { - VkDescriptorPool h = {}; - const VkResult r = vkCreateDescriptorPool(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyDescriptorPool}, descriptorPool); - } - - VkResult createDescriptorSetLayout( - const Device& device, - const VkDescriptorSetLayoutCreateInfo& createInfo, - DescriptorSetLayout& descriptorSetLayout) const noexcept - { - VkDescriptorSetLayout h = {}; - const VkResult r = - vkCreateDescriptorSetLayout(device, &createInfo, nullptr, &h); - - return wrapResult( - r, h, {device, vkDestroyDescriptorSetLayout}, descriptorSetLayout); - } - - VkResult createDevice(const PhysicalDevice& physicalDevice, - const VkDeviceCreateInfo& createInfo, - Device& result) const noexcept - { - VkDevice h = {}; - const VkResult r = vkCreateDevice(physicalDevice, &createInfo, nullptr, &h); - - return wrapResult(r, h, {vkDestroyDevice}, result); - } - - VkResult createEvent(const Device& device, - const VkEventCreateInfo& createInfo, - Event& event) const noexcept - { - VkEvent h = {}; - const VkResult r = vkCreateEvent(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyEvent}, event); - } - - VkResult createFence(const Device& device, - const VkFenceCreateInfo& createInfo, - Fence& fence) const noexcept - { - VkFence h = {}; - const VkResult r = vkCreateFence(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyFence}, fence); - } - - VkResult createFramebuffer(const Device& device, - const VkFramebufferCreateInfo& createInfo, - Framebuffer& framebuffer) const noexcept - { - VkFramebuffer h = {}; - const VkResult r = vkCreateFramebuffer(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyFramebuffer}, framebuffer); - } - - VkResult createImage(const Device& device, - const VkImageCreateInfo& createInfo, - Image& image) const noexcept - { - VkImage h = {}; - const VkResult r = vkCreateImage(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyImage}, image); - } - - VkResult createImageView(const Device& device, - const VkImageViewCreateInfo& createInfo, - ImageView& imageView) const noexcept - { - VkImageView h = {}; - const VkResult r = vkCreateImageView(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyImageView}, imageView); - } - - template - VkResult createGraphicsPipelines( - const Device& device, - const OptionalParameter& pipelineCache, - const std::array& createInfos, - std::array& pipelines) const noexcept - { - std::array pipelineHandles{}; - - if (const VkResult r = - vkCreateGraphicsPipelines(device, - pipelineCache.get(), - static_cast(createInfos.size()), - createInfos.data(), - nullptr, - pipelineHandles.data())) { - return r; - } - - pipelines = make_handle_array( - device.get(), vkDestroyPipeline, pipelineHandles); - return VK_SUCCESS; - } - - VkResult createPipelineCache(const Device& device, - const VkPipelineCacheCreateInfo& createInfo, - PipelineCache& pipelineCache) const noexcept - { - VkPipelineCache h = {}; - const VkResult r = vkCreatePipelineCache(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyPipelineCache}, pipelineCache); - } - - VkResult createPipelineLayout(const Device& device, - const VkPipelineLayoutCreateInfo& createInfo, - PipelineLayout& pipelineLayout) const noexcept - { - VkPipelineLayout h = {}; - const VkResult r = vkCreatePipelineLayout(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyPipelineLayout}, pipelineLayout); - } - - VkResult createQueryPool(const Device& device, - const VkQueryPoolCreateInfo& createInfo, - QueryPool& queryPool) const noexcept - { - VkQueryPool h = {}; - const VkResult r = vkCreateQueryPool(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyQueryPool}, queryPool); - } - - VkResult createRenderPass(const Device& device, - const VkRenderPassCreateInfo& createInfo, - RenderPass& renderPass) const noexcept - { - VkRenderPass h = {}; - const VkResult r = vkCreateRenderPass(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyRenderPass}, renderPass); - } - - VkResult createSampler(const Device& device, - const VkSamplerCreateInfo& createInfo, - Sampler& sampler) const noexcept - { - VkSampler h = {}; - const VkResult r = vkCreateSampler(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroySampler}, sampler); - } - - VkResult createSemaphore(const Device& device, - const VkSemaphoreCreateInfo& createInfo, - Semaphore& semaphore) const noexcept - { - VkSemaphore h = {}; - const VkResult r = vkCreateSemaphore(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroySemaphore}, semaphore); - } - - VkResult createShaderModule(const Device& device, - const VkShaderModuleCreateInfo& createInfo, - ShaderModule& shaderModule) const noexcept - { - VkShaderModule h = {}; - const VkResult r = vkCreateShaderModule(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyShaderModule}, shaderModule); - } - - VkResult deviceWaitIdle(const Device& device) const noexcept - { - return vkDeviceWaitIdle(device); - } - - template - VkResult enumerateDeviceExtensionProperties( - const PhysicalDevice& physicalDevice, - const char* const layerName, - Vector& properties) const noexcept - { - return detail::wrapVectorAccessor( - properties, - vkEnumerateDeviceExtensionProperties, - physicalDevice, - layerName); - } - - template - VkResult enumerateDeviceExtensionProperties( - const PhysicalDevice& physicalDevice, - Vector& properties) const noexcept - { - return detail::wrapVectorAccessor( - properties, - vkEnumerateDeviceExtensionProperties, - physicalDevice, - nullptr); - } - - template - VkResult enumeratePhysicalDevices(const Instance& instance, - Vector& physicalDevices) const noexcept - { - uint32_t count = 0u; - VkResult r = vkEnumeratePhysicalDevices(instance, &count, nullptr); - if (r > VK_INCOMPLETE) { - return r; - } - - physicalDevices = Vector(count); - if ((r = vkEnumeratePhysicalDevices( - instance, &count, physicalDevices.data()))) { - return r; - } - - return VK_SUCCESS; - } - - sk::Queue getDeviceQueue(const Device& device, - const uint32_t queueFamilyIndex, - const uint32_t queueIndex) const noexcept - { - VkQueue queue{}; - vkGetDeviceQueue(device, queueFamilyIndex, queueIndex, &queue); - return sk::Queue{queue}; - } - - VkPhysicalDeviceMemoryProperties getPhysicalDeviceMemoryProperties( - VkPhysicalDevice physicalDevice) const noexcept - { - VkPhysicalDeviceMemoryProperties properties{}; - vkGetPhysicalDeviceMemoryProperties(physicalDevice, &properties); - return properties; - } - - VkPhysicalDeviceProperties getPhysicalDeviceProperties( - const PhysicalDevice& physicalDevice) const noexcept - { - VkPhysicalDeviceProperties properties{}; - vkGetPhysicalDeviceProperties(physicalDevice, &properties); - return properties; - } - - template - VkResult getPhysicalDeviceQueueFamilyProperties( - const PhysicalDevice& physicalDevice, - Vector& queueFamilyProperties) const noexcept - { - uint32_t count = 0u; - vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &count, nullptr); - - queueFamilyProperties = Vector(count); - vkGetPhysicalDeviceQueueFamilyProperties( - physicalDevice, &count, queueFamilyProperties.data()); - - return VK_SUCCESS; - } - - VkMemoryRequirements getBufferMemoryRequirements( - const Device& device, - const Buffer& buffer) const noexcept - { - VkMemoryRequirements requirements; - vkGetBufferMemoryRequirements(device, buffer, &requirements); - return requirements; - } - - VkResult allocateMemory(const Device& device, - const VkMemoryAllocateInfo& info, - DeviceMemory& memory) const noexcept - { - VkDeviceMemory h = {}; - if (const VkResult r = vkAllocateMemory(device, &info, nullptr, &h)) { - return r; - } - - if (!h) { - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - - memory = DeviceMemory{h, {device, vkFreeMemory}}; - return VK_SUCCESS; - } - - VkResult mapMemory(const Device& device, - const DeviceMemory& memory, - VkDeviceSize offset, - VkDeviceSize size, - VkMemoryMapFlags flags, - MappedMemory& mappedMemory) const noexcept - { - void* data = nullptr; - if (const VkResult r = - vkMapMemory(device, memory, offset, size, flags, &data)) { - return r; - } - - mappedMemory = MappedMemory{*this, device, memory, data}; - return VK_SUCCESS; - } - - VkResult queueSubmit(const Queue& queue, - uint32_t submitCount, - const VkSubmitInfo& submits, - const Fence& fence) const noexcept - { - return vkQueueSubmit(queue, submitCount, &submits, fence); - } - - VkResult queueSubmit(const Queue& queue, - const VkSubmitInfo& submit, - const Fence& fence) const noexcept - { - return vkQueueSubmit(queue, 1u, &submit, fence); - } - - template - void updateDescriptorSets( - const Device& device, - std::array descriptorWrites, - std::array descriptorCopies) - const noexcept - { - vkUpdateDescriptorSets(device, - static_cast(descriptorWrites.size()), - descriptorWrites.data(), - static_cast(descriptorCopies.size()), - descriptorCopies.data()); - } - - VkResult resetFence(const Device& device, const Fence& fence) const noexcept - { - VkFence h = fence; - return vkResetFences(device, 1u, &h); - } - - VkResult waitForFence(const Device& device, - const Fence& fence, - uint64_t timeout) const noexcept - { - VkFence h = fence; - return vkWaitForFences(device, 1u, &h, VK_TRUE, timeout); - } - - VkResult waitForFence(const Device& device, const Fence& fence) const noexcept - { - VkFence h = fence; - return vkWaitForFences(device, 1u, &h, VK_TRUE, UINT64_MAX); - } - - // Scoped command buffer interface - SYBOK_NODISCARD - CommandScope beginCommandBuffer( - VkCommandBuffer commandBuffer, - VkCommandBufferBeginInfo beginInfo) const noexcept; - - // VK_EXT_debug_report - - VkResult createDebugReportCallbackEXT( - const Instance& instance, - const VkDebugReportCallbackCreateInfoEXT& createInfo, - DebugReportCallbackEXT& callback) const noexcept - { - VkDebugReportCallbackEXT h = {}; - - if (const VkResult r = - vkCreateDebugReportCallbackEXT(instance, &createInfo, nullptr, &h)) { - return r; - } - - if (!h) { - return VK_ERROR_FEATURE_NOT_PRESENT; - } - - callback = {h, {instance, vkDestroyDebugReportCallbackEXT}}; - return VK_SUCCESS; - } - - // VK_KHR_surface - - VkResult getPhysicalDeviceSurfaceCapabilitiesKHR( - const PhysicalDevice& physicalDevice, - const SurfaceKHR& surface, - VkSurfaceCapabilitiesKHR& capabilities) const noexcept - { - return vkGetPhysicalDeviceSurfaceCapabilitiesKHR( - physicalDevice, surface, &capabilities); - } - - template - VkResult getPhysicalDeviceSurfaceFormatsKHR( - const PhysicalDevice& physicalDevice, - const SurfaceKHR& surface, - Vector& surfaceFormats) const noexcept - { - return detail::wrapVectorAccessor( - surfaceFormats, - vkGetPhysicalDeviceSurfaceFormatsKHR, - physicalDevice, - surface.get()); - } - - template - VkResult getPhysicalDeviceSurfacePresentModesKHR( - const PhysicalDevice& physicalDevice, - const SurfaceKHR& surface, - Vector& presentModes) const noexcept - { - return detail::wrapVectorAccessor( - presentModes, - vkGetPhysicalDeviceSurfacePresentModesKHR, - physicalDevice, - surface.get()); - } - - VkResult getPhysicalDeviceSurfaceSupportKHR( - const PhysicalDevice& physicalDevice, - uint32_t queueFamilyIndex, - const SurfaceKHR& surface, - bool& supported) const noexcept - { - VkBool32 s = {}; - - if (VkResult r = vkGetPhysicalDeviceSurfaceSupportKHR( - physicalDevice, queueFamilyIndex, surface, &s)) { - return r; - } - - supported = s; - return VK_SUCCESS; - } - - // VK_KHR_swapchain - - VkResult acquireNextImageKHR(const Device& device, - const SwapchainKHR& swapchain, - uint64_t timeout, - const Semaphore& semaphore, - const OptionalParameter& fence, - uint32_t* pImageIndex) const noexcept - { - return vkAcquireNextImageKHR( - device, swapchain, timeout, semaphore, fence.get(), pImageIndex); - } - - template - VkResult getSwapchainImagesKHR(const Device& device, - const SwapchainKHR& swapchain, - Vector& images) const noexcept - { - return detail::wrapVectorAccessor( - images, vkGetSwapchainImagesKHR, device.get(), swapchain.get()); - } - - VkResult createSwapchainKHR(const Device& device, - const VkSwapchainCreateInfoKHR& createInfo, - SwapchainKHR& swapchain) const noexcept - { - VkSwapchainKHR h = {}; - const VkResult r = vkCreateSwapchainKHR(device, &createInfo, nullptr, &h); - - if (r) { - return r; - } - - if (!h) { - return VK_ERROR_INCOMPATIBLE_DRIVER; - } - - swapchain = {h, {device, vkDestroySwapchainKHR}}; - return VK_SUCCESS; - } - - VkResult queuePresentKHR(const Queue& queue, - const VkPresentInfoKHR& presentInfo) const noexcept - { - return vkQueuePresentKHR(queue, &presentInfo); - } - -#define SK_FUNC(name) \ - PFN_##name name {} // NOLINT - - // Vulkan 1.0 Core - SK_FUNC(vkAllocateCommandBuffers); - SK_FUNC(vkAllocateDescriptorSets); - SK_FUNC(vkAllocateMemory); - SK_FUNC(vkBeginCommandBuffer); - SK_FUNC(vkBindBufferMemory); - SK_FUNC(vkBindImageMemory); - SK_FUNC(vkCmdBeginQuery); - SK_FUNC(vkCmdBeginRenderPass); - SK_FUNC(vkCmdBindDescriptorSets); - SK_FUNC(vkCmdBindIndexBuffer); - SK_FUNC(vkCmdBindPipeline); - SK_FUNC(vkCmdBindVertexBuffers); - SK_FUNC(vkCmdBlitImage); - SK_FUNC(vkCmdClearAttachments); - SK_FUNC(vkCmdClearColorImage); - SK_FUNC(vkCmdClearDepthStencilImage); - SK_FUNC(vkCmdCopyBuffer); - SK_FUNC(vkCmdCopyBufferToImage); - SK_FUNC(vkCmdCopyImage); - SK_FUNC(vkCmdCopyImageToBuffer); - SK_FUNC(vkCmdCopyQueryPoolResults); - SK_FUNC(vkCmdDispatch); - SK_FUNC(vkCmdDispatchIndirect); - SK_FUNC(vkCmdDraw); - SK_FUNC(vkCmdDrawIndexed); - SK_FUNC(vkCmdDrawIndexedIndirect); - SK_FUNC(vkCmdDrawIndirect); - SK_FUNC(vkCmdEndQuery); - SK_FUNC(vkCmdEndRenderPass); - SK_FUNC(vkCmdExecuteCommands); - SK_FUNC(vkCmdFillBuffer); - SK_FUNC(vkCmdNextSubpass); - SK_FUNC(vkCmdPipelineBarrier); - SK_FUNC(vkCmdPushConstants); - SK_FUNC(vkCmdResetEvent); - SK_FUNC(vkCmdResetQueryPool); - SK_FUNC(vkCmdResolveImage); - SK_FUNC(vkCmdSetBlendConstants); - SK_FUNC(vkCmdSetDepthBias); - SK_FUNC(vkCmdSetDepthBounds); - SK_FUNC(vkCmdSetEvent); - SK_FUNC(vkCmdSetLineWidth); - SK_FUNC(vkCmdSetScissor); - SK_FUNC(vkCmdSetStencilCompareMask); - SK_FUNC(vkCmdSetStencilReference); - SK_FUNC(vkCmdSetStencilWriteMask); - SK_FUNC(vkCmdSetViewport); - SK_FUNC(vkCmdUpdateBuffer); - SK_FUNC(vkCmdWaitEvents); - SK_FUNC(vkCmdWriteTimestamp); - SK_FUNC(vkCreateBuffer); - SK_FUNC(vkCreateBufferView); - SK_FUNC(vkCreateCommandPool); - SK_FUNC(vkCreateComputePipelines); - SK_FUNC(vkCreateDescriptorPool); - SK_FUNC(vkCreateDescriptorSetLayout); - SK_FUNC(vkCreateDevice); - SK_FUNC(vkCreateEvent); - SK_FUNC(vkCreateFence); - SK_FUNC(vkCreateFramebuffer); - SK_FUNC(vkCreateGraphicsPipelines); - SK_FUNC(vkCreateImage); - SK_FUNC(vkCreateImageView); - SK_FUNC(vkCreateInstance); - SK_FUNC(vkCreatePipelineCache); - SK_FUNC(vkCreatePipelineLayout); - SK_FUNC(vkCreateQueryPool); - SK_FUNC(vkCreateRenderPass); - SK_FUNC(vkCreateSampler); - SK_FUNC(vkCreateSemaphore); - SK_FUNC(vkCreateShaderModule); - SK_FUNC(vkDestroyBuffer); - SK_FUNC(vkDestroyBufferView); - SK_FUNC(vkDestroyCommandPool); - SK_FUNC(vkDestroyDescriptorPool); - SK_FUNC(vkDestroyDescriptorSetLayout); - SK_FUNC(vkDestroyDevice); - SK_FUNC(vkDestroyEvent); - SK_FUNC(vkDestroyFence); - SK_FUNC(vkDestroyFramebuffer); - SK_FUNC(vkDestroyImage); - SK_FUNC(vkDestroyImageView); - SK_FUNC(vkDestroyPipeline); - SK_FUNC(vkDestroyPipelineCache); - SK_FUNC(vkDestroyPipelineLayout); - SK_FUNC(vkDestroyQueryPool); - SK_FUNC(vkDestroyRenderPass); - SK_FUNC(vkDestroySampler); - SK_FUNC(vkDestroySemaphore); - SK_FUNC(vkDestroyShaderModule); - SK_FUNC(vkDeviceWaitIdle); - SK_FUNC(vkEndCommandBuffer); - SK_FUNC(vkEnumerateDeviceExtensionProperties); - SK_FUNC(vkEnumerateDeviceLayerProperties); - SK_FUNC(vkEnumeratePhysicalDevices); - SK_FUNC(vkFlushMappedMemoryRanges); - SK_FUNC(vkFreeCommandBuffers); - SK_FUNC(vkFreeDescriptorSets); - SK_FUNC(vkFreeMemory); - SK_FUNC(vkGetBufferMemoryRequirements); - SK_FUNC(vkGetDeviceMemoryCommitment); - SK_FUNC(vkGetDeviceProcAddr); - SK_FUNC(vkGetDeviceQueue); - SK_FUNC(vkGetEventStatus); - SK_FUNC(vkGetFenceStatus); - SK_FUNC(vkGetImageMemoryRequirements); - SK_FUNC(vkGetImageSparseMemoryRequirements); - SK_FUNC(vkGetImageSubresourceLayout); - SK_FUNC(vkGetInstanceProcAddr); - SK_FUNC(vkGetPhysicalDeviceFeatures); - SK_FUNC(vkGetPhysicalDeviceFormatProperties); - SK_FUNC(vkGetPhysicalDeviceImageFormatProperties); - SK_FUNC(vkGetPhysicalDeviceMemoryProperties); - SK_FUNC(vkGetPhysicalDeviceProperties); - SK_FUNC(vkGetPhysicalDeviceQueueFamilyProperties); - SK_FUNC(vkGetPhysicalDeviceSparseImageFormatProperties); - SK_FUNC(vkGetPipelineCacheData); - SK_FUNC(vkGetQueryPoolResults); - SK_FUNC(vkGetRenderAreaGranularity); - SK_FUNC(vkInvalidateMappedMemoryRanges); - SK_FUNC(vkMapMemory); - SK_FUNC(vkMergePipelineCaches); - SK_FUNC(vkQueueBindSparse); - SK_FUNC(vkQueueSubmit); - SK_FUNC(vkQueueWaitIdle); - SK_FUNC(vkResetCommandBuffer); - SK_FUNC(vkResetCommandPool); - SK_FUNC(vkResetDescriptorPool); - SK_FUNC(vkResetEvent); - SK_FUNC(vkResetFences); - SK_FUNC(vkSetEvent); - SK_FUNC(vkUnmapMemory); - SK_FUNC(vkUpdateDescriptorSets); - SK_FUNC(vkWaitForFences); - - // VK_EXT_debug_report - SK_FUNC(vkCreateDebugReportCallbackEXT); - SK_FUNC(vkDebugReportMessageEXT); - SK_FUNC(vkDestroyDebugReportCallbackEXT); - - // VK_KHR_surface - SK_FUNC(vkDestroySurfaceKHR); - SK_FUNC(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); - SK_FUNC(vkGetPhysicalDeviceSurfaceFormatsKHR); - SK_FUNC(vkGetPhysicalDeviceSurfacePresentModesKHR); - SK_FUNC(vkGetPhysicalDeviceSurfaceSupportKHR); - - // VK_KHR_swapchain - SK_FUNC(vkAcquireNextImageKHR); - SK_FUNC(vkCreateSwapchainKHR); - SK_FUNC(vkDestroySwapchainKHR); - SK_FUNC(vkGetDeviceGroupPresentCapabilitiesKHR); - SK_FUNC(vkGetDeviceGroupSurfacePresentModesKHR); - SK_FUNC(vkGetPhysicalDevicePresentRectanglesKHR); - SK_FUNC(vkGetSwapchainImagesKHR); - SK_FUNC(vkQueuePresentKHR); - -#undef SK_FUNC - -private: - template - static inline VkResult wrapResult(const VkResult r, - const typename T::Handle handle, - typename T::Deleter&& deleter, - T& result) noexcept - { - if (r) { - return r; - } - - if (!handle) { - return VK_ERROR_INITIALIZATION_FAILED; - } - - result = T{handle, std::move(deleter)}; - return VK_SUCCESS; - } -}; - -/// Scope for commands that work both inside and outside a render pass -class CommonCommandScope -{ -public: - CommonCommandScope(const VulkanApi& api, - VkCommandBuffer commandBuffer, - VkResult result) noexcept - : _api{api} - , _commandBuffer{commandBuffer} - , _result{result} - {} - - CommonCommandScope(const CommonCommandScope&) noexcept = delete; - CommonCommandScope& operator=(const CommonCommandScope&) noexcept = delete; - - CommonCommandScope(CommonCommandScope&& scope) noexcept - : _api{scope._api} - , _commandBuffer{scope._commandBuffer} - , _result{scope._result} - { - scope._commandBuffer = {}; - } - - CommonCommandScope& operator=(CommonCommandScope&&) = delete; - - ~CommonCommandScope() noexcept = default; - - explicit operator bool() const noexcept { return _result == VK_SUCCESS; } - - VkResult error() const noexcept { return _result; } - - void bindPipeline(VkPipelineBindPoint pipelineBindPoint, - VkPipeline pipeline) const noexcept - { - _api.vkCmdBindPipeline(_commandBuffer, pipelineBindPoint, pipeline); - } - - void setViewport(uint32_t firstViewport, - uint32_t viewportCount, - const VkViewport* pViewports) const noexcept - { - _api.vkCmdSetViewport( - _commandBuffer, firstViewport, viewportCount, pViewports); - } - - void setScissor(uint32_t firstScissor, - uint32_t scissorCount, - const VkRect2D* pScissors) const noexcept - { - _api.vkCmdSetScissor(_commandBuffer, firstScissor, scissorCount, pScissors); - } - - void setLineWidth(float lineWidth) const noexcept - { - _api.vkCmdSetLineWidth(_commandBuffer, lineWidth); - } - - void setDepthBias(float depthBiasConstantFactor, - float depthBiasClamp, - float depthBiasSlopeFactor) const noexcept - { - _api.vkCmdSetDepthBias(_commandBuffer, - depthBiasConstantFactor, - depthBiasClamp, - depthBiasSlopeFactor); - } - - void setBlendConstants(const float blendConstants[4]) const noexcept - { - _api.vkCmdSetBlendConstants(_commandBuffer, blendConstants); - } - - void setDepthBounds(float minDepthBounds, float maxDepthBounds) const noexcept - { - _api.vkCmdSetDepthBounds(_commandBuffer, minDepthBounds, maxDepthBounds); - } - - void setStencilCompareMask(VkStencilFaceFlags faceMask, - uint32_t compareMask) const noexcept - { - _api.vkCmdSetStencilCompareMask(_commandBuffer, faceMask, compareMask); - } - - void setStencilWriteMask(VkStencilFaceFlags faceMask, - uint32_t writeMask) const noexcept - { - _api.vkCmdSetStencilWriteMask(_commandBuffer, faceMask, writeMask); - } - - void setStencilReference(VkStencilFaceFlags faceMask, - uint32_t reference) const noexcept - { - _api.vkCmdSetStencilReference(_commandBuffer, faceMask, reference); - } - - void bindDescriptorSets(VkPipelineBindPoint pipelineBindPoint, - VkPipelineLayout layout, - uint32_t firstSet, - uint32_t descriptorSetCount, - const VkDescriptorSet* pDescriptorSets, - uint32_t dynamicOffsetCount, - const uint32_t* pDynamicOffsets) const noexcept - { - _api.vkCmdBindDescriptorSets(_commandBuffer, - pipelineBindPoint, - layout, - firstSet, - descriptorSetCount, - pDescriptorSets, - dynamicOffsetCount, - pDynamicOffsets); - } - - void bindIndexBuffer(VkBuffer buffer, - VkDeviceSize offset, - VkIndexType indexType) const noexcept - { - _api.vkCmdBindIndexBuffer(_commandBuffer, buffer, offset, indexType); - } - - void bindVertexBuffers(uint32_t firstBinding, - uint32_t bindingCount, - const VkBuffer* pBuffers, - const VkDeviceSize* pOffsets) const noexcept - { - _api.vkCmdBindVertexBuffers( - _commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets); - } - - void waitEvents( - uint32_t eventCount, - const VkEvent* pEvents, - VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask, - uint32_t memoryBarrierCount, - const VkMemoryBarrier* pMemoryBarriers, - uint32_t bufferMemoryBarrierCount, - const VkBufferMemoryBarrier* pBufferMemoryBarriers, - uint32_t imageMemoryBarrierCount, - const VkImageMemoryBarrier* pImageMemoryBarriers) const noexcept - { - _api.vkCmdWaitEvents(_commandBuffer, - eventCount, - pEvents, - srcStageMask, - dstStageMask, - memoryBarrierCount, - pMemoryBarriers, - bufferMemoryBarrierCount, - pBufferMemoryBarriers, - imageMemoryBarrierCount, - pImageMemoryBarriers); - } - - void pipelineBarrier( - VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask, - VkDependencyFlags dependencyFlags, - uint32_t memoryBarrierCount, - const VkMemoryBarrier* pMemoryBarriers, - uint32_t bufferMemoryBarrierCount, - const VkBufferMemoryBarrier* pBufferMemoryBarriers, - uint32_t imageMemoryBarrierCount, - const VkImageMemoryBarrier* pImageMemoryBarriers) const noexcept - { - _api.vkCmdPipelineBarrier(_commandBuffer, - srcStageMask, - dstStageMask, - dependencyFlags, - memoryBarrierCount, - pMemoryBarriers, - bufferMemoryBarrierCount, - pBufferMemoryBarriers, - imageMemoryBarrierCount, - pImageMemoryBarriers); - } - - void beginQuery(VkQueryPool queryPool, - uint32_t query, - VkQueryControlFlags flags) const noexcept - { - _api.vkCmdBeginQuery(_commandBuffer, queryPool, query, flags); - } - - void endQuery(VkQueryPool queryPool, uint32_t query) const noexcept - { - _api.vkCmdEndQuery(_commandBuffer, queryPool, query); - } - - void writeTimestamp(VkPipelineStageFlagBits pipelineStage, - VkQueryPool queryPool, - uint32_t query) const noexcept - { - _api.vkCmdWriteTimestamp(_commandBuffer, pipelineStage, queryPool, query); - } - - void pushConstants(VkPipelineLayout layout, - VkShaderStageFlags stageFlags, - uint32_t offset, - uint32_t size, - const void* pValues) const noexcept - { - _api.vkCmdPushConstants( - _commandBuffer, layout, stageFlags, offset, size, pValues); - } - - void executeCommands(uint32_t commandBufferCount, - const VkCommandBuffer* pCommandBuffers) const noexcept - { - _api.vkCmdExecuteCommands( - _commandBuffer, commandBufferCount, pCommandBuffers); - } - -protected: - const VulkanApi& _api; - VkCommandBuffer _commandBuffer; - VkResult _result; -}; - -// Top level command scope outside a render pass -class CommandScope : public CommonCommandScope -{ -public: - CommandScope(const VulkanApi& api, - VkCommandBuffer commandBuffer, - VkResult result) noexcept - : CommonCommandScope{api, commandBuffer, result} - {} - - CommandScope(const CommandScope&) = delete; - CommandScope& operator=(const CommandScope&) = delete; - - CommandScope(CommandScope&& scope) noexcept - : CommonCommandScope{std::forward(scope)} - {} - - CommandScope& operator=(CommandScope&&) = delete; - - ~CommandScope() noexcept - { - assert(!_commandBuffer); // Buffer must be finished with end() - } - - VkResult end() noexcept - { - if (_commandBuffer) { - VkResult r = _api.vkEndCommandBuffer(_commandBuffer); - _commandBuffer = {}; - return r; - } - - return VK_NOT_READY; - } - - void dispatch(uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ) const noexcept - { - _api.vkCmdDispatch(_commandBuffer, groupCountX, groupCountY, groupCountZ); - } - - void dispatchIndirect(VkBuffer buffer, VkDeviceSize offset) const noexcept - { - _api.vkCmdDispatchIndirect(_commandBuffer, buffer, offset); - } - - void copyBuffer(VkBuffer srcBuffer, - VkBuffer dstBuffer, - uint32_t regionCount, - const VkBufferCopy* pRegions) const noexcept - { - _api.vkCmdCopyBuffer( - _commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions); - } - - void copyImage(VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkImageCopy* pRegions) const noexcept - { - _api.vkCmdCopyImage(_commandBuffer, - srcImage, - srcImageLayout, - dstImage, - dstImageLayout, - regionCount, - pRegions); - } - - void blitImage(VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkImageBlit* pRegions, - VkFilter filter) const noexcept - { - _api.vkCmdBlitImage(_commandBuffer, - srcImage, - srcImageLayout, - dstImage, - dstImageLayout, - regionCount, - pRegions, - filter); - } - - void copyBufferToImage(VkBuffer srcBuffer, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkBufferImageCopy* pRegions) const noexcept - { - _api.vkCmdCopyBufferToImage(_commandBuffer, - srcBuffer, - dstImage, - dstImageLayout, - regionCount, - pRegions); - } - - void copyImageToBuffer(VkImage srcImage, - VkImageLayout srcImageLayout, - VkBuffer dstBuffer, - uint32_t regionCount, - const VkBufferImageCopy* pRegions) const noexcept - { - _api.vkCmdCopyImageToBuffer(_commandBuffer, - srcImage, - srcImageLayout, - dstBuffer, - regionCount, - pRegions); - } - - void updateBuffer(VkBuffer dstBuffer, - VkDeviceSize dstOffset, - VkDeviceSize dataSize, - const void* pData) const noexcept - { - _api.vkCmdUpdateBuffer( - _commandBuffer, dstBuffer, dstOffset, dataSize, pData); - } - - void fillBuffer(VkBuffer dstBuffer, - VkDeviceSize dstOffset, - VkDeviceSize size, - uint32_t data) const noexcept - { - _api.vkCmdFillBuffer(_commandBuffer, dstBuffer, dstOffset, size, data); - } - - void clearColorImage(VkImage image, - VkImageLayout imageLayout, - const VkClearColorValue& color, - uint32_t rangeCount, - const VkImageSubresourceRange* pRanges) const noexcept - { - _api.vkCmdClearColorImage( - _commandBuffer, image, imageLayout, &color, rangeCount, pRanges); - } - - void clearDepthStencilImage( - VkImage image, - VkImageLayout imageLayout, - const VkClearDepthStencilValue& depthStencil, - uint32_t rangeCount, - const VkImageSubresourceRange* pRanges) const noexcept - { - _api.vkCmdClearDepthStencilImage( - _commandBuffer, image, imageLayout, &depthStencil, rangeCount, pRanges); - } - - void resolveImage(VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkImageResolve* pRegions) const noexcept - { - _api.vkCmdResolveImage(_commandBuffer, - srcImage, - srcImageLayout, - dstImage, - dstImageLayout, - regionCount, - pRegions); - } - - void setEvent(VkEvent event, VkPipelineStageFlags stageMask) const noexcept - { - _api.vkCmdSetEvent(_commandBuffer, event, stageMask); - } - - void resetEvent(VkEvent event, VkPipelineStageFlags stageMask) const noexcept - { - _api.vkCmdResetEvent(_commandBuffer, event, stageMask); - } - - void resetQueryPool(VkQueryPool queryPool, - uint32_t firstQuery, - uint32_t queryCount) const noexcept - { - _api.vkCmdResetQueryPool(_commandBuffer, queryPool, firstQuery, queryCount); - } - - void copyQueryPoolResults(VkQueryPool queryPool, - uint32_t firstQuery, - uint32_t queryCount, - VkBuffer dstBuffer, - VkDeviceSize dstOffset, - VkDeviceSize stride, - VkQueryResultFlags flags) const noexcept - { - _api.vkCmdCopyQueryPoolResults(_commandBuffer, - queryPool, - firstQuery, - queryCount, - dstBuffer, - dstOffset, - stride, - flags); - } - - SYBOK_NODISCARD - RenderCommandScope beginRenderPass( - const VkRenderPassBeginInfo& renderPassBegin, - VkSubpassContents contents) const noexcept; -}; - -class RenderCommandScope : public CommonCommandScope -{ -public: - RenderCommandScope(const VulkanApi& api, - VkCommandBuffer commandBuffer) noexcept - : CommonCommandScope{api, commandBuffer, VK_SUCCESS} - {} - - RenderCommandScope(const RenderCommandScope&) = delete; - RenderCommandScope& operator=(const RenderCommandScope&) = delete; - - RenderCommandScope(RenderCommandScope&& scope) noexcept - : CommonCommandScope{std::forward(scope)} - {} - - RenderCommandScope& operator=(RenderCommandScope&&) = delete; - - ~RenderCommandScope() noexcept { _api.vkCmdEndRenderPass(_commandBuffer); } - - void draw(uint32_t vertexCount, - uint32_t instanceCount, - uint32_t firstVertex, - uint32_t firstInstance) const noexcept - { - _api.vkCmdDraw( - _commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance); - } - - void drawIndexed(uint32_t indexCount, - uint32_t instanceCount, - uint32_t firstIndex, - int32_t vertexOffset, - uint32_t firstInstance) const noexcept - { - _api.vkCmdDrawIndexed(_commandBuffer, - indexCount, - instanceCount, - firstIndex, - vertexOffset, - firstInstance); - } - - void drawIndirect(VkBuffer buffer, - VkDeviceSize offset, - uint32_t drawCount, - uint32_t stride) const noexcept - { - _api.vkCmdDrawIndirect(_commandBuffer, buffer, offset, drawCount, stride); - } - - void drawIndexedIndirect(VkBuffer buffer, - VkDeviceSize offset, - uint32_t drawCount, - uint32_t stride) const noexcept - { - _api.vkCmdDrawIndexedIndirect( - _commandBuffer, buffer, offset, drawCount, stride); - } - - void clearAttachments(uint32_t attachmentCount, - const VkClearAttachment& attachments, - uint32_t rectCount, - const VkClearRect* pRects) const noexcept - { - _api.vkCmdClearAttachments( - _commandBuffer, attachmentCount, &attachments, rectCount, pRects); - } - - void nextSubpass(VkSubpassContents contents) const noexcept - { - _api.vkCmdNextSubpass(_commandBuffer, contents); - } -}; - -inline CommandScope -VulkanApi::beginCommandBuffer( - VkCommandBuffer commandBuffer, - const VkCommandBufferBeginInfo beginInfo) const noexcept -{ - if (const VkResult r = vkBeginCommandBuffer(commandBuffer, &beginInfo)) { - return {*this, nullptr, r}; - } - - return {*this, commandBuffer, VK_SUCCESS}; -} - -inline RenderCommandScope -CommandScope::beginRenderPass(const VkRenderPassBeginInfo& renderPassBegin, - VkSubpassContents contents) const noexcept -{ - _api.vkCmdBeginRenderPass(_commandBuffer, &renderPassBegin, contents); - - return {_api, _commandBuffer}; -} - -inline MappedMemory::~MappedMemory() noexcept -{ - if (_api && _memory) { - _api->vkUnmapMemory(_device, _memory); - } -} - -} // namespace sk - -#ifdef __GNUC__ -# pragma GCC diagnostic pop -#endif - -#endif // SYBOK_HPP diff --git a/subprojects/nk_pugl/pugl/include/.clang-tidy b/subprojects/nk_pugl/pugl/include/.clang-tidy deleted file mode 100644 index dd2fd47..0000000 --- a/subprojects/nk_pugl/pugl/include/.clang-tidy +++ /dev/null @@ -1,9 +0,0 @@ -Checks: > - *, - -*-magic-numbers, - -*-uppercase-literal-suffix, - -clang-diagnostic-unused-function, - -clang-diagnostic-unused-macros, - -llvmlibc-*, -FormatStyle: file -HeaderFilterRegex: 'pugl/.*' diff --git a/subprojects/nk_pugl/pugl/include/pugl/cairo.h b/subprojects/nk_pugl/pugl/include/pugl/cairo.h deleted file mode 100644 index 48e868e..0000000 --- a/subprojects/nk_pugl/pugl/include/pugl/cairo.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_CAIRO_H -#define PUGL_CAIRO_H - -#include "pugl/pugl.h" - -PUGL_BEGIN_DECLS - -/** - @defgroup cairo Cairo - Cairo graphics support. - @ingroup pugl - @{ -*/ - -/** - Cairo graphics backend accessor. - - Pass the returned value to puglSetBackend() to draw to a view with Cairo. -*/ -PUGL_CONST_API -const PuglBackend* -puglCairoBackend(void); - -/** - @} -*/ - -PUGL_END_DECLS - -#endif // PUGL_CAIRO_H diff --git a/subprojects/nk_pugl/pugl/include/pugl/gl.h b/subprojects/nk_pugl/pugl/include/pugl/gl.h deleted file mode 100644 index 51c4a7d..0000000 --- a/subprojects/nk_pugl/pugl/include/pugl/gl.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_GL_H -#define PUGL_GL_H - -#include "pugl/pugl.h" - -// IWYU pragma: begin_exports - -/* Unfortunately, GL includes vary across platforms, so include them here to - enable pure portable programs. */ - -#ifndef PUGL_NO_INCLUDE_GL_H -# ifdef __APPLE__ -# include -# else -# ifdef _WIN32 -# include -# endif -# include -# endif -#endif - -#ifndef PUGL_NO_INCLUDE_GLU_H -# ifdef __APPLE__ -# include -# else -# ifdef _WIN32 -# include -# endif -# include -# endif -#endif - -// IWYU pragma: end_exports - -PUGL_BEGIN_DECLS - -/** - @defgroup gl OpenGL - OpenGL graphics support. - @ingroup pugl - @{ -*/ - -/** - OpenGL extension function. -*/ -typedef void (*PuglGlFunc)(void); - -/** - Return the address of an OpenGL extension function. -*/ -PUGL_API -PuglGlFunc -puglGetProcAddress(const char* name); - -/** - Enter the OpenGL context. - - This can be used to enter the graphics context in unusual situations, for - doing things like loading textures. Note that this must not be used for - drawing, which may only be done while processing an expose event. -*/ -PUGL_API -PuglStatus -puglEnterContext(PuglView* view); - -/** - Leave the OpenGL context. - - This must only be called after puglEnterContext(). -*/ -PUGL_API -PuglStatus -puglLeaveContext(PuglView* view); - -/** - OpenGL graphics backend. - - Pass the returned value to puglSetBackend() to draw to a view with OpenGL. -*/ -PUGL_CONST_API -const PuglBackend* -puglGlBackend(void); - -PUGL_END_DECLS - -/** - @} -*/ - -#endif // PUGL_GL_H diff --git a/subprojects/nk_pugl/pugl/include/pugl/pugl.h b/subprojects/nk_pugl/pugl/include/pugl/pugl.h deleted file mode 100644 index cd77334..0000000 --- a/subprojects/nk_pugl/pugl/include/pugl/pugl.h +++ /dev/null @@ -1,1575 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_PUGL_H -#define PUGL_PUGL_H - -#include -#include -#include - -#if defined(_WIN32) && !defined(PUGL_STATIC) && defined(PUGL_INTERNAL) -# define PUGL_API __declspec(dllexport) -#elif defined(_WIN32) && !defined(PUGL_STATIC) -# define PUGL_API __declspec(dllimport) -#elif defined(__GNUC__) && !defined(PUGL_STATIC) -# define PUGL_API __attribute__((visibility("default"))) -#else -# define PUGL_API -#endif - -#ifndef PUGL_DISABLE_DEPRECATED -# if defined(__clang__) -# define PUGL_DEPRECATED_BY(rep) __attribute__((deprecated("", rep))) -# elif defined(__GNUC__) -# define PUGL_DEPRECATED_BY(rep) __attribute__((deprecated("Use " rep))) -# else -# define PUGL_DEPRECATED_BY(rep) -# endif -#endif - -#if defined(__GNUC__) -# define PUGL_CONST_FUNC __attribute__((const)) -#else -# define PUGL_CONST_FUNC -#endif - -#define PUGL_CONST_API \ - PUGL_API \ - PUGL_CONST_FUNC - -#ifdef __cplusplus -# define PUGL_BEGIN_DECLS extern "C" { -# define PUGL_END_DECLS } -#else -# define PUGL_BEGIN_DECLS -# define PUGL_END_DECLS -#endif - -PUGL_BEGIN_DECLS - -/** - @defgroup pugl Pugl C API - Pugl C API. - @{ -*/ - -/** - A rectangle. - - This is used to describe things like view position and size. Pugl generally - uses coordinates where the top left corner is 0,0. -*/ -typedef struct { - double x; - double y; - double width; - double height; -} PuglRect; - -/** - @defgroup events Events - - All updates to the view happen via events, which are dispatched to the - view's event function. Most events map directly to one from the underlying - window system, but some are constructed by Pugl itself so there is not - necessarily a direct correspondence. - - @{ -*/ - -/// Keyboard modifier flags -typedef enum { - PUGL_MOD_SHIFT = 1u << 0u, ///< Shift key - PUGL_MOD_CTRL = 1u << 1u, ///< Control key - PUGL_MOD_ALT = 1u << 2u, ///< Alt/Option key - PUGL_MOD_SUPER = 1u << 3u ///< Mod4/Command/Windows key -} PuglMod; - -/// Bitwise OR of #PuglMod values -typedef uint32_t PuglMods; - -/** - Keyboard key codepoints. - - All keys are identified by a Unicode code point in PuglEventKey::key. This - enumeration defines constants for special keys that do not have a standard - code point, and some convenience constants for control characters. Note - that all keys are handled in the same way, this enumeration is just for - convenience when writing hard-coded key bindings. - - Keys that do not have a standard code point use values in the Private Use - Area in the Basic Multilingual Plane (`U+E000` to `U+F8FF`). Applications - must take care to not interpret these values beyond key detection, the - mapping used here is arbitrary and specific to Pugl. -*/ -typedef enum { - // ASCII control codes - PUGL_KEY_BACKSPACE = 0x08, - PUGL_KEY_ESCAPE = 0x1B, - PUGL_KEY_DELETE = 0x7F, - - // Unicode Private Use Area - PUGL_KEY_F1 = 0xE000, - PUGL_KEY_F2, - PUGL_KEY_F3, - PUGL_KEY_F4, - PUGL_KEY_F5, - PUGL_KEY_F6, - PUGL_KEY_F7, - PUGL_KEY_F8, - PUGL_KEY_F9, - PUGL_KEY_F10, - PUGL_KEY_F11, - PUGL_KEY_F12, - PUGL_KEY_LEFT, - PUGL_KEY_UP, - PUGL_KEY_RIGHT, - PUGL_KEY_DOWN, - PUGL_KEY_PAGE_UP, - PUGL_KEY_PAGE_DOWN, - PUGL_KEY_HOME, - PUGL_KEY_END, - PUGL_KEY_INSERT, - PUGL_KEY_SHIFT, - PUGL_KEY_SHIFT_L = PUGL_KEY_SHIFT, - PUGL_KEY_SHIFT_R, - PUGL_KEY_CTRL, - PUGL_KEY_CTRL_L = PUGL_KEY_CTRL, - PUGL_KEY_CTRL_R, - PUGL_KEY_ALT, - PUGL_KEY_ALT_L = PUGL_KEY_ALT, - PUGL_KEY_ALT_R, - PUGL_KEY_SUPER, - PUGL_KEY_SUPER_L = PUGL_KEY_SUPER, - PUGL_KEY_SUPER_R, - PUGL_KEY_MENU, - PUGL_KEY_CAPS_LOCK, - PUGL_KEY_SCROLL_LOCK, - PUGL_KEY_NUM_LOCK, - PUGL_KEY_PRINT_SCREEN, - PUGL_KEY_PAUSE -} PuglKey; - -/// The type of a PuglEvent -typedef enum { - PUGL_NOTHING, ///< No event - PUGL_CREATE, ///< View created, a #PuglEventCreate - PUGL_DESTROY, ///< View destroyed, a #PuglEventDestroy - PUGL_CONFIGURE, ///< View moved/resized, a #PuglEventConfigure - PUGL_MAP, ///< View made visible, a #PuglEventMap - PUGL_UNMAP, ///< View made invisible, a #PuglEventUnmap - PUGL_UPDATE, ///< View ready to draw, a #PuglEventUpdate - PUGL_EXPOSE, ///< View must be drawn, a #PuglEventExpose - PUGL_CLOSE, ///< View will be closed, a #PuglEventClose - PUGL_FOCUS_IN, ///< Keyboard focus entered view, a #PuglEventFocus - PUGL_FOCUS_OUT, ///< Keyboard focus left view, a #PuglEventFocus - PUGL_KEY_PRESS, ///< Key pressed, a #PuglEventKey - PUGL_KEY_RELEASE, ///< Key released, a #PuglEventKey - PUGL_TEXT, ///< Character entered, a #PuglEventText - PUGL_POINTER_IN, ///< Pointer entered view, a #PuglEventCrossing - PUGL_POINTER_OUT, ///< Pointer left view, a #PuglEventCrossing - PUGL_BUTTON_PRESS, ///< Mouse button pressed, a #PuglEventButton - PUGL_BUTTON_RELEASE, ///< Mouse button released, a #PuglEventButton - PUGL_MOTION, ///< Pointer moved, a #PuglEventMotion - PUGL_SCROLL, ///< Scrolled, a #PuglEventScroll - PUGL_CLIENT, ///< Custom client message, a #PuglEventClient - PUGL_TIMER, ///< Timer triggered, a #PuglEventTimer - PUGL_LOOP_ENTER, ///< Recursive loop entered, a #PuglEventLoopEnter - PUGL_LOOP_LEAVE, ///< Recursive loop left, a #PuglEventLoopLeave -} PuglEventType; - -/// Common flags for all event types -typedef enum { - PUGL_IS_SEND_EVENT = 1, ///< Event is synthetic - PUGL_IS_HINT = 2 ///< Event is a hint (not direct user input) -} PuglEventFlag; - -/// Bitwise OR of #PuglEventFlag values -typedef uint32_t PuglEventFlags; - -/// Reason for a PuglEventCrossing -typedef enum { - PUGL_CROSSING_NORMAL, ///< Crossing due to pointer motion - PUGL_CROSSING_GRAB, ///< Crossing due to a grab - PUGL_CROSSING_UNGRAB ///< Crossing due to a grab release -} PuglCrossingMode; - -/** - Scroll direction. - - Describes the direction of a #PuglEventScroll along with whether the scroll - is a "smooth" scroll. The discrete directions are for devices like mouse - wheels with constrained axes, while a smooth scroll is for those with - arbitrary scroll direction freedom, like some touchpads. -*/ -typedef enum { - PUGL_SCROLL_UP, ///< Scroll up - PUGL_SCROLL_DOWN, ///< Scroll down - PUGL_SCROLL_LEFT, ///< Scroll left - PUGL_SCROLL_RIGHT, ///< Scroll right - PUGL_SCROLL_SMOOTH ///< Smooth scroll in any direction -} PuglScrollDirection; - -/// Common header for all event structs -typedef struct { - PuglEventType type; ///< Event type - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values -} PuglEventAny; - -/** - View create event. - - This event is sent when a view is realized before it is first displayed, - with the graphics context entered. This is typically used for setting up - the graphics system, for example by loading OpenGL extensions. - - This event type has no extra fields. -*/ -typedef PuglEventAny PuglEventCreate; - -/** - View destroy event. - - This event is the counterpart to #PuglEventCreate, and it is sent when the - view is being destroyed. This is typically used for tearing down the - graphics system, or otherwise freeing any resources allocated when the - create event was handled. - - This is the last event sent to any view, and immediately after it is - processed, the view is destroyed and may no longer be used. - - This event type has no extra fields. -*/ -typedef PuglEventAny PuglEventDestroy; - -/** - View resize or move event. - - A configure event is sent whenever the view is resized or moved. When a - configure event is received, the graphics context is active but not set up - for drawing. For example, it is valid to adjust the OpenGL viewport or - otherwise configure the context, but not to draw anything. -*/ -typedef struct { - PuglEventType type; ///< #PUGL_CONFIGURE - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - double x; ///< New parent-relative X coordinate - double y; ///< New parent-relative Y coordinate - double width; ///< New width - double height; ///< New height -} PuglEventConfigure; - -/** - View show event. - - This event is sent when a view is mapped to the screen and made visible. - - This event type has no extra fields. -*/ -typedef PuglEventAny PuglEventMap; - -/** - View hide event. - - This event is sent when a view is unmapped from the screen and made - invisible. - - This event type has no extra fields. -*/ -typedef PuglEventAny PuglEventUnmap; - -/** - View update event. - - This event is sent to every view near the end of a main loop iteration when - any pending exposures are about to be redrawn. It is typically used to mark - regions to expose with puglPostRedisplay() or puglPostRedisplayRect(). For - example, to continuously animate, a view calls puglPostRedisplay() when an - update event is received, and it will then shortly receive an expose event. -*/ -typedef PuglEventAny PuglEventUpdate; - -/** - Expose event for when a region must be redrawn. - - When an expose event is received, the graphics context is active, and the - view must draw the entire specified region. The contents of the region are - undefined, there is no preservation of anything drawn previously. -*/ -typedef struct { - PuglEventType type; ///< #PUGL_EXPOSE - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - double x; ///< View-relative X coordinate - double y; ///< View-relative Y coordinate - double width; ///< Width of exposed region - double height; ///< Height of exposed region -} PuglEventExpose; - -/** - View close event. - - This event is sent when the view is to be closed, for example when the user - clicks the close button. - - This event type has no extra fields. -*/ -typedef PuglEventAny PuglEventClose; - -/** - Keyboard focus event. - - This event is sent whenever the view gains or loses the keyboard focus. The - view with the keyboard focus will receive any key press or release events. -*/ -typedef struct { - PuglEventType type; ///< #PUGL_FOCUS_IN or #PUGL_FOCUS_OUT - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - PuglCrossingMode mode; ///< Reason for focus change -} PuglEventFocus; - -/** - Key press or release event. - - This event represents low-level key presses and releases. This can be used - for "direct" keyboard handing like key bindings, but must not be interpreted - as text input. - - Keys are represented portably as Unicode code points, using the "natural" - code point for the key where possible (see #PuglKey for details). The `key` - field is the code for the pressed key, without any modifiers applied. For - example, a press or release of the 'A' key will have `key` 97 ('a') - regardless of whether shift or control are being held. - - Alternatively, the raw `keycode` can be used to work directly with physical - keys, but note that this value is not portable and differs between platforms - and hardware. -*/ -typedef struct { - PuglEventType type; ///< #PUGL_KEY_PRESS or #PUGL_KEY_RELEASE - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - double time; ///< Time in seconds - double x; ///< View-relative X coordinate - double y; ///< View-relative Y coordinate - double xRoot; ///< Root-relative X coordinate - double yRoot; ///< Root-relative Y coordinate - PuglMods state; ///< Bitwise OR of #PuglMod flags - uint32_t keycode; ///< Raw key code - uint32_t key; ///< Unshifted Unicode character code, or 0 -} PuglEventKey; - -/** - Character input event. - - This event represents text input, usually as the result of a key press. The - text is given both as a Unicode character code and a UTF-8 string. - - Note that this event is generated by the platform's input system, so there - is not necessarily a direct correspondence between text events and physical - key presses. For example, with some input methods a sequence of several key - presses will generate a single character. -*/ -typedef struct { - PuglEventType type; ///< #PUGL_TEXT - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - double time; ///< Time in seconds - double x; ///< View-relative X coordinate - double y; ///< View-relative Y coordinate - double xRoot; ///< Root-relative X coordinate - double yRoot; ///< Root-relative Y coordinate - PuglMods state; ///< Bitwise OR of #PuglMod flags - uint32_t keycode; ///< Raw key code - uint32_t character; ///< Unicode character code - char string[8]; ///< UTF-8 string -} PuglEventText; - -/** - Pointer enter or leave event. - - This event is sent when the pointer enters or leaves the view. This can - happen for several reasons (not just the user dragging the pointer over the - window edge), as described by the `mode` field. -*/ -typedef struct { - PuglEventType type; ///< #PUGL_POINTER_IN or #PUGL_POINTER_OUT - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - double time; ///< Time in seconds - double x; ///< View-relative X coordinate - double y; ///< View-relative Y coordinate - double xRoot; ///< Root-relative X coordinate - double yRoot; ///< Root-relative Y coordinate - PuglMods state; ///< Bitwise OR of #PuglMod flags - PuglCrossingMode mode; ///< Reason for crossing -} PuglEventCrossing; - -/** - Button press or release event. -*/ -typedef struct { - PuglEventType type; ///< #PUGL_BUTTON_PRESS or #PUGL_BUTTON_RELEASE - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - double time; ///< Time in seconds - double x; ///< View-relative X coordinate - double y; ///< View-relative Y coordinate - double xRoot; ///< Root-relative X coordinate - double yRoot; ///< Root-relative Y coordinate - PuglMods state; ///< Bitwise OR of #PuglMod flags - uint32_t button; ///< Button number starting from 1 -} PuglEventButton; - -/** - Pointer motion event. -*/ -typedef struct { - PuglEventType type; ///< #PUGL_MOTION - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - double time; ///< Time in seconds - double x; ///< View-relative X coordinate - double y; ///< View-relative Y coordinate - double xRoot; ///< Root-relative X coordinate - double yRoot; ///< Root-relative Y coordinate - PuglMods state; ///< Bitwise OR of #PuglMod flags -} PuglEventMotion; - -/** - Scroll event. - - The scroll distance is expressed in "lines", an arbitrary unit that - corresponds to a single tick of a detented mouse wheel. For example, `dy` = - 1.0 scrolls 1 line up. Some systems and devices support finer resolution - and/or higher values for fast scrolls, so programs should handle any value - gracefully. -*/ -typedef struct { - PuglEventType type; ///< #PUGL_SCROLL - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - double time; ///< Time in seconds - double x; ///< View-relative X coordinate - double y; ///< View-relative Y coordinate - double xRoot; ///< Root-relative X coordinate - double yRoot; ///< Root-relative Y coordinate - PuglMods state; ///< Bitwise OR of #PuglMod flags - PuglScrollDirection direction; ///< Scroll direction - double dx; ///< Scroll X distance in lines - double dy; ///< Scroll Y distance in lines -} PuglEventScroll; - -/** - Custom client message event. - - This can be used to send a custom message to a view, which is delivered via - the window system and processed in the event loop as usual. Among other - things, this makes it possible to wake up the event loop for any reason. -*/ -typedef struct { - PuglEventType type; ///< #PUGL_CLIENT - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - uintptr_t data1; ///< Client-specific data - uintptr_t data2; ///< Client-specific data -} PuglEventClient; - -/** - Timer event. - - This event is sent at the regular interval specified in the call to - puglStartTimer() that activated it. - - The `id` is the application-specific ID given to puglStartTimer() which - distinguishes this timer from others. It should always be checked in the - event handler, even in applications that register only one timer. -*/ -typedef struct { - PuglEventType type; ///< #PUGL_TIMER - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - uintptr_t id; ///< Timer ID -} PuglEventTimer; - -/** - Recursive loop enter event. - - This event is sent when the window system enters a recursive loop. The main - loop will be stalled and no expose events will be received while in the - recursive loop. To give the application full control, Pugl does not do any - special handling of this situation, but this event can be used to install a - timer to perform continuous actions (such as drawing) on platforms that do - this. - - - MacOS: A recursive loop is entered while the window is being live resized. - - - Windows: A recursive loop is entered while the window is being live - resized or the menu is shown. - - - X11: A recursive loop is never entered and the event loop runs as usual - while the view is being resized. - - This event type has no extra fields. -*/ -typedef PuglEventAny PuglEventLoopEnter; - -/** - Recursive loop leave event. - - This event is sent after a loop enter event when the recursive loop is - finished and normal iteration will continue. - - This event type has no extra fields. -*/ -typedef PuglEventAny PuglEventLoopLeave; - -/** - View event. - - This is a union of all event types. The type must be checked to determine - which fields are safe to access. A pointer to PuglEvent can either be cast - to the appropriate type, or the union members used. - - The graphics system may only be accessed when handling certain events. The - graphics context is active for #PUGL_CREATE, #PUGL_DESTROY, #PUGL_CONFIGURE, - and #PUGL_EXPOSE, but only enabled for drawing for #PUGL_EXPOSE. -*/ -typedef union { - PuglEventAny any; ///< Valid for all event types - PuglEventType type; ///< Event type - PuglEventButton button; ///< #PUGL_BUTTON_PRESS, #PUGL_BUTTON_RELEASE - PuglEventConfigure configure; ///< #PUGL_CONFIGURE - PuglEventExpose expose; ///< #PUGL_EXPOSE - PuglEventKey key; ///< #PUGL_KEY_PRESS, #PUGL_KEY_RELEASE - PuglEventText text; ///< #PUGL_TEXT - PuglEventCrossing crossing; ///< #PUGL_POINTER_IN, #PUGL_POINTER_OUT - PuglEventMotion motion; ///< #PUGL_MOTION - PuglEventScroll scroll; ///< #PUGL_SCROLL - PuglEventFocus focus; ///< #PUGL_FOCUS_IN, #PUGL_FOCUS_OUT - PuglEventClient client; ///< #PUGL_CLIENT - PuglEventTimer timer; ///< #PUGL_TIMER -} PuglEvent; - -/** - @} - @defgroup status Status - - Most functions return a status code which can be used to check for errors. - - @{ -*/ - -/// Return status code -typedef enum { - PUGL_SUCCESS, ///< Success - PUGL_FAILURE, ///< Non-fatal failure - PUGL_UNKNOWN_ERROR, ///< Unknown system error - PUGL_BAD_BACKEND, ///< Invalid or missing backend - PUGL_BAD_CONFIGURATION, ///< Invalid view configuration - PUGL_BAD_PARAMETER, ///< Invalid parameter - PUGL_BACKEND_FAILED, ///< Backend initialization failed - PUGL_REGISTRATION_FAILED, ///< Class registration failed - PUGL_REALIZE_FAILED, ///< System view realization failed - PUGL_SET_FORMAT_FAILED, ///< Failed to set pixel format - PUGL_CREATE_CONTEXT_FAILED, ///< Failed to create drawing context - PUGL_UNSUPPORTED_TYPE, ///< Unsupported data type -} PuglStatus; - -/// Return a string describing a status code -PUGL_CONST_API -const char* -puglStrerror(PuglStatus status); - -/** - @} - @defgroup world World - - The top-level context of a Pugl application or plugin. - - The world contains all library-wide state. There is no static data in Pugl, - so it is safe to use multiple worlds in a single process. This is to - facilitate plugins or other situations where it is not possible to share a - world, but a single world should be shared for all views where possible. - - @{ -*/ - -/** - The "world" of application state. - - The world represents everything that is not associated with a particular - view. Several worlds can be created in a single process, but code using - different worlds must be isolated so they are never mixed. Views are - strongly associated with the world they were created in. -*/ -typedef struct PuglWorldImpl PuglWorld; - -/// Handle for the world's opaque user data -typedef void* PuglWorldHandle; - -/// The type of a World -typedef enum { - PUGL_PROGRAM, ///< Top-level application - PUGL_MODULE ///< Plugin or module within a larger application -} PuglWorldType; - -/// World flags -typedef enum { - /** - Set up support for threads if necessary. - - - X11: Calls XInitThreads() which is required for some drivers. - */ - PUGL_WORLD_THREADS = 1u << 0u -} PuglWorldFlag; - -/// Bitwise OR of #PuglWorldFlag values -typedef uint32_t PuglWorldFlags; - -/** - Create a new world. - - @param type The type, which dictates what this world is responsible for. - @param flags Flags to control world features. - @return A new world, which must be later freed with puglFreeWorld(). -*/ -PUGL_API -PuglWorld* -puglNewWorld(PuglWorldType type, PuglWorldFlags flags); - -/// Free a world allocated with puglNewWorld() -PUGL_API -void -puglFreeWorld(PuglWorld* world); - -/** - Set the user data for the world. - - This is usually a pointer to a struct that contains all the state which must - be accessed by several views. - - The handle is opaque to Pugl and is not interpreted in any way. -*/ -PUGL_API -void -puglSetWorldHandle(PuglWorld* world, PuglWorldHandle handle); - -/// Get the user data for the world -PUGL_API -PuglWorldHandle -puglGetWorldHandle(PuglWorld* world); - -/** - Return a pointer to the native handle of the world. - - X11: Returns a pointer to the `Display`. - - MacOS: Returns null. - - Windows: Returns the `HMODULE` of the calling process. -*/ -PUGL_API -void* -puglGetNativeWorld(PuglWorld* world); - -/** - Set the class name of the application. - - This is a stable identifier for the application, used as the window - class/instance name on X11 and Windows. It is not displayed to the user, - but can be used in scripts and by window managers, so it should be the same - for every instance of the application, but different from other - applications. -*/ -PUGL_API -PuglStatus -puglSetClassName(PuglWorld* world, const char* name); - -/** - Return the time in seconds. - - This is a monotonically increasing clock with high resolution. The returned - time is only useful to compare against other times returned by this - function, its absolute value has no meaning. -*/ -PUGL_API -double -puglGetTime(const PuglWorld* world); - -/** - Update by processing events from the window system. - - This function is a single iteration of the main loop, and should be called - repeatedly to update all views. - - If `timeout` is zero, then this function will not block. Plugins should - always use a timeout of zero to avoid blocking the host. - - If a positive `timeout` is given, then events will be processed for that - amount of time, starting from when this function was called. - - If a negative `timeout` is given, this function will block indefinitely - until an event occurs. - - For continuously animating programs, a timeout that is a reasonable fraction - of the ideal frame period should be used, to minimize input latency by - ensuring that as many input events are consumed as possible before drawing. - - @return #PUGL_SUCCESS if events are read, #PUGL_FAILURE if no events are - read, or an error. -*/ -PUGL_API -PuglStatus -puglUpdate(PuglWorld* world, double timeout); - -/** - @} - @defgroup view View - - A drawable region that receives events. - - A view can be thought of as a window, but does not necessarily correspond to - a top-level window in a desktop environment. For example, a view can be - embedded in some other window, or represent an embedded system where there - is no concept of multiple windows at all. - - @{ -*/ - -/// A drawable region that receives events -typedef struct PuglViewImpl PuglView; - -/** - A graphics backend. - - The backend dictates how graphics are set up for a view, and how drawing is - performed. A backend must be set by calling puglSetBackend() before - realising a view. - - If you are using a local copy of Pugl, it is possible to implement a custom - backend. See the definition of `PuglBackendImpl` in the source code for - details. -*/ -typedef struct PuglBackendImpl PuglBackend; - -/** - A native view handle. - - X11: This is a `Window`. - - MacOS: This is a pointer to an `NSView*`. - - Windows: This is a `HWND`. -*/ -typedef uintptr_t PuglNativeView; - -/// Handle for a view's opaque user data -typedef void* PuglHandle; - -/// A hint for configuring a view -typedef enum { - PUGL_USE_COMPAT_PROFILE, ///< Use compatible (not core) OpenGL profile - PUGL_USE_DEBUG_CONTEXT, ///< True to use a debug OpenGL context - PUGL_CONTEXT_VERSION_MAJOR, ///< OpenGL context major version - PUGL_CONTEXT_VERSION_MINOR, ///< OpenGL context minor version - PUGL_RED_BITS, ///< Number of bits for red channel - PUGL_GREEN_BITS, ///< Number of bits for green channel - PUGL_BLUE_BITS, ///< Number of bits for blue channel - PUGL_ALPHA_BITS, ///< Number of bits for alpha channel - PUGL_DEPTH_BITS, ///< Number of bits for depth buffer - PUGL_STENCIL_BITS, ///< Number of bits for stencil buffer - PUGL_SAMPLES, ///< Number of samples per pixel (AA) - PUGL_DOUBLE_BUFFER, ///< True if double buffering should be used - PUGL_SWAP_INTERVAL, ///< Number of frames between buffer swaps - PUGL_RESIZABLE, ///< True if view should be resizable - PUGL_IGNORE_KEY_REPEAT, ///< True if key repeat events are ignored - PUGL_REFRESH_RATE, ///< Refresh rate in Hz - - PUGL_NUM_VIEW_HINTS -} PuglViewHint; - -/// A special view hint value -typedef enum { - PUGL_DONT_CARE = -1, ///< Use best available value - PUGL_FALSE = 0, ///< Explicitly false - PUGL_TRUE = 1 ///< Explicitly true -} PuglViewHintValue; - -/// A function called when an event occurs -typedef PuglStatus (*PuglEventFunc)(PuglView* view, const PuglEvent* event); - -/** - @defgroup setup Setup - Functions for creating and destroying a view. - @{ -*/ - -/** - Create a new view. - - A newly created view does not correspond to a real system view or window. - It must first be configured, then the system view can be created with - puglRealize(). -*/ -PUGL_API -PuglView* -puglNewView(PuglWorld* world); - -/// Free a view created with puglNewView() -PUGL_API -void -puglFreeView(PuglView* view); - -/// Return the world that `view` is a part of -PUGL_API -PuglWorld* -puglGetWorld(PuglView* view); - -/** - Set the user data for a view. - - This is usually a pointer to a struct that contains all the state which must - be accessed by a view. Everything needed to process events should be stored - here, not in static variables. - - The handle is opaque to Pugl and is not interpreted in any way. -*/ -PUGL_API -void -puglSetHandle(PuglView* view, PuglHandle handle); - -/// Get the user data for a view -PUGL_API -PuglHandle -puglGetHandle(PuglView* view); - -/** - Set the graphics backend to use for a view. - - This must be called once to set the graphics backend before calling - puglRealize(). - - Pugl includes the following backends: - - - puglCairoBackend() - - puglGlBackend() - - puglVulkanBackend() - - Note that backends are modular and not compiled into the main Pugl library - to avoid unnecessary dependencies. To use a particular backend, - applications must link against the appropriate backend library, or be sure - to compile in the appropriate code if using a local copy of Pugl. -*/ -PUGL_API -PuglStatus -puglSetBackend(PuglView* view, const PuglBackend* backend); - -/// Set the function to call when an event occurs -PUGL_API -PuglStatus -puglSetEventFunc(PuglView* view, PuglEventFunc eventFunc); - -/** - Set a hint to configure view properties. - - This only has an effect when called before puglRealize(). -*/ -PUGL_API -PuglStatus -puglSetViewHint(PuglView* view, PuglViewHint hint, int value); - -/** - Get the value for a view hint. - - If the view has been realized, this can be used to get the actual value of a - hint which was initially set to PUGL_DONT_CARE, or has been adjusted from - the suggested value. -*/ -PUGL_API -int -puglGetViewHint(const PuglView* view, PuglViewHint hint); - -/** - @} - @defgroup frame Frame - Functions for working with the position and size of a view. - @{ -*/ - -/** - Get the current position and size of the view. - - The position is in screen coordinates with an upper left origin. -*/ -PUGL_API -PuglRect -puglGetFrame(const PuglView* view); - -/** - Set the current position and size of the view. - - The position is in screen coordinates with an upper left origin. - - @return #PUGL_UNKNOWN_ERROR on failure, in which case the view frame is - unchanged. -*/ -PUGL_API -PuglStatus -puglSetFrame(PuglView* view, PuglRect frame); - -/** - Set the default size of the view. - - This should be called before puglResize() to set the default size of the - view, which will be the initial size of the window if this is a top level - view. - - @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is - not yet realized. -*/ -PUGL_API -PuglStatus -puglSetDefaultSize(PuglView* view, int width, int height); - -/** - Set the minimum size of the view. - - If an initial minimum size is known, this should be called before - puglRealize() to avoid stutter, though it can be called afterwards as well. - - @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is - not yet realized. -*/ -PUGL_API -PuglStatus -puglSetMinSize(PuglView* view, int width, int height); - -/** - Set the maximum size of the view. - - If an initial maximum size is known, this should be called before - puglRealize() to avoid stutter, though it can be called afterwards as well. - - @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is - not yet realized. -*/ -PUGL_API -PuglStatus -puglSetMaxSize(PuglView* view, int width, int height); - -/** - Set the view aspect ratio range. - - The x and y values here represent a ratio of width to height. To set a - fixed aspect ratio, set the minimum and maximum values to the same ratio. - - Note that setting different minimum and maximum constraints does not - currenty work on MacOS (the minimum is used), so only setting a fixed aspect - ratio works properly across all platforms. - - If an initial aspect ratio is known, this should be called before - puglRealize() to avoid stutter, though it can be called afterwards as well. - - @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is - not yet realized. -*/ -PUGL_API -PuglStatus -puglSetAspectRatio(PuglView* view, int minX, int minY, int maxX, int maxY); - -/** - @} - @defgroup window Window - Functions to control the top-level window of a view. - @{ -*/ - -/** - Set the title of the window. - - This only makes sense for non-embedded views that will have a corresponding - top-level window, and sets the title, typically displayed in the title bar - or in window switchers. -*/ -PUGL_API -PuglStatus -puglSetWindowTitle(PuglView* view, const char* title); - -/** - Set the parent window for embedding a view in an existing window. - - This must be called before puglRealize(), reparenting is not supported. -*/ -PUGL_API -PuglStatus -puglSetParentWindow(PuglView* view, PuglNativeView parent); - -/** - Set the transient parent of the window. - - Set this for transient children like dialogs, to have them properly - associated with their parent window. This should be called before - puglRealize(). - - A view can either have a parent (for embedding) or a transient parent (for - top-level windows like dialogs), but not both. -*/ -PUGL_API -PuglStatus -puglSetTransientFor(PuglView* view, PuglNativeView parent); - -/** - Realize a view by creating a corresponding system view or window. - - After this call, the (initially invisible) underlying system view exists and - can be accessed with puglGetNativeWindow(). There is currently no - corresponding unrealize function, the system view will be destroyed along - with the view when puglFreeView() is called. - - The view should be fully configured using the above functions before this is - called. This function may only be called once per view. -*/ -PUGL_API -PuglStatus -puglRealize(PuglView* view); - -/** - Show the view. - - If the view has not yet been realized, the first call to this function will - do so automatically. - - If the view is currently hidden, it will be shown and possibly raised to the - top depending on the platform. -*/ -PUGL_API -PuglStatus -puglShow(PuglView* view); - -/// Hide the current window -PUGL_API -PuglStatus -puglHide(PuglView* view); - -/// Return true iff the view is currently visible -PUGL_API -bool -puglGetVisible(const PuglView* view); - -/// Return the native window handle -PUGL_API -PuglNativeView -puglGetNativeWindow(PuglView* view); - -/** - @} - @defgroup graphics Graphics - Functions for working with the graphics context and scheduling redisplays. - @{ -*/ - -/** - Get the graphics context. - - This is a backend-specific context used for drawing if the backend graphics - API requires one. It is only available during an expose. - - Cairo: Returns a pointer to a - [cairo_t](http://www.cairographics.org/manual/cairo-cairo-t.html). - - All other backends: returns null. -*/ -PUGL_API -void* -puglGetContext(PuglView* view); - -/** - Request a redisplay for the entire view. - - This will cause an expose event to be dispatched later. If called from - within the event handler, the expose should arrive at the end of the current - event loop iteration, though this is not strictly guaranteed on all - platforms. If called elsewhere, an expose will be enqueued to be processed - in the next event loop iteration. -*/ -PUGL_API -PuglStatus -puglPostRedisplay(PuglView* view); - -/** - Request a redisplay of the given rectangle within the view. - - This has the same semantics as puglPostRedisplay(), but allows giving a - precise region for redrawing only a portion of the view. -*/ -PUGL_API -PuglStatus -puglPostRedisplayRect(PuglView* view, PuglRect rect); - -/** - @} - @defgroup interaction Interaction - Functions for interacting with the user and window system. - @{ -*/ - -/** - A mouse cursor type. - - This is a portable subset of mouse cursors that exist on X11, MacOS, and - Windows. -*/ -typedef enum { - PUGL_CURSOR_ARROW, ///< Default pointing arrow - PUGL_CURSOR_CARET, ///< Caret (I-Beam) for text entry - PUGL_CURSOR_CROSSHAIR, ///< Cross-hair - PUGL_CURSOR_HAND, ///< Hand with a pointing finger - PUGL_CURSOR_NO, ///< Operation not allowed - PUGL_CURSOR_LEFT_RIGHT, ///< Left/right arrow for horizontal resize - PUGL_CURSOR_UP_DOWN, ///< Up/down arrow for vertical resize -} PuglCursor; - -/// Grab the keyboard input focus -PUGL_API -PuglStatus -puglGrabFocus(PuglView* view); - -/// Return whether `view` has the keyboard input focus -PUGL_API -bool -puglHasFocus(const PuglView* view); - -/** - Set the clipboard contents. - - This sets the system clipboard contents, which can be retrieved with - puglGetClipboard() or pasted into other applications. - - @param view The view. - @param type The MIME type of the data, "text/plain" is assumed if `NULL`. - @param data The data to copy to the clipboard. - @param len The length of data in bytes (including terminator if necessary). -*/ -PUGL_API -PuglStatus -puglSetClipboard(PuglView* view, - const char* type, - const void* data, - size_t len); - -/** - Get the clipboard contents. - - This gets the system clipboard contents, which may have been set with - puglSetClipboard() or copied from another application. - - @param view The view. - @param[out] type Set to the MIME type of the data. - @param[out] len Set to the length of the data in bytes. - @return The clipboard contents, or null. -*/ -PUGL_API -const void* -puglGetClipboard(PuglView* view, const char** type, size_t* len); - -/** - Set the mouse cursor. - - This changes the system cursor that is displayed when the pointer is inside - the view. May fail if setting the cursor is not supported on this system, - for example if compiled on X11 without Xcursor support. - - @return #PUGL_BAD_PARAMETER if the given cursor is invalid, - #PUGL_FAILURE if the cursor is known but loading it system fails. -*/ -PUGL_API -PuglStatus -puglSetCursor(PuglView* view, PuglCursor cursor); - -/** - Request user attention. - - This hints to the system that the window or application requires attention - from the user. The exact effect depends on the platform, but is usually - something like a flashing task bar entry or bouncing application icon. -*/ -PUGL_API -PuglStatus -puglRequestAttention(PuglView* view); - -/** - Activate a repeating timer event. - - This starts a timer which will send a #PuglEventTimer to `view` every - `timeout` seconds. This can be used to perform some action in a view at a - regular interval with relatively low frequency. Note that the frequency of - timer events may be limited by how often puglUpdate() is called. - - If the given timer already exists, it is replaced. - - @param view The view to begin sending #PUGL_TIMER events to. - - @param id The identifier for this timer. This is an application-specific ID - that should be a low number, typically the value of a constant or `enum` - that starts from 0. There is a platform-specific limit to the number of - supported timers, and overhead associated with each, so applications should - create only a few timers and perform several tasks in one if necessary. - - @param timeout The period, in seconds, of this timer. This is not - guaranteed to have a resolution better than 10ms (the maximum timer - resolution on Windows) and may be rounded up if it is too short. On X11 and - MacOS, a resolution of about 1ms can usually be relied on. - - @return #PUGL_FAILURE if timers are not supported by the system, - #PUGL_UNKNOWN_ERROR if setting the timer failed. -*/ -PUGL_API -PuglStatus -puglStartTimer(PuglView* view, uintptr_t id, double timeout); - -/** - Stop an active timer. - - @param view The view that the timer is set for. - @param id The ID previously passed to puglStartTimer(). - - @return #PUGL_FAILURE if timers are not supported by this system, - #PUGL_UNKNOWN_ERROR if stopping the timer failed. -*/ -PUGL_API -PuglStatus -puglStopTimer(PuglView* view, uintptr_t id); - -/** - Send an event to a view via the window system. - - If supported, the event will be delivered to the view via the event loop - like other events. Note that this function only works for certain event - types. - - Currently, only #PUGL_CLIENT events are supported on all platforms. - - X11: A #PUGL_EXPOSE event can be sent, which is similar to calling - puglPostRedisplayRect(), but will always send a message to the X server, - even when called in an event handler. - - @return #PUGL_UNSUPPORTED_TYPE if sending events of this type is not supported, - #PUGL_UNKNOWN_ERROR if sending the event failed. -*/ -PUGL_API -PuglStatus -puglSendEvent(PuglView* view, const PuglEvent* event); - -/** - @} -*/ - -#ifndef PUGL_DISABLE_DEPRECATED - -/** - @} - @defgroup deprecated Deprecated API - @{ -*/ - -/** - A native window handle. - - X11: This is a `Window`. - - MacOS: This is a pointer to an `NSView*`. - - Windows: This is a `HWND`. -*/ -typedef uintptr_t PuglNativeWindow; - -/** - Create a Pugl application and view. - - To create a window, call the various puglInit* functions as necessary, then - call puglRealize(). - - @deprecated Use puglNewApp() and puglNewView(). - - @param pargc Pointer to argument count (currently unused). - @param argv Arguments (currently unused). - @return A newly created view. -*/ -static inline PUGL_DEPRECATED_BY("puglNewView") -PuglView* -puglInit(const int* pargc, char** argv) -{ - (void)pargc; - (void)argv; - - return puglNewView(puglNewWorld(PUGL_MODULE, 0)); -} - -/** - Destroy an app and view created with `puglInit()`. - - @deprecated Use puglFreeApp() and puglFreeView(). -*/ -static inline PUGL_DEPRECATED_BY("puglFreeView") -void -puglDestroy(PuglView* view) -{ - PuglWorld* const world = puglGetWorld(view); - - puglFreeView(view); - puglFreeWorld(world); -} - -/** - Set the window class name before creating a window. -*/ -static inline PUGL_DEPRECATED_BY("puglSetClassName") -void -puglInitWindowClass(PuglView* view, const char* name) -{ - puglSetClassName(puglGetWorld(view), name); -} - -/** - Set the window size before creating a window. - - @deprecated Use puglSetFrame(). -*/ -static inline PUGL_DEPRECATED_BY("puglSetFrame") -void -puglInitWindowSize(PuglView* view, int width, int height) -{ - PuglRect frame = puglGetFrame(view); - - frame.width = width; - frame.height = height; - - puglSetFrame(view, frame); -} - -/** - Set the minimum window size before creating a window. -*/ -static inline PUGL_DEPRECATED_BY("puglSetMinSize") -void -puglInitWindowMinSize(PuglView* view, int width, int height) -{ - puglSetMinSize(view, width, height); -} - -/** - Set the window aspect ratio range before creating a window. - - The x and y values here represent a ratio of width to height. To set a - fixed aspect ratio, set the minimum and maximum values to the same ratio. - - Note that setting different minimum and maximum constraints does not - currenty work on MacOS (the minimum is used), so only setting a fixed aspect - ratio works properly across all platforms. -*/ -static inline PUGL_DEPRECATED_BY("puglSetAspectRatio") -void -puglInitWindowAspectRatio(PuglView* view, - int minX, - int minY, - int maxX, - int maxY) -{ - puglSetAspectRatio(view, minX, minY, maxX, maxY); -} - -/** - Set transient parent before creating a window. - - On X11, parent must be a Window. - On OSX, parent must be an NSView*. -*/ -static inline PUGL_DEPRECATED_BY("puglSetTransientFor") -void -puglInitTransientFor(PuglView* view, uintptr_t parent) -{ - puglSetTransientFor(view, (PuglNativeWindow)parent); -} - -/** - Enable or disable resizing before creating a window. - - @deprecated Use puglSetViewHint() with #PUGL_RESIZABLE. -*/ -static inline PUGL_DEPRECATED_BY("puglSetViewHint") -void -puglInitResizable(PuglView* view, bool resizable) -{ - puglSetViewHint(view, PUGL_RESIZABLE, resizable); -} - -/** - Get the current size of the view. - - @deprecated Use puglGetFrame(). - -*/ -static inline PUGL_DEPRECATED_BY("puglGetFrame") -void -puglGetSize(PuglView* view, int* width, int* height) -{ - const PuglRect frame = puglGetFrame(view); - - *width = (int)frame.width; - *height = (int)frame.height; -} - -/** - Ignore synthetic repeated key events. - - @deprecated Use puglSetViewHint() with #PUGL_IGNORE_KEY_REPEAT. -*/ -static inline PUGL_DEPRECATED_BY("puglSetViewHint") -void -puglIgnoreKeyRepeat(PuglView* view, bool ignore) -{ - puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, ignore); -} - -/** - Set a hint before creating a window. - - @deprecated Use puglSetWindowHint(). -*/ -static inline PUGL_DEPRECATED_BY("puglSetViewHint") -void -puglInitWindowHint(PuglView* view, PuglViewHint hint, int value) -{ - puglSetViewHint(view, hint, value); -} - -/** - Set the parent window before creating a window (for embedding). - - @deprecated Use puglSetWindowParent(). -*/ -static inline PUGL_DEPRECATED_BY("puglSetParentWindow") -void -puglInitWindowParent(PuglView* view, PuglNativeWindow parent) -{ - puglSetParentWindow(view, parent); -} - -/** - Set the graphics backend to use. - - @deprecated Use puglSetBackend(). -*/ -static inline PUGL_DEPRECATED_BY("puglSetBackend") -int -puglInitBackend(PuglView* view, const PuglBackend* backend) -{ - return (int)puglSetBackend(view, backend); -} - -/** - Realize a view by creating a corresponding system view or window. - - The view should be fully configured using the above functions before this is - called. This function may only be called once per view. - - @deprecated Use puglRealize(), or just show the view. -*/ -static inline PUGL_DEPRECATED_BY("puglRealize") -PuglStatus -puglCreateWindow(PuglView* view, const char* title) -{ - puglSetWindowTitle(view, title); - return puglRealize(view); -} - -/** - Block and wait for an event to be ready. - - This can be used in a loop to only process events via puglProcessEvents when - necessary. This function will block indefinitely if no events are - available, so is not appropriate for use in programs that need to perform - regular updates (e.g. animation). - - @deprecated Use puglPollEvents(). -*/ -PUGL_API -PUGL_DEPRECATED_BY("puglPollEvents") -PuglStatus -puglWaitForEvent(PuglView* view); - -/** - Process all pending window events. - - This handles input events as well as rendering, so it should be called - regularly and rapidly enough to keep the UI responsive. This function does - not block if no events are pending. - - @deprecated Use puglDispatchEvents(). -*/ -PUGL_API -PUGL_DEPRECATED_BY("puglDispatchEvents") -PuglStatus -puglProcessEvents(PuglView* view); - -/** - Poll for events that are ready to be processed. - - This polls for events that are ready for any view in the world, potentially - blocking depending on `timeout`. - - @param world The world to poll for events. - - @param timeout Maximum time to wait, in seconds. If zero, the call returns - immediately, if negative, the call blocks indefinitely. - - @return #PUGL_SUCCESS if events are read, #PUGL_FAILURE if not, or an error. - - @deprecated Use puglUpdate(). -*/ -PUGL_API -PUGL_DEPRECATED_BY("puglUpdate") -PuglStatus -puglPollEvents(PuglWorld* world, double timeout); - -/** - Dispatch any pending events to views. - - This processes all pending events, dispatching them to the appropriate - views. View event handlers will be called in the scope of this call. This - function does not block, if no events are pending then it will return - immediately. - - @deprecated Use puglUpdate(). -*/ -PUGL_API -PUGL_DEPRECATED_BY("puglUpdate") -PuglStatus -puglDispatchEvents(PuglWorld* world); - -PUGL_API -PUGL_DEPRECATED_BY("puglShow") -PuglStatus -puglShowWindow(PuglView* view); - -PUGL_API -PUGL_DEPRECATED_BY("puglHide") -PuglStatus -puglHideWindow(PuglView* view); - -#endif // PUGL_DISABLE_DEPRECATED - -/** - @} - @} -*/ - -PUGL_END_DECLS - -#endif // PUGL_PUGL_H diff --git a/subprojects/nk_pugl/pugl/include/pugl/stub.h b/subprojects/nk_pugl/pugl/include/pugl/stub.h deleted file mode 100644 index d1a699a..0000000 --- a/subprojects/nk_pugl/pugl/include/pugl/stub.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - Copyright 2019-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_STUB_H -#define PUGL_STUB_H - -#include "pugl/pugl.h" - -PUGL_BEGIN_DECLS - -/** - @defgroup stub Stub - Native graphics support. - @ingroup pugl - @{ -*/ - -/** - Stub graphics backend accessor. - - This backend just creates a simple native window without setting up any - portable graphics API. -*/ -PUGL_CONST_API -const PuglBackend* -puglStubBackend(void); - -/** - @} -*/ - -PUGL_END_DECLS - -#endif // PUGL_STUB_H diff --git a/subprojects/nk_pugl/pugl/include/pugl/vulkan.h b/subprojects/nk_pugl/pugl/include/pugl/vulkan.h deleted file mode 100644 index f12ad97..0000000 --- a/subprojects/nk_pugl/pugl/include/pugl/vulkan.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Note that this header includes Vulkan headers, so if you are writing a - program or plugin that dynamically loads vulkan, you should first define - `VK_NO_PROTOTYPES` before including it. -*/ - -#ifndef PUGL_VULKAN_H -#define PUGL_VULKAN_H - -#include "pugl/pugl.h" - -#include - -#include - -PUGL_BEGIN_DECLS - -/** - @defgroup vulkan Vulkan - Vulkan graphics support. - - Vulkan support differs from OpenGL because almost all most configuration is - done using the Vulkan API itself, rather than by setting view hints to - configure the context. Pugl only provides a minimal loader for loading the - Vulkan library, and a portable function to create a Vulkan surface for a - view, which hides the platform-specific implementation details. - - @ingroup pugl - @{ -*/ - -/** - Dynamic Vulkan loader. - - This can be used to dynamically load the Vulkan library. Applications or - plugins should not link against the Vulkan library, but instead use this at - runtime. This ensures that things will work on as many systems as possible, - and allows errors to be handled gracefully. - - This is not a "loader" in the sense of loading all the required Vulkan - functions (which is the application's responsibility), but just a minimal - implementation to portably load the Vulkan library and get the two functions - that are used to load everything else. - - Note that this owns the loaded Vulkan library, so it must outlive all use of - the Vulkan API. - - @see https://www.khronos.org/registry/vulkan/specs/1.0/html/chap4.html -*/ -typedef struct PuglVulkanLoaderImpl PuglVulkanLoader; - -/** - Create a new dynamic loader for Vulkan functions. - - This dynamically loads the Vulkan library and gets the load functions from - it. - - @return A new Vulkan loader, or null on failure. -*/ -PUGL_API -PuglVulkanLoader* -puglNewVulkanLoader(PuglWorld* world); - -/** - Free a loader created with puglNewVulkanLoader(). - - Note that this closes the Vulkan library, so no Vulkan objects or API may be - used after this is called. -*/ -PUGL_API -void -puglFreeVulkanLoader(PuglVulkanLoader* loader); - -/** - Return the `vkGetInstanceProcAddr` function. - - @return Null if the Vulkan library does not contain this function (which is - unlikely and indicates a broken system). -*/ -PUGL_API -PFN_vkGetInstanceProcAddr -puglGetInstanceProcAddrFunc(const PuglVulkanLoader* loader); - -/** - Return the `vkGetDeviceProcAddr` function. - - @return Null if the Vulkan library does not contain this function (which is - unlikely and indicates a broken system). -*/ -PUGL_API -PFN_vkGetDeviceProcAddr -puglGetDeviceProcAddrFunc(const PuglVulkanLoader* loader); - -/** - Return the Vulkan instance extensions required to draw to a PuglView. - - This simply returns static strings, it does not access Vulkan or the window - system. The returned array always contains at least "VK_KHR_surface". - - @param[out] count The number of extensions in the returned array. - @return An array of extension name strings. -*/ -PUGL_API -const char* const* -puglGetInstanceExtensions(uint32_t* count); - -/** - Create a Vulkan surface for a Pugl view. - - @param vkGetInstanceProcAddr Accessor for Vulkan functions. - @param view The view the surface is to be displayed on. - @param instance The Vulkan instance. - @param allocator Vulkan allocation callbacks, may be NULL. - @param[out] surface Pointed to a newly created Vulkan surface. - @return `VK_SUCCESS` on success, or a Vulkan error code. -*/ -PUGL_API -VkResult -puglCreateSurface(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr, - PuglView* view, - VkInstance instance, - const VkAllocationCallbacks* allocator, - VkSurfaceKHR* surface); - -/** - Vulkan graphics backend. - - Pass the returned value to puglSetBackend() to draw to a view with Vulkan. -*/ -PUGL_CONST_API -const PuglBackend* -puglVulkanBackend(void); - -/** - @} -*/ - -PUGL_END_DECLS - -#endif // PUGL_VULKAN_H diff --git a/subprojects/nk_pugl/pugl/meson.build b/subprojects/nk_pugl/pugl/meson.build deleted file mode 100644 index 02fae17..0000000 --- a/subprojects/nk_pugl/pugl/meson.build +++ /dev/null @@ -1,455 +0,0 @@ -project('pugl', ['c'], - version: '0.3.0', - license: 'ISC', - meson_version: '>= 0.49.2', - default_options: [ - 'c_std=c99', - 'cpp_std=c++11', - 'default_library=shared' - ]) - -pugl_src_root = meson.current_source_dir() -major_version = meson.project_version().split('.')[0] -version_suffix = '-@0@'.format(major_version) -versioned_name = 'pugl' + version_suffix - -# Load build tools -pkg = import('pkgconfig') -cc = meson.get_compiler('c') - -# Enable C++ support if we're building the examples -if get_option('examples') - add_languages(['cpp']) - cpp = meson.get_compiler('cpp') -endif - -# Enable Objective C support if we're building for MacOS -if host_machine.system() == 'darwin' - add_languages(['objc']) - objcc = meson.get_compiler('objc') -endif - -# Set ultra strict warnings for developers, if requested -if get_option('strict') - subdir('meson') - - # C warnings - c_warnings = all_c_warnings - if cc.get_id() == 'clang' - c_warnings += [ - '-Wno-bad-function-cast', - '-Wno-documentation', # Cairo - '-Wno-documentation-unknown-command', # Cairo - '-Wno-float-equal', - '-Wno-implicit-fallthrough', - '-Wno-padded', - '-Wno-reserved-id-macro', - '-Wno-switch-default', - '-Wno-switch-enum', - '-Wno-unused-macros', # Mac - ] - elif cc.get_id() == 'gcc' - c_warnings += [ - '-Wno-bad-function-cast', - '-Wno-float-equal', - '-Wno-inline', - '-Wno-padded', - '-Wno-pedantic', - '-Wno-suggest-attribute=const', - '-Wno-suggest-attribute=malloc', - '-Wno-suggest-attribute=pure', - '-Wno-switch-default', - '-Wno-switch-enum', - '-Wno-unsuffixed-float-constants', - ] - elif cc.get_id() == 'msvc' - c_warnings += [ - '/wd4028', # formal parameter different from declaration - '/wd4061', # enumerator in switch is not explicitly handled - '/wd4191', # unsafe conversion from type to type - '/wd4514', # unreferenced inline function has been removed - '/wd4706', # assignment within conditional expression - '/wd4710', # function not inlined - '/wd4711', # function selected for automatic inline expansion - '/wd4800', # implicit conversion from int to bool - '/wd4820', # padding added after construct - '/wd4996', # function or variable may be unsafe - '/wd5045', # will insert Spectre mitigation for memory load - ] - endif - - add_project_arguments(cc.get_supported_arguments(c_warnings), - language: ['c', 'objc']) - - # C++ warnings - cpp_warnings = all_cpp_warnings - if is_variable('cpp') - if cpp.get_id() == 'clang' - cpp_warnings += [ - '-Wno-documentation-unknown-command', # Cairo - '-Wno-old-style-cast', - '-Wno-padded', - '-Wno-reserved-id-macro', - '-Wno-switch-enum', - '-Wno-unused-macros', # Mac - ] - elif cpp.get_id() == 'gcc' - cpp_warnings += [ - '-Wno-effc++', - '-Wno-inline', - '-Wno-old-style-cast', - '-Wno-padded', - '-Wno-suggest-attribute=const', - '-Wno-suggest-attribute=malloc', - '-Wno-suggest-attribute=pure', - '-Wno-suggest-final-methods', - '-Wno-switch-default', - '-Wno-switch-enum', - '-Wno-unused-const-variable', - '-Wno-useless-cast', - ] - elif cpp.get_id() == 'msvc' - cpp_warnings += [ - '/wd4061', # enumerator in switch is not explicitly handled - '/wd4191', # unsafe conversion from type to type - '/wd4355', # 'this' used in base member initializer list - '/wd4514', # unreferenced inline function has been removed - '/wd4571', # structured exceptions (SEH) are no longer caught - '/wd4625', # copy constructor implicitly deleted - '/wd4626', # assignment operator implicitly deleted - '/wd4706', # assignment within conditional expression - '/wd4710', # function not inlined - '/wd4711', # function selected for automatic inline expansion - '/wd4800', # implicit conversion from int to bool - '/wd4820', # padding added after construct - '/wd4868', # compiler may not enforce left-to-right evaluation order - '/wd4996', # function or variable may be unsafe - '/wd5026', # move constructor implicitly deleted - '/wd5027', # move assignment operator implicitly deleted - '/wd5039', # potentially throwing function passed to C - '/wd5045', # will insert Spectre mitigation for memory load - ] - endif - - add_project_arguments(cpp.get_supported_arguments(cpp_warnings), - language: ['cpp']) - endif - - # Objective C warnings - if is_variable('objcc') - add_project_arguments(objcc.get_supported_arguments(all_objc_warnings), - language: ['objc']) - endif -endif - -# Disable deprecated API which is not used by tests or examples -add_project_arguments(['-DPUGL_DISABLE_DEPRECATED'], - language: ['c', 'cpp', 'objc']) - -c_headers = [ - 'include/pugl/pugl.h', - - 'include/pugl/cairo.h', - 'include/pugl/gl.h', - 'include/pugl/stub.h', - 'include/pugl/vulkan.h', -] - -c_header_files = files(c_headers) - -cpp_headers = [ - 'bindings/cxx/include/pugl/pugl.hpp', - - 'bindings/cxx/include/pugl/cairo.hpp', - 'bindings/cxx/include/pugl/gl.hpp', - 'bindings/cxx/include/pugl/stub.hpp', - 'bindings/cxx/include/pugl/vulkan.hpp', -] - -cpp_header_files = files(cpp_headers) - -core_sources = [ - 'src/implementation.c' -] - -# System libraries -m_dep = cc.find_library('m', required: false) -dl_dep = cc.find_library('dl', required: false) -thread_dep = dependency('threads') - -# Cairo (optional backend) -cairo_dep = dependency('cairo', - required: get_option('cairo')) - -# OpenGL (optional backend) -opengl_dep = dependency('GL', - required: get_option('opengl')) - -# Vulkan (optional backend) -vulkan_dep = dependency('vulkan', - required: get_option('vulkan')) - -core_args = [] - -# MacOS -if host_machine.system() == 'darwin' - cocoa_dep = dependency('Cocoa', required: false, modules: 'foundation') - corevideo_dep = dependency('CoreVideo', required: false) - - platform = 'mac' - platform_sources = ['src/mac.m', 'src/mac_stub.m'] - core_deps = [cocoa_dep, corevideo_dep] - extension = '.m' - - add_project_arguments(['-Wno-deprecated-declarations'], language: ['objc']) - add_project_arguments(['-Wno-direct-ivar-access'], language: ['objc']) - - add_project_arguments(['-DGL_SILENCE_DEPRECATION'], - language: ['c', 'objc']) - - add_project_link_arguments(['-Wl,-framework,Cocoa'], - language: ['c', 'objc']) - -# Windows -elif host_machine.system() == 'windows' - if cpp.get_id() == 'msvc' - msvc_args = [ - '/TP', - '/experimental:external', - '/external:W0', - '/external:anglebrackets', - ] - - add_project_arguments(msvc_args, language: ['c', 'cpp']) - endif - - win_args = [ - '-DWIN32_LEAN_AND_MEAN', - '-D_CRT_SECURE_NO_WARNINGS', - ] - - add_project_arguments(win_args, language: ['c', 'cpp']) - - platform = 'win' - platform_sources = ['src/win.c'] - core_deps = [] - extension = '.c' - -else # X11 - x11_dep = cc.find_library('X11') - - xcursor_dep = cc.find_library('Xcursor', required: false) - if xcursor_dep.found() - core_args += ['-DHAVE_XCURSOR'] - endif - - xrandr_dep = cc.find_library('Xrandr', required: false) - if xrandr_dep.found() - core_args += ['-DHAVE_XRANDR'] - endif - - xext_dep = cc.find_library('Xext', required: false) - if xext_dep.found() - xsync_fragment = '''#include - #include - int main(void) { XSyncQueryExtension(0, 0, 0); return 0; }''' - if cc.compiles(xsync_fragment, name: 'Xsync') - core_args += ['-DHAVE_XSYNC'] - endif - endif - - platform = 'x11' - platform_sources = ['src/x11.c'] - core_deps = [x11_dep, xcursor_dep, xrandr_dep, xext_dep] - extension = '.c' -endif - -# Build core library - -core_deps += [m_dep] -core_sources += platform_sources -core_name = 'pugl_@0@@1@'.format(platform, version_suffix) - -library_args = ['-DPUGL_INTERNAL'] -if get_option('default_library') == 'both' - if host_machine.system() == 'windows' - error('default_library=both is not supported on Windows') - endif - - library_type = 'both_libraries' -elif get_option('default_library') == 'shared' - library_type = 'shared_library' -else - library_type = 'static_library' - add_project_arguments(['-DPUGL_STATIC'], language: ['c', 'cpp', 'objc']) -endif - -libpugl = build_target( - core_name, core_sources, - version: meson.project_version(), - include_directories: include_directories(['include']), - c_args: library_args + core_args, - dependencies: core_deps, - gnu_symbol_visibility: 'hidden', - install: true, - target_type: library_type) - -pugl_dep = declare_dependency(link_with: libpugl, dependencies: core_deps) - -pkg.generate(libpugl, - name: 'Pugl', - filebase: versioned_name, - subdirs: [versioned_name], - version: meson.project_version(), - description: 'Pugl GUI library core') - -# Build stub backend - -name = 'pugl_' + platform + '_stub' + version_suffix -sources = 'src/' + platform + '_stub' + extension - -stub_backend = build_target( - name, sources, - version: meson.project_version(), - include_directories: include_directories(['include']), - c_args: library_args, - dependencies: [pugl_dep], - gnu_symbol_visibility: 'hidden', - install: true, - target_type: library_type) - -stub_backend_dep = declare_dependency(link_with: stub_backend) - -pkg.generate(stub_backend, - name: 'Pugl Stub', - filebase: 'pugl-stub-@0@'.format(major_version), - subdirs: [name], - version: meson.project_version(), - description: 'Native window pugl graphics backend') - -# Build GL backend -if opengl_dep.found() - name = 'pugl_' + platform + '_gl' + version_suffix - sources = 'src/' + platform + '_gl' + extension - - gl_backend = build_target( - name, sources, - version: meson.project_version(), - include_directories: include_directories(['include']), - c_args: library_args, - dependencies: [pugl_dep, opengl_dep], - gnu_symbol_visibility: 'hidden', - install: true, - target_type: library_type) - - gl_backend_dep = declare_dependency(link_with: gl_backend, - dependencies: [pugl_dep, opengl_dep]) - - pkg.generate(gl_backend, - name: 'Pugl OpenGL', - filebase: 'pugl-gl-@0@'.format(major_version), - subdirs: [name], - version: meson.project_version(), - description: 'Pugl GUI library with OpenGL backend') -endif - -# Build Cairo backend -if cairo_dep.found() - name = 'pugl_' + platform + '_cairo' + version_suffix - sources = ['src/' + platform + '_cairo' + extension, - 'src/' + platform + '_stub' + extension] - - cairo_backend = build_target( - name, sources, - version: meson.project_version(), - include_directories: include_directories(['include']), - c_args: library_args, - dependencies: [pugl_dep, cairo_dep, stub_backend_dep], - gnu_symbol_visibility: 'hidden', - install: true, - target_type: library_type) - - cairo_backend_dep = declare_dependency( - link_with: cairo_backend, - dependencies: [pugl_dep, cairo_dep, stub_backend_dep]) - - pkg.generate(cairo_backend, - name: 'Pugl Cairo', - filebase: 'pugl-cairo-@0@'.format(major_version), - subdirs: [name], - version: meson.project_version(), - description: 'Pugl GUI library with Cairo backend') -endif - -# Build Vulkan backend -if vulkan_dep.found() - name = 'pugl_' + platform + '_vulkan' + version_suffix - sources = ['src/' + platform + '_vulkan' + extension, - 'src/' + platform + '_stub' + extension] - - vulkan_deps = [pugl_dep, vulkan_dep, dl_dep] - vulkan_c_args = library_args - vulkan_link_args = [] - if platform == 'mac' - metal_dep = dependency('Metal', modules: 'foundation') - quartzcore_dep = dependency('QuartzCore', modules: 'foundation') - - vulkan_deps += [metal_dep, quartzcore_dep] - endif - - vulkan_backend = build_target( - name, sources, - version: meson.project_version(), - include_directories: include_directories(['include']), - c_args: library_args, - dependencies: vulkan_deps, - gnu_symbol_visibility: 'hidden', - install: true, - target_type: library_type) - - vulkan_backend_dep = declare_dependency( - link_with: vulkan_backend, - dependencies: [pugl_dep, vulkan_dep, thread_dep]) - - pkg.generate(vulkan_backend, - name: 'Pugl Vulkan', - filebase: 'pugl-vulkan-@0@'.format(major_version), - subdirs: [name], - version: meson.project_version(), - description: 'Pugl GUI library with Vulkan backend') -endif - -install_headers(c_headers, subdir: versioned_name / 'pugl') -install_headers(cpp_headers, subdir: 'puglxx' + version_suffix) - -if not get_option('docs').disabled() - subdir('doc') -else - build_docs = false -endif - -if get_option('examples') - subdir('examples') -endif - -if get_option('tests') - subdir('test') -endif - -if meson.version().version_compare('>=0.53.0') - summary('Platform', platform) - summary('Cairo backend', cairo_dep.found(), bool_yn: true) - summary('OpenGL backend', opengl_dep.found(), bool_yn: true) - summary('Vulkan backend', vulkan_dep.found(), bool_yn: true) - summary('Tests', get_option('tests'), bool_yn: true) - summary('Examples', get_option('examples'), bool_yn: true) - summary('Documentation', build_docs, bool_yn: true) - - summary('Install prefix', get_option('prefix')) - summary('Headers', get_option('prefix') / get_option('includedir')) - summary('Libraries', get_option('prefix') / get_option('libdir')) - - if get_option('examples') - summary('Executables', get_option('prefix') / get_option('bindir')) - endif -endif diff --git a/subprojects/nk_pugl/pugl/meson/meson.build b/subprojects/nk_pugl/pugl/meson/meson.build deleted file mode 100644 index 20e0522..0000000 --- a/subprojects/nk_pugl/pugl/meson/meson.build +++ /dev/null @@ -1,196 +0,0 @@ -# General code to enable approximately all warnings. -# -# This is trivial for clang and MSVC, but GCC does not have such an option, and -# has several esoteric warnings, so we need to enable everything we want -# explicitly. We enable everything that does not require a value argument, -# except for warnings that are only relevant for very old languages (earlier -# than C99 or C++11) or non-standard extensions. -# -# Omitted common warnings: -# -# Wabi= -# Waggregate-return -# Walloc-size-larger-than=BYTES -# Walloca-larger-than=BYTES -# Wframe-larger-than=BYTES -# Wlarger-than=BYTES -# Wstack-usage=BYTES -# Wsystem-headers -# Wtraditional -# Wtraditional-conversion -# Wtrampolines -# Wvla-larger-than=BYTES -# -# Omitted C warnings: -# -# Wc90-c99-compat -# Wdeclaration-after-statement -# Wtraditional -# Wtraditional-conversion -# -# Omitted C++ warnings: -# -# Wnamespaces -# Wtemplates - -gcc_common_warnings = [ - '-Walloc-zero', - '-Walloca', - '-Wanalyzer-too-complex', - '-Warith-conversion', - '-Warray-bounds=2', - '-Wattribute-alias=2', - '-Wcast-align=strict', - '-Wcast-qual', - '-Wconversion', - '-Wdate-time', - '-Wdisabled-optimization', - '-Wdouble-promotion', - '-Wduplicated-branches', - '-Wduplicated-cond', - '-Wfloat-equal', - '-Wformat-overflow=2', - '-Wformat-signedness', - '-Wformat-truncation=2', - '-Wformat=2', - '-Wimplicit-fallthrough=2', - '-Winit-self', - '-Winline', - '-Winvalid-pch', - '-Wlogical-op', - '-Wmissing-declarations', - '-Wmissing-include-dirs', - '-Wmultichar', - '-Wnormalized=nfc', - '-Wnull-dereference', - '-Wpacked', - '-Wpadded', - '-Wredundant-decls', - '-Wscalar-storage-order', - '-Wshadow', - '-Wshift-overflow=2', - '-Wsizeof-array-argument', - '-Wstack-protector', - '-Wstrict-aliasing=3', - '-Wstrict-overflow=5', - '-Wstringop-overflow=3', - '-Wsuggest-attribute=cold', - '-Wsuggest-attribute=const', - '-Wsuggest-attribute=format', - '-Wsuggest-attribute=malloc', - '-Wsuggest-attribute=noreturn', - '-Wsuggest-attribute=pure', - '-Wswitch-default', - '-Wswitch-enum', - '-Wsync-nand', - '-Wundef', - '-Wunused-const-variable=2', - '-Wunused-macros', - '-Wvarargs', - '-Wvector-operation-performance', - '-Wvla', - '-Wwrite-strings', -] - -gcc_c_warnings = [ - '-Wbad-function-cast', - '-Wc++-compat', - '-Wc99-c11-compat', - '-Wdesignated-init', - '-Wdiscarded-array-qualifiers', - '-Wdiscarded-qualifiers', - '-Wincompatible-pointer-types', - '-Wjump-misses-init', - '-Wmissing-prototypes', - '-Wnested-externs', - '-Wold-style-definition', - '-Wstrict-prototypes', - '-Wunsuffixed-float-constants', -] - -# Set all_c_warnings for the current C compiler -if is_variable('cc') - if cc.get_id() == 'clang' - all_c_warnings = ['-Weverything'] - elif cc.get_id() == 'gcc' - all_c_warnings = gcc_common_warnings + [ - '-Wbad-function-cast', - '-Wc++-compat', - '-Wc99-c11-compat', - '-Wdesignated-init', - '-Wdiscarded-array-qualifiers', - '-Wdiscarded-qualifiers', - '-Wincompatible-pointer-types', - '-Wjump-misses-init', - '-Wmissing-prototypes', - '-Wnested-externs', - '-Wold-style-definition', - '-Wstrict-prototypes', - '-Wunsuffixed-float-constants', - ] - elif cc.get_id() == 'msvc' - all_c_warnings = ['/Wall'] - else - all_c_warnings = [] - endif -endif - -# Set all_cpp_warnings for the current C++ compiler -if is_variable('cpp') - if cpp.get_id() == 'clang' - all_cpp_warnings = [ - '-Weverything', - '-Wno-c++98-compat', - '-Wno-c++98-compat-pedantic' - ] - elif cpp.get_id() == 'gcc' - all_cpp_warnings = gcc_common_warnings + [ - '-Wabi-tag', - '-Waligned-new=all', - '-Wcatch-value=3', - '-Wcomma-subscript', - '-Wconditionally-supported', - '-Wctor-dtor-privacy', - '-Wdeprecated-copy-dtor', - '-Weffc++', - '-Wextra-semi', - '-Wmismatched-tags', - '-Wmultiple-inheritance', - '-Wnoexcept', - '-Wnoexcept-type', - '-Wnon-virtual-dtor', - '-Wold-style-cast', - '-Woverloaded-virtual', - '-Wplacement-new=2', - '-Wredundant-tags', - '-Wregister', - '-Wsign-promo', - '-Wstrict-null-sentinel', - '-Wsuggest-final-methods', - '-Wsuggest-final-types', - '-Wsuggest-override', - '-Wuseless-cast', - '-Wvirtual-inheritance', - '-Wvolatile', - '-Wzero-as-null-pointer-constant', - ] - elif cpp.get_id() == 'msvc' - all_cpp_warnings = ['/Wall'] - else - all_cpp_warnings = [] - endif -endif - -# Set all_objc_warnings for the current Objective C compiler -if is_variable('objcc') - all_objc_warnings = [] - if objcc.get_id() == 'clang' - all_objc_warnings = ['-Weverything'] - elif objc.get_id() == 'gcc' - all_objc_warnings = gcc_common_warnings + [ - '-Wno-direct-ivar-access', - ] - else - all_objc_warnings = [] - endif -endif diff --git a/subprojects/nk_pugl/pugl/meson_options.txt b/subprojects/nk_pugl/pugl/meson_options.txt deleted file mode 100644 index dd6ea8c..0000000 --- a/subprojects/nk_pugl/pugl/meson_options.txt +++ /dev/null @@ -1,20 +0,0 @@ -option('cairo', type: 'feature', value: 'auto', - description : 'Enable support for the Cairo graphics API') - -option('examples', type: 'boolean', value: true, - description: 'Build example programs') - -option('docs', type: 'feature', value: 'auto', - description: 'Build documentation') - -option('opengl', type: 'feature', value: 'auto', - description : 'Enable support for the OpenGL graphics API') - -option('strict', type: 'boolean', value: false, - description: 'Enable ultra-strict warnings') - -option('tests', type: 'boolean', value: true, - description: 'Build tests') - -option('vulkan', type: 'feature', value: 'auto', - description : 'Enable support for the Vulkan graphics API') diff --git a/subprojects/nk_pugl/pugl/pugl.pc.in b/subprojects/nk_pugl/pugl/pugl.pc.in deleted file mode 100644 index 2cfa644..0000000 --- a/subprojects/nk_pugl/pugl/pugl.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@PREFIX@ -exec_prefix=@EXEC_PREFIX@ -libdir=@LIBDIR@ -includedir=@INCLUDEDIR@ - -Name: @NAME@ -Description: @DESCRIPTION@ -Version: @PUGL_VERSION@ -Requires: @REQUIRES@ -Libs: -L${libdir} @LIBS@ -Cflags: @CFLAGS@ diff --git a/subprojects/nk_pugl/pugl/resources/Info.plist.in b/subprojects/nk_pugl/pugl/resources/Info.plist.in deleted file mode 100644 index a08dbd0..0000000 --- a/subprojects/nk_pugl/pugl/resources/Info.plist.in +++ /dev/null @@ -1,20 +0,0 @@ - - - - - CFBundleIdentifier - net.drobilla.pugl.@NAME@ - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1.0 - MinimumOSVersion - 10.6 - CFBundleDisplayName - @NAME@ - CFBundleName - @NAME@ - NSHighResolutionCapable - - - diff --git a/subprojects/nk_pugl/pugl/resources/pugl.ipe b/subprojects/nk_pugl/pugl/resources/pugl.ipe deleted file mode 100644 index 238c09c..0000000 --- a/subprojects/nk_pugl/pugl/resources/pugl.ipe +++ /dev/null @@ -1,293 +0,0 @@ - - - - - - - -0 0 m --1 0.333 l --1 -0.333 l -h - - - - -0 0 m --1 0.333 l --1 -0.333 l -h - - - - -0 0 m --1 0.333 l --0.8 0 l --1 -0.333 l -h - - - - -0 0 m --1 0.333 l --0.8 0 l --1 -0.333 l -h - - - - -0.6 0 0 0.6 0 0 e -0.4 0 0 0.4 0 0 e - - - - -0.6 0 0 0.6 0 0 e - - - - - -0.5 0 0 0.5 0 0 e - - -0.6 0 0 0.6 0 0 e -0.4 0 0 0.4 0 0 e - - - - - --0.6 -0.6 m -0.6 -0.6 l -0.6 0.6 l --0.6 0.6 l -h --0.4 -0.4 m -0.4 -0.4 l -0.4 0.4 l --0.4 0.4 l -h - - - - --0.6 -0.6 m -0.6 -0.6 l -0.6 0.6 l --0.6 0.6 l -h - - - - - --0.5 -0.5 m -0.5 -0.5 l -0.5 0.5 l --0.5 0.5 l -h - - --0.6 -0.6 m -0.6 -0.6 l -0.6 0.6 l --0.6 0.6 l -h --0.4 -0.4 m -0.4 -0.4 l -0.4 0.4 l --0.4 0.4 l -h - - - - - - --0.43 -0.57 m -0.57 0.43 l -0.43 0.57 l --0.57 -0.43 l -h - - --0.43 0.57 m -0.57 -0.43 l -0.43 -0.57 l --0.57 0.43 l -h - - - - - -0 0 m --1 0.333 l --1 -0.333 l -h - - - - -0 0 m --1 0.333 l --0.8 0 l --1 -0.333 l -h - - - - -0 0 m --1 0.333 l --0.8 0 l --1 -0.333 l -h - - - - --1 0.333 m -0 0 l --1 -0.333 l - - - - -0 0 m --1 0.333 l --1 -0.333 l -h --1 0 m --2 0.333 l --2 -0.333 l -h - - - - -0 0 m --1 0.333 l --1 -0.333 l -h --1 0 m --2 0.333 l --2 -0.333 l -h - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -128 704 m -128 640 l -448 640 l -448 704 l -h - - -128 704 m -128 384 l -448 384 l -448 704 l -h - - -176 592 m -176 432 l -400 432 l -400 592 l -h - - -176 592 m -176 560 l -400 560 l -400 592 l -h - - -416 544 m -416 544 l -416 544 l -416 544 l -h - - - diff --git a/subprojects/nk_pugl/pugl/resources/pugl.png b/subprojects/nk_pugl/pugl/resources/pugl.png deleted file mode 100644 index 46416600a6ab5de6fc78e154cd3c9c7f58adbdd4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2641 zcmd^=e@s(X6vt0nYdb}R0Sed(3mb|8Zq^m0M9VLWb*We+9n=Z-#TJx;4r3V#ebFUO zfwD~JL{ceOYfi-YTK5C-1hFC8rX_SZm>pec z%i;K54dlnW<~^%0c~eh5+~8MV;WubHTHkg*V1HeEz(wjdVD@G*@L&gkV)5qzxMLq2 z02zRZSy*l}Tz`41RQ^^IiXzh7zTZH%>v~aU*cqhcZFKg*Lh5im_Gv$w?KpiH(m9!thJ&t;U zNWuB4p=az$Eu1yE0MoQiu!rZP`v&NN-*Y=eGCHA2Bb7)G%wg>$aay^)Edu5LaSJUGHeKtRMOp-MdigY~ zmj1b8!px2~w#yD=*5unEyRk%|tx5loRze!_)Ml{)9PqJ>KU`FlWjFLlQq3+|MXXS` zm@eIhNdR55Mq<%<)kQUt$ASe|XdsLpcUaCnSEpAsK3D_(#lz;k{-vwwPKTQ{n&oXfDm}hG)jLX5 z)B8o;>~21db~ujrgnHuj8}pL4S8mbEf767|&f8lCFmqmLkKg!c}hYzJ68N!fO}jpVS2A~ftVpLfXsW@%Hmub zG_ZTDm6}I{%n*~lGFPjs#w&h)_wedNcSU&M8xqr#dF*jTxp_IdP`MQ0rP1N14=(G= z27;*4Pvuhk@JNpcWln3S(x}{|(P$F7KC4eMe3Fjv45?R)=3MX-Y*h{lMiAAcvj=l> n(~$^10ibJQ9?kVGhIhpn&cwv~1Z9k1J%cTwoRG^wu}A*_5pqBs diff --git a/subprojects/nk_pugl/pugl/resources/pugl.svg b/subprojects/nk_pugl/pugl/resources/pugl.svg deleted file mode 100644 index 93189f4..0000000 --- a/subprojects/nk_pugl/pugl/resources/pugl.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/subprojects/nk_pugl/pugl/scripts/cat.py b/subprojects/nk_pugl/pugl/scripts/cat.py deleted file mode 100755 index 5f628b6..0000000 --- a/subprojects/nk_pugl/pugl/scripts/cat.py +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env python - -import sys - -for filename in sys.argv[1:]: - with open(filename, 'r') as f: - sys.stdout.write(f.read()) diff --git a/subprojects/nk_pugl/pugl/scripts/dox_to_sphinx.py b/subprojects/nk_pugl/pugl/scripts/dox_to_sphinx.py deleted file mode 100755 index c3f7c44..0000000 --- a/subprojects/nk_pugl/pugl/scripts/dox_to_sphinx.py +++ /dev/null @@ -1,653 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright 2020 David Robillard -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -""" -Write Sphinx markup from Doxygen XML. - -Takes a path to a directory of XML generated by Doxygen, and emits a directory -with a reStructuredText file for every documented symbol. -""" - -import argparse -import os -import sys -import textwrap -import xml.etree.ElementTree - -__author__ = "David Robillard" -__date__ = "2020-11-18" -__email__ = "d@drobilla.net" -__license__ = "ISC" -__version__ = __date__.replace("-", ".") - - -def load_index(index_path): - """ - Load the index from XML. - - :returns: A dictionary from ID to skeleton records with basic information - for every documented entity. Some records have an ``xml_filename`` key - with the filename of a definition file. These files will be loaded later - to flesh out the records in the index. - """ - - root = xml.etree.ElementTree.parse(index_path).getroot() - index = {} - - for compound in root: - compound_id = compound.get("refid") - compound_kind = compound.get("kind") - compound_name = compound.find("name").text - if compound_kind in ["dir", "file", "page"]: - continue - - # Add record for compound (compounds appear only once in the index) - assert compound_id not in index - index[compound_id] = { - "kind": compound_kind, - "name": compound_name, - "xml_filename": compound_id + ".xml", - "children": [], - } - - name_prefix = ( - ("%s::" % compound_name) if compound_kind == "namespace" else "" - ) - - for child in compound.findall("member"): - if child.get("refid") in index: - assert compound_kind == "group" - continue - - # Everything has a kind and a name - child_record = { - "kind": child.get("kind"), - "name": name_prefix + child.find("name").text, - } - - if child.get("kind") == "enum": - # Enums are not compounds, but we want to resolve the parent of - # their values so they are not written as top level documents - child_record["children"] = [] - - if child.get("kind") == "enumvalue": - # Remove namespace prefix - child_record["name"] = child.find("name").text - - index[child.get("refid")] = child_record - - return index - - -def resolve_index(index, root): - """ - Walk a definition document and extend the index for linking. - - This does two things: sets the "parent" and "children" fields of all - applicable records, and sets the "strong" field of enums so that the - correct Sphinx role can be used when referring to them. - """ - - def add_child(index, parent_id, child_id): - parent = index[parent_id] - child = index[child_id] - - if child["kind"] == "enumvalue": - assert parent["kind"] == "enum" - assert "parent" not in child or child["parent"] == parent_id - child["parent"] = parent_id - - else: - if parent["kind"] in ["class", "struct", "union"]: - assert "parent" not in child or child["parent"] == parent_id - child["parent"] = parent_id - - if child_id not in parent["children"]: - parent["children"] += [child_id] - - compound = root.find("compounddef") - compound_kind = compound.get("kind") - - if compound_kind == "group": - for subgroup in compound.findall("innergroup"): - add_child(index, compound.get("id"), subgroup.get("refid")) - - for klass in compound.findall("innerclass"): - add_child(index, compound.get("id"), klass.get("refid")) - - for section in compound.findall("sectiondef"): - if section.get("kind").startswith("private"): - for member in section.findall("memberdef"): - if member.get("id") in index: - del index[member.get("id")] - else: - for member in section.findall("memberdef"): - member_id = member.get("id") - add_child(index, compound.get("id"), member_id) - - if member.get("kind") == "enum": - index[member_id]["strong"] = member.get("strong") == "yes" - for value in member.findall("enumvalue"): - add_child(index, member_id, value.get("id")) - - -def sphinx_role(record, lang): - """ - Return the Sphinx role used for a record. - - This is used for the description directive like ".. c:function::", and - links like ":c:func:`foo`. - """ - - kind = record["kind"] - - if kind in ["class", "function", "namespace", "struct", "union"]: - return lang + ":" + kind - - if kind == "define": - return "c:macro" - - if kind == "enum": - return lang + (":enum-class" if record["strong"] else ":enum") - - if kind == "typedef": - return lang + ":type" - - if kind == "enumvalue": - return lang + ":enumerator" - - if kind == "variable": - return lang + (":member" if "parent" in record else ":var") - - raise RuntimeError("No known role for kind '%s'" % kind) - - -def child_identifier(lang, parent_name, child_name): - """ - Return the identifier for an enum value or struct member. - - Sphinx, for some reason, uses a different syntax for this in C and C++. - """ - - separator = "::" if lang == "cpp" else "." - - return "%s%s%s" % (parent_name, separator, child_name) - - -def link_markup(index, lang, refid): - """Return a Sphinx link for a Doxygen reference.""" - - record = index[refid] - kind, name = record["kind"], record["name"] - role = sphinx_role(record, lang) - - if kind in ["class", "enum", "struct", "typedef", "union"]: - return ":%s:`%s`" % (role, name) - - if kind == "function": - return ":%s:func:`%s`" % (lang, name) - - if kind == "enumvalue": - parent_name = index[record["parent"]]["name"] - return ":%s:`%s`" % (role, child_identifier(lang, parent_name, name)) - - if kind == "variable": - if "parent" not in record: - return ":%s:var:`%s`" % (lang, name) - - parent_name = index[record["parent"]]["name"] - return ":%s:`%s`" % (role, child_identifier(lang, parent_name, name)) - - raise RuntimeError("Unknown link target kind: %s" % kind) - - -def indent(markup, depth): - """ - Indent markup to a depth level. - - Like textwrap.indent() but takes an integer and works in reST indentation - levels for clarity." - """ - - return textwrap.indent(markup, " " * depth) - - -def heading(text, level): - """ - Return a ReST heading at a given level. - - Follows the style in the Python documentation guide, see - . - """ - - assert 1 <= level <= 6 - - chars = ("#", "*", "=", "-", "^", '"') - line = chars[level] * len(text) - - return "%s%s\n%s\n\n" % (line + "\n" if level < 3 else "", text, line) - - -def dox_to_rst(index, lang, node): - """ - Convert documentation commands (docCmdGroup) to Sphinx markup. - - This is used to convert the content of descriptions in the documentation. - It recursively parses all children tags and raises a RuntimeError if any - unknown tag is encountered. - """ - - def field_value(markup): - """Return a value for a field as a single line or indented block.""" - if "\n" in markup.strip(): - return "\n" + indent(markup, 1) - - return " " + markup.strip() - - if node.tag == "lsquo": - return "‘" - - if node.tag == "rsquo": - return "’" - - if node.tag == "computeroutput": - assert len(node) == 0 - return "``%s``" % node.text - - if node.tag == "itemizedlist": - markup = "" - for item in node.findall("listitem"): - assert len(item) == 1 - markup += "\n- %s" % dox_to_rst(index, lang, item[0]) - - return markup - - if node.tag == "para": - markup = node.text if node.text is not None else "" - for child in node: - markup += dox_to_rst(index, lang, child) - markup += child.tail if child.tail is not None else "" - - return markup.strip() + "\n\n" - - if node.tag == "parameterlist": - markup = "" - for item in node.findall("parameteritem"): - name = item.find("parameternamelist/parametername") - description = item.find("parameterdescription") - assert len(description) == 1 - markup += "\n\n:param %s:%s" % ( - name.text, - field_value(dox_to_rst(index, lang, description[0])), - ) - - return markup + "\n" - - if node.tag == "programlisting": - return "\n.. code-block:: %s\n\n%s" % ( - lang, - indent(plain_text(node), 1), - ) - - if node.tag == "ref": - refid = node.get("refid") - if refid not in index: - sys.stderr.write("warning: Unresolved link: %s\n" % refid) - return node.text - - assert len(node) == 0 - assert len(link_markup(index, lang, refid)) > 0 - return link_markup(index, lang, refid) - - if node.tag == "simplesect": - assert len(node) == 1 - - if node.get("kind") == "return": - return "\n:returns:" + field_value( - dox_to_rst(index, lang, node[0]) - ) - - if node.get("kind") == "see": - return dox_to_rst(index, lang, node[0]) - - raise RuntimeError("Unknown simplesect kind: %s" % node.get("kind")) - - if node.tag == "ulink": - return "`%s <%s>`_" % (node.text, node.get("url")) - - raise RuntimeError("Unknown documentation command: %s" % node.tag) - - -def description_markup(index, lang, node): - """Return the markup for a brief or detailed description.""" - - assert node.tag == "briefdescription" or node.tag == "detaileddescription" - assert not (node.tag == "briefdescription" and len(node) > 1) - assert len(node.text.strip()) == 0 - - return "".join([dox_to_rst(index, lang, child) for child in node]).strip() - - -def set_descriptions(index, lang, definition, record): - """Set a record's brief/detailed descriptions from the XML definition.""" - - for tag in ["briefdescription", "detaileddescription"]: - node = definition.find(tag) - if node is not None: - record[tag] = description_markup(index, lang, node) - - -def set_template_params(node, record): - """Set a record's template_params from the XML definition.""" - - template_param_list = node.find("templateparamlist") - if template_param_list is not None: - params = [] - for param in template_param_list.findall("param"): - if param.find("declname") is not None: - # Value parameter - type_text = plain_text(param.find("type")) - name_text = plain_text(param.find("declname")) - - params += ["%s %s" % (type_text, name_text)] - else: - # Type parameter - params += ["%s" % (plain_text(param.find("type")))] - - record["template_params"] = "%s" % ", ".join(params) - - -def plain_text(node): - """ - Return the plain text of a node with all tags ignored. - - This is needed where Doxygen may include refs but Sphinx needs plain text - because it parses things itself to generate links. - """ - - if node.tag == "sp": - markup = " " - elif node.text is not None: - markup = node.text - else: - markup = "" - - for child in node: - markup += plain_text(child) - markup += child.tail if child.tail is not None else "" - - return markup - - -def local_name(name): - """Return a name with all namespace prefixes stripped.""" - - return name[name.rindex("::") + 2 :] if "::" in name else name - - -def read_definition_doc(index, lang, root): - """Walk a definition document and update described records in the index.""" - - # Set descriptions for the compound itself - compound = root.find("compounddef") - compound_record = index[compound.get("id")] - set_descriptions(index, lang, compound, compound_record) - set_template_params(compound, compound_record) - - if compound.find("title") is not None: - compound_record["title"] = compound.find("title").text.strip() - - # Set documentation for all children - for section in compound.findall("sectiondef"): - if section.get("kind").startswith("private"): - continue - - for member in section.findall("memberdef"): - kind = member.get("kind") - record = index[member.get("id")] - set_descriptions(index, lang, member, record) - set_template_params(member, record) - - if compound.get("kind") in ["class", "struct", "union"]: - assert kind in ["function", "typedef", "variable"] - record["type"] = plain_text(member.find("type")) - - if kind == "enum": - for value in member.findall("enumvalue"): - set_descriptions( - index, lang, value, index[value.get("id")] - ) - - elif kind == "function": - record["prototype"] = "%s %s%s" % ( - plain_text(member.find("type")), - member.find("name").text, - member.find("argsstring").text, - ) - - elif kind == "typedef": - name = local_name(record["name"]) - args_text = member.find("argsstring").text - target_text = plain_text(member.find("type")) - if args_text is not None: # Function pointer - assert target_text[-2:] == "(*" and args_text[0] == ")" - record["type"] = target_text + args_text - record["definition"] = target_text + name + args_text - else: # Normal named typedef - assert target_text is not None - record["type"] = target_text - if member.find("definition").text.startswith("using"): - record["definition"] = "%s = %s" % ( - name, - target_text, - ) - else: - record["definition"] = "%s %s" % ( - target_text, - name, - ) - - elif kind == "variable": - record["definition"] = member.find("definition").text - - -def declaration_string(record): - """ - Return the string that describes a declaration. - - This is what follows the directive, and is in C/C++ syntax, except without - keywords like "typedef" and "using" as expected by Sphinx. For example, - "struct ThingImpl Thing" or "void run(int value)". - """ - - kind = record["kind"] - result = "" - - if "template_params" in record: - result = "template <%s> " % record["template_params"] - - if kind == "function": - result += record["prototype"] - elif kind == "typedef": - result += record["definition"] - elif kind == "variable": - if "parent" in record: - result += "%s %s" % (record["type"], local_name(record["name"])) - else: - result += record["definition"] - elif "type" in record: - result += "%s %s" % (record["type"], local_name(record["name"])) - else: - result += local_name(record["name"]) - - return result - - -def document_markup(index, lang, record): - """Return the complete document that describes some documented entity.""" - - kind = record["kind"] - role = sphinx_role(record, lang) - name = record["name"] - markup = "" - - if name != local_name(name): - markup += ".. cpp:namespace:: %s\n\n" % name[0 : name.rindex("::")] - - # Write top-level directive - markup += ".. %s:: %s\n" % (role, declaration_string(record)) - - # Write main description blurb - markup += "\n" + indent(record["briefdescription"] + "\n", 1) - if len(record["detaileddescription"]) > 0: - markup += "\n" + indent(record["detaileddescription"], 1) + "\n" - - assert ( - kind in ["class", "enum", "namespace", "struct", "union"] - or "children" not in record - ) - - # Sphinx C++ namespaces work by setting a scope, they have no content - child_indent = 0 if kind == "namespace" else 1 - - # Write inline children if applicable - markup += "\n" if "children" in record else "" - for child_id in record.get("children", []): - child_record = index[child_id] - child_role = sphinx_role(child_record, lang) - - child_header = ".. %s:: %s\n\n" % ( - child_role, - declaration_string(child_record), - ) - - markup += "\n" - markup += indent(child_header, child_indent) - markup += indent(child_record["briefdescription"], child_indent + 1) - markup += indent(child_record["detaileddescription"], child_indent + 1) - - return markup - - -def symbol_filename(name): - """Adapt the name of a symbol to be suitable for use as a filename.""" - - return name.replace("::", "__") - - -def emit_groups(index, lang, output_dir, force): - """Write a description file for every group documented in the index.""" - - for record in index.values(): - if record["kind"] != "group": - continue - - name = record["name"] - filename = os.path.join(output_dir, "%s.rst" % name) - if not force and os.path.exists(filename): - raise FileExistsError("File already exists: '%s'" % filename) - - with open(filename, "w") as rst: - rst.write(heading(record["title"], 1)) - - # Get all child group and symbol names - child_groups = {} - child_symbols = {} - for child_id in record["children"]: - child = index[child_id] - if child["kind"] == "group": - child_groups[child["name"]] = child - else: - child_symbols[child["name"]] = child - - # Emit description (document body) - if len(record["briefdescription"]) > 0: - rst.write(record["briefdescription"] + "\n\n") - if len(record["detaileddescription"]) > 0: - rst.write(record["detaileddescription"] + "\n\n") - - if len(child_groups) > 0: - # Emit TOC for child groups - rst.write(".. toctree::\n\n") - for name, group in child_groups.items(): - rst.write(indent(group["name"], 1) + "\n") - - # Emit symbols in sorted order - for name, symbol in child_symbols.items(): - rst.write("\n") - rst.write(document_markup(index, lang, symbol)) - rst.write("\n") - - -def run(index_xml_path, output_dir, language, force): - """Write a directory of Sphinx files from a Doxygen XML directory.""" - - # Build skeleton index from index.xml - xml_dir = os.path.dirname(index_xml_path) - index = load_index(index_xml_path) - - # Load all definition documents - definition_docs = [] - for record in index.values(): - if "xml_filename" in record: - xml_path = os.path.join(xml_dir, record["xml_filename"]) - definition_docs += [xml.etree.ElementTree.parse(xml_path)] - - # Do an initial pass of the definition documents to resolve the index - for root in definition_docs: - resolve_index(index, root) - - # Finally read the documentation from definition documents - for root in definition_docs: - read_definition_doc(index, language, root) - - # Create output directory - try: - os.makedirs(output_dir) - except OSError: - pass - - # Emit output files - emit_groups(index, language, output_dir, force) - - -if __name__ == "__main__": - ap = argparse.ArgumentParser( - usage="%(prog)s [OPTION]... XML_DIR OUTPUT_DIR", - description=__doc__, - formatter_class=argparse.RawDescriptionHelpFormatter, - ) - - ap.add_argument( - "-f", - "--force", - action="store_true", - help="overwrite files", - ) - - ap.add_argument( - "-l", - "--language", - default="c", - choices=["c", "cpp"], - help="language domain for output", - ) - - ap.add_argument("index_xml_path", help="path index.xml from Doxygen") - ap.add_argument("output_dir", help="output directory") - - print(sys.argv) - run(**vars(ap.parse_args(sys.argv[1:]))) diff --git a/subprojects/nk_pugl/pugl/src/.clang-tidy b/subprojects/nk_pugl/pugl/src/.clang-tidy deleted file mode 100644 index 11b620e..0000000 --- a/subprojects/nk_pugl/pugl/src/.clang-tidy +++ /dev/null @@ -1,17 +0,0 @@ -Checks: > - *, - -*-uppercase-literal-suffix, - -*magic-numbers, - -bugprone-reserved-identifier, - -bugprone-suspicious-string-compare, - -cert-dcl37-c, - -cert-dcl51-cpp, - -cert-flp30-c, - -clang-analyzer-security.FloatLoopCounter, - -clang-diagnostic-unused-macros, - -hicpp-multiway-paths-covered, - -hicpp-signed-bitwise, - -llvm-header-guard, - -llvmlibc-*, -FormatStyle: file -HeaderFilterRegex: 'pugl/.*' diff --git a/subprojects/nk_pugl/pugl/src/implementation.c b/subprojects/nk_pugl/pugl/src/implementation.c deleted file mode 100644 index 47b52b8..0000000 --- a/subprojects/nk_pugl/pugl/src/implementation.c +++ /dev/null @@ -1,456 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "implementation.h" - -#include "pugl/pugl.h" - -#include -#include -#include -#include - -const char* -puglStrerror(const PuglStatus status) -{ - // clang-format off - switch (status) { - case PUGL_SUCCESS: return "Success"; - case PUGL_FAILURE: return "Non-fatal failure"; - case PUGL_UNKNOWN_ERROR: return "Unknown system error"; - case PUGL_BAD_BACKEND: return "Invalid or missing backend"; - case PUGL_BAD_CONFIGURATION: return "Invalid view configuration"; - case PUGL_BAD_PARAMETER: return "Invalid parameter"; - case PUGL_BACKEND_FAILED: return "Backend initialisation failed"; - case PUGL_REGISTRATION_FAILED: return "Class registration failed"; - case PUGL_REALIZE_FAILED: return "View creation failed"; - case PUGL_SET_FORMAT_FAILED: return "Failed to set pixel format"; - case PUGL_CREATE_CONTEXT_FAILED: return "Failed to create drawing context"; - case PUGL_UNSUPPORTED_TYPE: return "Unsupported data type"; - } - // clang-format on - - return "Unknown error"; -} - -void -puglSetString(char** dest, const char* string) -{ - if (*dest != string) { - const size_t len = strlen(string); - - *dest = (char*)realloc(*dest, len + 1); - strncpy(*dest, string, len + 1); - } -} - -void -puglSetBlob(PuglBlob* const dest, const void* const data, const size_t len) -{ - if (data) { - dest->len = len; - dest->data = realloc(dest->data, len + 1); - memcpy(dest->data, data, len); - ((char*)dest->data)[len] = 0; - } else { - dest->len = 0; - dest->data = NULL; - } -} - -static void -puglSetDefaultHints(PuglHints hints) -{ - hints[PUGL_USE_COMPAT_PROFILE] = PUGL_TRUE; - hints[PUGL_CONTEXT_VERSION_MAJOR] = 2; - hints[PUGL_CONTEXT_VERSION_MINOR] = 0; - hints[PUGL_RED_BITS] = 8; - hints[PUGL_GREEN_BITS] = 8; - hints[PUGL_BLUE_BITS] = 8; - hints[PUGL_ALPHA_BITS] = 8; - hints[PUGL_DEPTH_BITS] = 0; - hints[PUGL_STENCIL_BITS] = 0; - hints[PUGL_SAMPLES] = 0; - hints[PUGL_DOUBLE_BUFFER] = PUGL_TRUE; - hints[PUGL_SWAP_INTERVAL] = PUGL_DONT_CARE; - hints[PUGL_RESIZABLE] = PUGL_FALSE; - hints[PUGL_IGNORE_KEY_REPEAT] = PUGL_FALSE; - hints[PUGL_REFRESH_RATE] = PUGL_DONT_CARE; -} - -PuglWorld* -puglNewWorld(PuglWorldType type, PuglWorldFlags flags) -{ - PuglWorld* world = (PuglWorld*)calloc(1, sizeof(PuglWorld)); - if (!world || !(world->impl = puglInitWorldInternals(type, flags))) { - free(world); - return NULL; - } - - world->startTime = puglGetTime(world); - - puglSetString(&world->className, "Pugl"); - - return world; -} - -void -puglFreeWorld(PuglWorld* const world) -{ - puglFreeWorldInternals(world); - free(world->className); - free(world->views); - free(world); -} - -void -puglSetWorldHandle(PuglWorld* world, PuglWorldHandle handle) -{ - world->handle = handle; -} - -PuglWorldHandle -puglGetWorldHandle(PuglWorld* world) -{ - return world->handle; -} - -PuglStatus -puglSetClassName(PuglWorld* const world, const char* const name) -{ - puglSetString(&world->className, name); - return PUGL_SUCCESS; -} - -PuglView* -puglNewView(PuglWorld* const world) -{ - PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); - if (!view || !(view->impl = puglInitViewInternals())) { - free(view); - return NULL; - } - - view->world = world; - view->minWidth = 1; - view->minHeight = 1; - - puglSetDefaultHints(view->hints); - - // Add to world view list - ++world->numViews; - world->views = - (PuglView**)realloc(world->views, world->numViews * sizeof(PuglView*)); - - world->views[world->numViews - 1] = view; - - return view; -} - -void -puglFreeView(PuglView* view) -{ - puglDispatchSimpleEvent(view, PUGL_DESTROY); - - // Remove from world view list - PuglWorld* world = view->world; - for (size_t i = 0; i < world->numViews; ++i) { - if (world->views[i] == view) { - if (i == world->numViews - 1) { - world->views[i] = NULL; - } else { - memmove(world->views + i, - world->views + i + 1, - sizeof(PuglView*) * (world->numViews - i - 1)); - world->views[world->numViews - 1] = NULL; - } - --world->numViews; - } - } - - free(view->title); - free(view->clipboard.data); - free(view->clipboardType.data); - puglFreeViewInternals(view); - free(view); -} - -PuglWorld* -puglGetWorld(PuglView* view) -{ - return view->world; -} - -PuglStatus -puglSetViewHint(PuglView* view, PuglViewHint hint, int value) -{ - if (value == PUGL_DONT_CARE) { - switch (hint) { - case PUGL_USE_COMPAT_PROFILE: - case PUGL_USE_DEBUG_CONTEXT: - case PUGL_CONTEXT_VERSION_MAJOR: - case PUGL_CONTEXT_VERSION_MINOR: - case PUGL_SWAP_INTERVAL: - return PUGL_BAD_PARAMETER; - default: - break; - } - } - - if (hint < PUGL_NUM_VIEW_HINTS) { - view->hints[hint] = value; - return PUGL_SUCCESS; - } - - return PUGL_BAD_PARAMETER; -} - -int -puglGetViewHint(const PuglView* view, PuglViewHint hint) -{ - if (hint < PUGL_NUM_VIEW_HINTS) { - return view->hints[hint]; - } - - return PUGL_DONT_CARE; -} - -PuglStatus -puglSetParentWindow(PuglView* view, PuglNativeView parent) -{ - view->parent = parent; - return PUGL_SUCCESS; -} - -PuglStatus -puglSetBackend(PuglView* view, const PuglBackend* backend) -{ - view->backend = backend; - return PUGL_SUCCESS; -} - -void -puglSetHandle(PuglView* view, PuglHandle handle) -{ - view->handle = handle; -} - -PuglHandle -puglGetHandle(PuglView* view) -{ - return view->handle; -} - -bool -puglGetVisible(const PuglView* view) -{ - return view->visible; -} - -PuglRect -puglGetFrame(const PuglView* view) -{ - return view->frame; -} - -void* -puglGetContext(PuglView* view) -{ - return view->backend->getContext(view); -} - -#ifndef PUGL_DISABLE_DEPRECATED - -PuglStatus -puglPollEvents(PuglWorld* world, double timeout) -{ - return puglUpdate(world, timeout); -} - -PuglStatus -puglDispatchEvents(PuglWorld* world) -{ - return puglUpdate(world, 0.0); -} - -PuglStatus -puglShowWindow(PuglView* view) -{ - return puglShow(view); -} - -PuglStatus -puglHideWindow(PuglView* view) -{ - return puglHide(view); -} - -#endif - -PuglStatus -puglSetEventFunc(PuglView* view, PuglEventFunc eventFunc) -{ - view->eventFunc = eventFunc; - return PUGL_SUCCESS; -} - -/// Return the code point for buf, or the replacement character on error -uint32_t -puglDecodeUTF8(const uint8_t* buf) -{ -#define FAIL_IF(cond) \ - do { \ - if (cond) \ - return 0xFFFD; \ - } while (0) - - // http://en.wikipedia.org/wiki/UTF-8 - - if (buf[0] < 0x80) { - return buf[0]; - } - - if (buf[0] < 0xC2) { - return 0xFFFD; - } - - if (buf[0] < 0xE0) { - FAIL_IF((buf[1] & 0xC0u) != 0x80); - return ((uint32_t)buf[0] << 6u) + buf[1] - 0x3080u; - } - - if (buf[0] < 0xF0) { - FAIL_IF((buf[1] & 0xC0u) != 0x80); - FAIL_IF(buf[0] == 0xE0 && buf[1] < 0xA0); - FAIL_IF((buf[2] & 0xC0u) != 0x80); - return ((uint32_t)buf[0] << 12u) + // - ((uint32_t)buf[1] << 6u) + // - ((uint32_t)buf[2] - 0xE2080u); - } - - if (buf[0] < 0xF5) { - FAIL_IF((buf[1] & 0xC0u) != 0x80); - FAIL_IF(buf[0] == 0xF0 && buf[1] < 0x90); - FAIL_IF(buf[0] == 0xF4 && buf[1] >= 0x90); - FAIL_IF((buf[2] & 0xC0u) != 0x80u); - FAIL_IF((buf[3] & 0xC0u) != 0x80u); - return (((uint32_t)buf[0] << 18u) + // - ((uint32_t)buf[1] << 12u) + // - ((uint32_t)buf[2] << 6u) + // - ((uint32_t)buf[3] - 0x3C82080u)); - } - - return 0xFFFD; -} - -static inline bool -puglMustConfigure(PuglView* view, const PuglEventConfigure* configure) -{ - return memcmp(configure, &view->lastConfigure, sizeof(PuglEventConfigure)); -} - -void -puglDispatchSimpleEvent(PuglView* view, const PuglEventType type) -{ - assert(type == PUGL_CREATE || type == PUGL_DESTROY || type == PUGL_MAP || - type == PUGL_UNMAP || type == PUGL_UPDATE || type == PUGL_CLOSE || - type == PUGL_LOOP_ENTER || type == PUGL_LOOP_LEAVE); - - const PuglEvent event = {{type, 0}}; - puglDispatchEvent(view, &event); -} - -void -puglDispatchEventInContext(PuglView* view, const PuglEvent* event) -{ - if (event->type == PUGL_CONFIGURE) { - view->frame.x = event->configure.x; - view->frame.y = event->configure.y; - view->frame.width = event->configure.width; - view->frame.height = event->configure.height; - - if (puglMustConfigure(view, &event->configure)) { - view->eventFunc(view, event); - view->lastConfigure = event->configure; - } - } else if (event->type == PUGL_EXPOSE) { - if (event->expose.width > 0 && event->expose.height > 0) { - view->eventFunc(view, event); - } - } else { - view->eventFunc(view, event); - } -} - -void -puglDispatchEvent(PuglView* view, const PuglEvent* event) -{ - switch (event->type) { - case PUGL_NOTHING: - break; - case PUGL_CREATE: - case PUGL_DESTROY: - view->backend->enter(view, NULL); - view->eventFunc(view, event); - view->backend->leave(view, NULL); - break; - case PUGL_CONFIGURE: - if (puglMustConfigure(view, &event->configure)) { - view->backend->enter(view, NULL); - puglDispatchEventInContext(view, event); - view->backend->leave(view, NULL); - } - break; - case PUGL_EXPOSE: - view->backend->enter(view, &event->expose); - puglDispatchEventInContext(view, event); - view->backend->leave(view, &event->expose); - break; - default: - view->eventFunc(view, event); - } -} - -const void* -puglGetInternalClipboard(const PuglView* const view, - const char** const type, - size_t* const len) -{ - if (len) { - *len = view->clipboard.len; - } - - if (type) { - *type = view->clipboardType.data; - } - - return view->clipboard.data; -} - -PuglStatus -puglSetInternalClipboard(PuglView* const view, - const char* const type, - const void* const data, - const size_t len) -{ - if (!type) { - return PUGL_UNSUPPORTED_TYPE; - } - - puglSetBlob(&view->clipboardType, type, strlen(type) + 1); - puglSetBlob(&view->clipboard, data, len); - return PUGL_SUCCESS; -} diff --git a/subprojects/nk_pugl/pugl/src/implementation.h b/subprojects/nk_pugl/pugl/src/implementation.h deleted file mode 100644 index 8c5398c..0000000 --- a/subprojects/nk_pugl/pugl/src/implementation.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_IMPLEMENTATION_H -#define PUGL_IMPLEMENTATION_H - -#include "types.h" - -#include "pugl/pugl.h" - -#include -#include - -PUGL_BEGIN_DECLS - -/// Set `blob` to `data` with length `len`, reallocating if necessary -void -puglSetBlob(PuglBlob* dest, const void* data, size_t len); - -/// Reallocate and set `*dest` to `string` -void -puglSetString(char** dest, const char* string); - -/// Allocate and initialise world internals (implemented once per platform) -PuglWorldInternals* -puglInitWorldInternals(PuglWorldType type, PuglWorldFlags flags); - -/// Destroy and free world internals (implemented once per platform) -void -puglFreeWorldInternals(PuglWorld* world); - -/// Allocate and initialise view internals (implemented once per platform) -PuglInternals* -puglInitViewInternals(void); - -/// Destroy and free view internals (implemented once per platform) -void -puglFreeViewInternals(PuglView* view); - -/// Return the Unicode code point for `buf` or the replacement character -uint32_t -puglDecodeUTF8(const uint8_t* buf); - -/// Dispatch an event with a simple `type` to `view` -void -puglDispatchSimpleEvent(PuglView* view, PuglEventType type); - -/// Dispatch `event` to `view` while already in the graphics context -void -puglDispatchEventInContext(PuglView* view, const PuglEvent* event); - -/// Dispatch `event` to `view`, entering graphics context if necessary -void -puglDispatchEvent(PuglView* view, const PuglEvent* event); - -/// Set internal (stored in view) clipboard contents -const void* -puglGetInternalClipboard(const PuglView* view, const char** type, size_t* len); - -/// Set internal (stored in view) clipboard contents -PuglStatus -puglSetInternalClipboard(PuglView* view, - const char* type, - const void* data, - size_t len); - -PUGL_END_DECLS - -#endif // PUGL_IMPLEMENTATION_H diff --git a/subprojects/nk_pugl/pugl/src/mac.h b/subprojects/nk_pugl/pugl/src/mac.h deleted file mode 100644 index 35e6e0d..0000000 --- a/subprojects/nk_pugl/pugl/src/mac.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - Copyright 2017 Hanspeter Portner - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_DETAIL_MAC_H -#define PUGL_DETAIL_MAC_H - -#include "pugl/pugl.h" - -#import - -#include - -@interface PuglWrapperView : NSView - -- (void)dispatchExpose:(NSRect)rect; -- (void)setReshaped; - -@end - -@interface PuglWindow : NSWindow - -- (void)setPuglview:(PuglView*)view; - -@end - -struct PuglWorldInternalsImpl { - NSApplication* app; - NSAutoreleasePool* autoreleasePool; -}; - -struct PuglInternalsImpl { - NSApplication* app; - PuglWrapperView* wrapperView; - NSView* drawView; - NSCursor* cursor; - PuglWindow* window; - uint32_t mods; - bool mouseTracked; -}; - -#endif // PUGL_DETAIL_MAC_H diff --git a/subprojects/nk_pugl/pugl/src/mac.m b/subprojects/nk_pugl/pugl/src/mac.m deleted file mode 100644 index 58f16c7..0000000 --- a/subprojects/nk_pugl/pugl/src/mac.m +++ /dev/null @@ -1,1468 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - Copyright 2017 Hanspeter Portner - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#define GL_SILENCE_DEPRECATION 1 - -#include "mac.h" - -#include "implementation.h" - -#include "pugl/pugl.h" - -#import - -#include - -#include - -#ifndef __MAC_10_10 -typedef NSUInteger NSEventModifierFlags; -#endif - -#ifndef __MAC_10_12 -typedef NSUInteger NSWindowStyleMask; -#endif - -static NSRect -rectToScreen(NSScreen* screen, NSRect rect) -{ - const double screenHeight = [screen frame].size.height; - - rect.origin.y = screenHeight - rect.origin.y - rect.size.height; - return rect; -} - -static NSScreen* -viewScreen(PuglView* view) -{ - return view->impl->window ? [view->impl->window screen] - : [NSScreen mainScreen]; -} - -static NSRect -nsRectToPoints(PuglView* view, const NSRect rect) -{ - const double scaleFactor = [viewScreen(view) backingScaleFactor]; - - return NSMakeRect(rect.origin.x / scaleFactor, - rect.origin.y / scaleFactor, - rect.size.width / scaleFactor, - rect.size.height / scaleFactor); -} - -static NSRect -nsRectFromPoints(PuglView* view, const NSRect rect) -{ - const double scaleFactor = [viewScreen(view) backingScaleFactor]; - - return NSMakeRect(rect.origin.x * scaleFactor, - rect.origin.y * scaleFactor, - rect.size.width * scaleFactor, - rect.size.height * scaleFactor); -} - -static NSPoint -nsPointFromPoints(PuglView* view, const NSPoint point) -{ - const double scaleFactor = [viewScreen(view) backingScaleFactor]; - - return NSMakePoint(point.x * scaleFactor, point.y * scaleFactor); -} - -static NSRect -rectToNsRect(const PuglRect rect) -{ - return NSMakeRect(rect.x, rect.y, rect.width, rect.height); -} - -static NSSize -sizePoints(PuglView* view, const double width, const double height) -{ - const double scaleFactor = [viewScreen(view) backingScaleFactor]; - - return NSMakeSize(width / scaleFactor, height / scaleFactor); -} - -static void -updateViewRect(PuglView* view) -{ - NSWindow* const window = view->impl->window; - if (window) { - const NSRect screenFramePt = [[NSScreen mainScreen] frame]; - const NSRect screenFramePx = nsRectFromPoints(view, screenFramePt); - const NSRect framePt = [window frame]; - const NSRect contentPt = [window contentRectForFrameRect:framePt]; - const NSRect contentPx = nsRectFromPoints(view, contentPt); - const double screenHeight = screenFramePx.size.height; - - view->frame.x = contentPx.origin.x; - view->frame.y = screenHeight - contentPx.origin.y - contentPx.size.height; - view->frame.width = contentPx.size.width; - view->frame.height = contentPx.size.height; - } -} - -@implementation PuglWindow { -@public - PuglView* puglview; -} - -- (id)initWithContentRect:(NSRect)contentRect - styleMask:(NSWindowStyleMask)aStyle - backing:(NSBackingStoreType)bufferingType - defer:(BOOL)flag -{ - (void)flag; - - NSWindow* result = [super initWithContentRect:contentRect - styleMask:aStyle - backing:bufferingType - defer:NO]; - - [result setAcceptsMouseMovedEvents:YES]; - return (PuglWindow*)result; -} - -- (void)setPuglview:(PuglView*)view -{ - puglview = view; - - [self setContentSize:sizePoints(view, view->frame.width, view->frame.height)]; -} - -- (BOOL)canBecomeKeyWindow -{ - return YES; -} - -- (BOOL)canBecomeMainWindow -{ - return YES; -} - -- (void)setIsVisible:(BOOL)flag -{ - if (flag && !puglview->visible) { - const PuglEventConfigure ev = { - PUGL_CONFIGURE, - 0, - puglview->frame.x, - puglview->frame.y, - puglview->frame.width, - puglview->frame.height, - }; - - puglDispatchEvent(puglview, (const PuglEvent*)&ev); - puglDispatchSimpleEvent(puglview, PUGL_MAP); - } else if (!flag && puglview->visible) { - puglDispatchSimpleEvent(puglview, PUGL_UNMAP); - } - - puglview->visible = flag; - - [super setIsVisible:flag]; -} - -@end - -@implementation PuglWrapperView { -@public - PuglView* puglview; - NSTrackingArea* trackingArea; - NSMutableAttributedString* markedText; - NSMutableDictionary* userTimers; - bool reshaped; -} - -- (void)dispatchExpose:(NSRect)rect -{ - const double scaleFactor = [[NSScreen mainScreen] backingScaleFactor]; - - if (reshaped) { - updateViewRect(puglview); - - const PuglEventConfigure ev = { - PUGL_CONFIGURE, - 0, - puglview->frame.x, - puglview->frame.y, - puglview->frame.width, - puglview->frame.height, - }; - - puglDispatchEvent(puglview, (const PuglEvent*)&ev); - reshaped = false; - } - - if (![[puglview->impl->drawView window] isVisible]) { - return; - } - - const PuglEventExpose ev = { - PUGL_EXPOSE, - 0, - rect.origin.x * scaleFactor, - rect.origin.y * scaleFactor, - rect.size.width * scaleFactor, - rect.size.height * scaleFactor, - }; - - puglDispatchEvent(puglview, (const PuglEvent*)&ev); -} - -- (NSSize)intrinsicContentSize -{ - if (puglview->defaultWidth || puglview->defaultHeight) { - return sizePoints( - puglview, puglview->defaultWidth, puglview->defaultHeight); - } - - return NSMakeSize(NSViewNoInstrinsicMetric, NSViewNoInstrinsicMetric); -} - -- (BOOL)isFlipped -{ - return YES; -} - -- (BOOL)acceptsFirstResponder -{ - return YES; -} - -- (void)setReshaped -{ - reshaped = true; -} - -static uint32_t -getModifiers(const NSEvent* const ev) -{ - const NSEventModifierFlags modifierFlags = [ev modifierFlags]; - - return (((modifierFlags & NSShiftKeyMask) ? PUGL_MOD_SHIFT : 0) | - ((modifierFlags & NSControlKeyMask) ? PUGL_MOD_CTRL : 0) | - ((modifierFlags & NSAlternateKeyMask) ? PUGL_MOD_ALT : 0) | - ((modifierFlags & NSCommandKeyMask) ? PUGL_MOD_SUPER : 0)); -} - -static PuglKey -keySymToSpecial(const NSEvent* const ev) -{ - NSString* chars = [ev charactersIgnoringModifiers]; - if ([chars length] == 1) { - switch ([chars characterAtIndex:0]) { - case NSF1FunctionKey: - return PUGL_KEY_F1; - case NSF2FunctionKey: - return PUGL_KEY_F2; - case NSF3FunctionKey: - return PUGL_KEY_F3; - case NSF4FunctionKey: - return PUGL_KEY_F4; - case NSF5FunctionKey: - return PUGL_KEY_F5; - case NSF6FunctionKey: - return PUGL_KEY_F6; - case NSF7FunctionKey: - return PUGL_KEY_F7; - case NSF8FunctionKey: - return PUGL_KEY_F8; - case NSF9FunctionKey: - return PUGL_KEY_F9; - case NSF10FunctionKey: - return PUGL_KEY_F10; - case NSF11FunctionKey: - return PUGL_KEY_F11; - case NSF12FunctionKey: - return PUGL_KEY_F12; - case NSDeleteCharacter: - return PUGL_KEY_BACKSPACE; - case NSDeleteFunctionKey: - return PUGL_KEY_DELETE; - case NSLeftArrowFunctionKey: - return PUGL_KEY_LEFT; - case NSUpArrowFunctionKey: - return PUGL_KEY_UP; - case NSRightArrowFunctionKey: - return PUGL_KEY_RIGHT; - case NSDownArrowFunctionKey: - return PUGL_KEY_DOWN; - case NSPageUpFunctionKey: - return PUGL_KEY_PAGE_UP; - case NSPageDownFunctionKey: - return PUGL_KEY_PAGE_DOWN; - case NSHomeFunctionKey: - return PUGL_KEY_HOME; - case NSEndFunctionKey: - return PUGL_KEY_END; - case NSInsertFunctionKey: - return PUGL_KEY_INSERT; - case NSMenuFunctionKey: - return PUGL_KEY_MENU; - case NSScrollLockFunctionKey: - return PUGL_KEY_SCROLL_LOCK; - case NSClearLineFunctionKey: - return PUGL_KEY_NUM_LOCK; - case NSPrintScreenFunctionKey: - return PUGL_KEY_PRINT_SCREEN; - case NSPauseFunctionKey: - return PUGL_KEY_PAUSE; - } - // SHIFT, CTRL, ALT, and SUPER are handled in [flagsChanged] - } - return (PuglKey)0; -} - -- (void)updateTrackingAreas -{ - if (trackingArea != nil) { - [self removeTrackingArea:trackingArea]; - [trackingArea release]; - } - - const int opts = (NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | - NSTrackingActiveAlways); - trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] - options:opts - owner:self - userInfo:nil]; - [self addTrackingArea:trackingArea]; - [super updateTrackingAreas]; -} - -- (NSPoint)eventLocation:(NSEvent*)event -{ - return nsPointFromPoints( - puglview, [self convertPoint:[event locationInWindow] fromView:nil]); -} - -static void -handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type) -{ - const NSPoint wloc = [view eventLocation:event]; - const NSPoint rloc = [NSEvent mouseLocation]; - const PuglEventCrossing ev = { - type, - 0, - [event timestamp], - wloc.x, - wloc.y, - rloc.x, - [[NSScreen mainScreen] frame].size.height - rloc.y, - getModifiers(event), - PUGL_CROSSING_NORMAL, - }; - - puglDispatchEvent(view->puglview, (const PuglEvent*)&ev); -} - -- (void)mouseEntered:(NSEvent*)event -{ - handleCrossing(self, event, PUGL_POINTER_IN); - [puglview->impl->cursor set]; - puglview->impl->mouseTracked = true; -} - -- (void)mouseExited:(NSEvent*)event -{ - [[NSCursor arrowCursor] set]; - handleCrossing(self, event, PUGL_POINTER_OUT); - puglview->impl->mouseTracked = false; -} - -- (void)cursorUpdate:(NSEvent*)event -{ - (void)event; - [puglview->impl->cursor set]; -} - -- (void)mouseMoved:(NSEvent*)event -{ - const NSPoint wloc = [self eventLocation:event]; - const NSPoint rloc = [NSEvent mouseLocation]; - const PuglEventMotion ev = { - PUGL_MOTION, - 0, - [event timestamp], - wloc.x, - wloc.y, - rloc.x, - [[NSScreen mainScreen] frame].size.height - rloc.y, - getModifiers(event), - }; - - puglDispatchEvent(puglview, (const PuglEvent*)&ev); -} - -- (void)mouseDragged:(NSEvent*)event -{ - [self mouseMoved:event]; -} - -- (void)rightMouseDragged:(NSEvent*)event -{ - [self mouseMoved:event]; -} - -- (void)otherMouseDragged:(NSEvent*)event -{ - [self mouseMoved:event]; -} - -- (void)mouseDown:(NSEvent*)event -{ - const NSPoint wloc = [self eventLocation:event]; - const NSPoint rloc = [NSEvent mouseLocation]; - const PuglEventButton ev = { - PUGL_BUTTON_PRESS, - 0, - [event timestamp], - wloc.x, - wloc.y, - rloc.x, - [[NSScreen mainScreen] frame].size.height - rloc.y, - getModifiers(event), - (uint32_t)[event buttonNumber] + 1, - }; - - puglDispatchEvent(puglview, (const PuglEvent*)&ev); -} - -- (void)mouseUp:(NSEvent*)event -{ - const NSPoint wloc = [self eventLocation:event]; - const NSPoint rloc = [NSEvent mouseLocation]; - const PuglEventButton ev = { - PUGL_BUTTON_RELEASE, - 0, - [event timestamp], - wloc.x, - wloc.y, - rloc.x, - [[NSScreen mainScreen] frame].size.height - rloc.y, - getModifiers(event), - (uint32_t)[event buttonNumber] + 1, - }; - - puglDispatchEvent(puglview, (const PuglEvent*)&ev); -} - -- (void)rightMouseDown:(NSEvent*)event -{ - [self mouseDown:event]; -} - -- (void)rightMouseUp:(NSEvent*)event -{ - [self mouseUp:event]; -} - -- (void)otherMouseDown:(NSEvent*)event -{ - [self mouseDown:event]; -} - -- (void)otherMouseUp:(NSEvent*)event -{ - [self mouseUp:event]; -} - -- (void)scrollWheel:(NSEvent*)event -{ - const NSPoint wloc = [self eventLocation:event]; - const NSPoint rloc = [NSEvent mouseLocation]; - const double dx = [event scrollingDeltaX]; - const double dy = [event scrollingDeltaY]; - const PuglScrollDirection dir = - ((dx == 0.0 && dy > 0.0) - ? PUGL_SCROLL_UP - : ((dx == 0.0 && dy < 0.0) - ? PUGL_SCROLL_DOWN - : ((dy == 0.0 && dx > 0.0) - ? PUGL_SCROLL_RIGHT - : ((dy == 0.0 && dx < 0.0) ? PUGL_SCROLL_LEFT - : PUGL_SCROLL_SMOOTH)))); - - const PuglEventScroll ev = { - PUGL_SCROLL, - 0, - [event timestamp], - wloc.x, - wloc.y, - rloc.x, - [[NSScreen mainScreen] frame].size.height - rloc.y, - getModifiers(event), - [event hasPreciseScrollingDeltas] ? PUGL_SCROLL_SMOOTH : dir, - dx, - dy, - }; - - puglDispatchEvent(puglview, (const PuglEvent*)&ev); -} - -- (void)keyDown:(NSEvent*)event -{ - if (puglview->hints[PUGL_IGNORE_KEY_REPEAT] && [event isARepeat]) { - return; - } - - const NSPoint wloc = [self eventLocation:event]; - const NSPoint rloc = [NSEvent mouseLocation]; - const PuglKey spec = keySymToSpecial(event); - const NSString* chars = [event charactersIgnoringModifiers]; - const char* str = [[chars lowercaseString] UTF8String]; - const uint32_t code = (spec ? spec : puglDecodeUTF8((const uint8_t*)str)); - - const PuglEventKey ev = { - PUGL_KEY_PRESS, - 0, - [event timestamp], - wloc.x, - wloc.y, - rloc.x, - [[NSScreen mainScreen] frame].size.height - rloc.y, - getModifiers(event), - [event keyCode], - (code != 0xFFFD) ? code : 0, - }; - - puglDispatchEvent(puglview, (const PuglEvent*)&ev); - - if (!spec) { - [self interpretKeyEvents:@[event]]; - } -} - -- (void)keyUp:(NSEvent*)event -{ - const NSPoint wloc = [self eventLocation:event]; - const NSPoint rloc = [NSEvent mouseLocation]; - const PuglKey spec = keySymToSpecial(event); - const NSString* chars = [event charactersIgnoringModifiers]; - const char* str = [[chars lowercaseString] UTF8String]; - const uint32_t code = (spec ? spec : puglDecodeUTF8((const uint8_t*)str)); - - const PuglEventKey ev = { - PUGL_KEY_RELEASE, - 0, - [event timestamp], - wloc.x, - wloc.y, - rloc.x, - [[NSScreen mainScreen] frame].size.height - rloc.y, - getModifiers(event), - [event keyCode], - (code != 0xFFFD) ? code : 0, - }; - - puglDispatchEvent(puglview, (const PuglEvent*)&ev); -} - -- (BOOL)hasMarkedText -{ - return [markedText length] > 0; -} - -- (NSRange)markedRange -{ - return (([markedText length] > 0) ? NSMakeRange(0, [markedText length] - 1) - : NSMakeRange(NSNotFound, 0)); -} - -- (NSRange)selectedRange -{ - return NSMakeRange(NSNotFound, 0); -} - -- (void)setMarkedText:(id)string - selectedRange:(NSRange)selected - replacementRange:(NSRange)replacement -{ - (void)selected; - (void)replacement; - [markedText release]; - markedText = - ([(NSObject*)string isKindOfClass:[NSAttributedString class]] - ? [[NSMutableAttributedString alloc] initWithAttributedString:string] - : [[NSMutableAttributedString alloc] initWithString:string]); -} - -- (void)unmarkText -{ - [[markedText mutableString] setString:@""]; -} - -- (NSArray*)validAttributesForMarkedText -{ - return @[]; -} - -- (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)range - actualRange: - (NSRangePointer)actual -{ - (void)range; - (void)actual; - return nil; -} - -- (NSUInteger)characterIndexForPoint:(NSPoint)point -{ - (void)point; - return 0; -} - -- (NSRect)firstRectForCharacterRange:(NSRange)range - actualRange:(NSRangePointer)actual -{ - (void)range; - (void)actual; - - const NSRect frame = [self bounds]; - return NSMakeRect(frame.origin.x, frame.origin.y, 0.0, 0.0); -} - -- (void)doCommandBySelector:(SEL)selector -{ - (void)selector; -} - -- (void)insertText:(id)string replacementRange:(NSRange)replacement -{ - (void)replacement; - - NSEvent* const event = [NSApp currentEvent]; - NSString* const characters = - ([(NSObject*)string isKindOfClass:[NSAttributedString class]] - ? [(NSAttributedString*)string string] - : (NSString*)string); - - const NSPoint wloc = [self eventLocation:event]; - const NSPoint rloc = [NSEvent mouseLocation]; - for (size_t i = 0; i < [characters length]; ++i) { - const uint32_t code = [characters characterAtIndex:i]; - char utf8[8] = {0}; - NSUInteger len = 0; - - [characters getBytes:utf8 - maxLength:sizeof(utf8) - usedLength:&len - encoding:NSUTF8StringEncoding - options:0 - range:NSMakeRange(i, i + 1) - remainingRange:nil]; - - PuglEventText ev = { - PUGL_TEXT, - 0, - [event timestamp], - wloc.x, - wloc.y, - rloc.x, - [[NSScreen mainScreen] frame].size.height - rloc.y, - getModifiers(event), - [event keyCode], - code, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - }; - - memcpy(ev.string, utf8, len); - puglDispatchEvent(puglview, (const PuglEvent*)&ev); - } -} - -- (void)flagsChanged:(NSEvent*)event -{ - const uint32_t mods = getModifiers(event); - PuglEventType type = PUGL_NOTHING; - PuglKey special = (PuglKey)0; - - if ((mods & PUGL_MOD_SHIFT) != (puglview->impl->mods & PUGL_MOD_SHIFT)) { - type = mods & PUGL_MOD_SHIFT ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE; - special = PUGL_KEY_SHIFT; - } else if ((mods & PUGL_MOD_CTRL) != (puglview->impl->mods & PUGL_MOD_CTRL)) { - type = mods & PUGL_MOD_CTRL ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE; - special = PUGL_KEY_CTRL; - } else if ((mods & PUGL_MOD_ALT) != (puglview->impl->mods & PUGL_MOD_ALT)) { - type = mods & PUGL_MOD_ALT ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE; - special = PUGL_KEY_ALT; - } else if ((mods & PUGL_MOD_SUPER) != - (puglview->impl->mods & PUGL_MOD_SUPER)) { - type = mods & PUGL_MOD_SUPER ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE; - special = PUGL_KEY_SUPER; - } - - if (special != 0) { - const NSPoint wloc = [self eventLocation:event]; - const NSPoint rloc = [NSEvent mouseLocation]; - PuglEventKey ev = {type, - 0, - [event timestamp], - wloc.x, - wloc.y, - rloc.x, - [[NSScreen mainScreen] frame].size.height - rloc.y, - mods, - [event keyCode], - special}; - puglDispatchEvent(puglview, (const PuglEvent*)&ev); - } - - puglview->impl->mods = mods; -} - -- (BOOL)preservesContentInLiveResize -{ - return NO; -} - -- (void)viewWillStartLiveResize -{ - puglDispatchSimpleEvent(puglview, PUGL_LOOP_ENTER); -} - -- (void)viewWillDraw -{ - puglDispatchSimpleEvent(puglview, PUGL_UPDATE); - [super viewWillDraw]; -} - -- (void)resizeTick -{ - puglPostRedisplay(puglview); -} - -- (void)timerTick:(NSTimer*)userTimer -{ - const NSNumber* userInfo = userTimer.userInfo; - const PuglEventTimer ev = {PUGL_TIMER, 0, userInfo.unsignedLongValue}; - - puglDispatchEvent(puglview, (const PuglEvent*)&ev); -} - -- (void)viewDidEndLiveResize -{ - puglDispatchSimpleEvent(puglview, PUGL_LOOP_LEAVE); -} - -@end - -@interface PuglWindowDelegate : NSObject - -- (instancetype)initWithPuglWindow:(PuglWindow*)window; - -@end - -@implementation PuglWindowDelegate { - PuglWindow* window; -} - -- (instancetype)initWithPuglWindow:(PuglWindow*)puglWindow -{ - if ((self = [super init])) { - window = puglWindow; - } - - return self; -} - -- (BOOL)windowShouldClose:(id)sender -{ - (void)sender; - - puglDispatchSimpleEvent(window->puglview, PUGL_CLOSE); - return YES; -} - -- (void)windowDidMove:(NSNotification*)notification -{ - (void)notification; - - updateViewRect(window->puglview); -} - -- (void)windowDidBecomeKey:(NSNotification*)notification -{ - (void)notification; - - PuglEvent ev = {{PUGL_FOCUS_IN, 0}}; - ev.focus.mode = PUGL_CROSSING_NORMAL; - puglDispatchEvent(window->puglview, &ev); -} - -- (void)windowDidResignKey:(NSNotification*)notification -{ - (void)notification; - - PuglEvent ev = {{PUGL_FOCUS_OUT, 0}}; - ev.focus.mode = PUGL_CROSSING_NORMAL; - puglDispatchEvent(window->puglview, &ev); -} - -@end - -PuglWorldInternals* -puglInitWorldInternals(PuglWorldType type, PuglWorldFlags PUGL_UNUSED(flags)) -{ - PuglWorldInternals* impl = - (PuglWorldInternals*)calloc(1, sizeof(PuglWorldInternals)); - - impl->app = [NSApplication sharedApplication]; - - if (type == PUGL_PROGRAM) { - impl->autoreleasePool = [NSAutoreleasePool new]; - } - - return impl; -} - -void -puglFreeWorldInternals(PuglWorld* world) -{ - if (world->impl->autoreleasePool) { - [world->impl->autoreleasePool drain]; - } - - free(world->impl); -} - -void* -puglGetNativeWorld(PuglWorld* PUGL_UNUSED(world)) -{ - return NULL; -} - -PuglInternals* -puglInitViewInternals(void) -{ - PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); - - impl->cursor = [NSCursor arrowCursor]; - - return impl; -} - -static NSLayoutConstraint* -puglConstraint(id item, NSLayoutAttribute attribute, float constant) -{ - return - [NSLayoutConstraint constraintWithItem:item - attribute:attribute - relatedBy:NSLayoutRelationGreaterThanOrEqual - toItem:nil - attribute:NSLayoutAttributeNotAnAttribute - multiplier:1.0 - constant:(CGFloat)constant]; -} - -PuglStatus -puglRealize(PuglView* view) -{ - PuglInternals* impl = view->impl; - if (impl->wrapperView) { - return PUGL_FAILURE; - } - - const NSScreen* const screen = [NSScreen mainScreen]; - const double scaleFactor = [screen backingScaleFactor]; - - // Getting depth from the display mode seems tedious, just set usual values - if (view->hints[PUGL_RED_BITS] == PUGL_DONT_CARE) { - view->hints[PUGL_RED_BITS] = 8; - } - if (view->hints[PUGL_BLUE_BITS] == PUGL_DONT_CARE) { - view->hints[PUGL_BLUE_BITS] = 8; - } - if (view->hints[PUGL_GREEN_BITS] == PUGL_DONT_CARE) { - view->hints[PUGL_GREEN_BITS] = 8; - } - if (view->hints[PUGL_ALPHA_BITS] == PUGL_DONT_CARE) { - view->hints[PUGL_ALPHA_BITS] = 8; - } - - CGDirectDisplayID displayId = CGMainDisplayID(); - CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayId); - - // Try to get refresh rate from mode (usually fails) - view->hints[PUGL_REFRESH_RATE] = (int)CGDisplayModeGetRefreshRate(mode); - - CGDisplayModeRelease(mode); - if (view->hints[PUGL_REFRESH_RATE] == 0) { - // Get refresh rate from a display link - // TODO: Keep and actually use the display link for something? - CVDisplayLinkRef link; - CVDisplayLinkCreateWithCGDisplay(displayId, &link); - - const CVTime p = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link); - const double r = p.timeScale / (double)p.timeValue; - view->hints[PUGL_REFRESH_RATE] = (int)lrint(r); - - CVDisplayLinkRelease(link); - } - - if (view->frame.width == 0.0 && view->frame.height == 0.0) { - if (view->defaultWidth == 0.0 && view->defaultHeight == 0.0) { - return PUGL_BAD_CONFIGURATION; - } - - const double screenWidthPx = [screen frame].size.width * scaleFactor; - const double screenHeightPx = [screen frame].size.height * scaleFactor; - - view->frame.width = view->defaultWidth; - view->frame.height = view->defaultHeight; - view->frame.x = screenWidthPx / 2.0 - view->frame.width / 2.0; - view->frame.y = screenHeightPx / 2.0 - view->frame.height / 2.0; - } - - const NSRect framePx = rectToNsRect(view->frame); - const NSRect framePt = NSMakeRect(framePx.origin.x / scaleFactor, - framePx.origin.y / scaleFactor, - framePx.size.width / scaleFactor, - framePx.size.height / scaleFactor); - - // Create wrapper view to handle input - impl->wrapperView = [PuglWrapperView alloc]; - impl->wrapperView->puglview = view; - impl->wrapperView->userTimers = [[NSMutableDictionary alloc] init]; - impl->wrapperView->markedText = [[NSMutableAttributedString alloc] init]; - [impl->wrapperView setAutoresizesSubviews:YES]; - [impl->wrapperView initWithFrame:framePt]; - [impl->wrapperView addConstraint:puglConstraint(impl->wrapperView, - NSLayoutAttributeWidth, - view->minWidth)]; - [impl->wrapperView addConstraint:puglConstraint(impl->wrapperView, - NSLayoutAttributeHeight, - view->minHeight)]; - - // Create draw view to be rendered to - PuglStatus st = PUGL_SUCCESS; - if ((st = view->backend->configure(view)) || - (st = view->backend->create(view))) { - return st; - } - - // Add draw view to wrapper view - [impl->wrapperView addSubview:impl->drawView]; - [impl->wrapperView setHidden:NO]; - [impl->drawView setHidden:NO]; - - if (view->parent) { - NSView* pview = (NSView*)view->parent; - [pview addSubview:impl->wrapperView]; - [impl->drawView setHidden:NO]; - [[impl->drawView window] makeFirstResponder:impl->wrapperView]; - } else { - unsigned style = - (NSClosableWindowMask | NSTitledWindowMask | NSMiniaturizableWindowMask); - if (view->hints[PUGL_RESIZABLE]) { - style |= NSResizableWindowMask; - } - - PuglWindow* window = [[[PuglWindow alloc] - initWithContentRect:rectToScreen([NSScreen mainScreen], framePt) - styleMask:style - backing:NSBackingStoreBuffered - defer:NO] retain]; - [window setPuglview:view]; - - if (view->title) { - NSString* titleString = - [[NSString alloc] initWithBytes:view->title - length:strlen(view->title) - encoding:NSUTF8StringEncoding]; - - [window setTitle:titleString]; - } - - if (view->minWidth || view->minHeight) { - [window - setContentMinSize:sizePoints(view, view->minWidth, view->minHeight)]; - } - impl->window = window; - - ((NSWindow*)window).delegate = - [[PuglWindowDelegate alloc] initWithPuglWindow:window]; - - if (view->minAspectX && view->minAspectY) { - [window setContentAspectRatio:sizePoints(view, - view->minAspectX, - view->minAspectY)]; - } - - puglSetFrame(view, view->frame); - - [window setContentView:impl->wrapperView]; - [view->world->impl->app activateIgnoringOtherApps:YES]; - [window makeFirstResponder:impl->wrapperView]; - [window makeKeyAndOrderFront:window]; - [impl->window setIsVisible:NO]; - } - - [impl->wrapperView updateTrackingAreas]; - - puglDispatchSimpleEvent(view, PUGL_CREATE); - - return PUGL_SUCCESS; -} - -PuglStatus -puglShow(PuglView* view) -{ - if (!view->impl->wrapperView) { - const PuglStatus st = puglRealize(view); - if (st) { - return st; - } - } - - if (![view->impl->window isVisible]) { - [view->impl->window setIsVisible:YES]; - [view->impl->drawView setNeedsDisplay:YES]; - updateViewRect(view); - } - - return PUGL_SUCCESS; -} - -PuglStatus -puglHide(PuglView* view) -{ - [view->impl->window setIsVisible:NO]; - return PUGL_SUCCESS; -} - -void -puglFreeViewInternals(PuglView* view) -{ - if (view) { - if (view->backend) { - view->backend->destroy(view); - } - - if (view->impl) { - [view->impl->wrapperView removeFromSuperview]; - view->impl->wrapperView->puglview = NULL; - if (view->impl->window) { - [view->impl->window close]; - } - [view->impl->wrapperView release]; - if (view->impl->window) { - [view->impl->window release]; - } - free(view->impl); - } - } -} - -PuglStatus -puglGrabFocus(PuglView* view) -{ - NSWindow* window = [view->impl->wrapperView window]; - - [window makeKeyWindow]; - [window makeFirstResponder:view->impl->wrapperView]; - return PUGL_SUCCESS; -} - -bool -puglHasFocus(const PuglView* view) -{ - PuglInternals* const impl = view->impl; - - return ([[impl->wrapperView window] isKeyWindow] && - [[impl->wrapperView window] firstResponder] == impl->wrapperView); -} - -PuglStatus -puglRequestAttention(PuglView* view) -{ - if (![view->impl->window isKeyWindow]) { - [view->world->impl->app requestUserAttention:NSInformationalRequest]; - } - - return PUGL_SUCCESS; -} - -PuglStatus -puglStartTimer(PuglView* view, uintptr_t id, double timeout) -{ - puglStopTimer(view, id); - - NSNumber* idNumber = [NSNumber numberWithUnsignedLong:id]; - - NSTimer* timer = [NSTimer timerWithTimeInterval:timeout - target:view->impl->wrapperView - selector:@selector(timerTick:) - userInfo:idNumber - repeats:YES]; - - [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; - - view->impl->wrapperView->userTimers[idNumber] = timer; - - return PUGL_SUCCESS; -} - -PuglStatus -puglStopTimer(PuglView* view, uintptr_t id) -{ - NSNumber* idNumber = [NSNumber numberWithUnsignedLong:id]; - NSTimer* timer = view->impl->wrapperView->userTimers[idNumber]; - - if (timer) { - [view->impl->wrapperView->userTimers removeObjectForKey:timer]; - [timer invalidate]; - return PUGL_SUCCESS; - } - - return PUGL_UNKNOWN_ERROR; -} - -PuglStatus -puglSendEvent(PuglView* view, const PuglEvent* event) -{ - if (event->type == PUGL_CLIENT) { - PuglWrapperView* wrapper = view->impl->wrapperView; - const NSWindow* window = [wrapper window]; - const NSRect rect = [wrapper frame]; - const NSPoint center = {NSMidX(rect), NSMidY(rect)}; - - NSEvent* nsevent = - [NSEvent otherEventWithType:NSApplicationDefined - location:center - modifierFlags:0 - timestamp:[[NSProcessInfo processInfo] systemUptime] - windowNumber:window.windowNumber - context:nil - subtype:PUGL_CLIENT - data1:(NSInteger)event->client.data1 - data2:(NSInteger)event->client.data2]; - - [view->world->impl->app postEvent:nsevent atStart:false]; - return PUGL_SUCCESS; - } - - return PUGL_UNSUPPORTED_TYPE; -} - -#ifndef PUGL_DISABLE_DEPRECATED -PuglStatus -puglWaitForEvent(PuglView* view) -{ - return puglPollEvents(view->world, -1.0); -} -#endif - -static void -dispatchClientEvent(PuglWorld* world, NSEvent* ev) -{ - NSWindow* win = [ev window]; - NSPoint loc = [ev locationInWindow]; - for (size_t i = 0; i < world->numViews; ++i) { - PuglView* view = world->views[i]; - PuglWrapperView* wrapper = view->impl->wrapperView; - if ([wrapper window] == win && NSPointInRect(loc, [wrapper frame])) { - const PuglEventClient event = { - PUGL_CLIENT, 0, (uintptr_t)[ev data1], (uintptr_t)[ev data2]}; - - puglDispatchEvent(view, (const PuglEvent*)&event); - } - } -} - -PuglStatus -puglUpdate(PuglWorld* world, const double timeout) -{ - NSDate* date = - ((timeout < 0) ? [NSDate distantFuture] - : [NSDate dateWithTimeIntervalSinceNow:timeout]); - - for (NSEvent* ev = NULL; - (ev = [world->impl->app nextEventMatchingMask:NSAnyEventMask - untilDate:date - inMode:NSDefaultRunLoopMode - dequeue:YES]);) { - if ([ev type] == NSApplicationDefined && [ev subtype] == PUGL_CLIENT) { - dispatchClientEvent(world, ev); - } - - [world->impl->app sendEvent:ev]; - - if (timeout < 0) { - // Now that we've waited and got an event, set the date to now to - // avoid looping forever - date = [NSDate date]; - } - } - - for (size_t i = 0; i < world->numViews; ++i) { - PuglView* const view = world->views[i]; - - if ([[view->impl->drawView window] isVisible]) { - puglDispatchSimpleEvent(view, PUGL_UPDATE); - } - - [view->impl->drawView displayIfNeeded]; - } - - return PUGL_SUCCESS; -} - -#ifndef PUGL_DISABLE_DEPRECATED -PuglStatus -puglProcessEvents(PuglView* view) -{ - return puglDispatchEvents(view->world); -} -#endif - -double -puglGetTime(const PuglWorld* world) -{ - return (mach_absolute_time() / 1e9) - world->startTime; -} - -PuglStatus -puglPostRedisplay(PuglView* view) -{ - [view->impl->drawView setNeedsDisplay:YES]; - return PUGL_SUCCESS; -} - -PuglStatus -puglPostRedisplayRect(PuglView* view, const PuglRect rect) -{ - const NSRect rectPx = rectToNsRect(rect); - - [view->impl->drawView setNeedsDisplayInRect:nsRectToPoints(view, rectPx)]; - - return PUGL_SUCCESS; -} - -PuglNativeView -puglGetNativeWindow(PuglView* view) -{ - return (PuglNativeView)view->impl->wrapperView; -} - -PuglStatus -puglSetWindowTitle(PuglView* view, const char* title) -{ - puglSetString(&view->title, title); - - if (view->impl->window) { - NSString* titleString = - [[NSString alloc] initWithBytes:title - length:strlen(title) - encoding:NSUTF8StringEncoding]; - - [view->impl->window setTitle:titleString]; - } - - return PUGL_SUCCESS; -} - -PuglStatus -puglSetFrame(PuglView* view, const PuglRect frame) -{ - PuglInternals* const impl = view->impl; - - // Update view frame to exactly the requested frame in Pugl coordinates - view->frame = frame; - - const NSRect framePx = rectToNsRect(frame); - const NSRect framePt = nsRectToPoints(view, framePx); - if (impl->window) { - // Resize window to fit new content rect - const NSRect screenPt = rectToScreen(viewScreen(view), framePt); - const NSRect winFrame = [impl->window frameRectForContentRect:screenPt]; - - [impl->window setFrame:winFrame display:NO]; - } - - // Resize views - const NSRect sizePx = NSMakeRect(0, 0, frame.width, frame.height); - const NSRect sizePt = [impl->drawView convertRectFromBacking:sizePx]; - - [impl->wrapperView setFrame:(impl->window ? sizePt : framePt)]; - [impl->drawView setFrame:sizePt]; - - return PUGL_SUCCESS; -} - -PuglStatus -puglSetDefaultSize(PuglView* const view, const int width, const int height) -{ - view->defaultWidth = width; - view->defaultHeight = height; - return PUGL_SUCCESS; -} - -PuglStatus -puglSetMinSize(PuglView* const view, const int width, const int height) -{ - view->minWidth = width; - view->minHeight = height; - - if (view->impl->window && (view->minWidth || view->minHeight)) { - [view->impl->window - setContentMinSize:sizePoints(view, view->minWidth, view->minHeight)]; - } - - return PUGL_SUCCESS; -} - -PuglStatus -puglSetMaxSize(PuglView* const view, const int width, const int height) -{ - view->maxWidth = width; - view->maxHeight = height; - - if (view->impl->window && (view->maxWidth || view->maxHeight)) { - [view->impl->window - setContentMaxSize:sizePoints(view, view->maxWidth, view->maxHeight)]; - } - - return PUGL_SUCCESS; -} - -PuglStatus -puglSetAspectRatio(PuglView* const view, - const int minX, - const int minY, - const int maxX, - const int maxY) -{ - view->minAspectX = minX; - view->minAspectY = minY; - view->maxAspectX = maxX; - view->maxAspectY = maxY; - - if (view->impl->window && view->minAspectX && view->minAspectY) { - [view->impl->window setContentAspectRatio:sizePoints(view, - view->minAspectX, - view->minAspectY)]; - } - - return PUGL_SUCCESS; -} - -PuglStatus -puglSetTransientFor(PuglView* view, PuglNativeView parent) -{ - view->transientParent = parent; - - if (view->impl->window) { - NSWindow* parentWindow = [(NSView*)parent window]; - if (parentWindow) { - [parentWindow addChildWindow:view->impl->window ordered:NSWindowAbove]; - return PUGL_SUCCESS; - } - } - - return PUGL_FAILURE; -} - -const void* -puglGetClipboard(PuglView* const view, - const char** const type, - size_t* const len) -{ - NSPasteboard* const pasteboard = [NSPasteboard generalPasteboard]; - - if ([[pasteboard types] containsObject:NSStringPboardType]) { - const NSString* str = [pasteboard stringForType:NSStringPboardType]; - const char* utf8 = [str UTF8String]; - - puglSetBlob(&view->clipboard, utf8, strlen(utf8) + 1); - } - - return puglGetInternalClipboard(view, type, len); -} - -static NSCursor* -puglGetNsCursor(const PuglCursor cursor) -{ - switch (cursor) { - case PUGL_CURSOR_ARROW: - return [NSCursor arrowCursor]; - case PUGL_CURSOR_CARET: - return [NSCursor IBeamCursor]; - case PUGL_CURSOR_CROSSHAIR: - return [NSCursor crosshairCursor]; - case PUGL_CURSOR_HAND: - return [NSCursor pointingHandCursor]; - case PUGL_CURSOR_NO: - return [NSCursor operationNotAllowedCursor]; - case PUGL_CURSOR_LEFT_RIGHT: - return [NSCursor resizeLeftRightCursor]; - case PUGL_CURSOR_UP_DOWN: - return [NSCursor resizeUpDownCursor]; - } - - return NULL; -} - -PuglStatus -puglSetCursor(PuglView* view, PuglCursor cursor) -{ - PuglInternals* const impl = view->impl; - NSCursor* const cur = puglGetNsCursor(cursor); - if (!cur) { - return PUGL_FAILURE; - } - - impl->cursor = cur; - - if (impl->mouseTracked) { - [cur set]; - } - - return PUGL_SUCCESS; -} - -PuglStatus -puglSetClipboard(PuglView* const view, - const char* const type, - const void* const data, - const size_t len) -{ - NSPasteboard* const pasteboard = [NSPasteboard generalPasteboard]; - const char* const str = (const char*)data; - - if (type && strcmp(type, "text/plain")) { - return PUGL_UNSUPPORTED_TYPE; - } - - PuglStatus st = puglSetInternalClipboard(view, type, data, len); - if (st) { - return st; - } - - NSString* nsString = [NSString stringWithUTF8String:str]; - if (nsString) { - [pasteboard declareTypes:[NSArray arrayWithObjects:NSStringPboardType, nil] - owner:nil]; - - [pasteboard setString:nsString forType:NSStringPboardType]; - - return PUGL_SUCCESS; - } - - return PUGL_UNKNOWN_ERROR; -} diff --git a/subprojects/nk_pugl/pugl/src/mac_cairo.m b/subprojects/nk_pugl/pugl/src/mac_cairo.m deleted file mode 100644 index 1c564a0..0000000 --- a/subprojects/nk_pugl/pugl/src/mac_cairo.m +++ /dev/null @@ -1,160 +0,0 @@ -/* - Copyright 2019-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "implementation.h" -#include "mac.h" -#include "stub.h" - -#include "pugl/cairo.h" - -#include - -#import - -#include - -@interface PuglCairoView : NSView -@end - -@implementation PuglCairoView { -@public - PuglView* puglview; - cairo_surface_t* surface; - cairo_t* cr; -} - -- (id)initWithFrame:(NSRect)frame -{ - self = [super initWithFrame:frame]; - - return self; -} - -- (void)resizeWithOldSuperviewSize:(NSSize)oldSize -{ - PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; - - [super resizeWithOldSuperviewSize:oldSize]; - [wrapper setReshaped]; -} - -- (void)drawRect:(NSRect)rect -{ - PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; - [wrapper dispatchExpose:rect]; -} - -@end - -static PuglStatus -puglMacCairoCreate(PuglView* view) -{ - PuglInternals* impl = view->impl; - PuglCairoView* drawView = [PuglCairoView alloc]; - - drawView->puglview = view; - [drawView initWithFrame:[impl->wrapperView bounds]]; - if (view->hints[PUGL_RESIZABLE]) { - [drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - } else { - [drawView setAutoresizingMask:NSViewNotSizable]; - } - - impl->drawView = drawView; - return PUGL_SUCCESS; -} - -static PuglStatus -puglMacCairoDestroy(PuglView* view) -{ - PuglCairoView* const drawView = (PuglCairoView*)view->impl->drawView; - - [drawView removeFromSuperview]; - [drawView release]; - - view->impl->drawView = nil; - return PUGL_SUCCESS; -} - -static PuglStatus -puglMacCairoEnter(PuglView* view, const PuglEventExpose* expose) -{ - PuglCairoView* const drawView = (PuglCairoView*)view->impl->drawView; - if (!expose) { - return PUGL_SUCCESS; - } - - assert(!drawView->surface); - assert(!drawView->cr); - - const double scale = 1.0 / [[NSScreen mainScreen] backingScaleFactor]; - CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort]; - const CGSize sizePx = {view->frame.width, view->frame.height}; - const CGSize sizePt = CGContextConvertSizeToUserSpace(context, sizePx); - - // Convert coordinates to standard Cairo space - CGContextTranslateCTM(context, 0.0, -sizePt.height); - CGContextScaleCTM(context, scale, -scale); - - drawView->surface = cairo_quartz_surface_create_for_cg_context( - context, (unsigned)sizePx.width, (unsigned)sizePx.height); - - drawView->cr = cairo_create(drawView->surface); - - return PUGL_SUCCESS; -} - -static PuglStatus -puglMacCairoLeave(PuglView* view, const PuglEventExpose* expose) -{ - PuglCairoView* const drawView = (PuglCairoView*)view->impl->drawView; - if (!expose) { - return PUGL_SUCCESS; - } - - assert(drawView->surface); - assert(drawView->cr); - - CGContextRef context = cairo_quartz_surface_get_cg_context(drawView->surface); - - cairo_destroy(drawView->cr); - cairo_surface_destroy(drawView->surface); - drawView->cr = NULL; - drawView->surface = NULL; - - CGContextFlush(context); - - return PUGL_SUCCESS; -} - -static void* -puglMacCairoGetContext(PuglView* view) -{ - return ((PuglCairoView*)view->impl->drawView)->cr; -} - -const PuglBackend* -puglCairoBackend(void) -{ - static const PuglBackend backend = {puglStubConfigure, - puglMacCairoCreate, - puglMacCairoDestroy, - puglMacCairoEnter, - puglMacCairoLeave, - puglMacCairoGetContext}; - - return &backend; -} diff --git a/subprojects/nk_pugl/pugl/src/mac_gl.m b/subprojects/nk_pugl/pugl/src/mac_gl.m deleted file mode 100644 index dd06cc0..0000000 --- a/subprojects/nk_pugl/pugl/src/mac_gl.m +++ /dev/null @@ -1,210 +0,0 @@ -/* - Copyright 2019-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "implementation.h" -#include "mac.h" -#include "stub.h" - -#include "pugl/gl.h" - -#ifndef __MAC_10_10 -# define NSOpenGLProfileVersion4_1Core NSOpenGLProfileVersion3_2Core -#endif - -@interface PuglOpenGLView : NSOpenGLView -@end - -@implementation PuglOpenGLView { -@public - PuglView* puglview; -} - -- (id)initWithFrame:(NSRect)frame -{ - const bool compat = puglview->hints[PUGL_USE_COMPAT_PROFILE]; - const unsigned samples = (unsigned)puglview->hints[PUGL_SAMPLES]; - const int major = puglview->hints[PUGL_CONTEXT_VERSION_MAJOR]; - const unsigned profile = - ((compat || major < 3) ? NSOpenGLProfileVersionLegacy - : (major >= 4 ? NSOpenGLProfileVersion4_1Core - : NSOpenGLProfileVersion3_2Core)); - - // Set attributes to default if they are unset - // (There is no GLX_DONT_CARE equivalent on MacOS) - if (puglview->hints[PUGL_DEPTH_BITS] == PUGL_DONT_CARE) { - puglview->hints[PUGL_DEPTH_BITS] = 0; - } - if (puglview->hints[PUGL_STENCIL_BITS] == PUGL_DONT_CARE) { - puglview->hints[PUGL_STENCIL_BITS] = 0; - } - if (puglview->hints[PUGL_SAMPLES] == PUGL_DONT_CARE) { - puglview->hints[PUGL_SAMPLES] = 1; - } - if (puglview->hints[PUGL_DOUBLE_BUFFER] == PUGL_DONT_CARE) { - puglview->hints[PUGL_DOUBLE_BUFFER] = 1; - } - if (puglview->hints[PUGL_SWAP_INTERVAL] == PUGL_DONT_CARE) { - puglview->hints[PUGL_SWAP_INTERVAL] = 1; - } - - const unsigned colorSize = (unsigned)(puglview->hints[PUGL_RED_BITS] + - puglview->hints[PUGL_BLUE_BITS] + - puglview->hints[PUGL_GREEN_BITS] + - puglview->hints[PUGL_ALPHA_BITS]); - - // clang-format off - NSOpenGLPixelFormatAttribute pixelAttribs[17] = { - NSOpenGLPFADoubleBuffer, - NSOpenGLPFAAccelerated, - NSOpenGLPFAOpenGLProfile, profile, - NSOpenGLPFAColorSize, colorSize, - NSOpenGLPFADepthSize, (unsigned)puglview->hints[PUGL_DEPTH_BITS], - NSOpenGLPFAStencilSize, (unsigned)puglview->hints[PUGL_STENCIL_BITS], - NSOpenGLPFAMultisample, samples ? 1 : 0, - NSOpenGLPFASampleBuffers, samples ? 1 : 0, - NSOpenGLPFASamples, samples, - 0}; - // clang-format on - - NSOpenGLPixelFormat* pixelFormat = - [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelAttribs]; - - if (pixelFormat) { - self = [super initWithFrame:frame pixelFormat:pixelFormat]; - [pixelFormat release]; - } else { - self = [super initWithFrame:frame]; - } - - [self setWantsBestResolutionOpenGLSurface:YES]; - - if (self) { - [[self openGLContext] makeCurrentContext]; - [self reshape]; - } - return self; -} - -- (void)reshape -{ - PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; - - [super reshape]; - [wrapper setReshaped]; -} - -- (void)drawRect:(NSRect)rect -{ - PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; - [wrapper dispatchExpose:rect]; -} - -@end - -static PuglStatus -puglMacGlCreate(PuglView* view) -{ - PuglInternals* impl = view->impl; - PuglOpenGLView* drawView = [PuglOpenGLView alloc]; - - drawView->puglview = view; - [drawView initWithFrame:[impl->wrapperView bounds]]; - if (view->hints[PUGL_RESIZABLE]) { - [drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - } else { - [drawView setAutoresizingMask:NSViewNotSizable]; - } - - impl->drawView = drawView; - return PUGL_SUCCESS; -} - -static PuglStatus -puglMacGlDestroy(PuglView* view) -{ - PuglOpenGLView* const drawView = (PuglOpenGLView*)view->impl->drawView; - - [drawView removeFromSuperview]; - [drawView release]; - - view->impl->drawView = nil; - return PUGL_SUCCESS; -} - -static PuglStatus -puglMacGlEnter(PuglView* view, const PuglEventExpose* PUGL_UNUSED(expose)) -{ - PuglOpenGLView* const drawView = (PuglOpenGLView*)view->impl->drawView; - - [[drawView openGLContext] makeCurrentContext]; - return PUGL_SUCCESS; -} - -static PuglStatus -puglMacGlLeave(PuglView* view, const PuglEventExpose* expose) -{ - PuglOpenGLView* const drawView = (PuglOpenGLView*)view->impl->drawView; - - if (expose) { - [[drawView openGLContext] flushBuffer]; - } - - [NSOpenGLContext clearCurrentContext]; - - return PUGL_SUCCESS; -} - -PuglGlFunc -puglGetProcAddress(const char* name) -{ - CFBundleRef framework = - CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); - - CFStringRef symbol = CFStringCreateWithCString( - kCFAllocatorDefault, name, kCFStringEncodingASCII); - - PuglGlFunc func = - (PuglGlFunc)CFBundleGetFunctionPointerForName(framework, symbol); - - CFRelease(symbol); - - return func; -} - -PuglStatus -puglEnterContext(PuglView* view) -{ - return view->backend->enter(view, NULL); -} - -PuglStatus -puglLeaveContext(PuglView* view) -{ - return view->backend->leave(view, NULL); -} - -const PuglBackend* -puglGlBackend(void) -{ - static const PuglBackend backend = {puglStubConfigure, - puglMacGlCreate, - puglMacGlDestroy, - puglMacGlEnter, - puglMacGlLeave, - puglStubGetContext}; - - return &backend; -} diff --git a/subprojects/nk_pugl/pugl/src/mac_stub.m b/subprojects/nk_pugl/pugl/src/mac_stub.m deleted file mode 100644 index ac7bfcc..0000000 --- a/subprojects/nk_pugl/pugl/src/mac_stub.m +++ /dev/null @@ -1,92 +0,0 @@ -/* - Copyright 2019-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "implementation.h" -#include "mac.h" -#include "stub.h" - -#include "pugl/stub.h" - -#import - -@interface PuglStubView : NSView -@end - -@implementation PuglStubView { -@public - PuglView* puglview; -} - -- (void)resizeWithOldSuperviewSize:(NSSize)oldSize -{ - PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; - - [super resizeWithOldSuperviewSize:oldSize]; - [wrapper setReshaped]; -} - -- (void)drawRect:(NSRect)rect -{ - PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; - - [wrapper dispatchExpose:rect]; -} - -@end - -static PuglStatus -puglMacStubCreate(PuglView* view) -{ - PuglInternals* impl = view->impl; - PuglStubView* drawView = [PuglStubView alloc]; - - drawView->puglview = view; - [drawView - initWithFrame:NSMakeRect(0, 0, view->frame.width, view->frame.height)]; - if (view->hints[PUGL_RESIZABLE]) { - [drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - } else { - [drawView setAutoresizingMask:NSViewNotSizable]; - } - - impl->drawView = drawView; - return PUGL_SUCCESS; -} - -static PuglStatus -puglMacStubDestroy(PuglView* view) -{ - PuglStubView* const drawView = (PuglStubView*)view->impl->drawView; - - [drawView removeFromSuperview]; - [drawView release]; - - view->impl->drawView = nil; - return PUGL_SUCCESS; -} - -const PuglBackend* -puglStubBackend(void) -{ - static const PuglBackend backend = {puglStubConfigure, - puglMacStubCreate, - puglMacStubDestroy, - puglStubEnter, - puglStubLeave, - puglStubGetContext}; - - return &backend; -} diff --git a/subprojects/nk_pugl/pugl/src/mac_vulkan.m b/subprojects/nk_pugl/pugl/src/mac_vulkan.m deleted file mode 100644 index 22fff10..0000000 --- a/subprojects/nk_pugl/pugl/src/mac_vulkan.m +++ /dev/null @@ -1,211 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#define VK_NO_PROTOTYPES 1 - -#include "implementation.h" -#include "mac.h" -#include "stub.h" -#include "types.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" -#include "pugl/vulkan.h" - -#include -#include - -#import -#import - -#include - -#include -#include - -@interface PuglVulkanView : NSView - -@end - -@implementation PuglVulkanView { -@public - PuglView* puglview; -} - -- (id)initWithFrame:(NSRect)frame -{ - self = [super initWithFrame:frame]; - - if (self) { - self.wantsLayer = YES; - self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawOnSetNeedsDisplay; - } - - return self; -} - -- (CALayer*)makeBackingLayer -{ - CAMetalLayer* layer = [CAMetalLayer layer]; - [layer setDelegate:self]; - return layer; -} - -- (void)setFrameSize:(NSSize)newSize -{ - PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; - - [super setFrameSize:newSize]; - [wrapper setReshaped]; - - self.layer.frame = self.bounds; -} - -- (void)displayLayer:(CALayer*)layer -{ - (void)layer; - PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; - [wrapper dispatchExpose:[self bounds]]; -} - -@end - -static PuglStatus -puglMacVulkanCreate(PuglView* view) -{ - PuglInternals* impl = view->impl; - PuglVulkanView* drawView = [PuglVulkanView alloc]; - const NSRect rect = NSMakeRect(0, 0, view->frame.width, view->frame.height); - - drawView->puglview = view; - [drawView initWithFrame:rect]; - if (view->hints[PUGL_RESIZABLE]) { - [drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - } else { - [drawView setAutoresizingMask:NSViewNotSizable]; - } - - impl->drawView = drawView; - return PUGL_SUCCESS; -} - -static PuglStatus -puglMacVulkanDestroy(PuglView* view) -{ - PuglVulkanView* const drawView = (PuglVulkanView*)view->impl->drawView; - - [drawView removeFromSuperview]; - [drawView release]; - - view->impl->drawView = nil; - return PUGL_SUCCESS; -} - -struct PuglVulkanLoaderImpl { - void* libvulkan; - PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; - PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; -}; - -PuglVulkanLoader* -puglNewVulkanLoader(PuglWorld* PUGL_UNUSED(world)) -{ - PuglVulkanLoader* loader = - (PuglVulkanLoader*)calloc(1, sizeof(PuglVulkanLoader)); - if (!loader) { - return NULL; - } - - if (!(loader->libvulkan = dlopen("libvulkan.dylib", RTLD_LAZY))) { - free(loader); - return NULL; - } - - loader->vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym( - loader->libvulkan, "vkGetInstanceProcAddr"); - - loader->vkGetDeviceProcAddr = - (PFN_vkGetDeviceProcAddr)dlsym(loader->libvulkan, "vkGetDeviceProcAddr"); - - return loader; -} - -void -puglFreeVulkanLoader(PuglVulkanLoader* loader) -{ - if (loader) { - dlclose(loader->libvulkan); - free(loader); - } -} - -PFN_vkGetInstanceProcAddr -puglGetInstanceProcAddrFunc(const PuglVulkanLoader* loader) -{ - return loader->vkGetInstanceProcAddr; -} - -PFN_vkGetDeviceProcAddr -puglGetDeviceProcAddrFunc(const PuglVulkanLoader* loader) -{ - return loader->vkGetDeviceProcAddr; -} - -const PuglBackend* -puglVulkanBackend(void) -{ - static const PuglBackend backend = {puglStubConfigure, - puglMacVulkanCreate, - puglMacVulkanDestroy, - puglStubEnter, - puglStubLeave, - puglStubGetContext}; - - return &backend; -} - -const char* const* -puglGetInstanceExtensions(uint32_t* const count) -{ - static const char* const extensions[] = {"VK_KHR_surface", - "VK_MVK_macos_surface"}; - - *count = 2; - return extensions; -} - -VkResult -puglCreateSurface(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr, - PuglView* const view, - VkInstance instance, - const VkAllocationCallbacks* const allocator, - VkSurfaceKHR* const surface) -{ - PuglInternals* const impl = view->impl; - - PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK = - (PFN_vkCreateMacOSSurfaceMVK)vkGetInstanceProcAddr( - instance, "vkCreateMacOSSurfaceMVK"); - - const VkMacOSSurfaceCreateInfoMVK info = { - VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, - NULL, - 0, - impl->drawView, - }; - - return vkCreateMacOSSurfaceMVK(instance, &info, allocator, surface); -} diff --git a/subprojects/nk_pugl/pugl/src/stub.h b/subprojects/nk_pugl/pugl/src/stub.h deleted file mode 100644 index c816679..0000000 --- a/subprojects/nk_pugl/pugl/src/stub.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_DETAIL_STUB_H -#define PUGL_DETAIL_STUB_H - -#include "pugl/pugl.h" - -#include - -PUGL_BEGIN_DECLS - -static inline PuglStatus -puglStubConfigure(PuglView* view) -{ - (void)view; - return PUGL_SUCCESS; -} - -static inline PuglStatus -puglStubCreate(PuglView* view) -{ - (void)view; - return PUGL_SUCCESS; -} - -static inline PuglStatus -puglStubDestroy(PuglView* view) -{ - (void)view; - return PUGL_SUCCESS; -} - -static inline PuglStatus -puglStubEnter(PuglView* view, const PuglEventExpose* expose) -{ - (void)view; - (void)expose; - return PUGL_SUCCESS; -} - -static inline PuglStatus -puglStubLeave(PuglView* view, const PuglEventExpose* expose) -{ - (void)view; - (void)expose; - return PUGL_SUCCESS; -} - -static inline void* -puglStubGetContext(PuglView* view) -{ - (void)view; - return NULL; -} - -PUGL_END_DECLS - -#endif // PUGL_DETAIL_STUB_H diff --git a/subprojects/nk_pugl/pugl/src/types.h b/subprojects/nk_pugl/pugl/src/types.h deleted file mode 100644 index 6fa658f..0000000 --- a/subprojects/nk_pugl/pugl/src/types.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_DETAIL_TYPES_H -#define PUGL_DETAIL_TYPES_H - -#include "pugl/pugl.h" - -#include -#include -#include - -// Unused parameter macro to suppresses warnings and make it impossible to use -#if defined(__cplusplus) -# define PUGL_UNUSED(name) -#elif defined(__GNUC__) || defined(__clang__) -# define PUGL_UNUSED(name) name##_unused __attribute__((__unused__)) -#else -# define PUGL_UNUSED(name) name -#endif - -/// Platform-specific world internals -typedef struct PuglWorldInternalsImpl PuglWorldInternals; - -/// Platform-specific view internals -typedef struct PuglInternalsImpl PuglInternals; - -/// View hints -typedef int PuglHints[PUGL_NUM_VIEW_HINTS]; - -/// Blob of arbitrary data -typedef struct { - void* data; ///< Dynamically allocated data - size_t len; ///< Length of data in bytes -} PuglBlob; - -/// Cross-platform view definition -struct PuglViewImpl { - PuglWorld* world; - const PuglBackend* backend; - PuglInternals* impl; - PuglHandle handle; - PuglEventFunc eventFunc; - char* title; - PuglBlob clipboard; - PuglBlob clipboardType; - PuglNativeView parent; - uintptr_t transientParent; - PuglRect frame; - PuglEventConfigure lastConfigure; - PuglHints hints; - int defaultWidth; - int defaultHeight; - int minWidth; - int minHeight; - int maxWidth; - int maxHeight; - int minAspectX; - int minAspectY; - int maxAspectX; - int maxAspectY; - bool visible; -}; - -/// Cross-platform world definition -struct PuglWorldImpl { - PuglWorldInternals* impl; - PuglWorldHandle handle; - char* className; - double startTime; - size_t numViews; - PuglView** views; -}; - -/// Opaque surface used by graphics backend -typedef void PuglSurface; - -/// Graphics backend interface -struct PuglBackendImpl { - /// Get visual information from display and setup view as necessary - PuglStatus (*configure)(PuglView*); - - /// Create surface and drawing context - PuglStatus (*create)(PuglView*); - - /// Destroy surface and drawing context - PuglStatus (*destroy)(PuglView*); - - /// Enter drawing context, for drawing if expose is non-null - PuglStatus (*enter)(PuglView*, const PuglEventExpose*); - - /// Leave drawing context, after drawing if expose is non-null - PuglStatus (*leave)(PuglView*, const PuglEventExpose*); - - /// Return the puglGetContext() handle for the application, if any - void* (*getContext)(PuglView*); -}; - -#endif // PUGL_DETAIL_TYPES_H diff --git a/subprojects/nk_pugl/pugl/src/win.c b/subprojects/nk_pugl/pugl/src/win.c deleted file mode 100644 index 1e11520..0000000 --- a/subprojects/nk_pugl/pugl/src/win.c +++ /dev/null @@ -1,1142 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "win.h" - -#include "implementation.h" -#include "stub.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -#include -#include - -#include -#include -#include -#include -#include - -#ifndef WM_MOUSEWHEEL -# define WM_MOUSEWHEEL 0x020A -#endif -#ifndef WM_MOUSEHWHEEL -# define WM_MOUSEHWHEEL 0x020E -#endif -#ifndef WHEEL_DELTA -# define WHEEL_DELTA 120 -#endif -#ifndef GWLP_USERDATA -# define GWLP_USERDATA (-21) -#endif - -#define PUGL_LOCAL_CLOSE_MSG (WM_USER + 50) -#define PUGL_LOCAL_MARK_MSG (WM_USER + 51) -#define PUGL_LOCAL_CLIENT_MSG (WM_USER + 52) -#define PUGL_USER_TIMER_MIN 9470 - -typedef BOOL(WINAPI* PFN_SetProcessDPIAware)(void); - -LRESULT CALLBACK -wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); - -static wchar_t* -puglUtf8ToWideChar(const char* const utf8) -{ - const int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0); - if (len > 0) { - wchar_t* result = (wchar_t*)calloc((size_t)len, sizeof(wchar_t)); - MultiByteToWideChar(CP_UTF8, 0, utf8, -1, result, len); - return result; - } - - return NULL; -} - -static char* -puglWideCharToUtf8(const wchar_t* const wstr, size_t* len) -{ - int n = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL); - if (n > 0) { - char* result = (char*)calloc((size_t)n, sizeof(char)); - WideCharToMultiByte(CP_UTF8, 0, wstr, -1, result, n, NULL, NULL); - *len = (size_t)n; - return result; - } - - return NULL; -} - -static bool -puglRegisterWindowClass(const char* name) -{ - WNDCLASSEX wc = {0}; - if (GetClassInfoEx(GetModuleHandle(NULL), name, &wc)) { - return true; // Already registered - } - - wc.cbSize = sizeof(wc); - wc.style = CS_OWNDC; - wc.lpfnWndProc = wndProc; - wc.hInstance = GetModuleHandle(NULL); - wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); - wc.lpszClassName = name; - - return RegisterClassEx(&wc); -} - -PuglWorldInternals* -puglInitWorldInternals(PuglWorldType PUGL_UNUSED(type), - PuglWorldFlags PUGL_UNUSED(flags)) -{ - PuglWorldInternals* impl = - (PuglWorldInternals*)calloc(1, sizeof(PuglWorldInternals)); - if (!impl) { - return NULL; - } - - HMODULE user32 = LoadLibrary("user32.dll"); - if (user32) { - PFN_SetProcessDPIAware SetProcessDPIAware = - (PFN_SetProcessDPIAware)GetProcAddress(user32, "SetProcessDPIAware"); - if (SetProcessDPIAware) { - SetProcessDPIAware(); - } - - FreeLibrary(user32); - } - - LARGE_INTEGER frequency; - QueryPerformanceFrequency(&frequency); - impl->timerFrequency = (double)frequency.QuadPart; - - return impl; -} - -void* -puglGetNativeWorld(PuglWorld* PUGL_UNUSED(world)) -{ - return GetModuleHandle(NULL); -} - -PuglInternals* -puglInitViewInternals(void) -{ - return (PuglInternals*)calloc(1, sizeof(PuglInternals)); -} - -static PuglStatus -puglPollWinEvents(PuglWorld* world, const double timeout) -{ - (void)world; - - if (timeout < 0) { - WaitMessage(); - } else { - MsgWaitForMultipleObjects( - 0, NULL, FALSE, (DWORD)(timeout * 1e3), QS_ALLEVENTS); - } - return PUGL_SUCCESS; -} - -PuglStatus -puglRealize(PuglView* view) -{ - PuglInternals* impl = view->impl; - if (impl->hwnd) { - return PUGL_FAILURE; - } - - // Getting depth from the display mode seems tedious, just set usual values - if (view->hints[PUGL_RED_BITS] == PUGL_DONT_CARE) { - view->hints[PUGL_RED_BITS] = 8; - } - if (view->hints[PUGL_BLUE_BITS] == PUGL_DONT_CARE) { - view->hints[PUGL_BLUE_BITS] = 8; - } - if (view->hints[PUGL_GREEN_BITS] == PUGL_DONT_CARE) { - view->hints[PUGL_GREEN_BITS] = 8; - } - if (view->hints[PUGL_ALPHA_BITS] == PUGL_DONT_CARE) { - view->hints[PUGL_ALPHA_BITS] = 8; - } - - // Get refresh rate for resize draw timer - DEVMODEA devMode = {0}; - EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &devMode); - view->hints[PUGL_REFRESH_RATE] = (int)devMode.dmDisplayFrequency; - - // Register window class if necessary - if (!puglRegisterWindowClass(view->world->className)) { - return PUGL_REGISTRATION_FAILED; - } - - if (!view->backend || !view->backend->configure) { - return PUGL_BAD_BACKEND; - } - - PuglStatus st = PUGL_SUCCESS; - if ((st = view->backend->configure(view)) || - (st = view->backend->create(view))) { - return st; - } - - if (view->title) { - puglSetWindowTitle(view, view->title); - } - - view->impl->cursor = LoadCursor(NULL, IDC_ARROW); - - puglSetFrame(view, view->frame); - SetWindowLongPtr(impl->hwnd, GWLP_USERDATA, (LONG_PTR)view); - - puglDispatchSimpleEvent(view, PUGL_CREATE); - - return PUGL_SUCCESS; -} - -PuglStatus -puglShow(PuglView* view) -{ - PuglInternals* impl = view->impl; - - if (!impl->hwnd) { - const PuglStatus st = puglRealize(view); - if (st) { - return st; - } - } - - ShowWindow(impl->hwnd, SW_SHOWNORMAL); - SetFocus(impl->hwnd); - return PUGL_SUCCESS; -} - -PuglStatus -puglHide(PuglView* view) -{ - PuglInternals* impl = view->impl; - - ShowWindow(impl->hwnd, SW_HIDE); - return PUGL_SUCCESS; -} - -void -puglFreeViewInternals(PuglView* view) -{ - if (view) { - if (view->backend) { - view->backend->destroy(view); - } - - ReleaseDC(view->impl->hwnd, view->impl->hdc); - DestroyWindow(view->impl->hwnd); - free(view->impl); - } -} - -void -puglFreeWorldInternals(PuglWorld* world) -{ - UnregisterClass(world->className, NULL); - free(world->impl); -} - -static PuglKey -keySymToSpecial(WPARAM sym) -{ - // clang-format off - switch (sym) { - case VK_F1: return PUGL_KEY_F1; - case VK_F2: return PUGL_KEY_F2; - case VK_F3: return PUGL_KEY_F3; - case VK_F4: return PUGL_KEY_F4; - case VK_F5: return PUGL_KEY_F5; - case VK_F6: return PUGL_KEY_F6; - case VK_F7: return PUGL_KEY_F7; - case VK_F8: return PUGL_KEY_F8; - case VK_F9: return PUGL_KEY_F9; - case VK_F10: return PUGL_KEY_F10; - case VK_F11: return PUGL_KEY_F11; - case VK_F12: return PUGL_KEY_F12; - case VK_BACK: return PUGL_KEY_BACKSPACE; - case VK_DELETE: return PUGL_KEY_DELETE; - case VK_LEFT: return PUGL_KEY_LEFT; - case VK_UP: return PUGL_KEY_UP; - case VK_RIGHT: return PUGL_KEY_RIGHT; - case VK_DOWN: return PUGL_KEY_DOWN; - case VK_PRIOR: return PUGL_KEY_PAGE_UP; - case VK_NEXT: return PUGL_KEY_PAGE_DOWN; - case VK_HOME: return PUGL_KEY_HOME; - case VK_END: return PUGL_KEY_END; - case VK_INSERT: return PUGL_KEY_INSERT; - case VK_SHIFT: - case VK_LSHIFT: return PUGL_KEY_SHIFT_L; - case VK_RSHIFT: return PUGL_KEY_SHIFT_R; - case VK_CONTROL: - case VK_LCONTROL: return PUGL_KEY_CTRL_L; - case VK_RCONTROL: return PUGL_KEY_CTRL_R; - case VK_MENU: - case VK_LMENU: return PUGL_KEY_ALT_L; - case VK_RMENU: return PUGL_KEY_ALT_R; - case VK_LWIN: return PUGL_KEY_SUPER_L; - case VK_RWIN: return PUGL_KEY_SUPER_R; - case VK_CAPITAL: return PUGL_KEY_CAPS_LOCK; - case VK_SCROLL: return PUGL_KEY_SCROLL_LOCK; - case VK_NUMLOCK: return PUGL_KEY_NUM_LOCK; - case VK_SNAPSHOT: return PUGL_KEY_PRINT_SCREEN; - case VK_PAUSE: return PUGL_KEY_PAUSE; - } - // clang-format on - - return (PuglKey)0; -} - -static uint32_t -getModifiers(void) -{ - // clang-format off - return (((GetKeyState(VK_SHIFT) < 0) ? PUGL_MOD_SHIFT : 0u) | - ((GetKeyState(VK_CONTROL) < 0) ? PUGL_MOD_CTRL : 0u) | - ((GetKeyState(VK_MENU) < 0) ? PUGL_MOD_ALT : 0u) | - ((GetKeyState(VK_LWIN) < 0) ? PUGL_MOD_SUPER : 0u) | - ((GetKeyState(VK_RWIN) < 0) ? PUGL_MOD_SUPER : 0u)); - // clang-format on -} - -static void -initMouseEvent(PuglEvent* event, - PuglView* view, - int button, - bool press, - LPARAM lParam) -{ - POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; - ClientToScreen(view->impl->hwnd, &pt); - - if (press) { - SetCapture(view->impl->hwnd); - } else { - ReleaseCapture(); - } - - event->button.time = GetMessageTime() / 1e3; - event->button.type = press ? PUGL_BUTTON_PRESS : PUGL_BUTTON_RELEASE; - event->button.x = GET_X_LPARAM(lParam); - event->button.y = GET_Y_LPARAM(lParam); - event->button.xRoot = pt.x; - event->button.yRoot = pt.y; - event->button.state = getModifiers(); - event->button.button = (uint32_t)button; -} - -static void -initScrollEvent(PuglEvent* event, PuglView* view, LPARAM lParam) -{ - POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; - ScreenToClient(view->impl->hwnd, &pt); - - event->scroll.time = GetMessageTime() / 1e3; - event->scroll.type = PUGL_SCROLL; - event->scroll.x = pt.x; - event->scroll.y = pt.y; - event->scroll.xRoot = GET_X_LPARAM(lParam); - event->scroll.yRoot = GET_Y_LPARAM(lParam); - event->scroll.state = getModifiers(); - event->scroll.dx = 0; - event->scroll.dy = 0; -} - -/// Return the code point for buf, or the replacement character on error -static uint32_t -puglDecodeUTF16(const wchar_t* buf, const int len) -{ - const uint32_t c0 = buf[0]; - const uint32_t c1 = buf[0]; - if (c0 >= 0xD800 && c0 < 0xDC00) { - if (len < 2) { - return 0xFFFD; // Surrogate, but length is only 1 - } else if (c1 >= 0xDC00 && c1 <= 0xDFFF) { - return ((c0 & 0x03FF) << 10) + (c1 & 0x03FF) + 0x10000; - } - - return 0xFFFD; // Unpaired surrogates - } - - return c0; -} - -static void -initKeyEvent(PuglEventKey* event, - PuglView* view, - bool press, - WPARAM wParam, - LPARAM lParam) -{ - POINT rpos = {0, 0}; - GetCursorPos(&rpos); - - POINT cpos = {rpos.x, rpos.y}; - ScreenToClient(view->impl->hwnd, &rpos); - - const unsigned scode = (uint32_t)((lParam & 0xFF0000) >> 16); - const unsigned vkey = - ((wParam == VK_SHIFT) ? MapVirtualKey(scode, MAPVK_VSC_TO_VK_EX) - : (unsigned)wParam); - - const unsigned vcode = MapVirtualKey(vkey, MAPVK_VK_TO_VSC); - const unsigned kchar = MapVirtualKey(vkey, MAPVK_VK_TO_CHAR); - const bool dead = kchar >> (sizeof(UINT) * 8 - 1) & 1; - const bool ext = lParam & 0x01000000; - - event->type = press ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE; - event->time = GetMessageTime() / 1e3; - event->state = getModifiers(); - event->xRoot = rpos.x; - event->yRoot = rpos.y; - event->x = cpos.x; - event->y = cpos.y; - event->keycode = (uint32_t)((lParam & 0xFF0000) >> 16); - event->key = 0; - - const PuglKey special = keySymToSpecial(vkey); - if (special) { - if (ext && (special == PUGL_KEY_CTRL || special == PUGL_KEY_ALT)) { - event->key = (uint32_t)special + 1u; // Right hand key - } else { - event->key = (uint32_t)special; - } - } else if (!dead) { - // Translate unshifted key - BYTE keyboardState[256] = {0}; - wchar_t buf[5] = {0}; - - event->key = puglDecodeUTF16( - buf, ToUnicode(vkey, vcode, keyboardState, buf, 4, 1 << 2)); - } -} - -static void -initCharEvent(PuglEvent* event, PuglView* view, WPARAM wParam, LPARAM lParam) -{ - const wchar_t utf16[2] = {wParam & 0xFFFF, - (wchar_t)((wParam >> 16) & 0xFFFF)}; - - initKeyEvent(&event->key, view, true, wParam, lParam); - event->type = PUGL_TEXT; - event->text.character = puglDecodeUTF16(utf16, 2); - - if (!WideCharToMultiByte( - CP_UTF8, 0, utf16, 2, event->text.string, 8, NULL, NULL)) { - memset(event->text.string, 0, 8); - } -} - -static bool -ignoreKeyEvent(PuglView* view, LPARAM lParam) -{ - return view->hints[PUGL_IGNORE_KEY_REPEAT] && (lParam & (1 << 30)); -} - -static RECT -handleConfigure(PuglView* view, PuglEvent* event) -{ - RECT rect; - GetClientRect(view->impl->hwnd, &rect); - MapWindowPoints(view->impl->hwnd, - view->parent ? (HWND)view->parent : HWND_DESKTOP, - (LPPOINT)&rect, - 2); - - const LONG width = rect.right - rect.left; - const LONG height = rect.bottom - rect.top; - - view->frame.x = rect.left; - view->frame.y = rect.top; - - event->configure.type = PUGL_CONFIGURE; - event->configure.x = view->frame.x; - event->configure.y = view->frame.y; - event->configure.width = width; - event->configure.height = height; - - if (view->frame.width != width || view->frame.height != height) { - view->frame.width = width; - view->frame.height = height; - } - - return rect; -} - -static void -handleCrossing(PuglView* view, const PuglEventType type, POINT pos) -{ - POINT root_pos = pos; - ClientToScreen(view->impl->hwnd, &root_pos); - - const PuglEventCrossing ev = { - type, - 0, - GetMessageTime() / 1e3, - (double)pos.x, - (double)pos.y, - (double)root_pos.x, - (double)root_pos.y, - getModifiers(), - PUGL_CROSSING_NORMAL, - }; - - puglDispatchEvent(view, (const PuglEvent*)&ev); -} - -static void -constrainAspect(const PuglView* const view, - RECT* const size, - const WPARAM wParam) -{ - const float minA = (float)view->minAspectX / (float)view->minAspectY; - const float maxA = (float)view->maxAspectX / (float)view->maxAspectY; - const float w = (float)(size->right - size->left); - const float h = (float)(size->bottom - size->top); - const float a = w / h; - - switch (wParam) { - case WMSZ_TOP: - size->top = (a < minA ? (LONG)((float)size->bottom - w * minA) - : a > maxA ? (LONG)((float)size->bottom - w * maxA) - : size->top); - break; - case WMSZ_TOPRIGHT: - case WMSZ_RIGHT: - case WMSZ_BOTTOMRIGHT: - size->right = (a < minA ? (LONG)((float)size->left + h * minA) - : a > maxA ? (LONG)((float)size->left + h * maxA) - : size->right); - break; - case WMSZ_BOTTOM: - size->bottom = (a < minA ? (LONG)((float)size->top + w * minA) - : a > maxA ? (LONG)((float)size->top + w * maxA) - : size->bottom); - break; - case WMSZ_BOTTOMLEFT: - case WMSZ_LEFT: - case WMSZ_TOPLEFT: - size->left = (a < minA ? (LONG)((float)size->right - h * minA) - : a > maxA ? (LONG)((float)size->right - h * maxA) - : size->left); - break; - } -} - -static LRESULT -handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) -{ - PuglEvent event = {{PUGL_NOTHING, 0}}; - RECT rect = {0, 0, 0, 0}; - POINT pt = {0, 0}; - MINMAXINFO* mmi = NULL; - void* dummy_ptr = NULL; - - if (InSendMessageEx(dummy_ptr)) { - event.any.flags |= PUGL_IS_SEND_EVENT; - } - - switch (message) { - case WM_SETCURSOR: - if (LOWORD(lParam) == HTCLIENT) { - SetCursor(view->impl->cursor); - } else { - return DefWindowProc(view->impl->hwnd, message, wParam, lParam); - } - break; - case WM_SHOWWINDOW: - if (wParam) { - handleConfigure(view, &event); - puglDispatchEvent(view, &event); - event.type = PUGL_NOTHING; - - RedrawWindow(view->impl->hwnd, - NULL, - NULL, - RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_INTERNALPAINT); - } - - if ((bool)wParam != view->visible) { - view->visible = wParam; - event.any.type = wParam ? PUGL_MAP : PUGL_UNMAP; - } - break; - case WM_SIZE: - handleConfigure(view, &event); - InvalidateRect(view->impl->hwnd, NULL, false); - break; - case WM_SIZING: - if (view->minAspectX) { - constrainAspect(view, (RECT*)lParam, wParam); - return TRUE; - } - break; - case WM_ENTERSIZEMOVE: - case WM_ENTERMENULOOP: - puglDispatchSimpleEvent(view, PUGL_LOOP_ENTER); - break; - case WM_TIMER: - if (wParam >= PUGL_USER_TIMER_MIN) { - PuglEvent ev = {{PUGL_TIMER, 0}}; - ev.timer.id = wParam - PUGL_USER_TIMER_MIN; - puglDispatchEvent(view, &ev); - } - break; - case WM_EXITSIZEMOVE: - case WM_EXITMENULOOP: - puglDispatchSimpleEvent(view, PUGL_LOOP_LEAVE); - break; - case WM_GETMINMAXINFO: - mmi = (MINMAXINFO*)lParam; - mmi->ptMinTrackSize.x = view->minWidth; - mmi->ptMinTrackSize.y = view->minHeight; - if (view->maxWidth > 0 && view->maxHeight > 0) { - mmi->ptMaxTrackSize.x = view->maxWidth; - mmi->ptMaxTrackSize.y = view->maxHeight; - } - break; - case WM_PAINT: - GetUpdateRect(view->impl->hwnd, &rect, false); - event.expose.type = PUGL_EXPOSE; - event.expose.x = rect.left; - event.expose.y = rect.top; - event.expose.width = rect.right - rect.left; - event.expose.height = rect.bottom - rect.top; - break; - case WM_ERASEBKGND: - return true; - case WM_MOUSEMOVE: - pt.x = GET_X_LPARAM(lParam); - pt.y = GET_Y_LPARAM(lParam); - - if (!view->impl->mouseTracked) { - TRACKMOUSEEVENT tme = {0}; - - tme.cbSize = sizeof(tme); - tme.dwFlags = TME_LEAVE; - tme.hwndTrack = view->impl->hwnd; - TrackMouseEvent(&tme); - - handleCrossing(view, PUGL_POINTER_IN, pt); - view->impl->mouseTracked = true; - } - - ClientToScreen(view->impl->hwnd, &pt); - event.motion.type = PUGL_MOTION; - event.motion.time = GetMessageTime() / 1e3; - event.motion.x = GET_X_LPARAM(lParam); - event.motion.y = GET_Y_LPARAM(lParam); - event.motion.xRoot = pt.x; - event.motion.yRoot = pt.y; - event.motion.state = getModifiers(); - break; - case WM_MOUSELEAVE: - GetCursorPos(&pt); - ScreenToClient(view->impl->hwnd, &pt); - handleCrossing(view, PUGL_POINTER_OUT, pt); - view->impl->mouseTracked = false; - break; - case WM_LBUTTONDOWN: - initMouseEvent(&event, view, 1, true, lParam); - break; - case WM_MBUTTONDOWN: - initMouseEvent(&event, view, 2, true, lParam); - break; - case WM_RBUTTONDOWN: - initMouseEvent(&event, view, 3, true, lParam); - break; - case WM_LBUTTONUP: - initMouseEvent(&event, view, 1, false, lParam); - break; - case WM_MBUTTONUP: - initMouseEvent(&event, view, 2, false, lParam); - break; - case WM_RBUTTONUP: - initMouseEvent(&event, view, 3, false, lParam); - break; - case WM_MOUSEWHEEL: - initScrollEvent(&event, view, lParam); - event.scroll.dy = GET_WHEEL_DELTA_WPARAM(wParam) / (double)WHEEL_DELTA; - event.scroll.direction = - (event.scroll.dy > 0 ? PUGL_SCROLL_UP : PUGL_SCROLL_DOWN); - break; - case WM_MOUSEHWHEEL: - initScrollEvent(&event, view, lParam); - event.scroll.dx = GET_WHEEL_DELTA_WPARAM(wParam) / (double)WHEEL_DELTA; - event.scroll.direction = - (event.scroll.dx > 0 ? PUGL_SCROLL_RIGHT : PUGL_SCROLL_LEFT); - break; - case WM_KEYDOWN: - if (!ignoreKeyEvent(view, lParam)) { - initKeyEvent(&event.key, view, true, wParam, lParam); - } - break; - case WM_KEYUP: - initKeyEvent(&event.key, view, false, wParam, lParam); - break; - case WM_CHAR: - initCharEvent(&event, view, wParam, lParam); - break; - case WM_SETFOCUS: - event.type = PUGL_FOCUS_IN; - break; - case WM_KILLFOCUS: - event.type = PUGL_FOCUS_OUT; - break; - case WM_SYSKEYDOWN: - initKeyEvent(&event.key, view, true, wParam, lParam); - break; - case WM_SYSKEYUP: - initKeyEvent(&event.key, view, false, wParam, lParam); - break; - case WM_SYSCHAR: - return TRUE; - case PUGL_LOCAL_CLIENT_MSG: - event.client.type = PUGL_CLIENT; - event.client.data1 = (uintptr_t)wParam; - event.client.data2 = (uintptr_t)lParam; - break; - case WM_QUIT: - case PUGL_LOCAL_CLOSE_MSG: - event.any.type = PUGL_CLOSE; - break; - default: - return DefWindowProc(view->impl->hwnd, message, wParam, lParam); - } - - puglDispatchEvent(view, &event); - - return 0; -} - -PuglStatus -puglGrabFocus(PuglView* view) -{ - SetFocus(view->impl->hwnd); - return PUGL_SUCCESS; -} - -bool -puglHasFocus(const PuglView* view) -{ - return GetFocus() == view->impl->hwnd; -} - -PuglStatus -puglRequestAttention(PuglView* view) -{ - FLASHWINFO info = { - sizeof(FLASHWINFO), view->impl->hwnd, FLASHW_ALL | FLASHW_TIMERNOFG, 1, 0}; - - FlashWindowEx(&info); - - return PUGL_SUCCESS; -} - -PuglStatus -puglStartTimer(PuglView* view, uintptr_t id, double timeout) -{ - const UINT msec = (UINT)floor(timeout * 1000.0); - - return (SetTimer(view->impl->hwnd, PUGL_USER_TIMER_MIN + id, msec, NULL) - ? PUGL_SUCCESS - : PUGL_UNKNOWN_ERROR); -} - -PuglStatus -puglStopTimer(PuglView* view, uintptr_t id) -{ - return (KillTimer(view->impl->hwnd, PUGL_USER_TIMER_MIN + id) - ? PUGL_SUCCESS - : PUGL_UNKNOWN_ERROR); -} - -PuglStatus -puglSendEvent(PuglView* view, const PuglEvent* event) -{ - if (event->type == PUGL_CLIENT) { - PostMessage(view->impl->hwnd, - PUGL_LOCAL_CLIENT_MSG, - (WPARAM)event->client.data1, - (LPARAM)event->client.data2); - - return PUGL_SUCCESS; - } - - return PUGL_UNSUPPORTED_TYPE; -} - -#ifndef PUGL_DISABLE_DEPRECATED -PuglStatus -puglWaitForEvent(PuglView* PUGL_UNUSED(view)) -{ - WaitMessage(); - return PUGL_SUCCESS; -} -#endif - -static PuglStatus -puglDispatchViewEvents(PuglView* view) -{ - /* Windows has no facility to process only currently queued messages, which - causes the event loop to run forever in cases like mouse movement where - the queue is constantly being filled with new messages. To work around - this, we post a message to ourselves before starting, record its time - when it is received, then break the loop on the first message that was - created afterwards. */ - - long markTime = 0; - MSG msg; - while (PeekMessage(&msg, view->impl->hwnd, 0, 0, PM_REMOVE)) { - if (msg.message == PUGL_LOCAL_MARK_MSG) { - markTime = GetMessageTime(); - } else { - TranslateMessage(&msg); - DispatchMessage(&msg); - if (markTime != 0 && GetMessageTime() > markTime) { - break; - } - } - } - - return PUGL_SUCCESS; -} - -static PuglStatus -puglDispatchWinEvents(PuglWorld* world) -{ - for (size_t i = 0; i < world->numViews; ++i) { - PostMessage(world->views[i]->impl->hwnd, PUGL_LOCAL_MARK_MSG, 0, 0); - } - - for (size_t i = 0; i < world->numViews; ++i) { - puglDispatchViewEvents(world->views[i]); - } - - return PUGL_SUCCESS; -} - -PuglStatus -puglUpdate(PuglWorld* world, double timeout) -{ - const double startTime = puglGetTime(world); - PuglStatus st = PUGL_SUCCESS; - - if (timeout < 0.0) { - st = puglPollWinEvents(world, timeout); - st = st ? st : puglDispatchWinEvents(world); - } else if (timeout == 0.0) { - st = puglDispatchWinEvents(world); - } else { - const double endTime = startTime + timeout - 0.001; - for (double t = startTime; t < endTime; t = puglGetTime(world)) { - if ((st = puglPollWinEvents(world, endTime - t)) || - (st = puglDispatchWinEvents(world))) { - break; - } - } - } - - for (size_t i = 0; i < world->numViews; ++i) { - if (world->views[i]->visible) { - puglDispatchSimpleEvent(world->views[i], PUGL_UPDATE); - } - - UpdateWindow(world->views[i]->impl->hwnd); - } - - return st; -} - -#ifndef PUGL_DISABLE_DEPRECATED -PuglStatus -puglProcessEvents(PuglView* view) -{ - return puglUpdate(view->world, 0.0); -} -#endif - -LRESULT CALLBACK -wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - PuglView* view = (PuglView*)GetWindowLongPtr(hwnd, GWLP_USERDATA); - - switch (message) { - case WM_CREATE: - PostMessage(hwnd, WM_SHOWWINDOW, TRUE, 0); - return 0; - case WM_CLOSE: - PostMessage(hwnd, PUGL_LOCAL_CLOSE_MSG, wParam, lParam); - return 0; - case WM_DESTROY: - return 0; - default: - if (view && hwnd == view->impl->hwnd) { - return handleMessage(view, message, wParam, lParam); - } else { - return DefWindowProc(hwnd, message, wParam, lParam); - } - } -} - -double -puglGetTime(const PuglWorld* world) -{ - LARGE_INTEGER count; - QueryPerformanceCounter(&count); - return ((double)count.QuadPart / world->impl->timerFrequency - - world->startTime); -} - -PuglStatus -puglPostRedisplay(PuglView* view) -{ - InvalidateRect(view->impl->hwnd, NULL, false); - return PUGL_SUCCESS; -} - -PuglStatus -puglPostRedisplayRect(PuglView* view, const PuglRect rect) -{ - const RECT r = {(long)floor(rect.x), - (long)floor(rect.y), - (long)ceil(rect.x + rect.width), - (long)ceil(rect.y + rect.height)}; - - InvalidateRect(view->impl->hwnd, &r, false); - - return PUGL_SUCCESS; -} - -PuglNativeView -puglGetNativeWindow(PuglView* view) -{ - return (PuglNativeView)view->impl->hwnd; -} - -PuglStatus -puglSetWindowTitle(PuglView* view, const char* title) -{ - puglSetString(&view->title, title); - - if (view->impl->hwnd) { - wchar_t* wtitle = puglUtf8ToWideChar(title); - if (wtitle) { - SetWindowTextW(view->impl->hwnd, wtitle); - free(wtitle); - } - } - - return PUGL_SUCCESS; -} - -PuglStatus -puglSetFrame(PuglView* view, const PuglRect frame) -{ - view->frame = frame; - - if (view->impl->hwnd) { - RECT rect = {(long)frame.x, - (long)frame.y, - (long)frame.x + (long)frame.width, - (long)frame.y + (long)frame.height}; - - AdjustWindowRectEx( - &rect, puglWinGetWindowFlags(view), FALSE, puglWinGetWindowExFlags(view)); - - if (!SetWindowPos(view->impl->hwnd, - HWND_TOP, - rect.left, - rect.top, - rect.right - rect.left, - rect.bottom - rect.top, - SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER)) { - return PUGL_UNKNOWN_ERROR; - } - } - - return PUGL_SUCCESS; -} - -PuglStatus -puglSetDefaultSize(PuglView* const view, const int width, const int height) -{ - view->defaultWidth = width; - view->defaultHeight = height; - return PUGL_SUCCESS; -} - -PuglStatus -puglSetMinSize(PuglView* const view, const int width, const int height) -{ - view->minWidth = width; - view->minHeight = height; - return PUGL_SUCCESS; -} - -PuglStatus -puglSetMaxSize(PuglView* const view, const int width, const int height) -{ - view->maxWidth = width; - view->maxHeight = height; - return PUGL_SUCCESS; -} - -PuglStatus -puglSetAspectRatio(PuglView* const view, - const int minX, - const int minY, - const int maxX, - const int maxY) -{ - view->minAspectX = minX; - view->minAspectY = minY; - view->maxAspectX = maxX; - view->maxAspectY = maxY; - return PUGL_SUCCESS; -} - -PuglStatus -puglSetTransientFor(PuglView* view, PuglNativeView parent) -{ - if (view->parent) { - return PUGL_FAILURE; - } - - view->transientParent = parent; - - if (view->impl->hwnd) { - SetWindowLongPtr(view->impl->hwnd, GWLP_HWNDPARENT, (LONG_PTR)parent); - return GetLastError() == NO_ERROR ? PUGL_SUCCESS : PUGL_FAILURE; - } - - return PUGL_SUCCESS; -} - -const void* -puglGetClipboard(PuglView* const view, - const char** const type, - size_t* const len) -{ - PuglInternals* const impl = view->impl; - - if (!IsClipboardFormatAvailable(CF_UNICODETEXT) || - !OpenClipboard(impl->hwnd)) { - return NULL; - } - - HGLOBAL mem = GetClipboardData(CF_UNICODETEXT); - wchar_t* wstr = mem ? (wchar_t*)GlobalLock(mem) : NULL; - if (!wstr) { - CloseClipboard(); - return NULL; - } - - free(view->clipboard.data); - view->clipboard.data = puglWideCharToUtf8(wstr, &view->clipboard.len); - GlobalUnlock(mem); - CloseClipboard(); - - return puglGetInternalClipboard(view, type, len); -} - -PuglStatus -puglSetClipboard(PuglView* const view, - const char* const type, - const void* const data, - const size_t len) -{ - PuglInternals* const impl = view->impl; - - if (type && strcmp(type, "text/plain")) { - return PUGL_UNSUPPORTED_TYPE; - } - - PuglStatus st = puglSetInternalClipboard(view, type, data, len); - if (st) { - return st; - } else if (!OpenClipboard(impl->hwnd)) { - return PUGL_UNKNOWN_ERROR; - } - - // Measure string and allocate global memory for clipboard - const char* str = (const char*)data; - const int wlen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); - HGLOBAL mem = - GlobalAlloc(GMEM_MOVEABLE, (size_t)(wlen + 1) * sizeof(wchar_t)); - if (!mem) { - CloseClipboard(); - return PUGL_UNKNOWN_ERROR; - } - - // Lock global memory - wchar_t* wstr = (wchar_t*)GlobalLock(mem); - if (!wstr) { - GlobalFree(mem); - CloseClipboard(); - return PUGL_UNKNOWN_ERROR; - } - - // Convert string into global memory and set it as clipboard data - MultiByteToWideChar(CP_UTF8, 0, str, (int)len, wstr, wlen); - wstr[wlen] = 0; - GlobalUnlock(mem); - SetClipboardData(CF_UNICODETEXT, mem); - CloseClipboard(); - return PUGL_SUCCESS; -} - -static const char* const cursor_ids[] = { - IDC_ARROW, // ARROW - IDC_IBEAM, // CARET - IDC_CROSS, // CROSSHAIR - IDC_HAND, // HAND - IDC_NO, // NO - IDC_SIZEWE, // LEFT_RIGHT - IDC_SIZENS, // UP_DOWN -}; - -PuglStatus -puglSetCursor(PuglView* view, PuglCursor cursor) -{ - PuglInternals* const impl = view->impl; - const unsigned index = (unsigned)cursor; - const unsigned count = sizeof(cursor_ids) / sizeof(cursor_ids[0]); - - if (index >= count) { - return PUGL_BAD_PARAMETER; - } - - const HCURSOR cur = LoadCursor(NULL, cursor_ids[index]); - if (!cur) { - return PUGL_FAILURE; - } - - impl->cursor = cur; - if (impl->mouseTracked) { - SetCursor(cur); - } - - return PUGL_SUCCESS; -} diff --git a/subprojects/nk_pugl/pugl/src/win.h b/subprojects/nk_pugl/pugl/src/win.h deleted file mode 100644 index ccab36a..0000000 --- a/subprojects/nk_pugl/pugl/src/win.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_DETAIL_WIN_H -#define PUGL_DETAIL_WIN_H - -#include "implementation.h" - -#include - -#include - -typedef PIXELFORMATDESCRIPTOR PuglWinPFD; - -struct PuglWorldInternalsImpl { - double timerFrequency; -}; - -struct PuglInternalsImpl { - PuglWinPFD pfd; - int pfId; - HWND hwnd; - HCURSOR cursor; - HDC hdc; - PuglSurface* surface; - bool flashing; - bool mouseTracked; -}; - -static inline PuglWinPFD -puglWinGetPixelFormatDescriptor(const PuglHints hints) -{ - const int rgbBits = (hints[PUGL_RED_BITS] + // - hints[PUGL_GREEN_BITS] + // - hints[PUGL_BLUE_BITS]); - - const DWORD dwFlags = hints[PUGL_DOUBLE_BUFFER] ? PFD_DOUBLEBUFFER : 0u; - - PuglWinPFD pfd; - ZeroMemory(&pfd, sizeof(pfd)); - pfd.nSize = sizeof(pfd); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | dwFlags; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cColorBits = (BYTE)rgbBits; - pfd.cRedBits = (BYTE)hints[PUGL_RED_BITS]; - pfd.cGreenBits = (BYTE)hints[PUGL_GREEN_BITS]; - pfd.cBlueBits = (BYTE)hints[PUGL_BLUE_BITS]; - pfd.cAlphaBits = (BYTE)hints[PUGL_ALPHA_BITS]; - pfd.cDepthBits = (BYTE)hints[PUGL_DEPTH_BITS]; - pfd.cStencilBits = (BYTE)hints[PUGL_STENCIL_BITS]; - pfd.iLayerType = PFD_MAIN_PLANE; - return pfd; -} - -static inline unsigned -puglWinGetWindowFlags(const PuglView* const view) -{ - const bool resizable = view->hints[PUGL_RESIZABLE]; - const unsigned sizeFlags = resizable ? (WS_SIZEBOX | WS_MAXIMIZEBOX) : 0u; - - return (WS_CLIPCHILDREN | WS_CLIPSIBLINGS | - (view->parent - ? WS_CHILD - : (WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX | sizeFlags))); -} - -static inline unsigned -puglWinGetWindowExFlags(const PuglView* const view) -{ - return WS_EX_NOINHERITLAYOUT | (view->parent ? 0u : WS_EX_APPWINDOW); -} - -static inline PuglStatus -puglWinCreateWindow(PuglView* const view, - const char* const title, - HWND* const hwnd, - HDC* const hdc) -{ - const char* className = (const char*)view->world->className; - const unsigned winFlags = puglWinGetWindowFlags(view); - const unsigned winExFlags = puglWinGetWindowExFlags(view); - - if (view->frame.width == 0.0 && view->frame.height == 0.0) { - if (view->defaultWidth == 0.0 && view->defaultHeight == 0.0) { - return PUGL_BAD_CONFIGURATION; - } - - RECT desktopRect; - GetClientRect(GetDesktopWindow(), &desktopRect); - - const int screenWidth = desktopRect.right - desktopRect.left; - const int screenHeight = desktopRect.bottom - desktopRect.top; - - view->frame.width = view->defaultWidth; - view->frame.height = view->defaultHeight; - view->frame.x = screenWidth / 2.0 - view->frame.width / 2.0; - view->frame.y = screenHeight / 2.0 - view->frame.height / 2.0; - } - - // The meaning of "parent" depends on the window type (WS_CHILD) - PuglNativeView parent = view->parent ? view->parent : view->transientParent; - - // Calculate total window size to accommodate requested view size - RECT wr = {(long)view->frame.x, - (long)view->frame.y, - (long)view->frame.width, - (long)view->frame.height}; - AdjustWindowRectEx(&wr, winFlags, FALSE, winExFlags); - - // Create window and get drawing context - if (!(*hwnd = CreateWindowEx(winExFlags, - className, - title, - winFlags, - CW_USEDEFAULT, - CW_USEDEFAULT, - wr.right - wr.left, - wr.bottom - wr.top, - (HWND)parent, - NULL, - NULL, - NULL))) { - return PUGL_REALIZE_FAILED; - } else if (!(*hdc = GetDC(*hwnd))) { - DestroyWindow(*hwnd); - *hwnd = NULL; - return PUGL_REALIZE_FAILED; - } - - return PUGL_SUCCESS; -} - -PuglStatus -puglWinStubConfigure(PuglView* view); - -PuglStatus -puglWinStubEnter(PuglView* view, const PuglEventExpose* expose); - -PuglStatus -puglWinStubLeave(PuglView* view, const PuglEventExpose* expose); - -#endif // PUGL_DETAIL_WIN_H diff --git a/subprojects/nk_pugl/pugl/src/win_cairo.c b/subprojects/nk_pugl/pugl/src/win_cairo.c deleted file mode 100644 index 9dc5ce0..0000000 --- a/subprojects/nk_pugl/pugl/src/win_cairo.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "stub.h" -#include "types.h" -#include "win.h" - -#include "pugl/cairo.h" - -#include -#include - -#include - -typedef struct { - cairo_surface_t* surface; - cairo_t* cr; - HDC drawDc; - HBITMAP drawBitmap; -} PuglWinCairoSurface; - -static PuglStatus -puglWinCairoCreateDrawContext(PuglView* view) -{ - PuglInternals* const impl = view->impl; - PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; - - surface->drawDc = CreateCompatibleDC(impl->hdc); - surface->drawBitmap = CreateCompatibleBitmap( - impl->hdc, (int)view->frame.width, (int)view->frame.height); - - DeleteObject(SelectObject(surface->drawDc, surface->drawBitmap)); - - return PUGL_SUCCESS; -} - -static PuglStatus -puglWinCairoDestroyDrawContext(PuglView* view) -{ - PuglInternals* const impl = view->impl; - PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; - - DeleteDC(surface->drawDc); - DeleteObject(surface->drawBitmap); - - surface->drawDc = NULL; - surface->drawBitmap = NULL; - - return PUGL_SUCCESS; -} - -static PuglStatus -puglWinCairoConfigure(PuglView* view) -{ - const PuglStatus st = puglWinStubConfigure(view); - - if (!st) { - view->impl->surface = - (PuglWinCairoSurface*)calloc(1, sizeof(PuglWinCairoSurface)); - } - - return st; -} - -static void -puglWinCairoClose(PuglView* view) -{ - PuglInternals* const impl = view->impl; - PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; - - cairo_surface_destroy(surface->surface); - - surface->surface = NULL; -} - -static PuglStatus -puglWinCairoOpen(PuglView* view) -{ - PuglInternals* const impl = view->impl; - PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; - - if (!(surface->surface = cairo_win32_surface_create(surface->drawDc)) || - cairo_surface_status(surface->surface) || - !(surface->cr = cairo_create(surface->surface)) || - cairo_status(surface->cr)) { - return PUGL_CREATE_CONTEXT_FAILED; - } - - return PUGL_SUCCESS; -} - -static PuglStatus -puglWinCairoDestroy(PuglView* view) -{ - PuglInternals* const impl = view->impl; - PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; - - puglWinCairoClose(view); - puglWinCairoDestroyDrawContext(view); - free(surface); - impl->surface = NULL; - - return PUGL_SUCCESS; -} - -static PuglStatus -puglWinCairoEnter(PuglView* view, const PuglEventExpose* expose) -{ - PuglStatus st = PUGL_SUCCESS; - - if (expose && !(st = puglWinCairoCreateDrawContext(view)) && - !(st = puglWinCairoOpen(view))) { - PAINTSTRUCT ps; - BeginPaint(view->impl->hwnd, &ps); - } - - return st; -} - -static PuglStatus -puglWinCairoLeave(PuglView* view, const PuglEventExpose* expose) -{ - PuglInternals* const impl = view->impl; - PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; - - if (expose) { - cairo_surface_flush(surface->surface); - BitBlt(impl->hdc, - 0, - 0, - (int)view->frame.width, - (int)view->frame.height, - surface->drawDc, - 0, - 0, - SRCCOPY); - - puglWinCairoClose(view); - puglWinCairoDestroyDrawContext(view); - - PAINTSTRUCT ps; - EndPaint(view->impl->hwnd, &ps); - } - - return PUGL_SUCCESS; -} - -static void* -puglWinCairoGetContext(PuglView* view) -{ - return ((PuglWinCairoSurface*)view->impl->surface)->cr; -} - -const PuglBackend* -puglCairoBackend() -{ - static const PuglBackend backend = {puglWinCairoConfigure, - puglStubCreate, - puglWinCairoDestroy, - puglWinCairoEnter, - puglWinCairoLeave, - puglWinCairoGetContext}; - - return &backend; -} diff --git a/subprojects/nk_pugl/pugl/src/win_gl.c b/subprojects/nk_pugl/pugl/src/win_gl.c deleted file mode 100644 index 4abd5ab..0000000 --- a/subprojects/nk_pugl/pugl/src/win_gl.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "stub.h" -#include "types.h" -#include "win.h" - -#include "pugl/gl.h" - -#include - -#include - -#include -#include - -#define WGL_DRAW_TO_WINDOW_ARB 0x2001 -#define WGL_ACCELERATION_ARB 0x2003 -#define WGL_SUPPORT_OPENGL_ARB 0x2010 -#define WGL_DOUBLE_BUFFER_ARB 0x2011 -#define WGL_PIXEL_TYPE_ARB 0x2013 -#define WGL_RED_BITS_ARB 0x2015 -#define WGL_GREEN_BITS_ARB 0x2017 -#define WGL_BLUE_BITS_ARB 0x2019 -#define WGL_ALPHA_BITS_ARB 0x201b -#define WGL_DEPTH_BITS_ARB 0x2022 -#define WGL_STENCIL_BITS_ARB 0x2023 -#define WGL_FULL_ACCELERATION_ARB 0x2027 -#define WGL_TYPE_RGBA_ARB 0x202b -#define WGL_SAMPLE_BUFFERS_ARB 0x2041 -#define WGL_SAMPLES_ARB 0x2042 - -#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define WGL_CONTEXT_FLAGS_ARB 0x2094 -#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 - -#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 -#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 -#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 - -typedef HGLRC (*WglCreateContextAttribs)(HDC, HGLRC, const int*); -typedef BOOL (*WglSwapInterval)(int); -typedef BOOL ( - *WglChoosePixelFormat)(HDC, const int*, const FLOAT*, UINT, int*, UINT*); - -typedef struct { - WglChoosePixelFormat wglChoosePixelFormat; - WglCreateContextAttribs wglCreateContextAttribs; - WglSwapInterval wglSwapInterval; -} PuglWinGlProcs; - -typedef struct { - PuglWinGlProcs procs; - HGLRC hglrc; -} PuglWinGlSurface; - -// Struct to manage the fake window used during configuration -typedef struct { - HWND hwnd; - HDC hdc; -} PuglFakeWindow; - -static PuglStatus -puglWinError(PuglFakeWindow* fakeWin, const PuglStatus status) -{ - if (fakeWin->hwnd) { - ReleaseDC(fakeWin->hwnd, fakeWin->hdc); - DestroyWindow(fakeWin->hwnd); - } - - return status; -} - -static PuglWinGlProcs -puglWinGlGetProcs(void) -{ - const PuglWinGlProcs procs = { - (WglChoosePixelFormat)(wglGetProcAddress("wglChoosePixelFormatARB")), - (WglCreateContextAttribs)(wglGetProcAddress("wglCreateContextAttribsARB")), - (WglSwapInterval)(wglGetProcAddress("wglSwapIntervalEXT"))}; - - return procs; -} - -static PuglStatus -puglWinGlConfigure(PuglView* view) -{ - PuglInternals* impl = view->impl; - - // Set attributes to default if they are unset - // (There is no GLX_DONT_CARE equivalent on Windows) - if (view->hints[PUGL_DEPTH_BITS] == PUGL_DONT_CARE) { - view->hints[PUGL_DEPTH_BITS] = 0; - } - if (view->hints[PUGL_STENCIL_BITS] == PUGL_DONT_CARE) { - view->hints[PUGL_STENCIL_BITS] = 0; - } - if (view->hints[PUGL_SAMPLES] == PUGL_DONT_CARE) { - view->hints[PUGL_SAMPLES] = 1; - } - if (view->hints[PUGL_DOUBLE_BUFFER] == PUGL_DONT_CARE) { - view->hints[PUGL_DOUBLE_BUFFER] = 1; - } - if (view->hints[PUGL_SWAP_INTERVAL] == PUGL_DONT_CARE) { - view->hints[PUGL_SWAP_INTERVAL] = 1; - } - - // clang-format off - const int pixelAttrs[] = { - WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, - WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, - WGL_SUPPORT_OPENGL_ARB, GL_TRUE, - WGL_DOUBLE_BUFFER_ARB, view->hints[PUGL_DOUBLE_BUFFER], - WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, - WGL_SAMPLE_BUFFERS_ARB, view->hints[PUGL_SAMPLES] ? 1 : 0, - WGL_SAMPLES_ARB, view->hints[PUGL_SAMPLES], - WGL_RED_BITS_ARB, view->hints[PUGL_RED_BITS], - WGL_GREEN_BITS_ARB, view->hints[PUGL_GREEN_BITS], - WGL_BLUE_BITS_ARB, view->hints[PUGL_BLUE_BITS], - WGL_ALPHA_BITS_ARB, view->hints[PUGL_ALPHA_BITS], - WGL_DEPTH_BITS_ARB, view->hints[PUGL_DEPTH_BITS], - WGL_STENCIL_BITS_ARB, view->hints[PUGL_STENCIL_BITS], - 0, - }; - // clang-format on - - PuglWinGlSurface* const surface = - (PuglWinGlSurface*)calloc(1, sizeof(PuglWinGlSurface)); - impl->surface = surface; - - // Create fake window for getting at GL context - PuglStatus st = PUGL_SUCCESS; - PuglFakeWindow fakeWin = {0, 0}; - static const char* title = "Pugl Configuration"; - if ((st = puglWinCreateWindow(view, title, &fakeWin.hwnd, &fakeWin.hdc))) { - return puglWinError(&fakeWin, st); - } - - // Set pixel format for fake window - const PuglWinPFD fakePfd = puglWinGetPixelFormatDescriptor(view->hints); - const int fakePfId = ChoosePixelFormat(fakeWin.hdc, &fakePfd); - if (!fakePfId || !SetPixelFormat(fakeWin.hdc, fakePfId, &fakePfd)) { - return puglWinError(&fakeWin, PUGL_SET_FORMAT_FAILED); - } - - // Create fake GL context to get at the functions we need - HGLRC fakeRc = wglCreateContext(fakeWin.hdc); - if (!fakeRc) { - return puglWinError(&fakeWin, PUGL_CREATE_CONTEXT_FAILED); - } - - // Enter fake context and get extension functions - wglMakeCurrent(fakeWin.hdc, fakeRc); - surface->procs = puglWinGlGetProcs(); - - if (surface->procs.wglChoosePixelFormat) { - // Choose pixel format based on attributes - UINT numFormats = 0; - if (!surface->procs.wglChoosePixelFormat( - fakeWin.hdc, pixelAttrs, NULL, 1u, &impl->pfId, &numFormats)) { - return puglWinError(&fakeWin, PUGL_SET_FORMAT_FAILED); - } - - DescribePixelFormat(impl->hdc, impl->pfId, sizeof(impl->pfd), &impl->pfd); - } else { - // Modern extensions not available, use basic pixel format - impl->pfd = fakePfd; - impl->pfId = fakePfId; - } - - // Dispose of fake window and context - wglMakeCurrent(NULL, NULL); - wglDeleteContext(fakeRc); - ReleaseDC(fakeWin.hwnd, fakeWin.hdc); - DestroyWindow(fakeWin.hwnd); - - return PUGL_SUCCESS; -} - -static PuglStatus -puglWinGlCreate(PuglView* view) -{ - PuglInternals* const impl = view->impl; - PuglWinGlSurface* const surface = (PuglWinGlSurface*)impl->surface; - PuglStatus st = PUGL_SUCCESS; - - const int contextAttribs[] = { - WGL_CONTEXT_MAJOR_VERSION_ARB, - view->hints[PUGL_CONTEXT_VERSION_MAJOR], - - WGL_CONTEXT_MINOR_VERSION_ARB, - view->hints[PUGL_CONTEXT_VERSION_MINOR], - - WGL_CONTEXT_FLAGS_ARB, - (view->hints[PUGL_USE_DEBUG_CONTEXT] ? WGL_CONTEXT_DEBUG_BIT_ARB : 0), - - WGL_CONTEXT_PROFILE_MASK_ARB, - (view->hints[PUGL_USE_COMPAT_PROFILE] - ? WGL_CONTEXT_CORE_PROFILE_BIT_ARB - : WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB), - - 0}; - - // Create real window with desired pixel format - if ((st = puglWinCreateWindow(view, "Pugl", &impl->hwnd, &impl->hdc))) { - return st; - } else if (!SetPixelFormat(impl->hdc, impl->pfId, &impl->pfd)) { - ReleaseDC(impl->hwnd, impl->hdc); - DestroyWindow(impl->hwnd); - impl->hwnd = NULL; - impl->hdc = NULL; - return PUGL_SET_FORMAT_FAILED; - } - - // Create GL context - if (surface->procs.wglCreateContextAttribs && - !(surface->hglrc = surface->procs.wglCreateContextAttribs( - impl->hdc, 0, contextAttribs))) { - return PUGL_CREATE_CONTEXT_FAILED; - } else if (!(surface->hglrc = wglCreateContext(impl->hdc))) { - return PUGL_CREATE_CONTEXT_FAILED; - } - - // Enter context and set swap interval - wglMakeCurrent(impl->hdc, surface->hglrc); - const int swapInterval = view->hints[PUGL_SWAP_INTERVAL]; - if (surface->procs.wglSwapInterval && swapInterval != PUGL_DONT_CARE) { - surface->procs.wglSwapInterval(swapInterval); - } - - return PUGL_SUCCESS; -} - -static PuglStatus -puglWinGlDestroy(PuglView* view) -{ - PuglWinGlSurface* surface = (PuglWinGlSurface*)view->impl->surface; - if (surface) { - wglMakeCurrent(NULL, NULL); - wglDeleteContext(surface->hglrc); - free(surface); - view->impl->surface = NULL; - } - - return PUGL_SUCCESS; -} - -static PuglStatus -puglWinGlEnter(PuglView* view, const PuglEventExpose* expose) -{ - PuglWinGlSurface* surface = (PuglWinGlSurface*)view->impl->surface; - - wglMakeCurrent(view->impl->hdc, surface->hglrc); - - if (expose) { - PAINTSTRUCT ps; - BeginPaint(view->impl->hwnd, &ps); - } - - return PUGL_SUCCESS; -} - -static PuglStatus -puglWinGlLeave(PuglView* view, const PuglEventExpose* expose) -{ - if (expose) { - PAINTSTRUCT ps; - EndPaint(view->impl->hwnd, &ps); - SwapBuffers(view->impl->hdc); - } - - wglMakeCurrent(NULL, NULL); - return PUGL_SUCCESS; -} - -PuglGlFunc -puglGetProcAddress(const char* name) -{ - const PuglGlFunc func = (PuglGlFunc)wglGetProcAddress(name); - - /* Windows has the annoying property that wglGetProcAddress returns NULL - for functions from OpenGL 1.1, so we fall back to pulling them directly - from opengl32.dll */ - - return func - ? func - : (PuglGlFunc)GetProcAddress(GetModuleHandle("opengl32.dll"), name); -} - -PuglStatus -puglEnterContext(PuglView* view) -{ - return view->backend->enter(view, NULL); -} - -PuglStatus -puglLeaveContext(PuglView* view) -{ - return view->backend->leave(view, NULL); -} - -const PuglBackend* -puglGlBackend(void) -{ - static const PuglBackend backend = {puglWinGlConfigure, - puglWinGlCreate, - puglWinGlDestroy, - puglWinGlEnter, - puglWinGlLeave, - puglStubGetContext}; - - return &backend; -} diff --git a/subprojects/nk_pugl/pugl/src/win_stub.c b/subprojects/nk_pugl/pugl/src/win_stub.c deleted file mode 100644 index cf86390..0000000 --- a/subprojects/nk_pugl/pugl/src/win_stub.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "stub.h" -#include "types.h" -#include "win.h" - -#include "pugl/stub.h" - -PuglStatus -puglWinStubConfigure(PuglView* view) -{ - PuglInternals* const impl = view->impl; - PuglStatus st = PUGL_SUCCESS; - - if ((st = puglWinCreateWindow(view, "Pugl", &impl->hwnd, &impl->hdc))) { - return st; - } - - impl->pfd = puglWinGetPixelFormatDescriptor(view->hints); - impl->pfId = ChoosePixelFormat(impl->hdc, &impl->pfd); - - if (!SetPixelFormat(impl->hdc, impl->pfId, &impl->pfd)) { - ReleaseDC(impl->hwnd, impl->hdc); - DestroyWindow(impl->hwnd); - impl->hwnd = NULL; - impl->hdc = NULL; - return PUGL_SET_FORMAT_FAILED; - } - - return PUGL_SUCCESS; -} - -PuglStatus -puglWinStubEnter(PuglView* view, const PuglEventExpose* expose) -{ - if (expose) { - PAINTSTRUCT ps; - BeginPaint(view->impl->hwnd, &ps); - } - - return PUGL_SUCCESS; -} - -PuglStatus -puglWinStubLeave(PuglView* view, const PuglEventExpose* expose) -{ - if (expose) { - PAINTSTRUCT ps; - EndPaint(view->impl->hwnd, &ps); - } - - return PUGL_SUCCESS; -} - -const PuglBackend* -puglStubBackend(void) -{ - static const PuglBackend backend = {puglWinStubConfigure, - puglStubCreate, - puglStubDestroy, - puglWinStubEnter, - puglWinStubLeave, - puglStubGetContext}; - - return &backend; -} diff --git a/subprojects/nk_pugl/pugl/src/win_vulkan.c b/subprojects/nk_pugl/pugl/src/win_vulkan.c deleted file mode 100644 index a892a16..0000000 --- a/subprojects/nk_pugl/pugl/src/win_vulkan.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#define VK_NO_PROTOTYPES 1 - -#include "stub.h" -#include "types.h" -#include "win.h" - -#include "pugl/stub.h" -#include "pugl/vulkan.h" - -#include -#include - -#include - -struct PuglVulkanLoaderImpl { - HMODULE libvulkan; - PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; - PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; -}; - -PuglVulkanLoader* -puglNewVulkanLoader(PuglWorld* PUGL_UNUSED(world)) -{ - PuglVulkanLoader* loader = - (PuglVulkanLoader*)calloc(1, sizeof(PuglVulkanLoader)); - if (!loader) { - return NULL; - } - - if (!(loader->libvulkan = LoadLibrary("vulkan-1.dll"))) { - free(loader); - return NULL; - } - - loader->vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)GetProcAddress( - loader->libvulkan, "vkGetInstanceProcAddr"); - - loader->vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)GetProcAddress( - loader->libvulkan, "vkGetDeviceProcAddr"); - - return loader; -} - -void -puglFreeVulkanLoader(PuglVulkanLoader* loader) -{ - if (loader) { - FreeLibrary(loader->libvulkan); - free(loader); - } -} - -PFN_vkGetInstanceProcAddr -puglGetInstanceProcAddrFunc(const PuglVulkanLoader* loader) -{ - return loader->vkGetInstanceProcAddr; -} - -PFN_vkGetDeviceProcAddr -puglGetDeviceProcAddrFunc(const PuglVulkanLoader* loader) -{ - return loader->vkGetDeviceProcAddr; -} - -const PuglBackend* -puglVulkanBackend() -{ - static const PuglBackend backend = {puglWinStubConfigure, - puglStubCreate, - puglStubDestroy, - puglWinStubEnter, - puglWinStubLeave, - puglStubGetContext}; - - return &backend; -} - -const char* const* -puglGetInstanceExtensions(uint32_t* const count) -{ - static const char* const extensions[] = {"VK_KHR_surface", - "VK_KHR_win32_surface"}; - - *count = 2; - return extensions; -} - -VkResult -puglCreateSurface(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr, - PuglView* const view, - VkInstance instance, - const VkAllocationCallbacks* const pAllocator, - VkSurfaceKHR* const pSurface) -{ - PuglInternals* const impl = view->impl; - - PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR = - (PFN_vkCreateWin32SurfaceKHR)vkGetInstanceProcAddr( - instance, "vkCreateWin32SurfaceKHR"); - - const VkWin32SurfaceCreateInfoKHR createInfo = { - VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, - NULL, - 0, - GetModuleHandle(NULL), - impl->hwnd, - }; - - return vkCreateWin32SurfaceKHR(instance, &createInfo, pAllocator, pSurface); -} diff --git a/subprojects/nk_pugl/pugl/src/x11.c b/subprojects/nk_pugl/pugl/src/x11.c deleted file mode 100644 index 2cdb0f3..0000000 --- a/subprojects/nk_pugl/pugl/src/x11.c +++ /dev/null @@ -1,1431 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - Copyright 2013 Robin Gareus - Copyright 2011-2012 Ben Loftis, Harrison Consoles - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#define _POSIX_C_SOURCE 199309L - -#include "x11.h" - -#include "implementation.h" -#include "types.h" - -#include "pugl/pugl.h" - -#include -#include -#include -#include -#include - -#ifdef HAVE_XRANDR -# include -#endif - -#ifdef HAVE_XSYNC -# include -# include -#endif - -#ifdef HAVE_XCURSOR -# include -# include -#endif - -#include -#include - -#include -#include -#include -#include -#include -#include - -#ifndef MIN -# define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif - -#ifndef MAX -# define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#endif - -enum WmClientStateMessageAction { - WM_STATE_REMOVE, - WM_STATE_ADD, - WM_STATE_TOGGLE -}; - -static bool -puglInitXSync(PuglWorldInternals* impl) -{ -#ifdef HAVE_XSYNC - int syncMajor = 0; - int syncMinor = 0; - int errorBase = 0; - XSyncSystemCounter* counters = NULL; - int numCounters = 0; - - if (XSyncQueryExtension(impl->display, &impl->syncEventBase, &errorBase) && - XSyncInitialize(impl->display, &syncMajor, &syncMinor) && - (counters = XSyncListSystemCounters(impl->display, &numCounters))) { - for (int n = 0; n < numCounters; ++n) { - if (!strcmp(counters[n].name, "SERVERTIME")) { - impl->serverTimeCounter = counters[n].counter; - impl->syncSupported = true; - break; - } - } - - XSyncFreeSystemCounterList(counters); - } -#else - (void)impl; -#endif - - return false; -} - -PuglWorldInternals* -puglInitWorldInternals(PuglWorldType type, PuglWorldFlags flags) -{ - if (type == PUGL_PROGRAM && (flags & PUGL_WORLD_THREADS)) { - XInitThreads(); - } - - Display* display = XOpenDisplay(NULL); - if (!display) { - return NULL; - } - - PuglWorldInternals* impl = - (PuglWorldInternals*)calloc(1, sizeof(PuglWorldInternals)); - - impl->display = display; - - // Intern the various atoms we will need - impl->atoms.CLIPBOARD = XInternAtom(display, "CLIPBOARD", 0); - impl->atoms.UTF8_STRING = XInternAtom(display, "UTF8_STRING", 0); - impl->atoms.TARGETS = XInternAtom(display, "TARGETS", 0); - impl->atoms.WM_PROTOCOLS = XInternAtom(display, "WM_PROTOCOLS", 0); - impl->atoms.WM_DELETE_WINDOW = XInternAtom(display, "WM_DELETE_WINDOW", 0); - impl->atoms.PUGL_CLIENT_MSG = XInternAtom(display, "_PUGL_CLIENT_MSG", 0); - impl->atoms.NET_WM_NAME = XInternAtom(display, "_NET_WM_NAME", 0); - impl->atoms.NET_WM_STATE = XInternAtom(display, "_NET_WM_STATE", 0); - impl->atoms.NET_WM_STATE_DEMANDS_ATTENTION = - XInternAtom(display, "_NET_WM_STATE_DEMANDS_ATTENTION", 0); - - // Open input method - XSetLocaleModifiers(""); - if (!(impl->xim = XOpenIM(display, NULL, NULL, NULL))) { - XSetLocaleModifiers("@im="); - impl->xim = XOpenIM(display, NULL, NULL, NULL); - } - - puglInitXSync(impl); - XFlush(display); - - return impl; -} - -void* -puglGetNativeWorld(PuglWorld* world) -{ - return world->impl->display; -} - -PuglInternals* -puglInitViewInternals(void) -{ - PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); - -#ifdef HAVE_XCURSOR - impl->cursorShape = XC_arrow; -#endif - - return impl; -} - -static PuglStatus -puglPollX11Socket(PuglWorld* world, const double timeout) -{ - if (XPending(world->impl->display) > 0) { - return PUGL_SUCCESS; - } - - const int fd = ConnectionNumber(world->impl->display); - const int nfds = fd + 1; - int ret = 0; - fd_set fds; - FD_ZERO(&fds); // NOLINT - FD_SET(fd, &fds); - - if (timeout < 0.0) { - ret = select(nfds, &fds, NULL, NULL, NULL); - } else { - const long sec = (long)timeout; - const long usec = (long)((timeout - (double)sec) * 1e6); - struct timeval tv = {sec, usec}; - ret = select(nfds, &fds, NULL, NULL, &tv); - } - - return ret < 0 ? PUGL_UNKNOWN_ERROR : PUGL_SUCCESS; -} - -static PuglView* -puglFindView(PuglWorld* world, const Window window) -{ - for (size_t i = 0; i < world->numViews; ++i) { - if (world->views[i]->impl->win == window) { - return world->views[i]; - } - } - - return NULL; -} - -static PuglStatus -updateSizeHints(const PuglView* view) -{ - if (!view->impl->win) { - return PUGL_SUCCESS; - } - - Display* display = view->world->impl->display; - XSizeHints sizeHints = {0}; - - if (!view->hints[PUGL_RESIZABLE]) { - sizeHints.flags = PBaseSize | PMinSize | PMaxSize; - sizeHints.base_width = (int)view->frame.width; - sizeHints.base_height = (int)view->frame.height; - sizeHints.min_width = (int)view->frame.width; - sizeHints.min_height = (int)view->frame.height; - sizeHints.max_width = (int)view->frame.width; - sizeHints.max_height = (int)view->frame.height; - } else { - if (view->defaultWidth || view->defaultHeight) { - sizeHints.flags |= PBaseSize; - sizeHints.base_width = view->defaultWidth; - sizeHints.base_height = view->defaultHeight; - } - - if (view->minWidth || view->minHeight) { - sizeHints.flags |= PMinSize; - sizeHints.min_width = view->minWidth; - sizeHints.min_height = view->minHeight; - } - - if (view->maxWidth || view->maxHeight) { - sizeHints.flags |= PMaxSize; - sizeHints.max_width = view->maxWidth; - sizeHints.max_height = view->maxHeight; - } - - if (view->minAspectX) { - sizeHints.flags |= PAspect; - sizeHints.min_aspect.x = view->minAspectX; - sizeHints.min_aspect.y = view->minAspectY; - sizeHints.max_aspect.x = view->maxAspectX; - sizeHints.max_aspect.y = view->maxAspectY; - } - } - - XSetNormalHints(display, view->impl->win, &sizeHints); - return PUGL_SUCCESS; -} - -#ifdef HAVE_XCURSOR -static PuglStatus -puglDefineCursorShape(PuglView* view, unsigned shape) -{ - PuglInternals* const impl = view->impl; - PuglWorld* const world = view->world; - Display* const display = world->impl->display; - const Cursor cur = XcursorShapeLoadCursor(display, shape); - - if (cur) { - XDefineCursor(display, impl->win, cur); - XFreeCursor(display, cur); - return PUGL_SUCCESS; - } - - return PUGL_FAILURE; -} -#endif - -PuglStatus -puglRealize(PuglView* view) -{ - PuglInternals* const impl = view->impl; - PuglWorld* const world = view->world; - PuglX11Atoms* const atoms = &view->world->impl->atoms; - Display* const display = world->impl->display; - const int screen = DefaultScreen(display); - const Window root = RootWindow(display, screen); - const Window parent = view->parent ? (Window)view->parent : root; - XSetWindowAttributes attr = {0}; - PuglStatus st = PUGL_SUCCESS; - - // Ensure that we're unrealized and that a reasonable backend has been set - if (impl->win) { - return PUGL_FAILURE; - } - - if (!view->backend || !view->backend->configure) { - return PUGL_BAD_BACKEND; - } - - // Set the size to the default if it has not already been set - if (view->frame.width == 0.0 && view->frame.height == 0.0) { - if (view->defaultWidth == 0.0 || view->defaultHeight == 0.0) { - return PUGL_BAD_CONFIGURATION; - } - - view->frame.width = view->defaultWidth; - view->frame.height = view->defaultHeight; - } - - // Center top-level windows if a position has not been set - if (!view->parent && view->frame.x == 0.0 && view->frame.y == 0.0) { - const int screenWidth = DisplayWidth(display, screen); - const int screenHeight = DisplayHeight(display, screen); - - view->frame.x = screenWidth / 2.0 - view->frame.width / 2.0; - view->frame.y = screenHeight / 2.0 - view->frame.height / 2.0; - } - - // Configure the backend to get the visual info - impl->display = display; - impl->screen = screen; - if ((st = view->backend->configure(view)) || !impl->vi) { - view->backend->destroy(view); - return st ? st : PUGL_BACKEND_FAILED; - } - - // Create a colormap based on the visual info from the backend - attr.colormap = XCreateColormap(display, parent, impl->vi->visual, AllocNone); - - // Set the event mask to request all of the event types we react to - attr.event_mask |= ButtonPressMask; - attr.event_mask |= ButtonReleaseMask; - attr.event_mask |= EnterWindowMask; - attr.event_mask |= ExposureMask; - attr.event_mask |= FocusChangeMask; - attr.event_mask |= KeyPressMask; - attr.event_mask |= KeyReleaseMask; - attr.event_mask |= LeaveWindowMask; - attr.event_mask |= PointerMotionMask; - attr.event_mask |= StructureNotifyMask; - attr.event_mask |= VisibilityChangeMask; - - // Create the window - impl->win = XCreateWindow(display, - parent, - (int)view->frame.x, - (int)view->frame.y, - (unsigned)view->frame.width, - (unsigned)view->frame.height, - 0, - impl->vi->depth, - InputOutput, - impl->vi->visual, - CWColormap | CWEventMask, - &attr); - - // Create the backend drawing context/surface - if ((st = view->backend->create(view))) { - return st; - } - -#ifdef HAVE_XRANDR - // Set refresh rate hint to the real refresh rate - XRRScreenConfiguration* conf = XRRGetScreenInfo(display, parent); - short current_rate = XRRConfigCurrentRate(conf); - - view->hints[PUGL_REFRESH_RATE] = current_rate; - XRRFreeScreenConfigInfo(conf); -#endif - - updateSizeHints(view); - - XClassHint classHint = {world->className, world->className}; - XSetClassHint(display, impl->win, &classHint); - - if (view->title) { - puglSetWindowTitle(view, view->title); - } - - if (parent == root) { - XSetWMProtocols(display, impl->win, &atoms->WM_DELETE_WINDOW, 1); - } - - if (view->transientParent) { - XSetTransientForHint(display, impl->win, (Window)view->transientParent); - } - - // Create input context - impl->xic = XCreateIC(world->impl->xim, - XNInputStyle, - XIMPreeditNothing | XIMStatusNothing, - XNClientWindow, - impl->win, - XNFocusWindow, - impl->win, - NULL); - -#ifdef HAVE_XCURSOR - puglDefineCursorShape(view, impl->cursorShape); -#endif - - puglDispatchSimpleEvent(view, PUGL_CREATE); - - return PUGL_SUCCESS; -} - -PuglStatus -puglShow(PuglView* view) -{ - PuglStatus st = PUGL_SUCCESS; - - if (!view->impl->win) { - if ((st = puglRealize(view))) { - return st; - } - } - - XMapRaised(view->impl->display, view->impl->win); - puglPostRedisplay(view); - - return st; -} - -PuglStatus -puglHide(PuglView* view) -{ - XUnmapWindow(view->impl->display, view->impl->win); - return PUGL_SUCCESS; -} - -void -puglFreeViewInternals(PuglView* view) -{ - if (view && view->impl) { - if (view->impl->xic) { - XDestroyIC(view->impl->xic); - } - if (view->backend) { - view->backend->destroy(view); - } - if (view->impl->display) { - XDestroyWindow(view->impl->display, view->impl->win); - } - XFree(view->impl->vi); - free(view->impl); - } -} - -void -puglFreeWorldInternals(PuglWorld* world) -{ - if (world->impl->xim) { - XCloseIM(world->impl->xim); - } - XCloseDisplay(world->impl->display); - free(world->impl->timers); - free(world->impl); -} - -static PuglKey -keySymToSpecial(KeySym sym) -{ - switch (sym) { - case XK_F1: - return PUGL_KEY_F1; - case XK_F2: - return PUGL_KEY_F2; - case XK_F3: - return PUGL_KEY_F3; - case XK_F4: - return PUGL_KEY_F4; - case XK_F5: - return PUGL_KEY_F5; - case XK_F6: - return PUGL_KEY_F6; - case XK_F7: - return PUGL_KEY_F7; - case XK_F8: - return PUGL_KEY_F8; - case XK_F9: - return PUGL_KEY_F9; - case XK_F10: - return PUGL_KEY_F10; - case XK_F11: - return PUGL_KEY_F11; - case XK_F12: - return PUGL_KEY_F12; - case XK_Left: - return PUGL_KEY_LEFT; - case XK_Up: - return PUGL_KEY_UP; - case XK_Right: - return PUGL_KEY_RIGHT; - case XK_Down: - return PUGL_KEY_DOWN; - case XK_Page_Up: - return PUGL_KEY_PAGE_UP; - case XK_Page_Down: - return PUGL_KEY_PAGE_DOWN; - case XK_Home: - return PUGL_KEY_HOME; - case XK_End: - return PUGL_KEY_END; - case XK_Insert: - return PUGL_KEY_INSERT; - case XK_Shift_L: - return PUGL_KEY_SHIFT_L; - case XK_Shift_R: - return PUGL_KEY_SHIFT_R; - case XK_Control_L: - return PUGL_KEY_CTRL_L; - case XK_Control_R: - return PUGL_KEY_CTRL_R; - case XK_Alt_L: - return PUGL_KEY_ALT_L; - case XK_ISO_Level3_Shift: - case XK_Alt_R: - return PUGL_KEY_ALT_R; - case XK_Super_L: - return PUGL_KEY_SUPER_L; - case XK_Super_R: - return PUGL_KEY_SUPER_R; - case XK_Menu: - return PUGL_KEY_MENU; - case XK_Caps_Lock: - return PUGL_KEY_CAPS_LOCK; - case XK_Scroll_Lock: - return PUGL_KEY_SCROLL_LOCK; - case XK_Num_Lock: - return PUGL_KEY_NUM_LOCK; - case XK_Print: - return PUGL_KEY_PRINT_SCREEN; - case XK_Pause: - return PUGL_KEY_PAUSE; - default: - break; - } - return (PuglKey)0; -} - -static int -lookupString(XIC xic, XEvent* xevent, char* str, KeySym* sym) -{ - Status status = 0; - -#ifdef X_HAVE_UTF8_STRING - const int n = Xutf8LookupString(xic, &xevent->xkey, str, 7, sym, &status); -#else - const int n = XmbLookupString(xic, &xevent->xkey, str, 7, sym, &status); -#endif - - return status == XBufferOverflow ? 0 : n; -} - -static void -translateKey(PuglView* view, XEvent* xevent, PuglEvent* event) -{ - const unsigned state = xevent->xkey.state; - const bool filter = XFilterEvent(xevent, None); - - event->key.keycode = xevent->xkey.keycode; - xevent->xkey.state = 0; - - // Lookup unshifted key - char ustr[8] = {0}; - KeySym sym = 0; - const int ufound = XLookupString(&xevent->xkey, ustr, 8, &sym, NULL); - const PuglKey special = keySymToSpecial(sym); - - event->key.key = - ((special || ufound <= 0) ? special : puglDecodeUTF8((const uint8_t*)ustr)); - - if (xevent->type == KeyPress && !filter && !special) { - // Lookup shifted key for possible text event - xevent->xkey.state = state; - - char sstr[8] = {0}; - const int sfound = lookupString(view->impl->xic, xevent, sstr, &sym); - if (sfound > 0) { - // Dispatch key event now - puglDispatchEvent(view, event); - - // "Return" a text event in its place - event->text.type = PUGL_TEXT; - event->text.character = puglDecodeUTF8((const uint8_t*)sstr); - memcpy(event->text.string, sstr, sizeof(sstr)); - } - } -} - -static uint32_t -translateModifiers(const unsigned xstate) -{ - return (((xstate & ShiftMask) ? PUGL_MOD_SHIFT : 0u) | - ((xstate & ControlMask) ? PUGL_MOD_CTRL : 0u) | - ((xstate & Mod1Mask) ? PUGL_MOD_ALT : 0u) | - ((xstate & Mod4Mask) ? PUGL_MOD_SUPER : 0u)); -} - -static PuglEvent -translateEvent(PuglView* view, XEvent xevent) -{ - const PuglX11Atoms* atoms = &view->world->impl->atoms; - - PuglEvent event = {{PUGL_NOTHING, 0}}; - event.any.flags = xevent.xany.send_event ? PUGL_IS_SEND_EVENT : 0; - - switch (xevent.type) { - case ClientMessage: - if (xevent.xclient.message_type == atoms->WM_PROTOCOLS) { - const Atom protocol = (Atom)xevent.xclient.data.l[0]; - if (protocol == atoms->WM_DELETE_WINDOW) { - event.type = PUGL_CLOSE; - } - } else if (xevent.xclient.message_type == atoms->PUGL_CLIENT_MSG) { - event.type = PUGL_CLIENT; - event.client.data1 = (uintptr_t)xevent.xclient.data.l[0]; - event.client.data2 = (uintptr_t)xevent.xclient.data.l[1]; - } - break; - case VisibilityNotify: - view->visible = xevent.xvisibility.state != VisibilityFullyObscured; - break; - case MapNotify: - event.type = PUGL_MAP; - break; - case UnmapNotify: - event.type = PUGL_UNMAP; - view->visible = false; - break; - case ConfigureNotify: - event.type = PUGL_CONFIGURE; - event.configure.x = xevent.xconfigure.x; - event.configure.y = xevent.xconfigure.y; - event.configure.width = xevent.xconfigure.width; - event.configure.height = xevent.xconfigure.height; - break; - case Expose: - event.type = PUGL_EXPOSE; - event.expose.x = xevent.xexpose.x; - event.expose.y = xevent.xexpose.y; - event.expose.width = xevent.xexpose.width; - event.expose.height = xevent.xexpose.height; - break; - case MotionNotify: - event.type = PUGL_MOTION; - event.motion.time = (double)xevent.xmotion.time / 1e3; - event.motion.x = xevent.xmotion.x; - event.motion.y = xevent.xmotion.y; - event.motion.xRoot = xevent.xmotion.x_root; - event.motion.yRoot = xevent.xmotion.y_root; - event.motion.state = translateModifiers(xevent.xmotion.state); - if (xevent.xmotion.is_hint == NotifyHint) { - event.motion.flags |= PUGL_IS_HINT; - } - break; - case ButtonPress: - if (xevent.xbutton.button >= 4 && xevent.xbutton.button <= 7) { - event.type = PUGL_SCROLL; - event.scroll.time = (double)xevent.xbutton.time / 1e3; - event.scroll.x = xevent.xbutton.x; - event.scroll.y = xevent.xbutton.y; - event.scroll.xRoot = xevent.xbutton.x_root; - event.scroll.yRoot = xevent.xbutton.y_root; - event.scroll.state = translateModifiers(xevent.xbutton.state); - event.scroll.dx = 0.0; - event.scroll.dy = 0.0; - switch (xevent.xbutton.button) { - case 4: - event.scroll.dy = 1.0; - event.scroll.direction = PUGL_SCROLL_UP; - break; - case 5: - event.scroll.dy = -1.0; - event.scroll.direction = PUGL_SCROLL_DOWN; - break; - case 6: - event.scroll.dx = -1.0; - event.scroll.direction = PUGL_SCROLL_LEFT; - break; - case 7: - event.scroll.dx = 1.0; - event.scroll.direction = PUGL_SCROLL_RIGHT; - break; - } - // fallthru - } - // fallthru - case ButtonRelease: - if (xevent.xbutton.button < 4 || xevent.xbutton.button > 7) { - event.button.type = ((xevent.type == ButtonPress) ? PUGL_BUTTON_PRESS - : PUGL_BUTTON_RELEASE); - event.button.time = (double)xevent.xbutton.time / 1e3; - event.button.x = xevent.xbutton.x; - event.button.y = xevent.xbutton.y; - event.button.xRoot = xevent.xbutton.x_root; - event.button.yRoot = xevent.xbutton.y_root; - event.button.state = translateModifiers(xevent.xbutton.state); - event.button.button = xevent.xbutton.button; - } - break; - case KeyPress: - case KeyRelease: - event.type = - ((xevent.type == KeyPress) ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE); - event.key.time = (double)xevent.xkey.time / 1e3; - event.key.x = xevent.xkey.x; - event.key.y = xevent.xkey.y; - event.key.xRoot = xevent.xkey.x_root; - event.key.yRoot = xevent.xkey.y_root; - event.key.state = translateModifiers(xevent.xkey.state); - translateKey(view, &xevent, &event); - break; - case EnterNotify: - case LeaveNotify: - event.type = - ((xevent.type == EnterNotify) ? PUGL_POINTER_IN : PUGL_POINTER_OUT); - event.crossing.time = (double)xevent.xcrossing.time / 1e3; - event.crossing.x = xevent.xcrossing.x; - event.crossing.y = xevent.xcrossing.y; - event.crossing.xRoot = xevent.xcrossing.x_root; - event.crossing.yRoot = xevent.xcrossing.y_root; - event.crossing.state = translateModifiers(xevent.xcrossing.state); - event.crossing.mode = PUGL_CROSSING_NORMAL; - if (xevent.xcrossing.mode == NotifyGrab) { - event.crossing.mode = PUGL_CROSSING_GRAB; - } else if (xevent.xcrossing.mode == NotifyUngrab) { - event.crossing.mode = PUGL_CROSSING_UNGRAB; - } - break; - - case FocusIn: - case FocusOut: - event.type = (xevent.type == FocusIn) ? PUGL_FOCUS_IN : PUGL_FOCUS_OUT; - event.focus.mode = PUGL_CROSSING_NORMAL; - if (xevent.xfocus.mode == NotifyGrab) { - event.focus.mode = PUGL_CROSSING_GRAB; - } else if (xevent.xfocus.mode == NotifyUngrab) { - event.focus.mode = PUGL_CROSSING_UNGRAB; - } - break; - - default: - break; - } - - return event; -} - -PuglStatus -puglGrabFocus(PuglView* view) -{ - XSetInputFocus( - view->impl->display, view->impl->win, RevertToNone, CurrentTime); - return PUGL_SUCCESS; -} - -bool -puglHasFocus(const PuglView* view) -{ - int revertTo = 0; - Window focusedWindow = 0; - XGetInputFocus(view->impl->display, &focusedWindow, &revertTo); - return focusedWindow == view->impl->win; -} - -PuglStatus -puglRequestAttention(PuglView* view) -{ - PuglInternals* const impl = view->impl; - const PuglX11Atoms* const atoms = &view->world->impl->atoms; - XEvent event = {0}; - - event.type = ClientMessage; - event.xclient.window = impl->win; - event.xclient.format = 32; - event.xclient.message_type = atoms->NET_WM_STATE; - event.xclient.data.l[0] = WM_STATE_ADD; - event.xclient.data.l[1] = (long)atoms->NET_WM_STATE_DEMANDS_ATTENTION; - event.xclient.data.l[2] = 0; - event.xclient.data.l[3] = 1; - event.xclient.data.l[4] = 0; - - const Window root = RootWindow(impl->display, impl->screen); - XSendEvent(impl->display, - root, - False, - SubstructureNotifyMask | SubstructureRedirectMask, - &event); - - return PUGL_SUCCESS; -} - -PuglStatus -puglStartTimer(PuglView* view, uintptr_t id, double timeout) -{ -#ifdef HAVE_XSYNC - if (view->world->impl->syncSupported) { - XSyncValue value; - XSyncIntToValue(&value, (int)floor(timeout * 1000.0)); - - PuglWorldInternals* w = view->world->impl; - Display* const display = w->display; - const XSyncCounter counter = w->serverTimeCounter; - const XSyncTestType type = XSyncPositiveTransition; - const XSyncTrigger trigger = {counter, XSyncRelative, value, type}; - XSyncAlarmAttributes attr = {trigger, value, True, XSyncAlarmActive}; - const XSyncAlarm alarm = XSyncCreateAlarm(display, 0x17, &attr); - const PuglTimer timer = {alarm, view, id}; - - if (alarm != None) { - for (size_t i = 0; i < w->numTimers; ++i) { - if (w->timers[i].view == view && w->timers[i].id == id) { - // Replace existing timer - XSyncDestroyAlarm(w->display, w->timers[i].alarm); - w->timers[i] = timer; - return PUGL_SUCCESS; - } - } - - // Add new timer - const size_t size = ++w->numTimers * sizeof(timer); - w->timers = (PuglTimer*)realloc(w->timers, size); - w->timers[w->numTimers - 1] = timer; - return PUGL_SUCCESS; - } - } -#else - (void)view; - (void)id; - (void)timeout; -#endif - - return PUGL_FAILURE; -} - -PuglStatus -puglStopTimer(PuglView* view, uintptr_t id) -{ -#ifdef HAVE_XSYNC - PuglWorldInternals* w = view->world->impl; - - for (size_t i = 0; i < w->numTimers; ++i) { - if (w->timers[i].view == view && w->timers[i].id == id) { - XSyncDestroyAlarm(w->display, w->timers[i].alarm); - - if (i == w->numTimers - 1) { - memset(&w->timers[i], 0, sizeof(PuglTimer)); - } else { - memmove(w->timers + i, - w->timers + i + 1, - sizeof(PuglTimer) * (w->numTimers - i - 1)); - - memset(&w->timers[i], 0, sizeof(PuglTimer)); - } - - --w->numTimers; - return PUGL_SUCCESS; - } - } -#else - (void)view; - (void)id; -#endif - - return PUGL_FAILURE; -} - -static XEvent -puglEventToX(PuglView* view, const PuglEvent* event) -{ - XEvent xev = {0}; - xev.xany.send_event = True; - - switch (event->type) { - case PUGL_EXPOSE: { - const double x = floor(event->expose.x); - const double y = floor(event->expose.y); - const double w = ceil(event->expose.x + event->expose.width) - x; - const double h = ceil(event->expose.y + event->expose.height) - y; - - xev.xexpose.type = Expose; - xev.xexpose.serial = 0; - xev.xexpose.display = view->impl->display; - xev.xexpose.window = view->impl->win; - xev.xexpose.x = (int)x; - xev.xexpose.y = (int)y; - xev.xexpose.width = (int)w; - xev.xexpose.height = (int)h; - break; - } - - case PUGL_CLIENT: - xev.xclient.type = ClientMessage; - xev.xclient.serial = 0; - xev.xclient.send_event = True; - xev.xclient.display = view->impl->display; - xev.xclient.window = view->impl->win; - xev.xclient.message_type = view->world->impl->atoms.PUGL_CLIENT_MSG; - xev.xclient.format = 32; - xev.xclient.data.l[0] = (long)event->client.data1; - xev.xclient.data.l[1] = (long)event->client.data2; - break; - - default: - break; - } - - return xev; -} - -PuglStatus -puglSendEvent(PuglView* view, const PuglEvent* event) -{ - XEvent xev = puglEventToX(view, event); - - if (xev.type) { - if (XSendEvent(view->impl->display, view->impl->win, False, 0, &xev)) { - return PUGL_SUCCESS; - } - - return PUGL_UNKNOWN_ERROR; - } - - return PUGL_UNSUPPORTED_TYPE; -} - -#ifndef PUGL_DISABLE_DEPRECATED -PuglStatus -puglWaitForEvent(PuglView* view) -{ - XEvent xevent; - XPeekEvent(view->impl->display, &xevent); - return PUGL_SUCCESS; -} -#endif - -static void -mergeExposeEvents(PuglEventExpose* dst, const PuglEventExpose* src) -{ - if (!dst->type) { - *dst = *src; - } else { - const double max_x = MAX(dst->x + dst->width, src->x + src->width); - const double max_y = MAX(dst->y + dst->height, src->y + src->height); - - dst->x = MIN(dst->x, src->x); - dst->y = MIN(dst->y, src->y); - dst->width = max_x - dst->x; - dst->height = max_y - dst->y; - } -} - -static void -handleSelectionNotify(const PuglWorld* world, PuglView* view) -{ - uint8_t* str = NULL; - Atom type = 0; - int fmt = 0; - unsigned long len = 0; - unsigned long left = 0; - - XGetWindowProperty(world->impl->display, - view->impl->win, - XA_PRIMARY, - 0, - 0x1FFFFFFF, - False, - AnyPropertyType, - &type, - &fmt, - &len, - &left, - &str); - - if (str && fmt == 8 && left == 0) { - char *type_name = XGetAtomName(world->impl->display, type); - if (type_name) { - puglSetBlob(&view->clipboardType, type_name, strlen(type_name) + 1); - XFree(type_name); - } else { - puglSetBlob(&view->clipboardType, NULL, 0); - } - puglSetBlob(&view->clipboard, str, len); - } - - XFree(str); -} - -static void -handleSelectionRequest(const PuglWorld* world, - PuglView* view, - const XSelectionRequestEvent* request) -{ - XSelectionEvent note = {SelectionNotify, - request->serial, - False, - world->impl->display, - request->requestor, - request->selection, - request->target, - None, - request->time}; - - const char* type = NULL; - size_t len = 0; - const void* data = puglGetInternalClipboard(view, &type, &len); - if (data && request->selection == world->impl->atoms.CLIPBOARD) { - const Atom types [2] = { - world->impl->atoms.TARGETS, - XInternAtom(world->impl->display, type, 0) - }; - - if (request->target == world->impl->atoms.TARGETS) { - note.property = request->property; - XChangeProperty(world->impl->display, - note.requestor, - note.property, - XA_ATOM, - 32, - PropModeReplace, - (const uint8_t*)types, - (int)(sizeof(types) / sizeof(Atom))); - } else if (request->target == types[1]) { - note.property = request->property; - XChangeProperty(world->impl->display, - note.requestor, - note.property, - note.target, - 8, - PropModeReplace, - (const uint8_t*)data, - (int)len); - } else { - note.property = None; - } - } else { - note.property = None; - } - - XSendEvent(world->impl->display, note.requestor, True, 0, (XEvent*)¬e); -} - -/// Flush pending configure and expose events for all views -static void -flushExposures(PuglWorld* world) -{ - for (size_t i = 0; i < world->numViews; ++i) { - PuglView* const view = world->views[i]; - - if (view->visible) { - puglDispatchSimpleEvent(view, PUGL_UPDATE); - } - - const PuglEvent configure = view->impl->pendingConfigure; - const PuglEvent expose = view->impl->pendingExpose; - - view->impl->pendingConfigure.type = PUGL_NOTHING; - view->impl->pendingExpose.type = PUGL_NOTHING; - - if (configure.type || expose.type) { - view->backend->enter(view, expose.type ? &expose.expose : NULL); - puglDispatchEventInContext(view, &configure); - puglDispatchEventInContext(view, &expose); - view->backend->leave(view, expose.type ? &expose.expose : NULL); - } - } -} - -static bool -handleTimerEvent(PuglWorld* world, XEvent xevent) -{ -#ifdef HAVE_XSYNC - if (xevent.type == world->impl->syncEventBase + XSyncAlarmNotify) { - XSyncAlarmNotifyEvent* notify = ((XSyncAlarmNotifyEvent*)&xevent); - - for (size_t i = 0; i < world->impl->numTimers; ++i) { - if (world->impl->timers[i].alarm == notify->alarm) { - PuglEvent event = {{PUGL_TIMER, 0}}; - event.timer.id = world->impl->timers[i].id; - puglDispatchEvent(world->impl->timers[i].view, - (const PuglEvent*)&event); - } - } - - return true; - } -#else - (void)world; - (void)xevent; -#endif - - return false; -} - -static PuglStatus -puglDispatchX11Events(PuglWorld* world) -{ - const PuglX11Atoms* const atoms = &world->impl->atoms; - - // Flush output to the server once at the start - Display* display = world->impl->display; - XFlush(display); - - // Process all queued events (without further flushing) - while (XEventsQueued(display, QueuedAfterReading) > 0) { - XEvent xevent; - XNextEvent(display, &xevent); - - if (handleTimerEvent(world, xevent)) { - continue; - } - - PuglView* view = puglFindView(world, xevent.xany.window); - if (!view) { - continue; - } - - // Handle special events - PuglInternals* const impl = view->impl; - if (xevent.type == KeyRelease && view->hints[PUGL_IGNORE_KEY_REPEAT]) { - XEvent next; - if (XCheckTypedWindowEvent(display, impl->win, KeyPress, &next) && - next.type == KeyPress && next.xkey.time == xevent.xkey.time && - next.xkey.keycode == xevent.xkey.keycode) { - continue; - } - } else if (xevent.type == FocusIn) { - XSetICFocus(impl->xic); - } else if (xevent.type == FocusOut) { - XUnsetICFocus(impl->xic); - } else if (xevent.type == SelectionClear) { - puglSetBlob(&view->clipboardType, NULL, 0); - puglSetBlob(&view->clipboard, NULL, 0); - } else if (xevent.type == SelectionNotify && - xevent.xselection.selection == atoms->CLIPBOARD && - xevent.xselection.property == XA_PRIMARY) { - handleSelectionNotify(world, view); - } else if (xevent.type == SelectionRequest) { - handleSelectionRequest(world, view, &xevent.xselectionrequest); - } - - // Translate X11 event to Pugl event - const PuglEvent event = translateEvent(view, xevent); - - if (event.type == PUGL_EXPOSE) { - // Expand expose event to be dispatched after loop - mergeExposeEvents(&view->impl->pendingExpose.expose, &event.expose); - } else if (event.type == PUGL_CONFIGURE) { - // Expand configure event to be dispatched after loop - view->impl->pendingConfigure = event; - view->frame.x = event.configure.x; - view->frame.y = event.configure.y; - view->frame.width = event.configure.width; - view->frame.height = event.configure.height; - } else if (event.type == PUGL_MAP && view->parent) { - XWindowAttributes attrs; - XGetWindowAttributes(view->impl->display, view->impl->win, &attrs); - - const PuglEventConfigure configure = {PUGL_CONFIGURE, - 0, - (double)attrs.x, - (double)attrs.y, - (double)attrs.width, - (double)attrs.height}; - - puglDispatchEvent(view, (const PuglEvent*)&configure); - puglDispatchEvent(view, &event); - } else { - // Dispatch event to application immediately - puglDispatchEvent(view, &event); - } - } - - return PUGL_SUCCESS; -} - -#ifndef PUGL_DISABLE_DEPRECATED -PuglStatus -puglProcessEvents(PuglView* view) -{ - return puglUpdate(view->world, 0.0); -} -#endif - -PuglStatus -puglUpdate(PuglWorld* world, double timeout) -{ - const double startTime = puglGetTime(world); - PuglStatus st = PUGL_SUCCESS; - - world->impl->dispatchingEvents = true; - - if (timeout < 0.0) { - st = puglPollX11Socket(world, timeout); - st = st ? st : puglDispatchX11Events(world); - } else if (timeout <= 0.001) { - st = puglDispatchX11Events(world); - } else { - const double endTime = startTime + timeout - 0.001; - for (double t = startTime; t < endTime; t = puglGetTime(world)) { - if ((st = puglPollX11Socket(world, endTime - t)) || - (st = puglDispatchX11Events(world))) { - break; - } - } - } - - flushExposures(world); - - world->impl->dispatchingEvents = false; - - return st; -} - -double -puglGetTime(const PuglWorld* world) -{ - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return ((double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0) - - world->startTime; -} - -PuglStatus -puglPostRedisplay(PuglView* view) -{ - const PuglRect rect = {0, 0, view->frame.width, view->frame.height}; - - return puglPostRedisplayRect(view, rect); -} - -PuglStatus -puglPostRedisplayRect(PuglView* view, PuglRect rect) -{ - const PuglEventExpose event = { - PUGL_EXPOSE, 0, rect.x, rect.y, rect.width, rect.height}; - - if (view->world->impl->dispatchingEvents) { - // Currently dispatching events, add/expand expose for the loop end - mergeExposeEvents(&view->impl->pendingExpose.expose, &event); - } else if (view->visible) { - // Not dispatching events, send an X expose so we wake up next time - return puglSendEvent(view, (const PuglEvent*)&event); - } - - return PUGL_SUCCESS; -} - -PuglNativeView -puglGetNativeWindow(PuglView* view) -{ - return (PuglNativeView)view->impl->win; -} - -PuglStatus -puglSetWindowTitle(PuglView* view, const char* title) -{ - Display* display = view->world->impl->display; - const PuglX11Atoms* const atoms = &view->world->impl->atoms; - - puglSetString(&view->title, title); - - if (view->impl->win) { - XStoreName(display, view->impl->win, title); - XChangeProperty(display, - view->impl->win, - atoms->NET_WM_NAME, - atoms->UTF8_STRING, - 8, - PropModeReplace, - (const uint8_t*)title, - (int)strlen(title)); - } - - return PUGL_SUCCESS; -} - -PuglStatus -puglSetFrame(PuglView* view, const PuglRect frame) -{ - if (view->impl->win) { - if (!XMoveResizeWindow(view->world->impl->display, - view->impl->win, - (int)frame.x, - (int)frame.y, - (unsigned)frame.width, - (unsigned)frame.height)) { - return PUGL_UNKNOWN_ERROR; - } - } - - view->frame = frame; - return PUGL_SUCCESS; -} - -PuglStatus -puglSetDefaultSize(PuglView* const view, const int width, const int height) -{ - view->defaultWidth = width; - view->defaultHeight = height; - return updateSizeHints(view); -} - -PuglStatus -puglSetMinSize(PuglView* const view, const int width, const int height) -{ - view->minWidth = width; - view->minHeight = height; - return updateSizeHints(view); -} - -PuglStatus -puglSetMaxSize(PuglView* const view, const int width, const int height) -{ - view->maxWidth = width; - view->maxHeight = height; - return updateSizeHints(view); -} - -PuglStatus -puglSetAspectRatio(PuglView* const view, - const int minX, - const int minY, - const int maxX, - const int maxY) -{ - view->minAspectX = minX; - view->minAspectY = minY; - view->maxAspectX = maxX; - view->maxAspectY = maxY; - - return updateSizeHints(view); -} - -PuglStatus -puglSetTransientFor(PuglView* view, PuglNativeView parent) -{ - Display* display = view->world->impl->display; - - view->transientParent = parent; - - if (view->impl->win) { - XSetTransientForHint( - display, view->impl->win, (Window)view->transientParent); - } - - return PUGL_SUCCESS; -} - -const void* -puglGetClipboard(PuglView* const view, - const char** const type, - size_t* const len) -{ - PuglInternals* const impl = view->impl; - const PuglX11Atoms* const atoms = &view->world->impl->atoms; - - const Window owner = XGetSelectionOwner(impl->display, atoms->CLIPBOARD); - if (owner != None && owner != impl->win) { - // Clear internal selection - puglSetBlob(&view->clipboardType, NULL, 0); - puglSetBlob(&view->clipboard, NULL, 0); - - const Atom type_atom = type && *type - ? XInternAtom(impl->display, *type, 0) - : atoms->UTF8_STRING; - - // Request selection from the owner - XConvertSelection(impl->display, - atoms->CLIPBOARD, - type_atom, - XA_PRIMARY, - impl->win, - CurrentTime); - - // Run event loop until data is received - while (!view->clipboard.data) { - puglUpdate(view->world, -1.0); - } - } - - return puglGetInternalClipboard(view, type, len); -} - -PuglStatus -puglSetClipboard(PuglView* const view, - const char* const type, - const void* const data, - const size_t len) -{ - PuglInternals* const impl = view->impl; - const PuglX11Atoms* const atoms = &view->world->impl->atoms; - - PuglStatus st = puglSetInternalClipboard(view, type, data, len); - if (st) { - return st; - } - - XSetSelectionOwner(impl->display, atoms->CLIPBOARD, impl->win, CurrentTime); - return PUGL_SUCCESS; -} - -#ifdef HAVE_XCURSOR -static const unsigned cursor_nums[] = { - XC_arrow, // ARROW - XC_xterm, // CARET - XC_crosshair, // CROSSHAIR - XC_hand2, // HAND - XC_pirate, // NO - XC_sb_h_double_arrow, // LEFT_RIGHT - XC_sb_v_double_arrow, // UP_DOWN -}; -#endif - -PuglStatus -puglSetCursor(PuglView* view, PuglCursor cursor) -{ -#ifdef HAVE_XCURSOR - PuglInternals* const impl = view->impl; - const unsigned index = (unsigned)cursor; - const unsigned count = sizeof(cursor_nums) / sizeof(cursor_nums[0]); - if (index >= count) { - return PUGL_BAD_PARAMETER; - } - - const unsigned shape = cursor_nums[index]; - if (!impl->win || impl->cursorShape == shape) { - return PUGL_SUCCESS; - } - - impl->cursorShape = cursor_nums[index]; - - return puglDefineCursorShape(view, impl->cursorShape); -#else - (void)view; - (void)cursor; - return PUGL_FAILURE; -#endif -} diff --git a/subprojects/nk_pugl/pugl/src/x11.h b/subprojects/nk_pugl/pugl/src/x11.h deleted file mode 100644 index 778e5ec..0000000 --- a/subprojects/nk_pugl/pugl/src/x11.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef PUGL_DETAIL_X11_H -#define PUGL_DETAIL_X11_H - -#include "types.h" - -#include "pugl/pugl.h" - -#include -#include -#include - -#include -#include -#include - -typedef struct { - Atom CLIPBOARD; - Atom UTF8_STRING; - Atom TARGETS; - Atom WM_PROTOCOLS; - Atom WM_DELETE_WINDOW; - Atom PUGL_CLIENT_MSG; - Atom NET_WM_NAME; - Atom NET_WM_STATE; - Atom NET_WM_STATE_DEMANDS_ATTENTION; -} PuglX11Atoms; - -typedef struct { - XID alarm; - PuglView* view; - uintptr_t id; -} PuglTimer; - -struct PuglWorldInternalsImpl { - Display* display; - PuglX11Atoms atoms; - XIM xim; - PuglTimer* timers; - size_t numTimers; - XID serverTimeCounter; - int syncEventBase; - bool syncSupported; - bool dispatchingEvents; -}; - -struct PuglInternalsImpl { - Display* display; - XVisualInfo* vi; - Window win; - XIC xic; - PuglSurface* surface; - PuglEvent pendingConfigure; - PuglEvent pendingExpose; - int screen; -#ifdef HAVE_XCURSOR - unsigned cursorShape; -#endif -}; - -PuglStatus -puglX11StubConfigure(PuglView* view); - -#endif // PUGL_DETAIL_X11_H diff --git a/subprojects/nk_pugl/pugl/src/x11_cairo.c b/subprojects/nk_pugl/pugl/src/x11_cairo.c deleted file mode 100644 index a0e7d08..0000000 --- a/subprojects/nk_pugl/pugl/src/x11_cairo.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "types.h" -#include "x11.h" - -#include "pugl/cairo.h" -#include "pugl/pugl.h" - -#include -#include -#include - -#include - -typedef struct { - cairo_surface_t* back; - cairo_surface_t* front; - cairo_t* cr; -} PuglX11CairoSurface; - -static void -puglX11CairoClose(PuglView* view) -{ - PuglInternals* const impl = view->impl; - PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface; - - cairo_surface_destroy(surface->front); - cairo_surface_destroy(surface->back); - surface->front = surface->back = NULL; -} - -static PuglStatus -puglX11CairoOpen(PuglView* view) -{ - PuglInternals* const impl = view->impl; - PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface; - - surface->back = cairo_xlib_surface_create(impl->display, - impl->win, - impl->vi->visual, - (int)view->frame.width, - (int)view->frame.height); - - surface->front = - cairo_surface_create_similar(surface->back, - cairo_surface_get_content(surface->back), - (int)view->frame.width, - (int)view->frame.height); - - if (cairo_surface_status(surface->back) || - cairo_surface_status(surface->front)) { - puglX11CairoClose(view); - return PUGL_CREATE_CONTEXT_FAILED; - } - - return PUGL_SUCCESS; -} - -static PuglStatus -puglX11CairoCreate(PuglView* view) -{ - PuglInternals* const impl = view->impl; - - impl->surface = (cairo_surface_t*)calloc(1, sizeof(PuglX11CairoSurface)); - - return PUGL_SUCCESS; -} - -static PuglStatus -puglX11CairoDestroy(PuglView* view) -{ - PuglInternals* const impl = view->impl; - PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface; - - puglX11CairoClose(view); - free(surface); - - return PUGL_SUCCESS; -} - -static PuglStatus -puglX11CairoEnter(PuglView* view, const PuglEventExpose* expose) -{ - PuglInternals* const impl = view->impl; - PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface; - PuglStatus st = PUGL_SUCCESS; - - if (expose && !(st = puglX11CairoOpen(view))) { - surface->cr = cairo_create(surface->front); - - if (cairo_status(surface->cr)) { - st = PUGL_CREATE_CONTEXT_FAILED; - } - } - - return st; -} - -static PuglStatus -puglX11CairoLeave(PuglView* view, const PuglEventExpose* expose) -{ - PuglInternals* const impl = view->impl; - PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface; - - if (expose) { - // Destroy front context and create a new one for drawing to the back - cairo_destroy(surface->cr); - surface->cr = cairo_create(surface->back); - - // Clip to expose region - cairo_rectangle( - surface->cr, expose->x, expose->y, expose->width, expose->height); - cairo_clip(surface->cr); - - // Paint front onto back - cairo_set_source_surface(surface->cr, surface->front, 0, 0); - cairo_paint(surface->cr); - - // Flush to X and close everything - cairo_destroy(surface->cr); - cairo_surface_flush(surface->back); - puglX11CairoClose(view); - surface->cr = NULL; - } - - return PUGL_SUCCESS; -} - -static void* -puglX11CairoGetContext(PuglView* view) -{ - PuglInternals* const impl = view->impl; - PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface; - - return surface->cr; -} - -const PuglBackend* -puglCairoBackend(void) -{ - static const PuglBackend backend = {puglX11StubConfigure, - puglX11CairoCreate, - puglX11CairoDestroy, - puglX11CairoEnter, - puglX11CairoLeave, - puglX11CairoGetContext}; - - return &backend; -} diff --git a/subprojects/nk_pugl/pugl/src/x11_gl.c b/subprojects/nk_pugl/pugl/src/x11_gl.c deleted file mode 100644 index 34152de..0000000 --- a/subprojects/nk_pugl/pugl/src/x11_gl.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "stub.h" -#include "types.h" -#include "x11.h" - -#include "pugl/gl.h" -#include "pugl/pugl.h" - -#include -#include -#include - -#include -#include -#include - -typedef struct { - GLXFBConfig fb_config; - GLXContext ctx; -} PuglX11GlSurface; - -static int -puglX11GlHintValue(const int value) -{ - return value == PUGL_DONT_CARE ? (int)GLX_DONT_CARE : value; -} - -static int -puglX11GlGetAttrib(Display* const display, - GLXFBConfig fb_config, - const int attrib) -{ - int value = 0; - glXGetFBConfigAttrib(display, fb_config, attrib, &value); - return value; -} - -static PuglStatus -puglX11GlConfigure(PuglView* view) -{ - PuglInternals* const impl = view->impl; - const int screen = impl->screen; - Display* const display = impl->display; - - PuglX11GlSurface* const surface = - (PuglX11GlSurface*)calloc(1, sizeof(PuglX11GlSurface)); - impl->surface = surface; - - // clang-format off - const int attrs[] = { - GLX_X_RENDERABLE, True, - GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, - GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, - GLX_RENDER_TYPE, GLX_RGBA_BIT, - GLX_SAMPLES, puglX11GlHintValue(view->hints[PUGL_SAMPLES]), - GLX_RED_SIZE, puglX11GlHintValue(view->hints[PUGL_RED_BITS]), - GLX_GREEN_SIZE, puglX11GlHintValue(view->hints[PUGL_GREEN_BITS]), - GLX_BLUE_SIZE, puglX11GlHintValue(view->hints[PUGL_BLUE_BITS]), - GLX_ALPHA_SIZE, puglX11GlHintValue(view->hints[PUGL_ALPHA_BITS]), - GLX_DEPTH_SIZE, puglX11GlHintValue(view->hints[PUGL_DEPTH_BITS]), - GLX_STENCIL_SIZE, puglX11GlHintValue(view->hints[PUGL_STENCIL_BITS]), - GLX_DOUBLEBUFFER, puglX11GlHintValue(view->hints[PUGL_DOUBLE_BUFFER]), - None - }; - // clang-format on - - int n_fbc = 0; - GLXFBConfig* fbc = glXChooseFBConfig(display, screen, attrs, &n_fbc); - if (n_fbc <= 0) { - return PUGL_CREATE_CONTEXT_FAILED; - } - - surface->fb_config = fbc[0]; - impl->vi = glXGetVisualFromFBConfig(impl->display, fbc[0]); - - view->hints[PUGL_RED_BITS] = - puglX11GlGetAttrib(display, fbc[0], GLX_RED_SIZE); - view->hints[PUGL_GREEN_BITS] = - puglX11GlGetAttrib(display, fbc[0], GLX_GREEN_SIZE); - view->hints[PUGL_BLUE_BITS] = - puglX11GlGetAttrib(display, fbc[0], GLX_BLUE_SIZE); - view->hints[PUGL_ALPHA_BITS] = - puglX11GlGetAttrib(display, fbc[0], GLX_ALPHA_SIZE); - view->hints[PUGL_DEPTH_BITS] = - puglX11GlGetAttrib(display, fbc[0], GLX_DEPTH_SIZE); - view->hints[PUGL_STENCIL_BITS] = - puglX11GlGetAttrib(display, fbc[0], GLX_STENCIL_SIZE); - view->hints[PUGL_SAMPLES] = puglX11GlGetAttrib(display, fbc[0], GLX_SAMPLES); - view->hints[PUGL_DOUBLE_BUFFER] = - puglX11GlGetAttrib(display, fbc[0], GLX_DOUBLEBUFFER); - - XFree(fbc); - - return PUGL_SUCCESS; -} - -static PuglStatus -puglX11GlEnter(PuglView* view, const PuglEventExpose* PUGL_UNUSED(expose)) -{ - PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface; - glXMakeCurrent(view->impl->display, view->impl->win, surface->ctx); - return PUGL_SUCCESS; -} - -static PuglStatus -puglX11GlLeave(PuglView* view, const PuglEventExpose* expose) -{ - if (expose && view->hints[PUGL_DOUBLE_BUFFER]) { - glXSwapBuffers(view->impl->display, view->impl->win); - } - - glXMakeCurrent(view->impl->display, None, NULL); - - return PUGL_SUCCESS; -} - -static PuglStatus -puglX11GlCreate(PuglView* view) -{ - PuglInternals* const impl = view->impl; - PuglX11GlSurface* const surface = (PuglX11GlSurface*)impl->surface; - Display* const display = impl->display; - GLXFBConfig fb_config = surface->fb_config; - - const int ctx_attrs[] = { - GLX_CONTEXT_MAJOR_VERSION_ARB, - view->hints[PUGL_CONTEXT_VERSION_MAJOR], - - GLX_CONTEXT_MINOR_VERSION_ARB, - view->hints[PUGL_CONTEXT_VERSION_MINOR], - - GLX_CONTEXT_FLAGS_ARB, - (view->hints[PUGL_USE_DEBUG_CONTEXT] ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), - - GLX_CONTEXT_PROFILE_MASK_ARB, - (view->hints[PUGL_USE_COMPAT_PROFILE] - ? GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB - : GLX_CONTEXT_CORE_PROFILE_BIT_ARB), - 0}; - - PFNGLXCREATECONTEXTATTRIBSARBPROC create_context = - (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress( - (const uint8_t*)"glXCreateContextAttribsARB"); - - PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT = - (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddress( - (const uint8_t*)"glXSwapIntervalEXT"); - - surface->ctx = create_context(display, fb_config, 0, True, ctx_attrs); - if (!surface->ctx) { - surface->ctx = - glXCreateNewContext(display, fb_config, GLX_RGBA_TYPE, 0, True); - } - - if (!surface->ctx) { - return PUGL_CREATE_CONTEXT_FAILED; - } - - const int swapInterval = view->hints[PUGL_SWAP_INTERVAL]; - if (glXSwapIntervalEXT && swapInterval != PUGL_DONT_CARE) { - puglX11GlEnter(view, NULL); - glXSwapIntervalEXT(display, impl->win, swapInterval); - puglX11GlLeave(view, NULL); - } - - glXGetConfig(impl->display, - impl->vi, - GLX_DOUBLEBUFFER, - &view->hints[PUGL_DOUBLE_BUFFER]); - - glXQueryDrawable(display, - impl->win, - GLX_SWAP_INTERVAL_EXT, - (unsigned int*)&view->hints[PUGL_SWAP_INTERVAL]); - - return PUGL_SUCCESS; -} - -static PuglStatus -puglX11GlDestroy(PuglView* view) -{ - PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface; - if (surface) { - glXDestroyContext(view->impl->display, surface->ctx); - free(surface); - view->impl->surface = NULL; - } - return PUGL_SUCCESS; -} - -PuglGlFunc -puglGetProcAddress(const char* name) -{ - return glXGetProcAddress((const uint8_t*)name); -} - -PuglStatus -puglEnterContext(PuglView* view) -{ - return view->backend->enter(view, NULL); -} - -PuglStatus -puglLeaveContext(PuglView* view) -{ - return view->backend->leave(view, NULL); -} - -const PuglBackend* -puglGlBackend(void) -{ - static const PuglBackend backend = {puglX11GlConfigure, - puglX11GlCreate, - puglX11GlDestroy, - puglX11GlEnter, - puglX11GlLeave, - puglStubGetContext}; - - return &backend; -} diff --git a/subprojects/nk_pugl/pugl/src/x11_stub.c b/subprojects/nk_pugl/pugl/src/x11_stub.c deleted file mode 100644 index de89a86..0000000 --- a/subprojects/nk_pugl/pugl/src/x11_stub.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "pugl/stub.h" - -#include "stub.h" -#include "types.h" -#include "x11.h" - -#include "pugl/pugl.h" - -#include - -PuglStatus -puglX11StubConfigure(PuglView* view) -{ - PuglInternals* const impl = view->impl; - XVisualInfo pat = {0}; - int n = 0; - - pat.screen = impl->screen; - impl->vi = XGetVisualInfo(impl->display, VisualScreenMask, &pat, &n); - - view->hints[PUGL_RED_BITS] = impl->vi->bits_per_rgb; - view->hints[PUGL_GREEN_BITS] = impl->vi->bits_per_rgb; - view->hints[PUGL_BLUE_BITS] = impl->vi->bits_per_rgb; - view->hints[PUGL_ALPHA_BITS] = 0; - - return PUGL_SUCCESS; -} - -const PuglBackend* -puglStubBackend(void) -{ - static const PuglBackend backend = { - puglX11StubConfigure, - puglStubCreate, - puglStubDestroy, - puglStubEnter, - puglStubLeave, - puglStubGetContext, - }; - - return &backend; -} diff --git a/subprojects/nk_pugl/pugl/src/x11_vulkan.c b/subprojects/nk_pugl/pugl/src/x11_vulkan.c deleted file mode 100644 index 1ff5759..0000000 --- a/subprojects/nk_pugl/pugl/src/x11_vulkan.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#define VK_NO_PROTOTYPES 1 - -#include "stub.h" -#include "types.h" -#include "x11.h" - -#include "pugl/pugl.h" -#include "pugl/vulkan.h" - -#include -#include - -#include - -#include -#include - -struct PuglVulkanLoaderImpl { - void* libvulkan; - PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; - PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; -}; - -PuglVulkanLoader* -puglNewVulkanLoader(PuglWorld* PUGL_UNUSED(world)) -{ - PuglVulkanLoader* loader = - (PuglVulkanLoader*)calloc(1, sizeof(PuglVulkanLoader)); - if (!loader) { - return NULL; - } - - if (!(loader->libvulkan = dlopen("libvulkan.so", RTLD_LAZY))) { - free(loader); - return NULL; - } - - loader->vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym( - loader->libvulkan, "vkGetInstanceProcAddr"); - - loader->vkGetDeviceProcAddr = - (PFN_vkGetDeviceProcAddr)dlsym(loader->libvulkan, "vkGetDeviceProcAddr"); - - return loader; -} - -void -puglFreeVulkanLoader(PuglVulkanLoader* loader) -{ - if (loader) { - dlclose(loader->libvulkan); - free(loader); - } -} - -PFN_vkGetInstanceProcAddr -puglGetInstanceProcAddrFunc(const PuglVulkanLoader* loader) -{ - return loader->vkGetInstanceProcAddr; -} - -PFN_vkGetDeviceProcAddr -puglGetDeviceProcAddrFunc(const PuglVulkanLoader* loader) -{ - return loader->vkGetDeviceProcAddr; -} - -const PuglBackend* -puglVulkanBackend(void) -{ - static const PuglBackend backend = {puglX11StubConfigure, - puglStubCreate, - puglStubDestroy, - puglStubEnter, - puglStubLeave, - puglStubGetContext}; - - return &backend; -} - -const char* const* -puglGetInstanceExtensions(uint32_t* const count) -{ - static const char* const extensions[] = {"VK_KHR_surface", - "VK_KHR_xlib_surface"}; - - *count = 2; - return extensions; -} - -VkResult -puglCreateSurface(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr, - PuglView* const view, - VkInstance instance, - const VkAllocationCallbacks* const allocator, - VkSurfaceKHR* const surface) -{ - PuglInternals* const impl = view->impl; - PuglWorldInternals* world_impl = view->world->impl; - - PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR = - (PFN_vkCreateXlibSurfaceKHR)vkGetInstanceProcAddr(instance, - "vkCreateXlibSurfaceKHR"); - - const VkXlibSurfaceCreateInfoKHR info = { - VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, - NULL, - 0, - world_impl->display, - impl->win, - }; - - return vkCreateXlibSurfaceKHR(instance, &info, allocator, surface); -} diff --git a/subprojects/nk_pugl/pugl/test/.clang-tidy b/subprojects/nk_pugl/pugl/test/.clang-tidy deleted file mode 100644 index 8014e6a..0000000 --- a/subprojects/nk_pugl/pugl/test/.clang-tidy +++ /dev/null @@ -1,16 +0,0 @@ -Checks: > - *, - -*-magic-numbers, - -*-uppercase-literal-suffix, - -bugprone-reserved-identifier, - -cert-dcl37-c, - -cert-dcl51-cpp, - -cppcoreguidelines-pro-type-static-cast-downcast, - -google-runtime-references, - -hicpp-multiway-paths-covered, - -hicpp-signed-bitwise, - -llvm-header-guard, - -llvmlibc-*, - -modernize-use-trailing-return-type, -FormatStyle: file -HeaderFilterRegex: 'pugl/.*|test/.*' diff --git a/subprojects/nk_pugl/pugl/test/meson.build b/subprojects/nk_pugl/pugl/test/meson.build deleted file mode 100644 index 340a7dd..0000000 --- a/subprojects/nk_pugl/pugl/test/meson.build +++ /dev/null @@ -1,33 +0,0 @@ -basic_tests = [ - 'realize', - 'redisplay', - 'show_hide', - 'stub_hints', - 'timer', - 'update', -] - -gl_tests = [ - 'gl_hints' -] - -includes = [ - '.', - '../include', -] - -foreach test : basic_tests - test(test, - executable('test_' + test, 'test_@0@.c'.format(test), - include_directories: include_directories(includes), - dependencies: [pugl_dep, stub_backend_dep])) -endforeach - -if opengl_dep.found() - foreach test : gl_tests - test(test, - executable('test_' + test, 'test_@0@.c'.format(test), - include_directories: include_directories(includes), - dependencies: [pugl_dep, gl_backend_dep])) - endforeach -endif diff --git a/subprojects/nk_pugl/pugl/test/test_build.c b/subprojects/nk_pugl/pugl/test/test_build.c deleted file mode 100644 index 957e0bd..0000000 --- a/subprojects/nk_pugl/pugl/test/test_build.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - Copyright 2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Tests that C headers compile without any warnings. -*/ - -#define PUGL_DISABLE_DEPRECATED - -#include "pugl/cairo.h" // IWYU pragma: keep -#include "pugl/gl.h" // IWYU pragma: keep -#include "pugl/pugl.h" // IWYU pragma: keep -#include "pugl/stub.h" // IWYU pragma: keep - -int -main(void) -{ - return 0; -} diff --git a/subprojects/nk_pugl/pugl/test/test_build.cpp b/subprojects/nk_pugl/pugl/test/test_build.cpp deleted file mode 100644 index 20235e8..0000000 --- a/subprojects/nk_pugl/pugl/test/test_build.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - Copyright 2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Tests that C++ headers compile without any warnings. -*/ - -#define PUGL_DISABLE_DEPRECATED - -#include "pugl/cairo.hpp" // IWYU pragma: keep -#include "pugl/gl.hpp" // IWYU pragma: keep -#include "pugl/pugl.h" // IWYU pragma: keep -#include "pugl/pugl.hpp" // IWYU pragma: keep -#include "pugl/stub.hpp" // IWYU pragma: keep - -int -main() -{ - return 0; -} diff --git a/subprojects/nk_pugl/pugl/test/test_clipboard.c b/subprojects/nk_pugl/pugl/test/test_clipboard.c deleted file mode 100644 index a458d00..0000000 --- a/subprojects/nk_pugl/pugl/test/test_clipboard.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - Copyright 2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Tests basic clipboard copy/paste functionality between two views. -*/ - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -#include -#include -#include -#include - -typedef struct { - PuglWorld* world; - PuglView* views[2]; - PuglTestOptions opts; - bool exposed; -} PuglTest; - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglTest* test = (PuglTest*)puglGetHandle(view); - - if (event->type == PUGL_EXPOSE) { - test->exposed = true; - } - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - PuglTest test = {puglNewWorld(PUGL_PROGRAM, 0), - {NULL, NULL}, - puglParseTestOptions(&argc, &argv), - false}; - - puglSetClassName(test.world, "Pugl Test"); - - // Set up views - for (unsigned i = 0u; i < 2; ++i) { - test.views[i] = puglNewView(test.world); - puglSetBackend(test.views[i], puglStubBackend()); - puglSetHandle(test.views[i], &test); - puglSetEventFunc(test.views[i], onEvent); - puglSetDefaultSize(test.views[i], 512, 512); - - assert(!puglShow(test.views[i])); - } - - // Update until view is exposed - while (!test.exposed) { - assert(!puglUpdate(test.world, 0.0)); - } - - // Set clipboard text via the first view - puglSetClipboard(test.views[0], NULL, "Text", 5); - - // Get clipboard contents via the second view - const char* type = NULL; - size_t len = 0; - const void* const contents = puglGetClipboard(test.views[1], &type, &len); - - // Check that the data made it over - assert(!strcmp(type, "text/plain")); - assert(len == 5); - assert(contents); - assert(!strcmp((const char*)contents, "Text")); - - // Try setting the clipboard to an unsupported type - assert(puglSetClipboard(test.views[0], "text/csv", "a,b,c", 6)); - - // Tear down - puglFreeView(test.views[0]); - puglFreeView(test.views[1]); - puglFreeWorld(test.world); - - return 0; -} diff --git a/subprojects/nk_pugl/pugl/test/test_gl_hints.c b/subprojects/nk_pugl/pugl/test/test_gl_hints.c deleted file mode 100644 index 3be3651..0000000 --- a/subprojects/nk_pugl/pugl/test/test_gl_hints.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - Copyright 2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Tests that all hints are set to real values after a view is realized. -*/ - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/gl.h" -#include "pugl/pugl.h" - -#include - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - (void)view; - (void)event; - - return PUGL_SUCCESS; -} - -int -main(void) -{ - PuglWorld* const world = puglNewWorld(PUGL_PROGRAM, 0); - PuglView* const view = puglNewView(world); - - // Set up view - puglSetClassName(world, "Pugl Test"); - puglSetBackend(view, puglGlBackend()); - puglSetEventFunc(view, onEvent); - puglSetDefaultSize(view, 512, 512); - - // Set all hints that support it to PUGL_DONT_CARE - assert(!puglSetViewHint(view, PUGL_RED_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_GREEN_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_BLUE_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_ALPHA_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_DEPTH_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_STENCIL_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_SAMPLES, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_DOUBLE_BUFFER, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_REFRESH_RATE, PUGL_DONT_CARE)); - - // Realize view and print all hints for debugging convenience - assert(!puglRealize(view)); - printViewHints(view); - - // Check that no hints are set to PUGL_DONT_CARE - assert(puglGetViewHint(view, PUGL_USE_COMPAT_PROFILE) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_USE_DEBUG_CONTEXT) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_CONTEXT_VERSION_MINOR) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_RED_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_GREEN_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_BLUE_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_ALPHA_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_DEPTH_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_STENCIL_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_SAMPLES) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_DOUBLE_BUFFER) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_SWAP_INTERVAL) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_RESIZABLE) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_IGNORE_KEY_REPEAT) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_REFRESH_RATE) != PUGL_DONT_CARE); - - // Tear down - puglFreeView(view); - puglFreeWorld(world); - - return 0; -} diff --git a/subprojects/nk_pugl/pugl/test/test_realize.c b/subprojects/nk_pugl/pugl/test/test_realize.c deleted file mode 100644 index 3c4e09a..0000000 --- a/subprojects/nk_pugl/pugl/test/test_realize.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - Copyright 2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Tests that realize sends a create event, and can safely be called twice. - - Without handling this case, an application that accidentally calls realize - twice could end up in a very confusing situation where multiple windows have - been allocated (and ultimately leaked) for a view. -*/ - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -#include -#include -#include - -typedef enum { - START, - CREATED, -} State; - -typedef struct { - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - State state; -} PuglTest; - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglTest* test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - switch (event->type) { - case PUGL_CREATE: - assert(test->state == START); - test->state = CREATED; - break; - default: - break; - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - PuglTest test = {puglNewWorld(PUGL_PROGRAM, 0), - NULL, - puglParseTestOptions(&argc, &argv), - START}; - - // Set up view - test.view = puglNewView(test.world); - puglSetClassName(test.world, "Pugl Test"); - puglSetBackend(test.view, puglStubBackend()); - puglSetHandle(test.view, &test); - puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); - - // Create initially invisible window - assert(!puglRealize(test.view)); - assert(!puglGetVisible(test.view)); - while (test.state < CREATED) { - assert(!puglUpdate(test.world, -1.0)); - } - - // Check that calling realize() again is okay - assert(puglRealize(test.view) == PUGL_FAILURE); - - // Tear down - puglFreeView(test.view); - puglFreeWorld(test.world); - - return 0; -} diff --git a/subprojects/nk_pugl/pugl/test/test_redisplay.c b/subprojects/nk_pugl/pugl/test/test_redisplay.c deleted file mode 100644 index c5b9887..0000000 --- a/subprojects/nk_pugl/pugl/test/test_redisplay.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - Copyright 2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Tests that redisplays posted in the event handler are dispatched at the end - of the same event loop iteration. -*/ - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -#include -#include -#include -#include - -#ifdef __APPLE__ -static const double timeout = 1 / 60.0; -#else -static const double timeout = -1.0; -#endif - -typedef enum { - START, - EXPOSED, - SHOULD_REDISPLAY, - POSTED_REDISPLAY, - REDISPLAYED, -} State; - -typedef struct { - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - State state; -} PuglTest; - -static const PuglRect redisplayRect = {2, 4, 8, 16}; -static const uintptr_t postRedisplayId = 42; - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglTest* test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - switch (event->type) { - case PUGL_UPDATE: - if (test->state == SHOULD_REDISPLAY) { - puglPostRedisplayRect(view, redisplayRect); - test->state = POSTED_REDISPLAY; - } - break; - - case PUGL_EXPOSE: - if (test->state == START) { - test->state = EXPOSED; - } else if (test->state == POSTED_REDISPLAY && - event->expose.x == redisplayRect.x && - event->expose.y == redisplayRect.y && - event->expose.width == redisplayRect.width && - event->expose.height == redisplayRect.height) { - test->state = REDISPLAYED; - } - break; - - case PUGL_CLIENT: - if (event->client.data1 == postRedisplayId) { - test->state = SHOULD_REDISPLAY; - } - break; - - default: - break; - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - PuglTest app = {puglNewWorld(PUGL_PROGRAM, 0), - NULL, - puglParseTestOptions(&argc, &argv), - START}; - - // Set up view - app.view = puglNewView(app.world); - puglSetClassName(app.world, "Pugl Test"); - puglSetBackend(app.view, puglStubBackend()); - puglSetHandle(app.view, &app); - puglSetEventFunc(app.view, onEvent); - puglSetDefaultSize(app.view, 512, 512); - - // Create and show window - assert(!puglRealize(app.view)); - assert(!puglShow(app.view)); - while (app.state != EXPOSED) { - assert(!puglUpdate(app.world, timeout)); - } - - // Send a custom event to trigger a redisplay in the event loop - PuglEvent client_event = {{PUGL_CLIENT, 0}}; - client_event.client.data1 = postRedisplayId; - client_event.client.data2 = 0; - assert(!puglSendEvent(app.view, &client_event)); - - // Loop until an expose happens in the same iteration as the redisplay - app.state = SHOULD_REDISPLAY; - while (app.state != REDISPLAYED) { - assert(!puglUpdate(app.world, timeout)); - assert(app.state != POSTED_REDISPLAY); - } - - // Tear down - puglFreeView(app.view); - puglFreeWorld(app.world); - - return 0; -} diff --git a/subprojects/nk_pugl/pugl/test/test_show_hide.c b/subprojects/nk_pugl/pugl/test/test_show_hide.c deleted file mode 100644 index 584448c..0000000 --- a/subprojects/nk_pugl/pugl/test/test_show_hide.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - Copyright 2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Tests the basic sanity of view/window create, configure, map, expose, unmap, - and destroy events. -*/ - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -#include -#include -#include - -typedef enum { - START, - CREATED, - CONFIGURED, - MAPPED, - EXPOSED, - UNMAPPED, - DESTROYED, -} State; - -typedef struct { - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - State state; -} PuglTest; - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglTest* test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - switch (event->type) { - case PUGL_CREATE: - assert(test->state == START); - test->state = CREATED; - break; - case PUGL_CONFIGURE: - if (test->state == CREATED) { - test->state = CONFIGURED; - } - break; - case PUGL_MAP: - assert(test->state == CONFIGURED || test->state == UNMAPPED); - test->state = MAPPED; - break; - case PUGL_EXPOSE: - assert(test->state == MAPPED || test->state == EXPOSED); - test->state = EXPOSED; - break; - case PUGL_UNMAP: - assert(test->state == EXPOSED); - test->state = UNMAPPED; - break; - case PUGL_DESTROY: - assert(test->state == UNMAPPED); - test->state = DESTROYED; - break; - default: - break; - } - - return PUGL_SUCCESS; -} - -static void -tick(PuglWorld* world) -{ -#ifdef __APPLE__ - // FIXME: Expose events are not events on MacOS, so we can't block - // indefinitely here since it will block forever - assert(!puglUpdate(world, 1 / 30.0)); -#else - assert(!puglUpdate(world, -1)); -#endif -} - -int -main(int argc, char** argv) -{ - PuglTest test = {puglNewWorld(PUGL_PROGRAM, 0), - NULL, - puglParseTestOptions(&argc, &argv), - START}; - - // Set up view - test.view = puglNewView(test.world); - puglSetClassName(test.world, "Pugl Test"); - puglSetBackend(test.view, puglStubBackend()); - puglSetHandle(test.view, &test); - puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); - - // Create initially invisible window - assert(!puglRealize(test.view)); - assert(!puglGetVisible(test.view)); - while (test.state < CREATED) { - tick(test.world); - } - - // Show and hide window a couple of times - for (unsigned i = 0u; i < 2u; ++i) { - assert(!puglShow(test.view)); - while (test.state != EXPOSED) { - tick(test.world); - } - - assert(puglGetVisible(test.view)); - assert(!puglHide(test.view)); - while (test.state != UNMAPPED) { - tick(test.world); - } - } - - // Tear down - assert(!puglGetVisible(test.view)); - puglFreeView(test.view); - assert(test.state == DESTROYED); - puglFreeWorld(test.world); - - return 0; -} diff --git a/subprojects/nk_pugl/pugl/test/test_stub_hints.c b/subprojects/nk_pugl/pugl/test/test_stub_hints.c deleted file mode 100644 index 1cc1180..0000000 --- a/subprojects/nk_pugl/pugl/test/test_stub_hints.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - Copyright 2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Tests that all hints are set to real values after a view is realized. -*/ - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -#include - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - (void)view; - (void)event; - - return PUGL_SUCCESS; -} - -int -main(void) -{ - PuglWorld* const world = puglNewWorld(PUGL_PROGRAM, 0); - PuglView* const view = puglNewView(world); - - // Set up view - puglSetClassName(world, "Pugl Test"); - puglSetBackend(view, puglStubBackend()); - puglSetEventFunc(view, onEvent); - puglSetDefaultSize(view, 512, 512); - - // Set all relevant hints that support it to PUGL_DONT_CARE - assert(!puglSetViewHint(view, PUGL_RED_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_GREEN_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_BLUE_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_ALPHA_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_REFRESH_RATE, PUGL_DONT_CARE)); - - // Realize view and print all hints for debugging convenience - assert(!puglRealize(view)); - printViewHints(view); - - // Check that no relevant hints are set to PUGL_DONT_CARE - assert(puglGetViewHint(view, PUGL_USE_COMPAT_PROFILE) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_USE_DEBUG_CONTEXT) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_CONTEXT_VERSION_MINOR) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_RED_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_GREEN_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_BLUE_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_ALPHA_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_RESIZABLE) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_IGNORE_KEY_REPEAT) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_REFRESH_RATE) != PUGL_DONT_CARE); - - // Tear down - puglFreeView(view); - puglFreeWorld(world); - - return 0; -} diff --git a/subprojects/nk_pugl/pugl/test/test_timer.c b/subprojects/nk_pugl/pugl/test/test_timer.c deleted file mode 100644 index 200ddc2..0000000 --- a/subprojects/nk_pugl/pugl/test/test_timer.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - Copyright 2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Tests that update events are received and than redisplays they trigger happen - immediately in the same event loop iteration. -*/ - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -#include -#include -#include -#include -#include -#include - -#ifdef __APPLE__ -static const double timeout = 1 / 60.0; -#else -static const double timeout = -1.0; -#endif - -#ifdef _WIN32 -// Windows SetTimer has a maximum resolution of 10ms -static const double tolerance = 0.012; -#else -static const double tolerance = 0.002; -#endif - -static const uintptr_t timerId = 1u; -static const double timerPeriod = 1 / 60.0; - -typedef enum { - START, - EXPOSED, -} State; - -typedef struct { - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - size_t numAlarms; - State state; -} PuglTest; - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglTest* test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - switch (event->type) { - case PUGL_EXPOSE: - test->state = EXPOSED; - break; - - case PUGL_TIMER: - assert(event->timer.id == timerId); - ++test->numAlarms; - break; - - default: - break; - } - - return PUGL_SUCCESS; -} - -static double -roundPeriod(const double period) -{ - return floor(period * 1000.0) / 1000.0; // Round down to milliseconds -} - -int -main(int argc, char** argv) -{ - PuglTest app = {puglNewWorld(PUGL_PROGRAM, 0), - NULL, - puglParseTestOptions(&argc, &argv), - 0, - START}; - - // Set up view - app.view = puglNewView(app.world); - puglSetClassName(app.world, "Pugl Test"); - puglSetBackend(app.view, puglStubBackend()); - puglSetHandle(app.view, &app); - puglSetEventFunc(app.view, onEvent); - puglSetDefaultSize(app.view, 512, 512); - - // Create and show window - assert(!puglRealize(app.view)); - assert(!puglShow(app.view)); - while (app.state != EXPOSED) { - assert(!puglUpdate(app.world, timeout)); - } - - // Register a timer with a longer period first - assert(!puglStartTimer(app.view, timerId, timerPeriod * 2.0)); - - // Replace it with the one we want (to ensure timers are replaced) - assert(!puglStartTimer(app.view, timerId, timerPeriod)); - - const double startTime = puglGetTime(app.world); - - puglUpdate(app.world, 1.0); - - // Calculate the actual period of the timer - const double endTime = puglGetTime(app.world); - const double duration = endTime - startTime; - const double expectedPeriod = roundPeriod(timerPeriod); - const double actualPeriod = roundPeriod(duration / (double)app.numAlarms); - const double difference = fabs(actualPeriod - expectedPeriod); - - if (difference > tolerance) { - fprintf( - stderr, "error: Period not within %f of %f\n", tolerance, expectedPeriod); - fprintf(stderr, "note: Actual period %f\n", actualPeriod); - } - - assert(difference <= tolerance); - - // Deregister timer and tick once to synchronize - assert(!puglStopTimer(app.view, timerId)); - puglUpdate(app.world, 0.0); - - // Update for a half second and check that we receive no more alarms - app.numAlarms = 0; - puglUpdate(app.world, 0.5); - assert(app.numAlarms == 0); - - puglFreeView(app.view); - puglFreeWorld(app.world); - - return 0; -} diff --git a/subprojects/nk_pugl/pugl/test/test_update.c b/subprojects/nk_pugl/pugl/test/test_update.c deleted file mode 100644 index 89de0b6..0000000 --- a/subprojects/nk_pugl/pugl/test/test_update.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - Copyright 2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/* - Tests that update events are received and that the redisplays they trigger - happen immediately in the same event loop iteration. -*/ - -#undef NDEBUG - -#include "test_utils.h" - -#include "pugl/pugl.h" -#include "pugl/stub.h" - -#include -#include -#include - -#ifdef __APPLE__ -static const double timeout = 1 / 60.0; -#else -static const double timeout = -1.0; -#endif - -typedef enum { - START, - EXPOSED1, - UPDATED, - EXPOSED2, -} State; - -typedef struct { - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - State state; -} PuglTest; - -static PuglStatus -onEvent(PuglView* view, const PuglEvent* event) -{ - PuglTest* test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - switch (event->type) { - case PUGL_EXPOSE: - switch (test->state) { - case START: - test->state = EXPOSED1; - break; - case UPDATED: - test->state = EXPOSED2; - break; - default: - break; - } - break; - - case PUGL_UPDATE: - if (test->state == EXPOSED1) { - puglPostRedisplay(view); - test->state = UPDATED; - } - break; - - default: - break; - } - - return PUGL_SUCCESS; -} - -int -main(int argc, char** argv) -{ - PuglTest app = {puglNewWorld(PUGL_PROGRAM, 0), - NULL, - puglParseTestOptions(&argc, &argv), - START}; - - // Set up view - app.view = puglNewView(app.world); - puglSetClassName(app.world, "Pugl Test"); - puglSetBackend(app.view, puglStubBackend()); - puglSetHandle(app.view, &app); - puglSetEventFunc(app.view, onEvent); - puglSetDefaultSize(app.view, 512, 512); - - // Create and show window - assert(!puglRealize(app.view)); - assert(!puglShow(app.view)); - - // Tick until an expose happens - while (app.state < EXPOSED1) { - assert(!puglUpdate(app.world, timeout)); - assert(app.state != UPDATED); - } - - // Tick once and ensure the update and the expose it posted both happened - assert(!puglUpdate(app.world, 0.0)); - assert(app.state == EXPOSED2); - - // Tear down - puglFreeView(app.view); - puglFreeWorld(app.world); - - return 0; -} diff --git a/subprojects/nk_pugl/pugl/test/test_utils.h b/subprojects/nk_pugl/pugl/test/test_utils.h deleted file mode 100644 index 2464737..0000000 --- a/subprojects/nk_pugl/pugl/test/test_utils.h +++ /dev/null @@ -1,356 +0,0 @@ -/* - Copyright 2012-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef TEST_TEST_UTILS_H -#define TEST_TEST_UTILS_H - -#define __STDC_FORMAT_MACROS 1 - -#include "pugl/pugl.h" - -#include -#include -#include -#include -#include -#include - -#ifdef __GNUC__ -# define PUGL_LOG_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1))) -#else -# define PUGL_LOG_FUNC(fmt, arg1) -#endif - -typedef struct { - int samples; - int doubleBuffer; - int sync; - bool continuous; - bool help; - bool ignoreKeyRepeat; - bool resizable; - bool verbose; - bool errorChecking; -} PuglTestOptions; - -PUGL_LOG_FUNC(1, 2) -static int -logError(const char* fmt, ...) -{ - fprintf(stderr, "error: "); - - va_list args; // NOLINT - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - - return 1; -} - -static inline int -printModifiers(const uint32_t mods) -{ - return fprintf(stderr, - "Modifiers:%s%s%s%s\n", - (mods & PUGL_MOD_SHIFT) ? " Shift" : "", - (mods & PUGL_MOD_CTRL) ? " Ctrl" : "", - (mods & PUGL_MOD_ALT) ? " Alt" : "", - (mods & PUGL_MOD_SUPER) ? " Super" : ""); -} - -static inline const char* -crossingModeString(const PuglCrossingMode mode) -{ - switch (mode) { - case PUGL_CROSSING_NORMAL: - return "normal"; - case PUGL_CROSSING_GRAB: - return "grab"; - case PUGL_CROSSING_UNGRAB: - return "ungrab"; - } - - return "unknown"; -} - -static inline const char* -scrollDirectionString(const PuglScrollDirection direction) -{ - switch (direction) { - case PUGL_SCROLL_UP: - return "up"; - case PUGL_SCROLL_DOWN: - return "down"; - case PUGL_SCROLL_LEFT: - return "left"; - case PUGL_SCROLL_RIGHT: - return "right"; - case PUGL_SCROLL_SMOOTH: - return "smooth"; - } - - return "unknown"; -} - -static inline int -printEvent(const PuglEvent* event, const char* prefix, const bool verbose) -{ -#define FFMT "%6.1f" -#define PFMT FFMT " " FFMT -#define PRINT(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) - - switch (event->type) { - case PUGL_NOTHING: - return 0; - case PUGL_KEY_PRESS: - return PRINT("%sKey press code %3u key U+%04X\n", - prefix, - event->key.keycode, - event->key.key); - case PUGL_KEY_RELEASE: - return PRINT("%sKey release code %3u key U+%04X\n", - prefix, - event->key.keycode, - event->key.key); - case PUGL_TEXT: - return PRINT("%sText entry code %3u char U+%04X (%s)\n", - prefix, - event->text.keycode, - event->text.character, - event->text.string); - case PUGL_BUTTON_PRESS: - case PUGL_BUTTON_RELEASE: - return (PRINT("%sMouse %u %s at " PFMT " ", - prefix, - event->button.button, - (event->type == PUGL_BUTTON_PRESS) ? "down" : "up ", - event->button.x, - event->button.y) + - printModifiers(event->scroll.state)); - case PUGL_SCROLL: - return (PRINT("%sScroll %5.1f %5.1f (%s) at " PFMT " ", - prefix, - event->scroll.dx, - event->scroll.dy, - scrollDirectionString(event->scroll.direction), - event->scroll.x, - event->scroll.y) + - printModifiers(event->scroll.state)); - case PUGL_POINTER_IN: - return PRINT("%sMouse enter at " PFMT " (%s)\n", - prefix, - event->crossing.x, - event->crossing.y, - crossingModeString(event->crossing.mode)); - case PUGL_POINTER_OUT: - return PRINT("%sMouse leave at " PFMT " (%s)\n", - prefix, - event->crossing.x, - event->crossing.y, - crossingModeString(event->crossing.mode)); - case PUGL_FOCUS_IN: - return PRINT( - "%sFocus in (%s)\n", prefix, crossingModeString(event->crossing.mode)); - case PUGL_FOCUS_OUT: - return PRINT( - "%sFocus out (%s)\n", prefix, crossingModeString(event->crossing.mode)); - case PUGL_CLIENT: - return PRINT("%sClient %" PRIXPTR " %" PRIXPTR "\n", - prefix, - event->client.data1, - event->client.data2); - case PUGL_LOOP_ENTER: - return PRINT("%sLoop enter\n", prefix); - case PUGL_LOOP_LEAVE: - return PRINT("%sLoop leave\n", prefix); - default: - break; - } - - if (verbose) { - switch (event->type) { - case PUGL_CREATE: - return fprintf(stderr, "%sCreate\n", prefix); - case PUGL_DESTROY: - return fprintf(stderr, "%sDestroy\n", prefix); - case PUGL_MAP: - return fprintf(stderr, "%sMap\n", prefix); - case PUGL_UNMAP: - return fprintf(stderr, "%sUnmap\n", prefix); - case PUGL_UPDATE: - return fprintf(stderr, "%sUpdate\n", prefix); - case PUGL_CONFIGURE: - return PRINT("%sConfigure " PFMT " " PFMT "\n", - prefix, - event->configure.x, - event->configure.y, - event->configure.width, - event->configure.height); - case PUGL_EXPOSE: - return PRINT("%sExpose " PFMT " " PFMT "\n", - prefix, - event->expose.x, - event->expose.y, - event->expose.width, - event->expose.height); - case PUGL_CLOSE: - return PRINT("%sClose\n", prefix); - case PUGL_MOTION: - return PRINT("%sMouse motion at " PFMT "\n", - prefix, - event->motion.x, - event->motion.y); - case PUGL_TIMER: - return PRINT("%sTimer %" PRIuPTR "\n", prefix, event->timer.id); - default: - return PRINT("%sUnknown event type %d\n", prefix, (int)event->type); - } - } - -#undef PRINT -#undef PFMT -#undef FFMT - - return 0; -} - -static inline const char* -puglViewHintString(const PuglViewHint hint) -{ - switch (hint) { - case PUGL_USE_COMPAT_PROFILE: - return "Use compatible profile"; - case PUGL_USE_DEBUG_CONTEXT: - return "Use debug context"; - case PUGL_CONTEXT_VERSION_MAJOR: - return "Context major version"; - case PUGL_CONTEXT_VERSION_MINOR: - return "Context minor version"; - case PUGL_RED_BITS: - return "Red bits"; - case PUGL_GREEN_BITS: - return "Green bits"; - case PUGL_BLUE_BITS: - return "Blue bits"; - case PUGL_ALPHA_BITS: - return "Alpha bits"; - case PUGL_DEPTH_BITS: - return "Depth bits"; - case PUGL_STENCIL_BITS: - return "Stencil bits"; - case PUGL_SAMPLES: - return "Samples"; - case PUGL_DOUBLE_BUFFER: - return "Double buffer"; - case PUGL_SWAP_INTERVAL: - return "Swap interval"; - case PUGL_RESIZABLE: - return "Resizable"; - case PUGL_IGNORE_KEY_REPEAT: - return "Ignore key repeat"; - case PUGL_REFRESH_RATE: - return "Refresh rate"; - case PUGL_NUM_VIEW_HINTS: - return "Unknown"; - } - - return "Unknown"; -} - -static inline void -printViewHints(const PuglView* view) -{ - for (int i = 0; i < PUGL_NUM_VIEW_HINTS; ++i) { - const PuglViewHint hint = (PuglViewHint)i; - fprintf(stderr, - "%s: %d\n", - puglViewHintString(hint), - puglGetViewHint(view, hint)); - } -} - -static inline void -puglPrintTestUsage(const char* prog, const char* posHelp) -{ - printf("Usage: %s [OPTION]... %s\n\n" - " -a Enable anti-aliasing\n" - " -c Continuously animate and draw\n" - " -d Directly draw to window (no double-buffering)\n" - " -e Enable platform error-checking\n" - " -f Fast drawing, explicitly disable vertical sync\n" - " -h Display this help\n" - " -i Ignore key repeat\n" - " -v Print verbose output\n" - " -r Resizable window\n" - " -s Explicitly enable vertical sync\n", - prog, - posHelp); -} - -static inline PuglTestOptions -puglParseTestOptions(int* pargc, char*** pargv) -{ - PuglTestOptions opts = { - 0, - PUGL_TRUE, - PUGL_DONT_CARE, - false, - false, - false, - false, - false, - false, - }; - - char** const argv = *pargv; - int i = 1; - for (; i < *pargc; ++i) { - if (!strcmp(argv[i], "-a")) { - opts.samples = 4; - } else if (!strcmp(argv[i], "-c")) { - opts.continuous = true; - } else if (!strcmp(argv[i], "-d")) { - opts.doubleBuffer = PUGL_FALSE; - } else if (!strcmp(argv[i], "-e")) { - opts.errorChecking = PUGL_TRUE; - } else if (!strcmp(argv[i], "-f")) { - opts.sync = PUGL_FALSE; - } else if (!strcmp(argv[i], "-h")) { - opts.help = true; - return opts; - } else if (!strcmp(argv[i], "-i")) { - opts.ignoreKeyRepeat = true; - } else if (!strcmp(argv[i], "-r")) { - opts.resizable = true; - } else if (!strcmp(argv[i], "-s")) { - opts.sync = PUGL_TRUE; - } else if (!strcmp(argv[i], "-v")) { - opts.verbose = true; - } else if (argv[i][0] != '-') { - break; - } else { - opts.help = true; - logError("Unknown option: %s\n", argv[i]); - } - } - - *pargc -= i; - *pargv += i; - - return opts; -} - -#endif // TEST_TEST_UTILS_H -- 2.38.5

uSAz4o&1pNm*R!U!BvIYUG7T0KR^#j}r}{z8ux+2HuioEzy@de; z0+?`PU?6}IFt}t)o;uY(0%KPaMNQ!oWlD%f6^i3dU$3W|+a;O0y1H(N_({T$y@FhlBIXa1 zIt@0<+2^DBV?FYQ+@?DJAQQsXD@^l*F(6K;BBw2z)Ul7Ibv4OUGZUF(eH=wa6)G&3 zIfy?R7uNorTV8P6J231x%Suas0yg)^&!4wJm%D>=G&D5V)vy6cu&|!q-srB&wcq4f zE9cPAVE_m^f=2X`Kp|kCGvAb+Zavthd-1LQ1~1^Yq;TfN=I06U;OGc}9I9F`FhcPL z{nLQ^F1weJzw+OQe&BwB3ANCMW!Fb~Z*8hMs3c<-#3-|oz;>|xrgyyQUEMp?<8yRM z_`!9jqqn2b!k8ePhPKY*NAOoOP40IqhHb-k7dQw6!ne!sl00bUqg=VjfC4|P89cYV zj0fl@NmW|aaSG+v0gDyNa~KlWQ__(P^n!uaf$L$ul}g6`Lt4<{Bv{AgXe5PNn8i2r z8x-;dqOJA7@Gw?O+h=%PJ$|{5L`>KlYmx&gdpx}QrMf=$mW2vP6n?<*M!RuFKqlx_ zb8fOE*TPGg{e5*-#c`wif^sH8-c-km5)L$Obbl7sQ%HIE!9Dl`5B@-fZsCH<%}1H+ z&#XS9#9Dl!qJ6la^qn@U``cU8nu&|TMhk)OU4695rVsWh99){vQa&kPM`lP~yj~=H ze8_G!Z3F*RKSQSYN<&BJfnQ$LzOUSQFdtao=Oik|FIhT3)i@{UR&VJlSCG0!7I~sCS zRf$kdL^%8Tfi-e05sj(SuM-o5!eL{jra5 zku7)*>7tkG$G@l6Eh%O^r+1#i!&RaFcXLrwB0)zi91ssHK7;RkKl<1qL_{Z<94liL zom6nXOSffH8Siic#E1&3QmYws~AbA@C%x3Au>s0b-d4RiNG?M zxye)$q*kavlaHwSUrBId#%9~9B=WY6F!J*osrL_}ME|Dxz=-|oSP}ePDPN#>H9I2` zUe*B;QMFLUVAyhc#_7M!0}5G+ydmlMQxfImaxN#Svn*$66NQTz%gpQlGb1BxcwBuW zuQHf@XpAmzW>Gl?x&dB^Hp-9y_a|JVu@9g)F&}Fgv!o+&9BB{YQ zj_m%q;`rqNB@F9&;Fr0eDD zx=Fk*XuHi;uFLj5yr`I$_f|B=p9G9mfY#rsCroEIf3amFyqBPKo{*U9pl}^I!p8c( z+mA99IzDQ{1VR*442Ld?qUR5=L#?da6vYJGX`&2`iobt{FH95$w3J-#iZTp{okUjx zUtBskPYw4qC;$O`GCwcJ@=YJ#thSc3hc}}225o~|k5msbxJaug!zvat>h~2MBd+-0 zI#^Z1COF_Is9hy&ZmELpy~lH*N(>v7;D{2~Kw>vai1dc-+w>3SUnOT+(uEwWSI`@- zyJ&|)?xv6K73+4Jv>`s=&kmeLycLn?>Zii#WNd(%%4C|NLg zJ8Gy@c6R=kMzb&9HGIP7B}>T$#J;58>|7!QH99V{8>9kJNzL_I4G7YEw6@fw1$&#K z#%`+quLfyLNuoWI8FmZvAW%AV%4EoR8C*m%|0C1whc6uWx*e=0USrkjd)bvpEp(;7 zPA}O@(2!n}_&BX>yUW-NHw~=H^K?Gneog&c%Z9HnTi>$pE)~*NNq%+Nv)}#-!OM7T zP1h$=W)Tf^z+Jx-z;2aFwS9gfvdphk+0or7Z0$)_RvE$byfUri%iQW(+u7vx6pSYZ z8{ce?m;wuat`J*5g>b9YQj~|#w>LgI=4W0{Q25WMkr8rUHg9~w9B2U7)w*nvm5BzK z0^&<*p4gKVo4Vtwt-$l7m3zU9hyp{Jpm%0^%!t=$?es*{^t1pl`Va>S*y9rnqpmA` z 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⋘+$~gNA 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 G|NjBgQ8PXO diff --git a/subprojects/nk_pugl/nuklear/example/images/image2.png b/subprojects/nk_pugl/nuklear/example/images/image2.png deleted file mode 100644 index 4acafe533ebd169fb5265b7d6c4c775075bf4dec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5671 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