Large refactor - IMGUI to Nuklear

This commit is contained in:
John Alanbrook 2022-06-21 17:48:19 +00:00
parent b82ea3d670
commit 162aebe3fa
142 changed files with 67753 additions and 181473 deletions

View file

@ -10,8 +10,9 @@ endif
UNAME_P != uname -m
#CC specifies which compiler we're using
CC = clang -std=c99
CXX = clang++
CC = gcc -std=c99
MUSL = /usr/local/musl
ifeq ($(DEBUG), 1)
DEFFALGS += -DDEBUG
@ -58,15 +59,11 @@ ehead != $(call findindir,./source/engine,*.h)
eobjects != $(call make_objs, ./source/engine)
eobjects != $(call rm,$(eobjects),sqlite pl_mpeg_extract_frames pl_mpeg_player yugine.c yugine.c)
imguisrcs = imgui imgui_draw imgui_widgets imgui_tables backends/imgui_impl_glfw backends/imgui_impl_opengl3
imguiobjs != $(call prefix,$(imguisrcs),$(objprefix)/source/editor/imgui/,.o)
eddirs != find ./source/editor -type d
eddirs += ./source/editor
edhead != $(call findindir,./source/editor,*.h)
edobjects != find ./source/editor -maxdepth 1 -type f -name '*.c' -o -name '*.cpp'
edobjects != $(call make_obj,$(edobjects))
edobjects += $(imguiobjs)
bsdirs != find ./source/brainstorm -type d
bsobjects != $(call make_objs, ./source/brainstorm)
@ -80,7 +77,8 @@ COMPINCLUDE = $(edirs) $(eddirs) $(pindirs) $(bsdirs)
#COMPILER_FLAGS specifies the additional compilation options we're using
WARNING_FLAGS = #-Wall -Wextra -Wwrite-strings -Wno-unused-parameter -Wno-unused-function -Wno-missing-braces -Wno-incompatible-function-pointer-types -Wno-gnu-statement-expression -Wno-complex-component-init -pedantic
COMPILER_FLAGS = $(includeflag) -g -O0 $(WARNING_FLAGS) -DGLEW_STATIC -D_GLFW_X11 -D_POSIX_C_SOURCE=1993809L -c -MMD -MP $< -o $@
#COMPILER_FLAGS = $(includeflag) -g -O0 $(WARNING_FLAGS) -DGLEW_STATIC -D_GLFW_X11 -D_POSIX_C_SOURCE=1993809L -c -MMD -MP $< -o $@
COMPILER_FLAGS = $(includeflag) -I/usr/local/lib-I$MUSL/include -g -O0 $(WARNING_FLAGS) -DGLEW_STATIC -D_GLFW_X11 -D_POSIX_C_SOURCE=1993809L -c $< -o $@
LIBPATH = -L./bin
@ -92,7 +90,7 @@ ifeq ($(UNAME), Windows_NT)
EXT = .exe
else
LINKER_FLAGS =
ELIBS = editor engine
ELIBS = editor engine m
CLIBS = glfw SDL2 SDL2_mixer dl pthread
EXT =
endif
@ -100,7 +98,7 @@ endif
ELIBS != $(call prefix, $(ELIBS), -l)
CLIBS != $(call prefix, $(CLIBS), -l)
LELIBS = -Wl,-Bstatic $(ELIBS) -Wl,-Bdynamic $(CLIBS)
LELIBS = $(ELIBS) $(CLIBS)
objects = $(bsobjects) $(eobjects) $(pinobjects)
DEPENDS = $(objects:.o=.d)
@ -118,13 +116,12 @@ LINK = $(LIBPATH) $(LINKER_FLAGS) $(LELIBS) -o $@
engine: $(yuginec:.%.c=$(objprefix)%.o) $(ENGINE)
@echo Linking engine
@$(CXX) $< $(linkinclude:%=-I%) $(LINK)
@$(CC) $< $(linkinclude:%=-I%) $(LINK)
@echo Finished build
editor: $(yuginec:.%.c=$(objprefix)%.o) $(EDITOR) $(ENGINE)
@echo Linking editor
$(CXX) $< $(linkinclude:%=-I%) $(LINK)
@mv editor yugine/editor
$(CC) $< $(linkinclude:%=-I%) $(LINK)
@echo Finished build
$(ENGINE): $(eobjects)
@ -139,18 +136,18 @@ $(EDITOR): $(edobjects)
xbrainstorm: $(ENGINE) $(bsobjects)
@echo Making brainstorm
@$(CXX) $(bsobjects) $(LINK) -o $@
@$(CC) $(bsobjects) $(LINK) -o $@
@mv xbrainstorm brainstorm/brainstorm$(EXT)
pinball: $(ENGINE) $(pinobjects)
@echo Making pinball
@$(CXX) $(pinobjects) $(LINK) -o $@
@$(CC) $(pinobjects) $(LINK) -o $@
@mv pinball paladin/pinball
$(objprefix)/%.o:%.cpp
@mkdir -p $(@D)
@echo Making C++ object $@
-@$(CXX) $(COMPILER_FLAGS)
-@$(CC) $(COMPILER_FLAGS)
$(objprefix)/%.o:%.c
@mkdir -p $(@D)

View file

@ -0,0 +1,205 @@
# Nuklear
[![](https://github.com/Immediate-Mode-UI/Nuklear/workflows/C%2FC++%20CI/badge.svg )](https://github.com/Immediate-Mode-UI/Nuklear/actions)
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/input handling but instead provides a
highly modular, library-based approach, with 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 focuses only 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 control of memory usage if needed / 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://Immediate-Mode-UI.github.io/Nuklear/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 defining 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 languages created by other authors.
I cannot attest for their quality since I am not necessarily proficient in any 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
- [D](https://github.com/Timu5/bindbc-nuklear) by Mateusz Muszyński
- [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ÖVE-Nuklear](https://github.com/keharriso/love-nuklear) by Kevin Harrison
- [MoonNuklear](https://github.com/stetre/moonnuklear) by Stefano Trettel
- 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
- [V](https://github.com/nsauzede/vnk) by Nicolas Sauzede
## 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. Finally Apoorva Joshi for his single-header [file packer](http://apoorvaj.io/single-header-packer.html).
## 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.
-----------------------------------------------------------------------------
```
## Reviewers guide
When reviewing pull request there are common things a reviewer should keep
in mind.
Reviewing changes to `src/*` and `nuklear.h`:
* Ensure C89 compatibility.
* The code should work for several backends to an acceptable degree.
* Check no other parts of `nuklear.h` are related to the PR and thus nothing is missing.
* Recommend simple optimizations.
* Pass small structs by value instead of by pointer.
* Use local buffers over heap allocation when possible.
* Check that the coding style is consistent with code around it.
* Variable/function name casing.
* Indentation.
* Curly bracket (`{}`) placement.
* Ensure that the contributor has bumped the appropriate version in
[clib.json](https://github.com/Immediate-Mode-UI/Nuklear/blob/master/clib.json)
and added their changes to the
[CHANGELOG](https://github.com/Immediate-Mode-UI/Nuklear/blob/master/src/CHANGELOG).
* Have at least one other person review the changes before merging.
Reviewing changes to `demo/*`, `example/*` and other files in the repo:
* Focus on getting working code merged.
* We want to make it easy for people to get started with Nuklear, and any
`demo` and `example` improvements helps in this regard.
* Use of newer C features, or even other languages is not discouraged.
* If another language is used, ensure that the build process is easy to figure out.
* Messy or less efficient code can be merged so long as these outliers are pointed out
and easy to find.
* Version shouldn't be bumped for these changes.
* Changes that improves code to be more inline with `nuklear.h` are ofc always welcome.

View file

@ -0,0 +1,9 @@
{
"name": "nuklear",
"version": "4.9.6",
"repo": "Immediate-Mode-UI/Nuklear",
"description": "A small ANSI C gui toolkit",
"keywords": ["gl", "ui", "toolkit"],
"license": "MIT, Unlicense",
"src": ["nuklear.h"]
}

View file

@ -0,0 +1,25 @@
# Install
BIN = demo
# Flags
CFLAGS += -std=c99 -Wall -Wextra -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)

View file

@ -0,0 +1,240 @@
/* nuklear - v1.32.0 - public domain */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <limits.h>
#include <time.h>
#include <GLFW/glfw3.h>
#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
#define NK_KEYSTATE_BASED_INPUT
#include "../../nuklear.h"
#include "nuklear_glfw_gl2.h"
#define STB_IMAGE_IMPLEMENTATION
#include "../../demo/common/filebrowser/stb_image.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_CANVAS
/* #define INCLUDE_FILE_BROWSER */
/* #define INCLUDE_OVERVIEW */
/* #define INCLUDE_NODE_EDITOR */
#ifdef INCLUDE_ALL
#define INCLUDE_STYLE
#define INCLUDE_CALCULATOR
#define INCLUDE_CANVAS
#define INCLUDE_OVERVIEW
#define INCLUDE_NODE_EDITOR
#endif
#ifdef INCLUDE_STYLE
#include "../../demo/common/style.c"
#endif
#ifdef INCLUDE_CALCULATOR
#include "../../demo/common/calculator.c"
#endif
#ifdef INCLUDE_CANVAS
#include "../../demo/common/canvas.c"
#endif
#ifdef INCLUDE_FILE_BROWSER
#include "../../demo/common/file_browser.c"
#endif
#ifdef INCLUDE_OVERVIEW
#include "../../demo/common/overview.c"
#endif
#ifdef INCLUDE_NODE_EDITOR
#include "../../demo/common/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;
/* GUI */
struct nk_context *ctx;
struct nk_colorf bg;
#ifdef INCLUDE_FILE_BROWSER
struct file_browser browser;
struct media media;
#endif
/* 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;
#ifdef INCLUDE_FILE_BROWSER
/* icons */
glEnable(GL_TEXTURE_2D);
media.icons.home = icon_load("../../demo/common/filebrowser/icon/home.png");
media.icons.directory = icon_load("../../demo/common/filebrowser/icon/directory.png");
media.icons.computer = icon_load("../../demo/common/filebrowser/icon/computer.png");
media.icons.desktop = icon_load("../../demo/common/filebrowser/icon/desktop.png");
media.icons.default_file = icon_load("../../demo/common/filebrowser/icon/default.png");
media.icons.text_file = icon_load("../../demo/common/filebrowser/icon/text.png");
media.icons.music_file = icon_load("../../demo/common/filebrowser/icon/music.png");
media.icons.font_file = icon_load("../../demo/common/filebrowser/icon/font.png");
media.icons.img_file = icon_load("../../demo/common/filebrowser/icon/img.png");
media.icons.movie_file = icon_load("../../demo/common/filebrowser/icon/movie.png");
media_init(&media);
file_browser_init(&browser, &media);
#endif
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_CANVAS
canvas(ctx);
#endif
#ifdef INCLUDE_FILE_BROWSER
file_browser_run(&browser, 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);
}
#ifdef INCLUDE_FILE_BROWSER
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);
#endif
nk_glfw3_shutdown();
glfwTerminate();
return 0;
}

View file

@ -0,0 +1,383 @@
/*
* 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 <GLFW/glfw3.h>
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}
};
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_clear(&dev->cmds);
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;
NK_UNUSED(mods);
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_clipboard_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_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';
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_clipboard_copy;
glfw.ctx.clip.paste = nk_glfw3_clipboard_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

View file

@ -0,0 +1,26 @@
# Install
BIN = demo
# Flags
CFLAGS += -std=c89 -Wall -Wextra -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)

View file

@ -0,0 +1,209 @@
/* nuklear - 1.32.0 - public domain */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <limits.h>
#include <time.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#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
#define NK_KEYSTATE_BASED_INPUT
#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_CANVAS */
#define INCLUDE_OVERVIEW
/*#define INCLUDE_NODE_EDITOR */
#ifdef INCLUDE_ALL
#define INCLUDE_STYLE
#define INCLUDE_CALCULATOR
#define INCLUDE_CANVAS
#define INCLUDE_OVERVIEW
#define INCLUDE_NODE_EDITOR
#endif
#ifdef INCLUDE_STYLE
#include "../../demo/common/style.c"
#endif
#ifdef INCLUDE_CALCULATOR
#include "../../demo/common/calculator.c"
#endif
#ifdef INCLUDE_CANVAS
#include "../../demo/common/canvas.c"
#endif
#ifdef INCLUDE_OVERVIEW
#include "../../demo/common/overview.c"
#endif
#ifdef INCLUDE_NODE_EDITOR
#include "../../demo/common/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 */
// struct nk_glfw glfw = {0};
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(&glfw, 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(&glfw, &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(&glfw);
/*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(&glfw);
/* 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_CANVAS
canvas(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(&glfw, NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
glfwSwapBuffers(win);
}
nk_glfw3_shutdown(&glfw);
glfwTerminate();
return 0;
}

View file

@ -0,0 +1,500 @@
/*
* 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 <glad/gl.h>
#include <GLFW/glfw3.h>
enum nk_glfw_init_state{
NK_GLFW3_DEFAULT=0,
NK_GLFW3_INSTALL_CALLBACKS
};
#ifndef NK_GLFW_TEXT_MAX
#define NK_GLFW_TEXT_MAX 256
#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 {
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;
};
NK_API struct nk_context* nk_glfw3_init(struct nk_glfw* glfw, GLFWwindow *win, enum nk_glfw_init_state);
NK_API void nk_glfw3_shutdown(struct nk_glfw* glfw);
NK_API void nk_glfw3_font_stash_begin(struct nk_glfw* glfw, struct nk_font_atlas **atlas);
NK_API void nk_glfw3_font_stash_end(struct nk_glfw* glfw);
NK_API void nk_glfw3_new_frame(struct nk_glfw* glfw);
NK_API void nk_glfw3_render(struct nk_glfw* glfw, enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer);
NK_API void nk_glfw3_device_destroy(struct nk_glfw* glfw);
NK_API void nk_glfw3_device_create(struct nk_glfw* glfw);
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_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_vertex {
float position[2];
float uv[2];
nk_byte col[4];
};
#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(struct nk_glfw* glfw)
{
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(struct nk_glfw* glfw, 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(struct nk_glfw* glfw)
{
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(struct nk_glfw* glfw, 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}
};
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);
nk_buffer_clear(&dev->cmds);
}
/* 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)
{
struct nk_glfw* glfw = glfwGetWindowUserPointer(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)
{
struct nk_glfw* glfw = glfwGetWindowUserPointer(win);
(void)xoff;
glfw->scroll.x += (float)xoff;
glfw->scroll.y += (float)yoff;
}
NK_API void
nk_glfw3_mouse_button_callback(GLFWwindow* win, int button, int action, int mods)
{
struct nk_glfw* glfw = glfwGetWindowUserPointer(win);
double x, y;
NK_UNUSED(mods);
if (button != GLFW_MOUSE_BUTTON_LEFT) return;
glfwGetCursorPos(win, &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_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)
{
struct nk_glfw* glfw = (struct nk_glfw*)usr.ptr;
const char *text = glfwGetClipboardString(glfw->win);
if (text) nk_textedit_paste(edit, text, nk_strlen(text));
(void)usr;
}
NK_INTERN void
nk_glfw3_clipboard_copy(nk_handle usr, const char *text, int len)
{
struct nk_glfw* glfw = (struct nk_glfw*)usr.ptr;
char *str = 0;
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(struct nk_glfw* glfw, GLFWwindow *win, enum nk_glfw_init_state init_state)
{
glfwSetWindowUserPointer(win, glfw);
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_clipboard_copy;
glfw->ctx.clip.paste = nk_glfw3_clipboard_paste;
glfw->ctx.clip.userdata = nk_handle_ptr(&glfw);
glfw->last_button_click = 0;
nk_glfw3_device_create(glfw);
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_glfw* glfw, 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(struct nk_glfw* glfw)
{
const void *image; int w, h;
image = nk_font_atlas_bake(&glfw->atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
nk_glfw3_device_upload_atlas(glfw, 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(struct nk_glfw* glfw)
{
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(struct nk_glfw* glfw)
{
nk_font_atlas_clear(&glfw->atlas);
nk_free(&glfw->ctx);
nk_glfw3_device_destroy(glfw);
memset(glfw, 0, sizeof(*glfw));
}
#endif

View file

@ -0,0 +1,26 @@
# Install
BIN = demo
# Flags
CFLAGS += -std=c89 -Wall -Wextra -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)

View file

@ -0,0 +1,230 @@
/* nuklear - 1.32.0 - public domain */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <limits.h>
#include <time.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#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_GL4_IMPLEMENTATION
#define NK_KEYSTATE_BASED_INPUT
#include "../../nuklear.h"
#include "nuklear_glfw_gl4.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_CANVAS */
#define INCLUDE_OVERVIEW
/*#define INCLUDE_NODE_EDITOR */
#ifdef INCLUDE_ALL
#define INCLUDE_STYLE
#define INCLUDE_CALCULATOR
#define INCLUDE_CANVAS
#define INCLUDE_OVERVIEW
#define INCLUDE_NODE_EDITOR
#endif
#ifdef INCLUDE_STYLE
#include "../../demo/common/style.c"
#endif
#ifdef INCLUDE_CALCULATOR
#include "../../demo/common/calculator.c"
#endif
#ifdef INCLUDE_CANVAS
#include "../../demo/common/canvas.c"
#endif
#ifdef INCLUDE_OVERVIEW
#include "../../demo/common/overview.c"
#endif
#ifdef INCLUDE_NODE_EDITOR
#include "../../demo/common/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;
struct nk_image img;
/* GLFW */
glfwSetErrorCallback(error_callback);
if (!glfwInit()) {
fprintf(stdout, "[GFLW] failed to init!\n");
exit(1);
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
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, MAX_VERTEX_BUFFER, MAX_ELEMENT_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_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
/* Create bindless texture.
* The index returned is not the opengl resource id.
* IF you need the GL resource id use: nk_glfw3_get_tex_ogl_id() */
{int tex_index = 0;
enum {tex_width = 256, tex_height = 256};
char pixels[tex_width * tex_height * 4];
memset(pixels, 128, sizeof(pixels));
tex_index = nk_glfw3_create_texture(pixels, tex_width, tex_height);
img = nk_image_id(tex_index);}
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);
/* Bindless Texture */
if (nk_begin(ctx, "Texture", nk_rect(250, 150, 230, 250),
NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
{
struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
struct nk_rect total_space = nk_window_get_content_region(ctx);
nk_draw_image(canvas, total_space, &img, nk_white);
}
nk_end(ctx);
/* -------------- EXAMPLES ---------------- */
#ifdef INCLUDE_CALCULATOR
calculator(ctx);
#endif
#ifdef INCLUDE_CANVAS
canvas(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);
glfwSwapBuffers(win);
}
nk_glfw3_shutdown();
glfwTerminate();
return 0;
}

View file

@ -0,0 +1,650 @@
/*
* 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_GL4_H_
#define NK_GLFW_GL4_H_
#include <string.h>
#include <GLFW/glfw3.h>
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, int max_vertex_buffer, int max_element_buffer);
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);
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);
NK_API GLuint nk_glfw3_get_tex_ogl_id(int tex_index);
NK_API GLuint64 nk_glfw3_get_tex_ogl_handle(int tex_index);
NK_API int nk_glfw3_create_texture(const void* image, int width, int height);
NK_API void nk_glfw3_destroy_texture(int tex_index);
#endif
/*
* ==============================================================
*
* IMPLEMENTATION
*
* ===============================================================
*/
#ifdef NK_GLFW_GL4_IMPLEMENTATION
#undef NK_GLFW_GL4_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
#ifndef NK_GLFW_MAX_TEXTURES
#define NK_GLFW_MAX_TEXTURES 256
#endif
struct nk_glfw_vertex {
float position[2];
float uv[2];
nk_byte col[4];
};
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;
int font_tex_index;
int max_vertex_buffer;
int max_element_buffer;
struct nk_glfw_vertex *vert_buffer;
int *elem_buffer;
GLsync buffer_sync;
GLuint tex_ids[NK_GLFW_MAX_TEXTURES];
GLuint64 tex_handles[NK_GLFW_MAX_TEXTURES];
};
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;
#define NK_SHADER_VERSION "#version 450 core\n"
#define NK_SHADER_BINDLESS "#extension GL_ARB_bindless_texture : require\n"
#define NK_SHADER_64BIT "#extension GL_ARB_gpu_shader_int64 : require\n"
NK_API void
nk_glfw3_device_create()
{
GLint status;
GLint len = 0;
static const GLchar *vertex_shader =
NK_SHADER_VERSION
NK_SHADER_BINDLESS
NK_SHADER_64BIT
"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
NK_SHADER_BINDLESS
NK_SHADER_64BIT
"precision mediump float;\n"
"uniform uint64_t Texture;\n"
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"out vec4 Out_Color;\n"
"void main(){\n"
" sampler2D smp = sampler2D(Texture);\n"
" Out_Color = Frag_Color * texture(smp, 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);
glGetShaderiv(dev->vert_shdr, GL_INFO_LOG_LENGTH, &len);
if (len > 1) {
char *log = (char*)calloc((size_t)len, sizeof(char));
glGetShaderInfoLog(dev->vert_shdr, len, NULL, log);
fprintf(stdout, "[GL]: failed to compile shader: %s", log);
free(log);
}
glGetShaderiv(dev->frag_shdr, GL_INFO_LOG_LENGTH, &len);
if (len > 1) {
char *log = (char*)calloc((size_t)len, sizeof(char));
glGetShaderInfoLog(dev->frag_shdr, len, NULL, log);
fprintf(stdout, "[GL]: failed to compile shader: %s", log);
free(log);
}
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);
GLuint pos = (GLuint)dev->attrib_pos;
GLuint uv = (GLuint)dev->attrib_uv;
GLuint col = (GLuint)dev->attrib_col;
glCreateVertexArrays(1, &dev->vao);
glCreateBuffers(1, &dev->vbo);
glCreateBuffers(1, &dev->ebo);
glEnableVertexArrayAttrib(dev->vao, pos);
glEnableVertexArrayAttrib(dev->vao, uv);
glEnableVertexArrayAttrib(dev->vao, col);
glVertexArrayAttribBinding(dev->vao, pos, 0);
glVertexArrayAttribBinding(dev->vao, uv, 0);
glVertexArrayAttribBinding(dev->vao, col, 0);
glVertexArrayAttribFormat(dev->vao, pos, 2, GL_FLOAT, GL_FALSE, vp);
glVertexArrayAttribFormat(dev->vao, uv, 2, GL_FLOAT, GL_FALSE, vt);
glVertexArrayAttribFormat(dev->vao, col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vc);
glVertexArrayElementBuffer(dev->vao, dev->ebo);
glVertexArrayVertexBuffer(dev->vao, 0, dev->vbo, 0, vs);
}
/* Persistent mapped buffers */
{GLsizei vb_size = dev->max_vertex_buffer;
GLsizei eb_size = dev->max_element_buffer;
GLbitfield flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
glNamedBufferStorage(dev->vbo, vb_size, 0, flags);
glNamedBufferStorage(dev->ebo, eb_size, 0, flags);
dev->vert_buffer = (struct nk_glfw_vertex*) glMapNamedBufferRange(dev->vbo, 0, vb_size, flags);
dev->elem_buffer = (int*) glMapNamedBufferRange(dev->ebo, 0, eb_size, flags);}
memset(dev->tex_ids, 0, sizeof(dev->tex_ids));
memset(dev->tex_handles, 0, sizeof(dev->tex_handles));
}
NK_INTERN int
nk_glfw3_get_available_tex_index()
{
int i = 0;
struct nk_glfw_device *dev = &glfw.ogl;
for (i = 0; i < NK_GLFW_MAX_TEXTURES; i++) {
if (dev->tex_ids[i] == 0)
return i;
} assert(0); /* max textures reached */
return -1;
}
NK_API GLuint
nk_glfw3_get_tex_ogl_id(int tex_index)
{
struct nk_glfw_device *dev = &glfw.ogl;
assert(tex_index >= 0 && tex_index < NK_GLFW_MAX_TEXTURES);
return dev->tex_ids[tex_index];
}
NK_API GLuint64
nk_glfw3_get_tex_ogl_handle(int tex_index)
{
struct nk_glfw_device *dev = &glfw.ogl;
assert(tex_index >= 0 && tex_index < NK_GLFW_MAX_TEXTURES);
return dev->tex_handles[tex_index];
}
NK_API int
nk_glfw3_create_texture(const void* image, int width, int height)
{
GLuint id;
GLsizei w = (GLsizei)width;
GLsizei h = (GLsizei)height;
struct nk_glfw_device *dev = &glfw.ogl;
int tex_index = nk_glfw3_get_available_tex_index();
if (tex_index < 0)
return -1;
glCreateTextures(GL_TEXTURE_2D, 1, &id);
dev->tex_ids[tex_index] = id;
glTextureParameteri(id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTextureParameteri(id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTextureParameteri(id, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTextureParameteri(id, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTextureStorage2D(id, 1, GL_RGBA8, w, h);
if (image)
glTextureSubImage2D(id, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, image);
else glClearTexImage(id, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
{GLuint64 handle = glGetTextureHandleARB(id);
glMakeTextureHandleResidentARB(handle);
dev->tex_handles[tex_index] = handle;
return tex_index;}
}
NK_API void
nk_glfw3_destroy_texture(int tex_index)
{
struct nk_glfw_device *dev = &glfw.ogl;
GLuint id = nk_glfw3_get_tex_ogl_id(tex_index);
if (id == 0) return;
{GLuint64 handle = nk_glfw3_get_tex_ogl_handle(tex_index);
glMakeTextureHandleNonResidentARB(handle);
glDeleteTextures(1, &id);
dev->tex_ids[tex_index] = 0;
dev->tex_handles[tex_index] = 0;}
}
NK_INTERN void
nk_glfw3_device_upload_atlas(const void *image, int width, int height)
{
struct nk_glfw_device *dev = &glfw.ogl;
dev->font_tex_index = nk_glfw3_create_texture(image, width, height);
}
NK_API void
nk_glfw3_device_destroy(void)
{
int i = 0;
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);
nk_glfw3_destroy_texture(dev->font_tex_index);
for (i = 0; i < NK_GLFW_MAX_TEXTURES; i++)
nk_glfw3_destroy_texture(i);
glUnmapNamedBuffer(dev->vbo);
glUnmapNamedBuffer(dev->ebo);
glDeleteBuffers(1, &dev->vbo);
glDeleteBuffers(1, &dev->ebo);
glDeleteVertexArrays(1, &dev->vao);
nk_buffer_free(&dev->cmds);
}
NK_INTERN void
nk_glfw3_wait_for_buffer_unlock()
{
struct nk_glfw_device *dev = &glfw.ogl;
if(!dev->buffer_sync)
return;
while (1) {
GLenum wait = glClientWaitSync(dev->buffer_sync, GL_SYNC_FLUSH_COMMANDS_BIT, 1);
if (wait == GL_ALREADY_SIGNALED || wait == GL_CONDITION_SATISFIED)
return;
}
}
NK_INTERN void
nk_glfw3_lock_buffer()
{
struct nk_glfw_device *dev = &glfw.ogl;
if(dev->buffer_sync) glDeleteSync(dev->buffer_sync);
dev->buffer_sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
}
NK_API void
nk_glfw3_render(enum nk_anti_aliasing AA)
{
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);
/* setup program */
glUseProgram(dev->prog);
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;
glBindVertexArray(dev->vao);
/* load draw vertices & elements directly into vertex + element buffer */
vertices = dev->vert_buffer;
elements = dev->elem_buffer;
{
/* Wait until GPU is done with buffer */
nk_glfw3_wait_for_buffer_unlock();
{
/* 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}
};
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)dev->max_vertex_buffer);
nk_buffer_init_fixed(&ebuf, elements, (size_t)dev->max_element_buffer);
nk_convert(&glfw.ctx, &dev->cmds, &vbuf, &ebuf, &config);
}
}
/* iterate over and execute each draw command */
nk_draw_foreach(cmd, &glfw.ctx, &dev->cmds)
{
int tex_index;
GLuint64 tex_handle;
if (!cmd->elem_count) continue;
tex_index = cmd->texture.id;
tex_handle = nk_glfw3_get_tex_ogl_handle(tex_index);
/* tex handle must be made resident in each context that uses it */
if (!glIsTextureHandleResidentARB(tex_handle))
glMakeTextureHandleResidentARB(tex_handle);
glUniformHandleui64ARB(dev->uniform_tex, tex_handle);
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_clear(&dev->cmds);
}
/* default OpenGL state */
glUseProgram(0);
glBindVertexArray(0);
glDisable(GL_BLEND);
glDisable(GL_SCISSOR_TEST);
/* Lock buffer until GPU has finished draw command */
nk_glfw3_lock_buffer();
}
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;
NK_UNUSED(mods);
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_clipboard_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_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';
glfwSetClipboardString(glfw.win, str);
free(str);
}
NK_API struct nk_context*
nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state init_state,
int max_vertex_buffer, int max_element_buffer)
{
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_clipboard_copy;
glfw.ctx.clip.paste = nk_glfw3_clipboard_paste;
glfw.ctx.clip.userdata = nk_handle_ptr(0);
glfw.last_button_click = 0;
{struct nk_glfw_device *dev = &glfw.ogl;
dev->max_vertex_buffer = max_vertex_buffer;
dev->max_element_buffer = max_element_buffer;
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_index), &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_GL4_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);
nk_input_key(ctx, NK_KEY_TEXT_SELECT_ALL, glfwGetKey(win, GLFW_KEY_A) == 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_GL4_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

View file

@ -0,0 +1,24 @@
# 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)

View file

@ -0,0 +1,2 @@
#!/bin/sh
cat ../nuklear.h|./doc > index.html

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,11 @@
<!--
This page is here in order to allow redirecting the old nuklear.html URL over to index.html
-->
<html>
<head>
<meta http-equiv="refresh" content="0; URL=index.html" />
</head>
<body>
<p>If you are not redirected in five seconds, <a href="index.html">click here</a>.</p>
</body>
</html>

View file

@ -0,0 +1,141 @@
/// ## 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 <stdio.h>
int main() {
printf("%s\n", "<meta charset='utf-8' emacsmode='-*- markdown -*-'>");
printf("%s\n", "<link rel='stylesheet' href='https://casual-effects.com/markdeep/latest/apidoc.css?'>");
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", "<script>markdeepOptions={tocStyle:'medium'};</script>");
printf("%s\n", "<!-- Markdeep: --><script src='https://casual-effects.com/markdeep/latest/markdeep.min.js?'></script>");
}
///
/// ## **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; some 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
///
/// <pre>
/// This is an embedded html node by the way!
/// </pre>
///
/// ## Credits
/// - API doc style created by [Aras Pranckevičius](https://github.com/aras-p)
/// - Markdeep by [Morgan McGuire](https://casual-effects.com/markdeep/).

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,334 @@
/// ## Changelog
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~none
/// [date] ([x.y.z]) - [description]
/// - [date]: date on which the change has been pushed
/// - [x.y.z]: Version string, represented in Semantic Versioning format
/// - [x]: Major version with API and library breaking changes
/// - [y]: Minor version with non-breaking API and library changes
/// - [z]: Patch version with no direct changes to the API
///
/// - 2022/05/27 (4.10.0) - Add nk_input_has_mouse_click_in_button_rect() to fix window move bug
/// - 2022/04/18 (4.9.7) - Change button behavior when NK_BUTTON_TRIGGER_ON_RELEASE is defined to
/// only trigger when the mouse position was inside the same button on down
/// - 2022/02/03 (4.9.6) - Allow overriding the NK_INV_SQRT function, similar to NK_SIN and NK_COS
/// - 2021/12/22 (4.9.5) - Revert layout bounds not accounting for padding due to regressions
/// - 2021/12/22 (4.9.4) - Fix checking hovering when window is minimized
/// - 2021/12/22 (4.09.3) - Fix layout bounds not accounting for padding
/// - 2021/12/19 (4.09.2) - Update to stb_rect_pack.h v1.01 and stb_truetype.h v1.26
/// - 2021/12/16 (4.09.1) - Fix the majority of GCC warnings
/// - 2021/10/16 (4.09.0) - Added nk_spacer() widget
/// - 2021/09/22 (4.08.6) - Fix "may be used uninitialized" warnings in nk_widget
/// - 2021/09/22 (4.08.5) - GCC __builtin_offsetof only exists in version 4 and later
/// - 2021/09/15 (4.08.4) - Fix "'num_len' may be used uninitialized" in nk_do_property
/// - 2021/09/15 (4.08.3) - Fix "Templates cannot be declared to have 'C' Linkage"
/// - 2021/09/08 (4.08.2) - Fix warnings in C89 builds
/// - 2021/09/08 (4.08.1) - Use compiler builtins for NK_OFFSETOF when possible
/// - 2021/08/17 (4.08.0) - Implemented 9-slice scaling support for widget styles
/// - 2021/08/16 (4.07.5) - Replace usage of memset in nk_font_atlas_bake with NK_MEMSET
/// - 2021/08/15 (4.07.4) - Fix conversion and sign conversion warnings
/// - 2021/08/08 (4.07.3) - Fix crash when baking merged fonts
/// - 2021/08/08 (4.07.2) - Fix Multiline Edit wrong offset
/// - 2021/03/17 (4.07.1) - Fix warning about unused parameter
/// - 2021/03/17 (4.07.0) - Fix nk_property hover bug
/// - 2021/03/15 (4.06.4) - Change nk_propertyi back to int
/// - 2021/03/15 (4.06.3) - Update documentation for functions that now return nk_bool
/// - 2020/12/19 (4.06.2) - Fix additional C++ style comments which are not allowed in ISO C90.
/// - 2020/10/11 (4.06.1) - Fix C++ style comments which are not allowed in ISO C90.
/// - 2020/10/07 (4.06.0) - Fix nk_combo return type wrongly changed to nk_bool
/// - 2020/09/05 (4.05.0) - Use the nk_font_atlas allocator for stb_truetype memory management.
/// - 2020/09/04 (4.04.1) - Replace every boolean int by nk_bool
/// - 2020/09/04 (4.04.0) - Add nk_bool with NK_INCLUDE_STANDARD_BOOL
/// - 2020/06/13 (4.03.1) - Fix nk_pool allocation sizes.
/// - 2020/06/04 (4.03.0) - Made nk_combo header symbols optional.
/// - 2020/05/27 (4.02.5) - Fix nk_do_edit: Keep scroll position when re-activating edit widget.
/// - 2020/05/09 (4.02.4) - Fix nk_menubar height calculation bug
/// - 2020/05/08 (4.02.3) - Fix missing stdarg.h with NK_INCLUDE_STANDARD_VARARGS
/// - 2020/04/30 (4.02.2) - Fix nk_edit border drawing bug
/// - 2020/04/09 (4.02.1) - Removed unused nk_sqrt function to fix compiler warnings
/// - Fixed compiler warnings if you bring your own methods for
/// nk_cos/nk_sin/nk_strtod/nk_memset/nk_memcopy/nk_dtoa
/// - 2020/04/06 (4.01.10) - Fix bug: Do not use pool before checking for NULL
/// - 2020/03/22 (4.01.9) - Fix bug where layout state wasn't restored correctly after
/// popping a tree.
/// - 2020/03/11 (4.01.8) - Fix bug where padding is subtracted from widget
/// - 2020/03/06 (4.01.7) - Fix bug where width padding was applied twice
/// - 2020/02/06 (4.01.6) - Update stb_truetype.h and stb_rect_pack.h and separate them
/// - 2019/12/10 (4.01.5) - Fix off-by-one error in NK_INTERSECT
/// - 2019/10/09 (4.01.4) - Fix bug for autoscrolling in nk_do_edit
/// - 2019/09/20 (4.01.3) - Fixed a bug wherein combobox cannot be closed by clicking the header
/// when NK_BUTTON_TRIGGER_ON_RELEASE is defined.
/// - 2019/09/10 (4.01.2) - Fixed the nk_cos function, which deviated significantly.
/// - 2019/09/08 (4.01.1) - Fixed a bug wherein re-baking of fonts caused a segmentation
/// fault due to dst_font->glyph_count not being zeroed on subsequent
/// bakes of the same set of fonts.
/// - 2019/06/23 (4.01.0) - Added nk_***_get_scroll and nk_***_set_scroll for groups, windows, and popups.
/// - 2019/06/12 (4.00.3) - Fix panel background drawing bug.
/// - 2018/10/31 (4.00.2) - Added NK_KEYSTATE_BASED_INPUT to "fix" state based backends
/// like GLFW without breaking key repeat behavior on event based.
/// - 2018/04/01 (4.00.1) - Fixed calling `nk_convert` multiple time per single frame.
/// - 2018/04/01 (4.00.0) - BREAKING CHANGE: nk_draw_list_clear no longer tries to
/// clear provided buffers. So make sure to either free
/// or clear each passed buffer after calling nk_convert.
/// - 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 separated 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 formatted 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: Modifying window position and size functions 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 boundaries.
/// - 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 clipboard 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 programmatic way to 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 `<stdint.h>` 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 glyphs.
/// - 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 `<stdio.h>`
/// 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 <stdio.h>. 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.0.
/// - 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 committing.
/// - 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 glyphs 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 falsely
/// becoming 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 dependent button
/// behavior instead of passing it for every function call.
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -0,0 +1,24 @@
/// ## 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. <br /><br />
///
/// 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) <br />
/// Uses [stddoc.c](https://github.com/r-lyeh/stddoc.c) from r-lyeh@github.com for documentation generation <br /><br />
/// Embeds ProggyClean.ttf font by Tristan Grimmer (MIT license). <br />
///
/// 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. Finally Apoorva Joshi
/// for his single header file packer.

View file

@ -0,0 +1,215 @@
/// # 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. <br /><br />
///
/// The implementation mode requires to define the preprocessor macro
/// NK_IMPLEMENTATION in *one* .c/.cpp file before #including 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 `<stdint.h>` 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 `<stdlib.h>` 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 `<stdio.h>` and provide additional functions depending on file loading.
/// NK_INCLUDE_STANDARD_VARARGS | If defined it will include header <stdarg.h> and provide additional functions depending on file loading.
/// NK_INCLUDE_STANDARD_BOOL | If defined it will include header `<stdbool.h>` for nk_bool otherwise nuklear defines nk_bool as int.
/// 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.
/// NK_UINT_DRAW_INDEX | Defining this will set the size of vertex index elements when using NK_VERTEX_BUFFER_OUTPUT to 32bit instead of the default of 16bit
/// NK_KEYSTATE_BASED_INPUT | Define this if your backend uses key state for each frame rather than key press/release events
///
/// !!! 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_STANDARD_BOOL
/// - NK_INCLUDE_VERTEX_BUFFER_OUTPUT
/// - NK_INCLUDE_FONT_BAKING
/// - NK_INCLUDE_DEFAULT_FONT
/// - NK_INCLUDE_STANDARD_VARARGS
/// - NK_INCLUDE_COMMAND_USERDATA
/// - NK_UINT_DRAW_INDEX
///
/// ### 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 <assert.h> 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_INV_SQRT | You can define this to your own inverse 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
///

View file

@ -0,0 +1,43 @@
/// ## 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.
/// ------------------------------------------------------------------------------
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -0,0 +1,5 @@
File Packer:
------------
- [Click to generate nuklear.h](http://apoorvaj.io/single-header-packer.html?macro=NK&pre=https://raw.githubusercontent.com/vurtun/nuklear/master/src/HEADER&pub=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear.h&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_internal.h&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_math.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_util.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_color.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_utf8.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_buffer.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_string.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_draw.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_vertex.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_font.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_input.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_style.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_context.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_pool.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_page_element.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_table.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_panel.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_window.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_popup.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_contextual.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_menu.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_layout.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_tree.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_group.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_list_view.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_widget.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_text.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_image.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_button.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_toggle.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_selectable.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_slider.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_progress.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_scrollbar.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_text_editor.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_edit.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_property.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_chart.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_color_picker.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_combo.c&priv=https://raw.githubusercontent.com/vurtun/nuklear/master/src/nuklear_tooltip.c&post=https://raw.githubusercontent.com/vurtun/nuklear/master/src/LICENSE&post=https://raw.githubusercontent.com/vurtun/nuklear/master/src/CHANGELOG&post=https://raw.githubusercontent.com/vurtun/nuklear/master/src/CREDITS)
- On Linux/Mac just run ./paq.sh > ../nuklear.h
- On Windows just run paq.bat

View file

@ -0,0 +1,167 @@
import fnmatch
import os.path
import sys
import re
def print_help():
print(
"""usage: python single_header_packer.py --macro <macro> [--intro <files>] --extern <files> --pub <files> --priv1 <files> --priv2 <files> [--outro <files>]
where <files> can be a comma-separated list of files. e.g. --priv *.c,inc/*.h
The 'extern' files are placed between 'priv1' and 'priv2'.
The resulting code is packed as follows:
/*
[intro file contents]
*/
#ifndef <macro>_SINGLE_HEADER
#define <macro>_SINGLE_HEADER
[public header file contents]
#endif /* <macro>_SINGLE_HEADER */
#ifdef <macro>_IMPLEMENTATION
[private header and source file contents]
#endif /* <macro>_IMPLEMENTATION */
/*
[outro file contents]
*/""")
def parse_files(arg):
files = []
paths = arg.split(",")
for path in paths:
if "*" in path:
# Wildcard
d = os.path.dirname(path)
if d == "": d = "."
if d == " ": continue
if not os.path.exists(d):
print(d + " does not exist.")
exit()
wildcard = os.path.basename(path)
unsorted = []
for file in os.listdir(d):
if fnmatch.fnmatch(file, wildcard):
unsorted.append(os.path.join(d, file))
unsorted.sort()
files.extend(unsorted)
else:
# Regular file
if not os.path.exists(path):
print(path + " does not exist.")
exit()
elif os.path.isdir(path):
print(path + " is a directory. Expected a file name.")
exit()
else:
files.append(path)
return files;
def omit_includes(str, files):
for file in files:
fname = os.path.basename(file)
if ".h" in file:
str = str.replace("#include \"" + fname + "\"", "");
str = str.replace("#include <" + fname + ">", "");
return str
def fix_comments(str):
return re.sub(r"//(.*)(\n|$)", "/* \\1 */\\2", str)
# Main start
# ==========
if len(sys.argv) < 2:
print_help()
exit()
intro_files = []
pub_files = []
priv_files1 = []
outro_files2 = []
extern_files = []
cur_arg = 1
macro = ""
# Parse args
# ----------
while cur_arg < len(sys.argv):
if sys.argv[cur_arg] == "--help":
print_help()
exit()
elif sys.argv[cur_arg] == "--macro":
cur_arg += 1
macro = sys.argv[cur_arg]
elif sys.argv[cur_arg] == "--intro":
cur_arg += 1
intro_files = parse_files(sys.argv[cur_arg])
elif sys.argv[cur_arg] == "--pub":
cur_arg += 1
pub_files = parse_files(sys.argv[cur_arg])
elif sys.argv[cur_arg] == "--priv1":
cur_arg += 1
priv_files1 = parse_files(sys.argv[cur_arg])
elif sys.argv[cur_arg] == "--priv2":
cur_arg += 1
priv_files2 = parse_files(sys.argv[cur_arg])
elif sys.argv[cur_arg] == "--extern":
cur_arg += 1
extern_files = parse_files(sys.argv[cur_arg])
elif sys.argv[cur_arg] == "--outro":
cur_arg += 1
outro_files = parse_files(sys.argv[cur_arg])
else:
print("Unknown argument " + sys.argv[cur_arg])
cur_arg += 1
if macro == "":
print("Option --macro <macro> is mandatory")
exit()
# Print concatenated output
# -------------------------
print("/*")
for f in intro_files:
sys.stdout.write(open(f, 'r').read())
print("*/")
# print("\n#ifndef " + macro + "_SINGLE_HEADER");
# print("#define " + macro + "_SINGLE_HEADER");
print("#ifndef NK_SINGLE_FILE");
print(" #define NK_SINGLE_FILE");
print("#endif");
print("");
for f in pub_files:
sys.stdout.write(open(f, 'r').read())
# print("#endif /* " + macro + "_SINGLE_HEADER */");
print("\n#ifdef " + macro + "_IMPLEMENTATION");
print("");
for f in priv_files1:
print(omit_includes(open(f, 'r').read(),
pub_files + priv_files1 + priv_files2 + extern_files))
for f in extern_files:
print(fix_comments(open(f, 'r').read()))
for f in priv_files2:
print(omit_includes(open(f, 'r').read(),
pub_files + priv_files1 + priv_files2 + extern_files))
print("#endif /* " + macro + "_IMPLEMENTATION */");
print("\n/*")
for f in outro_files:
sys.stdout.write(open(f, 'r').read())
print("*/\n")

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,106 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* 9-SLICE
*
* ===============================================================*/
NK_API struct nk_nine_slice
nk_sub9slice_ptr(void *ptr, nk_ushort w, nk_ushort h, struct nk_rect rgn, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)
{
struct nk_nine_slice s;
struct nk_image *i = &s.img;
nk_zero(&s, sizeof(s));
i->handle.ptr = ptr;
i->w = w; i->h = h;
i->region[0] = (nk_ushort)rgn.x;
i->region[1] = (nk_ushort)rgn.y;
i->region[2] = (nk_ushort)rgn.w;
i->region[3] = (nk_ushort)rgn.h;
s.l = l; s.t = t; s.r = r; s.b = b;
return s;
}
NK_API struct nk_nine_slice
nk_sub9slice_id(int id, nk_ushort w, nk_ushort h, struct nk_rect rgn, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)
{
struct nk_nine_slice s;
struct nk_image *i = &s.img;
nk_zero(&s, sizeof(s));
i->handle.id = id;
i->w = w; i->h = h;
i->region[0] = (nk_ushort)rgn.x;
i->region[1] = (nk_ushort)rgn.y;
i->region[2] = (nk_ushort)rgn.w;
i->region[3] = (nk_ushort)rgn.h;
s.l = l; s.t = t; s.r = r; s.b = b;
return s;
}
NK_API struct nk_nine_slice
nk_sub9slice_handle(nk_handle handle, nk_ushort w, nk_ushort h, struct nk_rect rgn, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)
{
struct nk_nine_slice s;
struct nk_image *i = &s.img;
nk_zero(&s, sizeof(s));
i->handle = handle;
i->w = w; i->h = h;
i->region[0] = (nk_ushort)rgn.x;
i->region[1] = (nk_ushort)rgn.y;
i->region[2] = (nk_ushort)rgn.w;
i->region[3] = (nk_ushort)rgn.h;
s.l = l; s.t = t; s.r = r; s.b = b;
return s;
}
NK_API struct nk_nine_slice
nk_nine_slice_handle(nk_handle handle, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)
{
struct nk_nine_slice s;
struct nk_image *i = &s.img;
nk_zero(&s, sizeof(s));
i->handle = handle;
i->w = 0; i->h = 0;
i->region[0] = 0;
i->region[1] = 0;
i->region[2] = 0;
i->region[3] = 0;
s.l = l; s.t = t; s.r = r; s.b = b;
return s;
}
NK_API struct nk_nine_slice
nk_nine_slice_ptr(void *ptr, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)
{
struct nk_nine_slice s;
struct nk_image *i = &s.img;
nk_zero(&s, sizeof(s));
NK_ASSERT(ptr);
i->handle.ptr = ptr;
i->w = 0; i->h = 0;
i->region[0] = 0;
i->region[1] = 0;
i->region[2] = 0;
i->region[3] = 0;
s.l = l; s.t = t; s.r = r; s.b = b;
return s;
}
NK_API struct nk_nine_slice
nk_nine_slice_id(int id, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)
{
struct nk_nine_slice s;
struct nk_image *i = &s.img;
nk_zero(&s, sizeof(s));
i->handle.id = id;
i->w = 0; i->h = 0;
i->region[0] = 0;
i->region[1] = 0;
i->region[2] = 0;
i->region[3] = 0;
s.l = l; s.t = t; s.r = r; s.b = b;
return s;
}
NK_API int
nk_nine_slice_is_sub9slice(const struct nk_nine_slice* slice)
{
NK_ASSERT(slice);
return !(slice->img.w == 0 && slice->img.h == 0);
}

View file

@ -0,0 +1,277 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ==============================================================
*
* BUFFER
*
* ===============================================================*/
#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
NK_LIB void*
nk_malloc(nk_handle unused, void *old,nk_size size)
{
NK_UNUSED(unused);
NK_UNUSED(old);
return malloc(size);
}
NK_LIB 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_LIB 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_LIB 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_LIB 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;
}

View file

@ -0,0 +1,672 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ==============================================================
*
* BUTTON
*
* ===============================================================*/
NK_LIB 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_LIB nk_bool
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_button_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_LIB 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;
switch(background->type) {
case NK_STYLE_ITEM_IMAGE:
nk_draw_image(out, *bounds, &background->data.image, nk_white);
break;
case NK_STYLE_ITEM_NINE_SLICE:
nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_white);
break;
case 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);
break;
}
return background;
}
NK_LIB nk_bool
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_LIB 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_LIB nk_bool
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_LIB 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_LIB nk_bool
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_LIB 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_LIB nk_bool
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_LIB 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_LIB nk_bool
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_LIB 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_LIB nk_bool
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;
}
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool 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 nk_bool nk_button_label(struct nk_context *ctx, const char *title)
{
return nk_button_text(ctx, title, nk_strlen(title));
}
NK_API nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool 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 nk_bool 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 nk_bool
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 nk_bool
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 nk_bool 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 nk_bool 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);
}

View file

@ -0,0 +1,325 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ==============================================================
*
* CHART
*
* ===============================================================*/
NK_API nk_bool
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;
switch(background->type) {
case NK_STYLE_ITEM_IMAGE:
nk_draw_image(&win->buffer, bounds, &background->data.image, nk_white);
break;
case NK_STYLE_ITEM_NINE_SLICE:
nk_draw_nine_slice(&win->buffer, bounds, &background->data.slice, nk_white);
break;
case NK_STYLE_ITEM_COLOR:
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);
break;
}
return 1;
}
NK_API nk_bool
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);
}
}

View file

@ -0,0 +1,414 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ==============================================================
*
* 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];
}

View file

@ -0,0 +1,201 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ==============================================================
*
* COLOR PICKER
*
* ===============================================================*/
NK_LIB nk_bool
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];
nk_bool value_changed = 0;
nk_bool 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_LIB 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_LIB nk_bool
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;
}
NK_API nk_bool
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;
}

View file

@ -0,0 +1,839 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ==============================================================
*
* COMBO
*
* ===============================================================*/
NK_INTERN nk_bool
nk_combo_begin(struct nk_context *ctx, struct nk_window *win,
struct nk_vec2 size, nk_bool 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 nk_bool
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;
}
switch(background->type) {
case NK_STYLE_ITEM_IMAGE:
text.background = nk_rgba(0, 0, 0, 0);
nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
break;
case NK_STYLE_ITEM_NINE_SLICE:
text.background = nk_rgba(0, 0, 0, 0);
nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_white);
break;
case NK_STYLE_ITEM_COLOR:
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);
break;
}
{
/* print currently selected text item */
struct nk_rect label;
struct nk_rect button;
struct nk_rect content;
int draw_button_symbol;
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;
/* represents whether or not the combo's button symbol should be drawn */
draw_button_symbol = sym != NK_SYMBOL_NONE;
/* 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.h = header.h - 2 * style->combo.content_padding.y;
if (draw_button_symbol)
label.w = button.x - (style->combo.content_padding.x + style->combo.spacing.x) - label.x;
else
label.w = header.w - 2 * style->combo.content_padding.x;
nk_widget_text(&win->buffer, label, selected, len, &text,
NK_TEXT_LEFT, ctx->style.font);
/* draw open/close button */
if (draw_button_symbol)
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 nk_bool
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 nk_bool
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;
switch(background->type) {
case NK_STYLE_ITEM_IMAGE:
nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
break;
case NK_STYLE_ITEM_NINE_SLICE:
nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_white);
break;
case NK_STYLE_ITEM_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);
break;
}
{
struct nk_rect content;
struct nk_rect button;
struct nk_rect bounds;
int draw_button_symbol;
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;
/* represents whether or not the combo's button symbol should be drawn */
draw_button_symbol = sym != NK_SYMBOL_NONE;
/* 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;
if (draw_button_symbol)
bounds.w = (button.x - (style->combo.content_padding.x + style->combo.spacing.x)) - bounds.x;
else
bounds.w = header.w - 4 * style->combo.content_padding.x;
nk_fill_rect(&win->buffer, bounds, 0, color);
/* draw open/close button */
if (draw_button_symbol)
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 nk_bool
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;
}
switch(background->type) {
case NK_STYLE_ITEM_IMAGE:
sym_background = nk_rgba(0, 0, 0, 0);
nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
break;
case NK_STYLE_ITEM_NINE_SLICE:
sym_background = nk_rgba(0, 0, 0, 0);
nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_white);
break;
case NK_STYLE_ITEM_COLOR:
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);
break;
}
{
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 nk_bool
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;
}
switch(background->type) {
case NK_STYLE_ITEM_IMAGE:
text.background = nk_rgba(0, 0, 0, 0);
nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
break;
case NK_STYLE_ITEM_NINE_SLICE:
text.background = nk_rgba(0, 0, 0, 0);
nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_white);
break;
case NK_STYLE_ITEM_COLOR:
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);
break;
}
{
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 nk_bool
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;
switch (background->type) {
case NK_STYLE_ITEM_IMAGE:
nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
break;
case NK_STYLE_ITEM_NINE_SLICE:
nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_white);
break;
case NK_STYLE_ITEM_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);
break;
}
{
struct nk_rect bounds = {0,0,0,0};
struct nk_rect content;
struct nk_rect button;
int draw_button_symbol;
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;
/* represents whether or not the combo's button symbol should be drawn */
draw_button_symbol = sym != NK_SYMBOL_NONE;
/* 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;
if (draw_button_symbol)
bounds.w = (button.x - style->combo.content_padding.y) - bounds.x;
else
bounds.w = header.w - 2 * style->combo.content_padding.x;
nk_draw_image(&win->buffer, bounds, &img, nk_white);
/* draw open/close button */
if (draw_button_symbol)
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 nk_bool
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;
}
switch(background->type) {
case NK_STYLE_ITEM_IMAGE:
text.background = nk_rgba(0, 0, 0, 0);
nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
break;
case NK_STYLE_ITEM_NINE_SLICE:
text.background = nk_rgba(0, 0, 0, 0);
nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_white);
break;
case NK_STYLE_ITEM_COLOR:
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);
break;
}
{
struct nk_rect content;
struct nk_rect button;
struct nk_rect label;
struct nk_rect image;
int draw_button_symbol;
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;
/* represents whether or not the combo's button symbol should be drawn */
draw_button_symbol = sym != NK_SYMBOL_NONE;
/* 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;
if (draw_button_symbol)
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.h = header.h - 2 * style->combo.content_padding.y;
if (draw_button_symbol)
label.w = (button.x - style->combo.content_padding.x) - label.x;
else
label.w = (header.x + header.w - style->combo.content_padding.x) - label.x;
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
nk_combo_item_label(struct nk_context *ctx, const char *label, nk_flags align)
{
return nk_contextual_item_label(ctx, label, align);
}
NK_API nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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);
}

View file

@ -0,0 +1,344 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ==============================================================
*
* CONTEXT
*
* ===============================================================*/
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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));
/* 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++;
}
NK_LIB 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_LIB void
nk_start(struct nk_context *ctx, struct nk_window *win)
{
NK_ASSERT(ctx);
NK_ASSERT(win);
nk_start_buffer(ctx, &win->buffer);
}
NK_LIB 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_LIB 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_LIB 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_LIB 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_LIB 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;
}

View file

@ -0,0 +1,221 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ==============================================================
*
* CONTEXTUAL
*
* ===============================================================*/
NK_API nk_bool
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 = {-1,-1,0,0};
int is_clicked = 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;
if (ctx->current != ctx->active)
return 0;
/* 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_open && win->popup.active_con)
win->popup.active_con = 0;
if ((!is_open && !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;
win->popup.type = NK_PANEL_NONE;
if (win->popup.win)
win->popup.win->flags = 0;
}
return ret;
}
NK_API nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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;
}

View file

@ -0,0 +1,558 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ==============================================================
*
* DRAW
*
* ===============================================================*/
NK_LIB void
nk_command_buffer_init(struct nk_command_buffer *cb,
struct nk_buffer *b, enum nk_command_clipping clip)
{
NK_ASSERT(cb);
NK_ASSERT(b);
if (!cb || !b) return;
cb->base = b;
cb->use_clipping = (int)clip;
cb->begin = b->allocated;
cb->end = b->allocated;
cb->last = b->allocated;
}
NK_LIB void
nk_command_buffer_reset(struct nk_command_buffer *b)
{
NK_ASSERT(b);
if (!b) return;
b->begin = 0;
b->end = 0;
b->last = 0;
b->clip = nk_null_rect;
#ifdef NK_INCLUDE_COMMAND_USERDATA
b->userdata.ptr = 0;
#endif
}
NK_LIB 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_draw_nine_slice(struct nk_command_buffer *b, struct nk_rect r,
const struct nk_nine_slice *slc, struct nk_color col)
{
struct nk_image img;
const struct nk_image *slcimg = (const struct nk_image*)slc;
nk_ushort rgnX, rgnY, rgnW, rgnH;
rgnX = slcimg->region[0];
rgnY = slcimg->region[1];
rgnW = slcimg->region[2];
rgnH = slcimg->region[3];
/* top-left */
img.handle = slcimg->handle;
img.w = slcimg->w;
img.h = slcimg->h;
img.region[0] = rgnX;
img.region[1] = rgnY;
img.region[2] = slc->l;
img.region[3] = slc->t;
nk_draw_image(b,
nk_rect(r.x, r.y, (float)slc->l, (float)slc->t),
&img, col);
#define IMG_RGN(x, y, w, h) img.region[0] = (nk_ushort)(x); img.region[1] = (nk_ushort)(y); img.region[2] = (nk_ushort)(w); img.region[3] = (nk_ushort)(h);
/* top-center */
IMG_RGN(rgnX + slc->l, rgnY, rgnW - slc->l - slc->r, slc->t);
nk_draw_image(b,
nk_rect(r.x + (float)slc->l, r.y, (float)(r.w - slc->l - slc->r), (float)slc->t),
&img, col);
/* top-right */
IMG_RGN(rgnX + rgnW - slc->r, rgnY, slc->r, slc->t);
nk_draw_image(b,
nk_rect(r.x + r.w - (float)slc->r, r.y, (float)slc->r, (float)slc->t),
&img, col);
/* center-left */
IMG_RGN(rgnX, rgnY + slc->t, slc->l, rgnH - slc->t - slc->b);
nk_draw_image(b,
nk_rect(r.x, r.y + (float)slc->t, (float)slc->l, (float)(r.h - slc->t - slc->b)),
&img, col);
/* center */
IMG_RGN(rgnX + slc->l, rgnY + slc->t, rgnW - slc->l - slc->r, rgnH - slc->t - slc->b);
nk_draw_image(b,
nk_rect(r.x + (float)slc->l, r.y + (float)slc->t, (float)(r.w - slc->l - slc->r), (float)(r.h - slc->t - slc->b)),
&img, col);
/* center-right */
IMG_RGN(rgnX + rgnW - slc->r, rgnY + slc->t, slc->r, rgnH - slc->t - slc->b);
nk_draw_image(b,
nk_rect(r.x + r.w - (float)slc->r, r.y + (float)slc->t, (float)slc->r, (float)(r.h - slc->t - slc->b)),
&img, col);
/* bottom-left */
IMG_RGN(rgnX, rgnY + rgnH - slc->b, slc->l, slc->b);
nk_draw_image(b,
nk_rect(r.x, r.y + r.h - (float)slc->b, (float)slc->l, (float)slc->b),
&img, col);
/* bottom-center */
IMG_RGN(rgnX + slc->l, rgnY + rgnH - slc->b, rgnW - slc->l - slc->r, slc->b);
nk_draw_image(b,
nk_rect(r.x + (float)slc->l, r.y + r.h - (float)slc->b, (float)(r.w - slc->l - slc->r), (float)slc->b),
&img, col);
/* bottom-right */
IMG_RGN(rgnX + rgnW - slc->r, rgnY + rgnH - slc->b, slc->r, slc->b);
nk_draw_image(b,
nk_rect(r.x + r.w - (float)slc->r, r.y + r.h - (float)slc->b, (float)slc->r, (float)slc->b),
&img, col);
#undef IMG_RGN
}
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';
}

View file

@ -0,0 +1,820 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* FILTER
*
* ===============================================================*/
NK_API nk_bool
nk_filter_default(const struct nk_text_edit *box, nk_rune unicode)
{
NK_UNUSED(unicode);
NK_UNUSED(box);
return nk_true;
}
NK_API nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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_LIB 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, nk_bool is_selected)
{
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);
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);
nk_widget_text(out, label, line, (int)((text + text_len) - line),
&txt, NK_TEXT_LEFT, font);
}}
}
NK_LIB 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;
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;
/* keep scroll position when re-activating edit widget */
struct nk_vec2 oldscrollbar = edit->scrollbar;
nk_textedit_clear_state(edit, type, filter);
edit->scrollbar = oldscrollbar;
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, " ", 4);
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 */
switch(background->type) {
case NK_STYLE_ITEM_IMAGE:
nk_draw_image(out, bounds, &background->data.image, nk_white);
break;
case NK_STYLE_ITEM_NINE_SLICE:
nk_draw_nine_slice(out, bounds, &background->data.slice, nk_white);
break;
case 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);
break;
}}
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 - area.w + scroll_increment);
} 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 + row_height)
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, 0,
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->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);
} 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);
}
if (edit->select_start != edit->select_end) {
/* 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);
}
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);
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_true);
}
}
/* 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);
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);
}
nk_push_scissor(out, old_clip);}
return ret;
}
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;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,236 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* GROUP
*
* ===============================================================*/
NK_API nk_bool
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 nk_bool
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 nk_bool
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);
if (!x_offset) {
x_offset = nk_add_value(ctx, win, id_hash, 0);
y_offset = nk_add_value(ctx, win, id_hash+1, 0);
NK_ASSERT(x_offset);
NK_ASSERT(y_offset);
if (!x_offset || !y_offset) return 0;
*x_offset = *y_offset = 0;
} else y_offset = nk_find_value(win, id_hash+1);
return nk_group_scrolled_offset_begin(ctx, x_offset, y_offset, title, flags);
}
NK_API nk_bool
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 void
nk_group_get_scroll(struct nk_context *ctx, const char *id, nk_uint *x_offset, nk_uint *y_offset)
{
int id_len;
nk_hash id_hash;
struct nk_window *win;
nk_uint *x_offset_ptr;
nk_uint *y_offset_ptr;
NK_ASSERT(ctx);
NK_ASSERT(id);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout || !id)
return;
/* 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_ptr = nk_find_value(win, id_hash);
if (!x_offset_ptr) {
x_offset_ptr = nk_add_value(ctx, win, id_hash, 0);
y_offset_ptr = nk_add_value(ctx, win, id_hash+1, 0);
NK_ASSERT(x_offset_ptr);
NK_ASSERT(y_offset_ptr);
if (!x_offset_ptr || !y_offset_ptr) return;
*x_offset_ptr = *y_offset_ptr = 0;
} else y_offset_ptr = nk_find_value(win, id_hash+1);
if (x_offset)
*x_offset = *x_offset_ptr;
if (y_offset)
*y_offset = *y_offset_ptr;
}
NK_API void
nk_group_set_scroll(struct nk_context *ctx, const char *id, nk_uint x_offset, nk_uint y_offset)
{
int id_len;
nk_hash id_hash;
struct nk_window *win;
nk_uint *x_offset_ptr;
nk_uint *y_offset_ptr;
NK_ASSERT(ctx);
NK_ASSERT(id);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout || !id)
return;
/* 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_ptr = nk_find_value(win, id_hash);
if (!x_offset_ptr) {
x_offset_ptr = nk_add_value(ctx, win, id_hash, 0);
y_offset_ptr = nk_add_value(ctx, win, id_hash+1, 0);
NK_ASSERT(x_offset_ptr);
NK_ASSERT(y_offset_ptr);
if (!x_offset_ptr || !y_offset_ptr) return;
*x_offset_ptr = *y_offset_ptr = 0;
} else y_offset_ptr = nk_find_value(win, id_hash+1);
*x_offset_ptr = x_offset;
*y_offset_ptr = y_offset;
}

View file

@ -0,0 +1,139 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* 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, nk_ushort w, nk_ushort 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] = (nk_ushort)r.x;
s.region[1] = (nk_ushort)r.y;
s.region[2] = (nk_ushort)r.w;
s.region[3] = (nk_ushort)r.h;
return s;
}
NK_API struct nk_image
nk_subimage_id(int id, nk_ushort w, nk_ushort 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] = (nk_ushort)r.x;
s.region[1] = (nk_ushort)r.y;
s.region[2] = (nk_ushort)r.w;
s.region[3] = (nk_ushort)r.h;
return s;
}
NK_API struct nk_image
nk_subimage_handle(nk_handle handle, nk_ushort w, nk_ushort 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] = (nk_ushort)r.x;
s.region[1] = (nk_ushort)r.y;
s.region[2] = (nk_ushort)r.w;
s.region[3] = (nk_ushort)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 nk_bool
nk_image_is_subimage(const struct nk_image* img)
{
NK_ASSERT(img);
return !(img->w == 0 && img->h == 0);
}
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);
}

View file

@ -0,0 +1,280 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* 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, nk_bool down)
{
struct nk_input *in;
NK_ASSERT(ctx);
if (!ctx) return;
in = &ctx->input;
#ifdef NK_KEYSTATE_BASED_INPUT
if (in->keyboard.keys[key].down != down)
in->keyboard.keys[key].clicked++;
#else
in->keyboard.keys[key].clicked++;
#endif
in->keyboard.keys[key].down = down;
}
NK_API void
nk_input_button(struct nk_context *ctx, enum nk_buttons id, int x, int y, nk_bool 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++;
#ifdef NK_BUTTON_TRIGGER_ON_RELEASE
if (down == 1 && id == NK_BUTTON_LEFT)
{
in->mouse.down_pos.x = btn->clicked_pos.x;
in->mouse.down_pos.y = btn->clicked_pos.y;
}
#endif
}
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 nk_bool
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 nk_bool
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 nk_bool
nk_input_has_mouse_click_in_button_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];
#ifdef NK_BUTTON_TRIGGER_ON_RELEASE
if (!NK_INBOX(btn->clicked_pos.x,btn->clicked_pos.y,b.x,b.y,b.w,b.h)
|| !NK_INBOX(i->mouse.down_pos.x,i->mouse.down_pos.y,b.x,b.y,b.w,b.h))
#else
if (!NK_INBOX(btn->clicked_pos.x,btn->clicked_pos.y,b.x,b.y,b.w,b.h))
#endif
return nk_false;
return nk_true;
}
NK_API nk_bool
nk_input_has_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id,
struct nk_rect b, nk_bool 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 nk_bool
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 nk_bool
nk_input_is_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id,
struct nk_rect b, nk_bool 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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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;
}

View file

@ -0,0 +1,356 @@
#ifndef NK_INTERNAL_H
#define NK_INTERNAL_H
#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 <stdlib.h> /* malloc, free */
#endif
#ifdef NK_INCLUDE_STANDARD_IO
#include <stdio.h> /* fopen, fclose,... */
#endif
#ifdef NK_INCLUDE_STANDARD_VARARGS
#include <stdarg.h> /* valist, va_start, va_end, ... */
#endif
#ifndef NK_ASSERT
#include <assert.h>
#define NK_ASSERT(expr) assert(expr)
#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);
#ifdef NK_INCLUDE_STANDARD_BOOL
NK_STATIC_ASSERT(sizeof(nk_bool) == sizeof(bool));
#else
NK_STATIC_ASSERT(sizeof(nk_bool) == 4);
#endif
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};
/* 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;
/* math */
#ifndef NK_INV_SQRT
NK_LIB float nk_inv_sqrt(float n);
#endif
#ifndef NK_SIN
NK_LIB float nk_sin(float x);
#endif
#ifndef NK_COS
NK_LIB float nk_cos(float x);
#endif
NK_LIB nk_uint nk_round_up_pow2(nk_uint v);
NK_LIB struct nk_rect nk_shrink_rect(struct nk_rect r, float amount);
NK_LIB struct nk_rect nk_pad_rect(struct nk_rect r, struct nk_vec2 pad);
NK_LIB void nk_unify(struct nk_rect *clip, const struct nk_rect *a, float x0, float y0, float x1, float y1);
NK_LIB double nk_pow(double x, int n);
NK_LIB int nk_ifloord(double x);
NK_LIB int nk_ifloorf(float x);
NK_LIB int nk_iceilf(float x);
NK_LIB int nk_log10(double n);
/* util */
enum {NK_DO_NOT_STOP_ON_NEW_LINE, NK_STOP_ON_NEW_LINE};
NK_LIB nk_bool nk_is_lower(int c);
NK_LIB nk_bool nk_is_upper(int c);
NK_LIB int nk_to_upper(int c);
NK_LIB int nk_to_lower(int c);
#ifndef NK_MEMCPY
NK_LIB void* nk_memcopy(void *dst, const void *src, nk_size n);
#endif
#ifndef NK_MEMSET
NK_LIB void nk_memset(void *ptr, int c0, nk_size size);
#endif
NK_LIB void nk_zero(void *ptr, nk_size size);
NK_LIB char *nk_itoa(char *s, long n);
NK_LIB int nk_string_float_limit(char *string, int prec);
#ifndef NK_DTOA
NK_LIB char *nk_dtoa(char *s, double n);
#endif
NK_LIB 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);
NK_LIB 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);
#ifdef NK_INCLUDE_STANDARD_VARARGS
NK_LIB int nk_strfmt(char *buf, int buf_size, const char *fmt, va_list args);
#endif
#ifdef NK_INCLUDE_STANDARD_IO
NK_LIB char *nk_file_load(const char* path, nk_size* siz, struct nk_allocator *alloc);
#endif
/* buffer */
#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR
NK_LIB void* nk_malloc(nk_handle unused, void *old,nk_size size);
NK_LIB void nk_mfree(nk_handle unused, void *ptr);
#endif
NK_LIB void* nk_buffer_align(void *unaligned, nk_size align, nk_size *alignment, enum nk_buffer_allocation_type type);
NK_LIB void* nk_buffer_alloc(struct nk_buffer *b, enum nk_buffer_allocation_type type, nk_size size, nk_size align);
NK_LIB void* nk_buffer_realloc(struct nk_buffer *b, nk_size capacity, nk_size *size);
/* draw */
NK_LIB void nk_command_buffer_init(struct nk_command_buffer *cb, struct nk_buffer *b, enum nk_command_clipping clip);
NK_LIB void nk_command_buffer_reset(struct nk_command_buffer *b);
NK_LIB void* nk_command_buffer_push(struct nk_command_buffer* b, enum nk_command_type t, nk_size size);
NK_LIB 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);
/* buffering */
NK_LIB void nk_start_buffer(struct nk_context *ctx, struct nk_command_buffer *b);
NK_LIB void nk_start(struct nk_context *ctx, struct nk_window *win);
NK_LIB void nk_start_popup(struct nk_context *ctx, struct nk_window *win);
NK_LIB void nk_finish_popup(struct nk_context *ctx, struct nk_window*);
NK_LIB void nk_finish_buffer(struct nk_context *ctx, struct nk_command_buffer *b);
NK_LIB void nk_finish(struct nk_context *ctx, struct nk_window *w);
NK_LIB void nk_build(struct nk_context *ctx);
/* text editor */
NK_LIB void nk_textedit_clear_state(struct nk_text_edit *state, enum nk_text_edit_type type, nk_plugin_filter filter);
NK_LIB void nk_textedit_click(struct nk_text_edit *state, float x, float y, const struct nk_user_font *font, float row_height);
NK_LIB void nk_textedit_drag(struct nk_text_edit *state, float x, float y, const struct nk_user_font *font, float row_height);
NK_LIB 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);
/* window */
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_LIB void *nk_create_window(struct nk_context *ctx);
NK_LIB void nk_remove_window(struct nk_context*, struct nk_window*);
NK_LIB void nk_free_window(struct nk_context *ctx, struct nk_window *win);
NK_LIB struct nk_window *nk_find_window(struct nk_context *ctx, nk_hash hash, const char *name);
NK_LIB void nk_insert_window(struct nk_context *ctx, struct nk_window *win, enum nk_window_insert_location loc);
/* pool */
NK_LIB void nk_pool_init(struct nk_pool *pool, struct nk_allocator *alloc, unsigned int capacity);
NK_LIB void nk_pool_free(struct nk_pool *pool);
NK_LIB void nk_pool_init_fixed(struct nk_pool *pool, void *memory, nk_size size);
NK_LIB struct nk_page_element *nk_pool_alloc(struct nk_pool *pool);
/* page-element */
NK_LIB struct nk_page_element* nk_create_page_element(struct nk_context *ctx);
NK_LIB void nk_link_page_element_into_freelist(struct nk_context *ctx, struct nk_page_element *elem);
NK_LIB void nk_free_page_element(struct nk_context *ctx, struct nk_page_element *elem);
/* table */
NK_LIB struct nk_table* nk_create_table(struct nk_context *ctx);
NK_LIB void nk_remove_table(struct nk_window *win, struct nk_table *tbl);
NK_LIB void nk_free_table(struct nk_context *ctx, struct nk_table *tbl);
NK_LIB void nk_push_table(struct nk_window *win, struct nk_table *tbl);
NK_LIB nk_uint *nk_add_value(struct nk_context *ctx, struct nk_window *win, nk_hash name, nk_uint value);
NK_LIB nk_uint *nk_find_value(struct nk_window *win, nk_hash name);
/* panel */
NK_LIB void *nk_create_panel(struct nk_context *ctx);
NK_LIB void nk_free_panel(struct nk_context*, struct nk_panel *pan);
NK_LIB nk_bool nk_panel_has_header(nk_flags flags, const char *title);
NK_LIB struct nk_vec2 nk_panel_get_padding(const struct nk_style *style, enum nk_panel_type type);
NK_LIB float nk_panel_get_border(const struct nk_style *style, nk_flags flags, enum nk_panel_type type);
NK_LIB struct nk_color nk_panel_get_border_color(const struct nk_style *style, enum nk_panel_type type);
NK_LIB nk_bool nk_panel_is_sub(enum nk_panel_type type);
NK_LIB nk_bool nk_panel_is_nonblock(enum nk_panel_type type);
NK_LIB nk_bool nk_panel_begin(struct nk_context *ctx, const char *title, enum nk_panel_type panel_type);
NK_LIB void nk_panel_end(struct nk_context *ctx);
/* layout */
NK_LIB float nk_layout_row_calculate_usable_space(const struct nk_style *style, enum nk_panel_type type, float total_space, int columns);
NK_LIB void nk_panel_layout(const struct nk_context *ctx, struct nk_window *win, float height, int cols);
NK_LIB void nk_row_layout(struct nk_context *ctx, enum nk_layout_format fmt, float height, int cols, int width);
NK_LIB void nk_panel_alloc_row(const struct nk_context *ctx, struct nk_window *win);
NK_LIB void nk_layout_widget_space(struct nk_rect *bounds, const struct nk_context *ctx, struct nk_window *win, int modify);
NK_LIB void nk_panel_alloc_space(struct nk_rect *bounds, const struct nk_context *ctx);
NK_LIB void nk_layout_peek(struct nk_rect *bounds, struct nk_context *ctx);
/* popup */
NK_LIB nk_bool nk_nonblock_begin(struct nk_context *ctx, nk_flags flags, struct nk_rect body, struct nk_rect header, enum nk_panel_type panel_type);
/* text */
struct nk_text {
struct nk_vec2 padding;
struct nk_color background;
struct nk_color text;
};
NK_LIB 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);
NK_LIB 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);
/* button */
NK_LIB nk_bool nk_button_behavior(nk_flags *state, struct nk_rect r, const struct nk_input *i, enum nk_button_behavior behavior);
NK_LIB 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);
NK_LIB nk_bool 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);
NK_LIB 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);
NK_LIB nk_bool 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);
NK_LIB 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);
NK_LIB nk_bool 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);
NK_LIB 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_LIB nk_bool 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);
NK_LIB 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);
NK_LIB nk_bool 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);
NK_LIB 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);
NK_LIB nk_bool 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);
/* toggle */
enum nk_toggle_type {
NK_TOGGLE_CHECK,
NK_TOGGLE_OPTION
};
NK_LIB nk_bool nk_toggle_behavior(const struct nk_input *in, struct nk_rect select, nk_flags *state, nk_bool active);
NK_LIB void nk_draw_checkbox(struct nk_command_buffer *out, nk_flags state, const struct nk_style_toggle *style, nk_bool 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);
NK_LIB void nk_draw_option(struct nk_command_buffer *out, nk_flags state, const struct nk_style_toggle *style, nk_bool 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);
NK_LIB nk_bool nk_do_toggle(nk_flags *state, struct nk_command_buffer *out, struct nk_rect r, nk_bool *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);
/* progress */
NK_LIB 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, nk_bool modifiable);
NK_LIB 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);
NK_LIB nk_size nk_do_progress(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, nk_size value, nk_size max, nk_bool modifiable, const struct nk_style_progress *style, struct nk_input *in);
/* slider */
NK_LIB 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);
NK_LIB 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);
NK_LIB 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);
/* scrollbar */
NK_LIB 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_LIB 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);
NK_LIB 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);
NK_LIB 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);
/* selectable */
NK_LIB void nk_draw_selectable(struct nk_command_buffer *out, nk_flags state, const struct nk_style_selectable *style, nk_bool active, const struct nk_rect *bounds, const struct nk_rect *icon, const struct nk_image *img, enum nk_symbol_type sym, const char *string, int len, nk_flags align, const struct nk_user_font *font);
NK_LIB nk_bool nk_do_selectable(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value, const struct nk_style_selectable *style, const struct nk_input *in, const struct nk_user_font *font);
NK_LIB nk_bool nk_do_selectable_image(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value, const struct nk_image *img, const struct nk_style_selectable *style, const struct nk_input *in, const struct nk_user_font *font);
/* edit */
NK_LIB 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, nk_bool is_selected);
NK_LIB 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);
/* color-picker */
NK_LIB nk_bool 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);
NK_LIB 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_LIB nk_bool 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);
/* 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_LIB struct nk_property_variant nk_property_variant_int(int value, int min_value, int max_value, int step);
NK_LIB struct nk_property_variant nk_property_variant_float(float value, float min_value, float max_value, float step);
NK_LIB struct nk_property_variant nk_property_variant_double(double value, double min_value, double max_value, double step);
NK_LIB 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);
NK_LIB 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);
NK_LIB 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);
NK_LIB 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);
NK_LIB 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);
#ifdef NK_INCLUDE_FONT_BAKING
#define STB_RECT_PACK_IMPLEMENTATION
#define STB_TRUETYPE_IMPLEMENTATION
/* Allow consumer to define own STBTT_malloc/STBTT_free, and use the font atlas' allocator otherwise */
#ifndef STBTT_malloc
static void*
nk_stbtt_malloc(nk_size size, void *user_data) {
struct nk_allocator *alloc = (struct nk_allocator *) user_data;
return alloc->alloc(alloc->userdata, 0, size);
}
static void
nk_stbtt_free(void *ptr, void *user_data) {
struct nk_allocator *alloc = (struct nk_allocator *) user_data;
alloc->free(alloc->userdata, ptr);
}
#define STBTT_malloc(x,u) nk_stbtt_malloc(x,u)
#define STBTT_free(x,u) nk_stbtt_free(x,u)
#endif /* STBTT_malloc */
#endif /* NK_INCLUDE_FONT_BAKING */
#endif

View file

@ -0,0 +1,768 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* 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_LIB float
nk_layout_row_calculate_usable_space(const struct nk_style *style, enum nk_panel_type type,
float total_space, int columns)
{
float panel_spacing;
float panel_space;
struct nk_vec2 spacing;
NK_UNUSED(type);
spacing = style->window.spacing;
/* calculate the usable panel space */
panel_spacing = (float)NK_MAX(columns - 1, 0) * spacing.x;
panel_space = total_space - panel_spacing;
return panel_space;
}
NK_LIB 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_LIB 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_LIB 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_LIB 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;
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;
panel_space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type,
layout->bounds.w, layout->row.columns);
#define NK_FRAC(x) (x - (float)(int)x) /* will be used to remove fookin gaps */
/* 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 */
float w = NK_MAX(1.0f,panel_space) / (float)layout->row.columns;
item_offset = (float)layout->row.index * w;
item_width = w + NK_FRAC(item_offset);
item_spacing = (float)layout->row.index * spacing.x;
} break;
case NK_LAYOUT_DYNAMIC_ROW: {
/* scaling single ratio widget width */
float w = layout->row.item_width * panel_space;
item_offset = layout->row.item_offset;
item_width = w + NK_FRAC(item_offset);
item_spacing = 0;
if (modify) {
layout->row.item_offset += w + 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 + NK_FRAC(bounds->x);
bounds->h = layout->row.height * layout->row.item.h + NK_FRAC(bounds->y);
return;
}
case NK_LAYOUT_DYNAMIC: {
/* scaling arrays of panel width ratios for every widget */
float ratio, w;
NK_ASSERT(layout->row.ratio);
ratio = (layout->row.ratio[layout->row.index] < 0) ?
layout->row.item_width : layout->row.ratio[layout->row.index];
w = (ratio * panel_space);
item_spacing = (float)layout->row.index * spacing.x;
item_offset = layout->row.item_offset;
item_width = w + NK_FRAC(item_offset);
if (modify) {
layout->row.item_offset += w;
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;
}
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*/
float w;
NK_ASSERT(layout->row.index < layout->row.columns);
NK_ASSERT(layout->row.index < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);
w = layout->row.templates[layout->row.index];
item_offset = layout->row.item_offset;
item_width = w + NK_FRAC(item_offset);
item_spacing = (float)layout->row.index * spacing.x;
if (modify) layout->row.item_offset += w;
} break;
#undef NK_FRAC
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;
if (((bounds->x + bounds->w) > layout->max_x) && modify)
layout->max_x = bounds->x + bounds->w;
bounds->x -= (float)*layout->offset_x;
}
NK_LIB 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_LIB 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) {
*bounds = nk_rect(0,0,0,0);
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_API void
nk_spacer(struct nk_context *ctx )
{
struct nk_rect dummy_rect = { 0, 0, 0, 0 };
nk_panel_alloc_space( &dummy_rect, ctx );
}

View file

@ -0,0 +1,82 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* LIST VIEW
*
* ===============================================================*/
NK_API nk_bool
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);
if (!x_offset) {
x_offset = nk_add_value(ctx, win, title_hash, 0);
y_offset = nk_add_value(ctx, win, title_hash+1, 0);
NK_ASSERT(x_offset);
NK_ASSERT(y_offset);
if (!x_offset || !y_offset) return 0;
*x_offset = *y_offset = 0;
} else y_offset = nk_find_value(win, title_hash+1);
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->count = NK_MIN(view->count, row_count - view->begin);
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);
}

View file

@ -0,0 +1,302 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* 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
*/
#ifndef NK_INV_SQRT
#define NK_INV_SQRT nk_inv_sqrt
NK_LIB float
nk_inv_sqrt(float n)
{
float x2;
const float threehalfs = 1.5f;
union {nk_uint i; float f;} conv = {0};
conv.f = n;
x2 = n * 0.5f;
conv.i = 0x5f375A84 - (conv.i >> 1);
conv.f = conv.f * (threehalfs - (x2 * conv.f * conv.f));
return conv.f;
}
#endif
#ifndef NK_SIN
#define NK_SIN nk_sin
NK_LIB 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))))));
}
#endif
#ifndef NK_COS
#define NK_COS nk_cos
NK_LIB float
nk_cos(float x)
{
/* New implementation. Also generated using lolremez. */
/* Old version significantly deviated from expected results. */
NK_STORAGE const float a0 = 9.9995999154986614e-1f;
NK_STORAGE const float a1 = 1.2548995793001028e-3f;
NK_STORAGE const float a2 = -5.0648546280678015e-1f;
NK_STORAGE const float a3 = 1.2942246466519995e-2f;
NK_STORAGE const float a4 = 2.8668384702547972e-2f;
NK_STORAGE const float a5 = 7.3726485210586547e-3f;
NK_STORAGE const float a6 = -3.8510875386947414e-3f;
NK_STORAGE const float a7 = 4.7196604604366623e-4f;
NK_STORAGE const float a8 = -1.8776444013090451e-5f;
return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*(a7 + x*a8)))))));
}
#endif
NK_LIB 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_LIB 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_LIB int
nk_ifloord(double x)
{
x = (double)((int)x - ((x < 0.0) ? 1 : 0));
return (int)x;
}
NK_LIB int
nk_ifloorf(float x)
{
x = (float)((int)x - ((x < 0.0f) ? 1 : 0));
return (int)x;
}
NK_LIB 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_LIB 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_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_LIB 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_LIB 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]);
}
NK_LIB 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);
}
}

View file

@ -0,0 +1,297 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* MENU
*
* ===============================================================*/
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->menu.h += layout->row.height + ctx->style.window.spacing.y;
layout->bounds.y += layout->menu.h;
layout->bounds.h -= layout->menu.h;
*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);
}
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 nk_bool
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 nk_bool 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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
nk_menu_item_label(struct nk_context *ctx, const char *label, nk_flags align)
{
return nk_contextual_item_label(ctx, label, align);
}
NK_API nk_bool
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 nk_bool
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 nk_bool 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 nk_bool 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);
}

View file

@ -0,0 +1,62 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* PAGE ELEMENT
*
* ===============================================================*/
NK_LIB 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_LIB 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_LIB 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);}
}

View file

@ -0,0 +1,621 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* PANEL
*
* ===============================================================*/
NK_LIB 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_LIB 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);
}
NK_LIB nk_bool
nk_panel_has_header(nk_flags flags, const char *title)
{
nk_bool 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_LIB 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_LIB 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_LIB 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_LIB nk_bool
nk_panel_is_sub(enum nk_panel_type type)
{
return (type & NK_PANEL_SET_SUB)?1:0;
}
NK_LIB nk_bool
nk_panel_is_nonblock(enum nk_panel_type type)
{
return (type & NK_PANEL_SET_NONBLOCK)?1:0;
}
NK_LIB nk_bool
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)) {
nk_bool left_mouse_down;
unsigned int left_mouse_clicked;
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_clicked = in->mouse.buttons[NK_BUTTON_LEFT].clicked;
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 && !left_mouse_clicked) {
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;
switch(background->type) {
case NK_STYLE_ITEM_IMAGE:
text.background = nk_rgba(0,0,0,0);
nk_draw_image(&win->buffer, header, &background->data.image, nk_white);
break;
case NK_STYLE_ITEM_NINE_SLICE:
text.background = nk_rgba(0, 0, 0, 0);
nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_white);
break;
case NK_STYLE_ITEM_COLOR:
text.background = background->data.color;
nk_fill_rect(out, header, 0, background->data.color);
break;
}
/* 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);
switch(style->window.fixed_background.type) {
case NK_STYLE_ITEM_IMAGE:
nk_draw_image(out, body, &style->window.fixed_background.data.image, nk_white);
break;
case NK_STYLE_ITEM_NINE_SLICE:
nk_draw_nine_slice(out, body, &style->window.fixed_background.data.slice, nk_white);
break;
case NK_STYLE_ITEM_COLOR:
nk_fill_rect(out, body, 0, style->window.fixed_background.data.color);
break;
}
}
/* 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_LIB 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;
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->footer_height > 0) {
empty_space.x = window->bounds.x;
empty_space.y = layout->bounds.y + layout->bounds.h;
empty_space.w = window->bounds.w;
empty_space.h = layout->footer_height;
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);
}

View file

@ -0,0 +1,66 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* POOL
*
* ===============================================================*/
NK_LIB void
nk_pool_init(struct nk_pool *pool, struct nk_allocator *alloc,
unsigned int capacity)
{
NK_ASSERT(capacity >= 1);
nk_zero(pool, sizeof(*pool));
pool->alloc = *alloc;
pool->capacity = capacity;
pool->type = NK_BUFFER_DYNAMIC;
pool->pages = 0;
}
NK_LIB void
nk_pool_free(struct nk_pool *pool)
{
struct nk_page *iter;
if (!pool) return;
iter = pool->pages;
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_LIB 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;
/* first nk_page_element is embedded in nk_page, additional elements follow in adjacent space */
pool->capacity = (unsigned)(1 + (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_LIB 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) {
NK_ASSERT(pool->pages);
if (!pool->pages) return 0;
NK_ASSERT(pool->pages->size < pool->capacity);
return 0;
} else {
nk_size size = sizeof(struct nk_page);
size += (pool->capacity - 1) * sizeof(struct nk_page_element);
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++];
}

View file

@ -0,0 +1,263 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* POPUP
*
* ===============================================================*/
NK_API nk_bool
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_LIB nk_bool
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;
#ifdef NK_BUTTON_TRIGGER_ON_RELEASE
pressed = nk_input_is_mouse_released(&ctx->input, NK_BUTTON_LEFT);
#else
pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT);
#endif
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);
}
NK_API void
nk_popup_get_scroll(struct nk_context *ctx, nk_uint *offset_x, nk_uint *offset_y)
{
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 (offset_x)
*offset_x = popup->scrollbar.x;
if (offset_y)
*offset_y = popup->scrollbar.y;
}
NK_API void
nk_popup_set_scroll(struct nk_context *ctx, nk_uint offset_x, nk_uint offset_y)
{
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;
popup->scrollbar.x = offset_x;
popup->scrollbar.y = offset_y;
}

View file

@ -0,0 +1,158 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* PROGRESS
*
* ===============================================================*/
NK_LIB 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, nk_bool 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_LIB 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 */
switch(background->type) {
case NK_STYLE_ITEM_IMAGE:
nk_draw_image(out, *bounds, &background->data.image, nk_white);
break;
case NK_STYLE_ITEM_NINE_SLICE:
nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_white);
break;
case 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);
break;
}
/* draw cursor */
switch(cursor->type) {
case NK_STYLE_ITEM_IMAGE:
nk_draw_image(out, *scursor, &cursor->data.image, nk_white);
break;
case NK_STYLE_ITEM_NINE_SLICE:
nk_draw_nine_slice(out, *scursor, &cursor->data.slice, nk_white);
break;
case 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);
break;
}
}
NK_LIB nk_size
nk_do_progress(nk_flags *state,
struct nk_command_buffer *out, struct nk_rect bounds,
nk_size value, nk_size max, nk_bool 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;
}
NK_API nk_bool
nk_progress(struct nk_context *ctx, nk_size *cur, nk_size max, nk_bool 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, nk_bool modifyable)
{
nk_progress(ctx, &cur, max, modifyable);
return cur;
}

View file

@ -0,0 +1,503 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* PROPERTY
*
* ===============================================================*/
NK_LIB 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_LIB 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)
{
nk_widget_state_reset(ws);
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_LIB 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 */
switch(background->type) {
case NK_STYLE_ITEM_IMAGE:
text.background = nk_rgba(0, 0, 0, 0);
nk_draw_image(out, *bounds, &background->data.image, nk_white);
break;
case NK_STYLE_ITEM_NINE_SLICE:
text.background = nk_rgba(0, 0, 0, 0);
nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_white);
break;
case NK_STYLE_ITEM_COLOR:
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);
break;
}
/* draw label */
text.padding = nk_vec2(0,0);
nk_widget_text(out, *label, name, len, &text, NK_TEXT_CENTERED, font);
}
NK_LIB 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
};
nk_bool active, old;
int num_len = 0, 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;
}
}
}
NK_LIB 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_LIB 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_LIB 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_LIB 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;
}

View file

@ -0,0 +1,310 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* SCROLLBAR
*
* ===============================================================*/
NK_LIB 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;
unsigned int left_mouse_clicked;
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_clicked = in->mouse.buttons[NK_BUTTON_LEFT].clicked;
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 && !left_mouse_clicked) {
/* 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_LIB 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 */
switch (background->type) {
case NK_STYLE_ITEM_IMAGE:
nk_draw_image(out, *bounds, &background->data.image, nk_white);
break;
case NK_STYLE_ITEM_NINE_SLICE:
nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_white);
break;
case 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);
break;
}
/* draw cursor */
switch (cursor->type) {
case NK_STYLE_ITEM_IMAGE:
nk_draw_image(out, *scroll, &cursor->data.image, nk_white);
break;
case NK_STYLE_ITEM_NINE_SLICE:
nk_draw_nine_slice(out, *scroll, &cursor->data.slice, nk_white);
break;
case 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);
break;
}
}
NK_LIB 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_LIB 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;
}

View file

@ -0,0 +1,329 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* SELECTABLE
*
* ===============================================================*/
NK_LIB void
nk_draw_selectable(struct nk_command_buffer *out,
nk_flags state, const struct nk_style_selectable *style, nk_bool active,
const struct nk_rect *bounds,
const struct nk_rect *icon, const struct nk_image *img, enum nk_symbol_type sym,
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 */
switch (background->type) {
case NK_STYLE_ITEM_IMAGE:
text.background = nk_rgba(0, 0, 0, 0);
nk_draw_image(out, *bounds, &background->data.image, nk_white);
break;
case NK_STYLE_ITEM_NINE_SLICE:
text.background = nk_rgba(0, 0, 0, 0);
nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_white);
break;
case NK_STYLE_ITEM_COLOR:
text.background = background->data.color;
nk_fill_rect(out, *bounds, style->rounding, background->data.color);
break;
}
if (icon) {
if (img) nk_draw_image(out, *icon, img, nk_white);
else nk_draw_symbol(out, sym, *icon, text.background, text.text, 1, font);
}
nk_widget_text(out, *bounds, string, len, &text, align, font);
}
NK_LIB nk_bool
nk_do_selectable(nk_flags *state, struct nk_command_buffer *out,
struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *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,NK_SYMBOL_NONE, str, len, align, font);
if (style->draw_end) style->draw_end(out, style->userdata);
return old_value != *value;
}
NK_LIB nk_bool
nk_do_selectable_image(nk_flags *state, struct nk_command_buffer *out,
struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value,
const struct nk_image *img, const struct nk_style_selectable *style,
const struct nk_input *in, const struct nk_user_font *font)
{
nk_bool 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, NK_SYMBOL_NONE, str, len, align, font);
if (style->draw_end) style->draw_end(out, style->userdata);
return old_value != *value;
}
NK_LIB nk_bool
nk_do_selectable_symbol(nk_flags *state, struct nk_command_buffer *out,
struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value,
enum nk_symbol_type sym, 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, 0, sym, str, len, align, font);
if (style->draw_end) style->draw_end(out, style->userdata);
return old_value != *value;
}
NK_API nk_bool
nk_selectable_text(struct nk_context *ctx, const char *str, int len,
nk_flags align, nk_bool *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 nk_bool
nk_selectable_image_text(struct nk_context *ctx, struct nk_image img,
const char *str, int len, nk_flags align, nk_bool *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 nk_bool
nk_selectable_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym,
const char *str, int len, nk_flags align, nk_bool *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_symbol(&ctx->last_widget_state, &win->buffer, bounds,
str, len, align, value, sym, &style->selectable, in, style->font);
}
NK_API nk_bool
nk_selectable_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym,
const char *title, nk_flags align, nk_bool *value)
{
return nk_selectable_symbol_text(ctx, sym, title, nk_strlen(title), align, value);
}
NK_API nk_bool nk_select_text(struct nk_context *ctx, const char *str, int len,
nk_flags align, nk_bool value)
{
nk_selectable_text(ctx, str, len, align, &value);return value;
}
NK_API nk_bool nk_selectable_label(struct nk_context *ctx, const char *str, nk_flags align, nk_bool *value)
{
return nk_selectable_text(ctx, str, nk_strlen(str), align, value);
}
NK_API nk_bool nk_selectable_image_label(struct nk_context *ctx,struct nk_image img,
const char *str, nk_flags align, nk_bool *value)
{
return nk_selectable_image_text(ctx, img, str, nk_strlen(str), align, value);
}
NK_API nk_bool nk_select_label(struct nk_context *ctx, const char *str, nk_flags align, nk_bool value)
{
nk_selectable_text(ctx, str, nk_strlen(str), align, &value);return value;
}
NK_API nk_bool nk_select_image_label(struct nk_context *ctx, struct nk_image img,
const char *str, nk_flags align, nk_bool value)
{
nk_selectable_image_text(ctx, img, str, nk_strlen(str), align, &value);return value;
}
NK_API nk_bool nk_select_image_text(struct nk_context *ctx, struct nk_image img,
const char *str, int len, nk_flags align, nk_bool value)
{
nk_selectable_image_text(ctx, img, str, len, align, &value);return value;
}
NK_API nk_bool
nk_select_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym,
const char *title, int title_len, nk_flags align, nk_bool value)
{
nk_selectable_symbol_text(ctx, sym, title, title_len, align, &value);return value;
}
NK_API nk_bool
nk_select_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym,
const char *title, nk_flags align, nk_bool value)
{
return nk_select_symbol_text(ctx, sym, title, nk_strlen(title), align, value);
}

View file

@ -0,0 +1,261 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* SLIDER
*
* ===============================================================*/
NK_LIB 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_LIB 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 */
switch(background->type) {
case NK_STYLE_ITEM_IMAGE:
nk_draw_image(out, *bounds, &background->data.image, nk_white);
break;
case NK_STYLE_ITEM_NINE_SLICE:
nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_white);
break;
case 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);
break;
}
/* 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_LIB 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;
}
NK_API nk_bool
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 nk_bool
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;
}

View file

@ -0,0 +1,451 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* 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;
}

View file

@ -0,0 +1,773 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* 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_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_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_nine_slice(struct nk_nine_slice slice)
{
struct nk_style_item i;
i.type = NK_STYLE_ITEM_NINE_SLICE;
i.data.slice = slice;
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->image_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 nk_bool
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 nk_bool
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 nk_bool NK_STYLE_PUSH_IMPLEMENATION(struct nk, style_item, style_items)
NK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(nk,float, floats)
NK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(struct nk, vec2, vectors)
NK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(nk,flags, flags)
NK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(struct nk,color, colors)
NK_API nk_bool NK_STYLE_POP_IMPLEMENATION(style_item, style_items)
NK_API nk_bool NK_STYLE_POP_IMPLEMENATION(float,floats)
NK_API nk_bool NK_STYLE_POP_IMPLEMENATION(vec2, vectors)
NK_API nk_bool NK_STYLE_POP_IMPLEMENATION(flags,flags)
NK_API nk_bool NK_STYLE_POP_IMPLEMENATION(color,colors)
NK_API nk_bool
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;
}

View file

@ -0,0 +1,90 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* TABLE
*
* ===============================================================*/
NK_LIB 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_LIB 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_LIB 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_LIB 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_LIB 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_LIB 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;
}

View file

@ -0,0 +1,292 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* TEXT
*
* ===============================================================*/
NK_LIB 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_LIB 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));
}
}
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, ...)
{
va_list args;
va_start(args, fmt);
nk_labelfv_colored(ctx, flags, color, fmt, args);
va_end(args);
}
NK_API void
nk_labelf_colored_wrap(struct nk_context *ctx, struct nk_color color,
const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
nk_labelfv_colored_wrap(ctx, color, fmt, args);
va_end(args);
}
NK_API void
nk_labelf(struct nk_context *ctx, nk_flags flags, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
nk_labelfv(ctx, flags, fmt, args);
va_end(args);
}
NK_API void
nk_labelf_wrap(struct nk_context *ctx, const char *fmt,...)
{
va_list args;
va_start(args, fmt);
nk_labelfv_wrap(ctx, fmt, args);
va_end(args);
}
NK_API void
nk_labelfv_colored(struct nk_context *ctx, nk_flags flags,
struct nk_color color, const char *fmt, va_list args)
{
char buf[256];
nk_strfmt(buf, NK_LEN(buf), fmt, args);
nk_label_colored(ctx, buf, flags, color);
}
NK_API void
nk_labelfv_colored_wrap(struct nk_context *ctx, struct nk_color color,
const char *fmt, va_list args)
{
char buf[256];
nk_strfmt(buf, NK_LEN(buf), fmt, args);
nk_label_colored_wrap(ctx, buf, color);
}
NK_API void
nk_labelfv(struct nk_context *ctx, nk_flags flags, const char *fmt, va_list args)
{
char buf[256];
nk_strfmt(buf, NK_LEN(buf), fmt, args);
nk_label(ctx, buf, flags);
}
NK_API void
nk_labelfv_wrap(struct nk_context *ctx, const char *fmt, va_list args)
{
char buf[256];
nk_strfmt(buf, NK_LEN(buf), fmt, args);
nk_label_wrap(ctx, buf);
}
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);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,320 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* TOGGLE
*
* ===============================================================*/
NK_LIB nk_bool
nk_toggle_behavior(const struct nk_input *in, struct nk_rect select,
nk_flags *state, nk_bool 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_LIB void
nk_draw_checkbox(struct nk_command_buffer *out,
nk_flags state, const struct nk_style_toggle *style, nk_bool 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_LIB void
nk_draw_option(struct nk_command_buffer *out,
nk_flags state, const struct nk_style_toggle *style, nk_bool 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_LIB nk_bool
nk_do_toggle(nk_flags *state,
struct nk_command_buffer *out, struct nk_rect r,
nk_bool *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);
}
/*----------------------------------------------------------------
*
* CHECKBOX
*
* --------------------------------------------------------------*/
NK_API nk_bool
nk_check_text(struct nk_context *ctx, const char *text, int len, nk_bool 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 nk_bool
nk_checkbox_text(struct nk_context *ctx, const char *text, int len, nk_bool *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 nk_bool
nk_checkbox_flags_text(struct nk_context *ctx, const char *text, int len,
unsigned int *flags, unsigned int value)
{
nk_bool 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 nk_bool nk_check_label(struct nk_context *ctx, const char *label, nk_bool 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 nk_bool nk_checkbox_label(struct nk_context *ctx, const char *label, nk_bool *active)
{
return nk_checkbox_text(ctx, label, nk_strlen(label), active);
}
NK_API nk_bool 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 nk_bool
nk_option_text(struct nk_context *ctx, const char *text, int len, nk_bool 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 (int)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 nk_bool
nk_radio_text(struct nk_context *ctx, const char *text, int len, nk_bool *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 nk_bool
nk_option_label(struct nk_context *ctx, const char *label, nk_bool active)
{
return nk_option_text(ctx, label, nk_strlen(label), active);
}
NK_API nk_bool
nk_radio_label(struct nk_context *ctx, const char *label, nk_bool *active)
{
return nk_radio_text(ctx, label, nk_strlen(label), active);
}

View file

@ -0,0 +1,111 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* TOOLTIP
*
* ===============================================================*/
NK_API nk_bool
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, ...)
{
va_list args;
va_start(args, fmt);
nk_tooltipfv(ctx, fmt, args);
va_end(args);
}
NK_API void
nk_tooltipfv(struct nk_context *ctx, const char *fmt, va_list args)
{
char buf[256];
nk_strfmt(buf, NK_LEN(buf), fmt, args);
nk_tooltip(ctx, buf);
}
#endif

View file

@ -0,0 +1,350 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* TREE
*
* ===============================================================*/
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;
switch(background->type) {
case NK_STYLE_ITEM_IMAGE:
nk_draw_image(out, header, &background->data.image, nk_white);
break;
case NK_STYLE_ITEM_NINE_SLICE:
nk_draw_nine_slice(out, header, &background->data.slice, nk_white);
break;
case NK_STYLE_ITEM_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);
break;
}
} 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 nk_bool
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 nk_bool
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 + (float)*layout->offset_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 nk_bool
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 nk_bool
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);
}
NK_INTERN int
nk_tree_element_image_push_hashed_base(struct nk_context *ctx, enum nk_tree_type type,
struct nk_image *img, const char *title, int title_len,
enum nk_collapse_states *state, nk_bool *selected)
{
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 padding;
int text_len;
float text_width;
struct nk_vec2 item_spacing;
struct nk_rect header = {0,0,0,0};
struct nk_rect sym = {0,0,0,0};
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;
padding = style->selectable.padding;
/* 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;
switch (background->type) {
case NK_STYLE_ITEM_IMAGE:
nk_draw_image(out, header, &background->data.image, nk_white);
break;
case NK_STYLE_ITEM_NINE_SLICE:
nk_draw_nine_slice(out, header, &background->data.slice, nk_white);
break;
case NK_STYLE_ITEM_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);
break;
}
}
in = (!(layout->flags & NK_WINDOW_ROM)) ? &ctx->input: 0;
in = (in && widget_state == NK_WIDGET_VALID) ? &ctx->input : 0;
/* 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;
if (nk_do_button_symbol(&ws, &win->buffer, sym, symbol, NK_BUTTON_DEFAULT, button, in, style->font))
*state = (*state == NK_MAXIMIZED) ? NK_MINIMIZED : NK_MAXIMIZED;}
/* draw label */
{nk_flags dummy = 0;
struct nk_rect label;
/* calculate size of the text and tooltip */
text_len = nk_strlen(title);
text_width = style->font->width(style->font->userdata, style->font->height, title, text_len);
text_width += (4 * padding.x);
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 = NK_MIN(header.w - (sym.w + item_spacing.y + style->tab.indent), text_width);
label.h = style->font->height;
if (img) {
nk_do_selectable_image(&dummy, &win->buffer, label, title, title_len, NK_TEXT_LEFT,
selected, img, &style->selectable, in, style->font);
} else nk_do_selectable(&dummy, &win->buffer, label, title, title_len, NK_TEXT_LEFT,
selected, &style->selectable, in, 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_element_base(struct nk_context *ctx, enum nk_tree_type type,
struct nk_image *img, const char *title, enum nk_collapse_states initial_state,
nk_bool *selected, 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_element_image_push_hashed_base(ctx, type, img, title,
nk_strlen(title), (enum nk_collapse_states*)state, selected);
}
NK_API nk_bool
nk_tree_element_push_hashed(struct nk_context *ctx, enum nk_tree_type type,
const char *title, enum nk_collapse_states initial_state,
nk_bool *selected, const char *hash, int len, int seed)
{
return nk_tree_element_base(ctx, type, 0, title, initial_state, selected, hash, len, seed);
}
NK_API nk_bool
nk_tree_element_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,
nk_bool *selected, const char *hash, int len,int seed)
{
return nk_tree_element_base(ctx, type, &img, title, initial_state, selected, hash, len, seed);
}
NK_API void
nk_tree_element_pop(struct nk_context *ctx)
{
nk_tree_state_pop(ctx);
}

View file

@ -0,0 +1,144 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* 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;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,230 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* WIDGET
*
* ===============================================================*/
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 nk_bool
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 nk_bool
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 nk_bool
nk_widget_has_mouse_click_down(struct nk_context *ctx, enum nk_buttons btn, nk_bool 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 */
enum nk_widget_layout_states state;
NK_UNUSED(item_padding);
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return NK_WIDGET_INVALID;
state = nk_widget(bounds, ctx);
return state;
}
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;
}

View file

@ -0,0 +1,671 @@
#include "nuklear.h"
#include "nuklear_internal.h"
/* ===============================================================
*
* WINDOW
*
* ===============================================================*/
NK_LIB 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_LIB 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_LIB 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;
}
NK_LIB 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_LIB 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 nk_bool
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 nk_bool
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 name_hash;
int name_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;
name_len = (int)nk_strlen(name);
name_hash = nk_murmur_hash(name, (int)name_len, NK_WINDOW_TITLE);
win = nk_find_window(ctx, name_hash, name);
if (!win) {
/* create new window */
nk_size name_length = (nk_size)name_len;
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 = name_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 void
nk_window_get_scroll(struct nk_context *ctx, nk_uint *offset_x, nk_uint *offset_y)
{
struct nk_window *win;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current)
return ;
win = ctx->current;
if (offset_x)
*offset_x = win->scrollbar.x;
if (offset_y)
*offset_y = win->scrollbar.y;
}
NK_API nk_bool
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 nk_bool
nk_window_is_hovered(struct nk_context *ctx)
{
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current || (ctx->current->flags & NK_WINDOW_HIDDEN))
return 0;
else {
struct nk_rect actual_bounds = ctx->current->bounds;
if (ctx->begin->flags & NK_WINDOW_MINIMIZED) {
actual_bounds.h = ctx->current->layout->header_height;
}
return nk_input_is_mouse_hovering_rect(&ctx->input, actual_bounds);
}
}
NK_API nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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 nk_bool
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_set_scroll(struct nk_context *ctx, nk_uint offset_x, nk_uint offset_y)
{
struct nk_window *win;
NK_ASSERT(ctx);
NK_ASSERT(ctx->current);
if (!ctx || !ctx->current)
return;
win = ctx->current;
win->scrollbar.x = offset_x;
win->scrollbar.y = offset_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;
}

View file

@ -0,0 +1 @@
build.py --macro NK --intro HEADER --pub nuklear.h --priv1 nuklear_internal.h,nuklear_math.c,nuklear_util.c,nuklear_color.c,nuklear_utf8.c,nuklear_buffer.c,nuklear_string.c,nuklear_draw.c,nuklear_vertex.c --extern stb_rect_pack.h,stb_truetype.h --priv2 nuklear_font.c,nuklear_input.c,nuklear_style.c,nuklear_context.c,nuklear_pool.c,nuklear_page_element.c,nuklear_table.c,nuklear_panel.c,nuklear_window.c,nuklear_popup.c,nuklear_contextual.c,nuklear_menu.c,nuklear_layout.c,nuklear_tree.c,nuklear_group.c,nuklear_list_view.c,nuklear_widget.c,nuklear_text.c,nuklear_image.c,nuklear_9slice.c,nuklear_button.c,nuklear_toggle.c,nuklear_selectable.c,nuklear_slider.c,nuklear_progress.c,nuklear_scrollbar.c,nuklear_text_editor.c,nuklear_edit.c,nuklear_property.c,nuklear_chart.c,nuklear_color_picker.c,nuklear_combo.c,nuklear_tooltip.c --outro LICENSE,CHANGELOG,CREDITS > ..\nuklear.h

View file

@ -0,0 +1,3 @@
#!/bin/sh
python build.py --macro NK --intro HEADER --pub nuklear.h --priv1 nuklear_internal.h,nuklear_math.c,nuklear_util.c,nuklear_color.c,nuklear_utf8.c,nuklear_buffer.c,nuklear_string.c,nuklear_draw.c,nuklear_vertex.c --extern stb_rect_pack.h,stb_truetype.h --priv2 nuklear_font.c,nuklear_input.c,nuklear_style.c,nuklear_context.c,nuklear_pool.c,nuklear_page_element.c,nuklear_table.c,nuklear_panel.c,nuklear_window.c,nuklear_popup.c,nuklear_contextual.c,nuklear_menu.c,nuklear_layout.c,nuklear_tree.c,nuklear_group.c,nuklear_list_view.c,nuklear_widget.c,nuklear_text.c,nuklear_image.c,nuklear_9slice.c,nuklear_button.c,nuklear_toggle.c,nuklear_selectable.c,nuklear_slider.c,nuklear_progress.c,nuklear_scrollbar.c,nuklear_text_editor.c,nuklear_edit.c,nuklear_property.c,nuklear_chart.c,nuklear_color_picker.c,nuklear_combo.c,nuklear_tooltip.c --outro LICENSE,CHANGELOG,CREDITS > ../nuklear.h

View file

@ -1,15 +1,15 @@
// [DEAR IMGUI]
// This is a slightly modified version of stb_rect_pack.h 1.00.
// Those changes would need to be pushed into nothings/stb:
// - Added STBRP__CDECL
// Grep for [DEAR IMGUI] to find the changes.
// stb_rect_pack.h - v1.00 - public domain - rectangle packing
// stb_rect_pack.h - v1.01 - public domain - rectangle packing
// Sean Barrett 2014
//
// Useful for e.g. packing rectangular textures into an atlas.
// Does not do rotation.
//
// Before #including,
//
// #define STB_RECT_PACK_IMPLEMENTATION
//
// in the file that you want to have the implementation.
//
// Not necessarily the awesomest packing method, but better than
// the totally naive one in stb_truetype (which is primarily what
// this is meant to replace).
@ -41,6 +41,7 @@
//
// Version history:
//
// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
// 0.99 (2019-02-07) warning fixes
// 0.11 (2017-03-03) return packing success/fail result
@ -81,11 +82,10 @@ typedef struct stbrp_context stbrp_context;
typedef struct stbrp_node stbrp_node;
typedef struct stbrp_rect stbrp_rect;
#ifdef STBRP_LARGE_RECTS
typedef int stbrp_coord;
#else
typedef unsigned short stbrp_coord;
#endif
#define STBRP__MAXVAL 0x7fffffff
// Mostly for internal use, but this is the maximum supported coordinate value.
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
// Assign packed locations to rectangles. The rectangles are of type
@ -213,10 +213,9 @@ struct stbrp_context
#define STBRP_ASSERT assert
#endif
// [DEAR IMGUI] Added STBRP__CDECL
#ifdef _MSC_VER
#define STBRP__NOTUSED(v) (void)(v)
#define STBRP__CDECL __cdecl
#define STBRP__CDECL __cdecl
#else
#define STBRP__NOTUSED(v) (void)sizeof(v)
#define STBRP__CDECL
@ -262,9 +261,6 @@ STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_ou
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
{
int i;
#ifndef STBRP_LARGE_RECTS
STBRP_ASSERT(width <= 0xffff && height <= 0xffff);
#endif
for (i=0; i < num_nodes-1; ++i)
nodes[i].next = &nodes[i+1];
@ -283,11 +279,7 @@ STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height,
context->extra[0].y = 0;
context->extra[0].next = &context->extra[1];
context->extra[1].x = (stbrp_coord) width;
#ifdef STBRP_LARGE_RECTS
context->extra[1].y = (1<<30);
#else
context->extra[1].y = 65535;
#endif
context->extra[1].next = NULL;
}
@ -529,7 +521,6 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i
return res;
}
// [DEAR IMGUI] Added STBRP__CDECL
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
@ -541,7 +532,6 @@ static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
return (p->w > q->w) ? -1 : (p->w < q->w);
}
// [DEAR IMGUI] Added STBRP__CDECL
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
@ -549,12 +539,6 @@ static int STBRP__CDECL rect_original_order(const void *a, const void *b)
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
}
#ifdef STBRP_LARGE_RECTS
#define STBRP__MAXVAL 0xffffffff
#else
#define STBRP__MAXVAL 0xffff
#endif
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
{
int i, all_rects_packed = 1;

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,20 @@
extern "C" {
#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
#define NK_KEYSTATE_BASED_INPUT
#include "nuklear.h"
#include "nuklear_glfw_gl3.h"
#define MAX_VERTEX_BUFFER 512 * 1024
#define MAX_ELEMENT_BUFFER 128 * 1024
#include "openglrender.h"
#include "editor.h"
#include "window.h"
@ -28,12 +44,10 @@ extern "C" {
#include "debug.h"
#include "script.h"
}
#include <stb_ds.h>
#define ASSET_TEXT_BUF 1024*1024 /* 1 MB buffer for editing text files */
#include <imgui.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h>
struct gameproject *cur_project;
struct vec *projects;
static char setpath[MAXPATH];
@ -58,7 +72,7 @@ const char *allowed_extensions[] = { "jpg", "png", "gltf", "glsl" };
static const char *editor_filename = "editor.ini";
static ImGuiIO *io = NULL;
//static ImGuiIO *io = NULL;
struct asset {
char *key;
@ -175,8 +189,10 @@ static bool kmp_match(const char *search, const char *text, int *pi)
}
static int MyCallback(ImGuiInputTextCallbackData * data)
static int MyCallback()//ImGuiInputTextCallbackData * data)
{
/*
if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion) {
data->InsertChars(data->CursorPos, "..");
} else if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory) {
@ -201,12 +217,13 @@ static int MyCallback(ImGuiInputTextCallbackData * data)
NULL) ? false : true;
}
*/
return 0;
}
static int TextEditCallback(ImGuiInputTextCallbackData * data)
static int TextEditCallback()//ImGuiInputTextCallbackData * data)
{
/*
static int dirty = 0;
if (data->EventChar == '\n') {
@ -223,7 +240,7 @@ static int TextEditCallback(ImGuiInputTextCallbackData * data)
dirty = 0;
char *c = &data->Buf[data->CursorPos - 2];
/* Seek to last newline */
while (*c != '\n')
c--;
c++;
@ -239,7 +256,7 @@ static int TextEditCallback(ImGuiInputTextCallbackData * data)
}
}
*/
return 0;
}
@ -399,6 +416,9 @@ static void edit_mouse_cb(GLFWwindow *w, int button, int action, int mods)
}
}
struct nk_context *nkctx;
struct nk_glfw nkglfw = {0};
void editor_init(struct mSDLWindow *window)
{
projects = vec_make(sizeof(struct gameproject), 5);
@ -413,13 +433,8 @@ void editor_init(struct mSDLWindow *window)
fclose(feditor);
}
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGui::StyleColorsClassic();
ImGui_ImplGlfw_InitForOpenGL(window->window, true);
ImGui_ImplOpenGL3_Init();
nkctx = nk_glfw3_init(&nkglfw, window->window, NK_GLFW3_INSTALL_CALLBACKS);
//set_style(nkctx, THEME_WHITE);
glfwSetKeyCallback(window->window, edit_input_cb);
glfwSetMouseButtonCallback(window->window, edit_mouse_cb);
@ -427,13 +442,16 @@ void editor_init(struct mSDLWindow *window)
void editor_input()
{
io = &ImGui::GetIO();
//io = &ImGui::GetIO();
}
int editor_wantkeyboard()
{
/*
if (io == NULL) return 0;
return io->WantCaptureKeyboard;
*/
return 0;
}
void editor_project_gui()
@ -455,6 +473,7 @@ void editor_project_gui()
/*
if (ImGui::BeginMainMenuBar()) {
ImGui::Text("Current level: %s",
current_level[0] ==
@ -683,7 +702,7 @@ void editor_project_gui()
ImGui::SameLine();
ImGui::Checkbox("Draw", &grid2_draw);
/*
ImGui::SliderFloat("Grid Opacity", &gridOpacity, 0.f, 1.f);
ImGui::SliderFloat("Small unit", &smallGridUnit, 0.5f, 5.f);
ImGui::SliderFloat("Big unit", &bigGridUnit, 10.f, 50.f);
@ -691,7 +710,7 @@ void editor_project_gui()
ImGui::SliderFloat("Big thickness", &gridBigThickness, 1.f, 10.f, "%1.f");
ImGui::ColorEdit3("1 pt grid color", (float*)&gridSmallColor);
ImGui::ColorEdit3("10 pt grid color", (float*)&gridBigColor);
*/
//ImGui::SliderInt("MSAA", &msaaSamples, 0, 4);
ImGui::End();
}
@ -749,23 +768,21 @@ void editor_project_gui()
}
*/
}
void editor_render()
{
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
nk_glfw3_new_frame(&nkglfw);
if (cur_project)
editor_project_gui();
else
editor_proj_select_gui();
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
nk_end(nkctx);
nk_glfw3_render(&nkglfw, NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
}
@ -795,10 +812,12 @@ int is_allowed_extension(const char *ext)
void editor_level_btn(char *level)
{
/*
if (ImGui::Button(level)) {
load_level(level);
strcpy(current_level, level);
}
*/
}
void editor_selectasset(struct fileasset *asset)
@ -810,7 +829,7 @@ void editor_selectasset(struct fileasset *asset)
tex_gui_anim.tex = (struct Texture *) asset->data;
asset->type = ASSET_TYPE_IMAGE;
tex_anim_set(&tex_gui_anim);
tex_scale = float ((float) ASSET_WIN_SIZE / tex_gui_anim.tex->width);
//float tex_scale = float((float) ASSET_WIN_SIZE / tex_gui_anim.tex->width);
if (tex_scale >= 10.f)
tex_scale = 10.f;
} else if (!strcmp(ext + 1, "glsl")) {
@ -840,6 +859,7 @@ void editor_selectasset_str(char *path)
void editor_asset_tex_gui(struct Texture *tex)
{
/*
ImGui::Text("%dx%d", tex->width, tex->height);
ImGui::SliderFloat("Zoom", &tex_scale, 0.01f, 10.f);
@ -850,11 +870,11 @@ void editor_asset_tex_gui(struct Texture *tex)
if (old_sprite != tex->opts.sprite)
tex_gpu_load(tex);
/*
ImGui::RadioButton("Raw", &tex_view, 0);
ImGui::SameLine(); ImGui::RadioButton("View 1", &tex_view, 1);
ImGui::SameLine(); ImGui::RadioButton("View 2", &tex_view, 2);
*/
ImGui::Checkbox("Animation", (bool *) &tex->opts.animation);
@ -917,11 +937,13 @@ void editor_asset_tex_gui(struct Texture *tex)
ImVec2(tex->width * tex_scale,
tex->height * tex_scale));
}
*/
}
void editor_asset_text_gui(char *text)
{
/*
ImGui::InputTextMultiline("File edit", text, ASSET_TEXT_BUF,
ImVec2(600, 500),
ImGuiInputTextFlags_CallbackAlways |
@ -933,10 +955,12 @@ void editor_asset_text_gui(char *text)
fwrite(text, len, 1, f);
fclose(f);
}
*/
}
void editor_asset_gui(struct fileasset *asset)
{
/*
ImGui::Begin("Asset Viewer");
ImGui::Text("%s", selected_asset->filename);
@ -959,6 +983,7 @@ void editor_asset_gui(struct fileasset *asset)
}
ImGui::End();
*/
}
void editor_load_projects()
@ -980,16 +1005,19 @@ void editor_save_projects()
void editor_project_btn_gui(struct gameproject *gp)
{
/*
if (ImGui::Button(gp->name))
editor_init_project(gp);
ImGui::SameLine();
ImGui::Text("%s", gp->path);
*/
}
void editor_proj_select_gui()
{
/*
ImGui::Begin("Project Select");
vec_walk(projects, (void (*)(void *)) &editor_project_btn_gui);
@ -1005,6 +1033,7 @@ void editor_proj_select_gui()
}
ImGui::End();
*/
}
void editor_init_project(struct gameproject *gp)
@ -1097,6 +1126,7 @@ void spotlight_gui(struct mSpotLight *spot)
void staticactor_gui(struct mStaticActor *sa)
{
object_gui(&sa->obj);
/*
if (ImGui::CollapsingHeader("Model")) {
ImGui::Checkbox("Cast Shadows", &sa->castShadows);
ImGui::Text("Model path: %s", sa->currentModelPath);
@ -1108,6 +1138,7 @@ void staticactor_gui(struct mStaticActor *sa)
}
}
*/
}
void trans_drawgui(struct mTransform *T)
@ -1115,10 +1146,11 @@ void trans_drawgui(struct mTransform *T)
/*ImGui::DragFloat3("Position", (float *) &T->position, 0.01f, -1000.f,
1000.f, "%4.2f");
ImGui::DragFloat("Rotation", (float *) &T->rotation[0] , 0.5f, 0.f,
360.f, "%4.2f"); */
360.f, "%4.2f");
ImGui::DragFloat("Scale", (float *) &T->scale, 0.001f, 0.f, 1000.f,
"%3.1f");
*/
}
void object_gui(struct mGameObject *go)
@ -1129,8 +1161,8 @@ void object_gui(struct mGameObject *go)
draw_point(temp_pos[0], temp_pos[1], 3);
ImGui::DragFloat2("Position", (float *) temp_pos, 1.f, 0.f, 0.f,
"%.0f");
//ImGui::DragFloat2("Position", (float *) temp_pos, 1.f, 0.f, 0.f,
// "%.0f");
cpVect tvect = { temp_pos[0], temp_pos[1] };
cpBodySetPosition(go->body, tvect);
@ -1138,13 +1170,13 @@ void object_gui(struct mGameObject *go)
float mtry = cpBodyGetAngle(go->body);
float modtry = fmodf(mtry * RAD2DEGS, 360.f);
float modtry2 = modtry;
ImGui::DragFloat("Angle", &modtry, 0.5f, -1000.f, 1000.f, "%3.1f");
//ImGui::DragFloat("Angle", &modtry, 0.5f, -1000.f, 1000.f, "%3.1f");
modtry -= modtry2;
cpBodySetAngle(go->body, mtry + (modtry * DEG2RADS));
ImGui::DragFloat("Scale", &go->scale, 0.001f, 0.f, 1000.f, "%3.3f");
// ImGui::DragFloat("Scale", &go->scale, 0.001f, 0.f, 1000.f, "%3.3f");
if (ImGui::Button("Start")) {
/* if (ImGui::Button("Start")) {
}
@ -1208,6 +1240,7 @@ void object_gui(struct mGameObject *go)
if (n >= 0)
gameobject_delcomponent(go, n);
*/
}
@ -1216,6 +1249,7 @@ void sprite_gui(struct mSprite *sprite)
//ImGui::Text("Path", sprite->tex->path);
//ImGui::SameLine();
/*
if (ImGui::Button("Load texture") && selected_asset != NULL) {
sprite_loadtex(sprite, selected_asset->filename);
}
@ -1248,14 +1282,14 @@ void sprite_gui(struct mSprite *sprite)
sprite->pos[0] = -0.5f;
sprite->pos[1] = 0.f;
}
*/
}
void circle_gui(struct phys2d_circle *circle)
{
ImGui::DragFloat("Radius", &circle->radius, 1.f, 1.f, 10000.f);
ImGui::DragFloat2("Offset", circle->offset, 1.f, 0.f, 0.f);
// ImGui::DragFloat("Radius", &circle->radius, 1.f, 1.f, 10000.f);
// ImGui::DragFloat2("Offset", circle->offset, 1.f, 0.f, 0.f);
phys2d_applycircle(circle);
@ -1266,8 +1300,8 @@ void circle_gui(struct phys2d_circle *circle)
void segment_gui(struct phys2d_segment *seg)
{
ImGui::DragFloat2("a", seg->a, 1.f, 0.f, 0.f);
ImGui::DragFloat2("b", seg->b, 1.f, 0.f, 0.f);
// ImGui::DragFloat2("a", seg->a, 1.f, 0.f, 0.f);
// ImGui::DragFloat2("b", seg->b, 1.f, 0.f, 0.f);
phys2d_applyseg(seg);
@ -1277,12 +1311,12 @@ void segment_gui(struct phys2d_segment *seg)
void box_gui(struct phys2d_box *box)
{
/*
ImGui::DragFloat("Width", &box->w, 1.f, 0.f, 1000.f);
ImGui::DragFloat("Height", &box->h, 1.f, 0.f, 1000.f);
ImGui::DragFloat2("Offset", box->offset, 1.f, 0.f, 0.f);
ImGui::DragFloat("Radius", &box->r, 1.f, 0.f, 100.f);
*/
phys2d_applybox(box);
@ -1291,7 +1325,7 @@ void box_gui(struct phys2d_box *box)
void poly_gui(struct phys2d_poly *poly)
{
/*
if (ImGui::Button("Add Poly Vertex"))
phys2d_polyaddvert(poly);
@ -1305,14 +1339,14 @@ void poly_gui(struct phys2d_poly *poly)
phys2d_applypoly(poly);
*/
}
void edge_gui(struct phys2d_edge *edge)
{
/*
if (ImGui::Button("Add Edge Vertex"))
phys2d_edgeaddvert(edge);
@ -1327,7 +1361,7 @@ void edge_gui(struct phys2d_edge *edge)
phys2d_applyedge(edge);
*/
}
void editor_makenewobject()
@ -1337,6 +1371,7 @@ void editor_makenewobject()
int obj_gui_hierarchy(struct mGameObject *selected)
{
/*
for (int i = 0; i < gameobjects->len; i++) {
struct mGameObject *go =
(struct mGameObject *) vec_get(gameobjects, i);
@ -1345,7 +1380,7 @@ int obj_gui_hierarchy(struct mGameObject *selected)
pickGameObject(i);
}
}
*/
return 0;
}
@ -1356,11 +1391,11 @@ void get_levels()
void editor_prefab_btn(char *prefab)
{
if (ImGui::Button(prefab)) {
gameobject_makefromprefab(prefab);
// if (ImGui::Button(prefab)) {
// gameobject_makefromprefab(prefab);
/*GameObject* newprefab = (GameObject*)createPrefab(*prefab); */
/*cam_inverse_goto(&camera, &newprefab->transform); */
}
// }
}
@ -1386,7 +1421,9 @@ void game_pause()
void pinball_flipper_gui(struct flipper *flip)
{
/*
ImGui::DragFloat("Angle start", &flip->angle1, 0, 360);
ImGui::DragFloat("Angle end", &flip->angle2, 0, 360);
ImGui::DragFloat("Flipper speed", &flip->flipspeed, 0, 100);
*/
}

View file

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2014-2021 Omar Cornut
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.

View file

@ -1,477 +0,0 @@
// dear imgui: Renderer + Platform Backend for Allegro 5
// (Info: Allegro 5 is a cross-platform general purpose library for handling windows, inputs, graphics, etc.)
// Implemented features:
// [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Platform: Clipboard support (from Allegro 5.1.12)
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// Issues:
// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
// [ ] Platform: Missing gamepad support.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-08-17: Calling io.AddFocusEvent() on ALLEGRO_EVENT_DISPLAY_SWITCH_OUT/ALLEGRO_EVENT_DISPLAY_SWITCH_IN events.
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
// 2021-05-19: Renderer: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 2021-02-18: Change blending equation to preserve alpha in output buffer.
// 2020-08-10: Inputs: Fixed horizontal mouse wheel direction.
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
// 2019-05-11: Inputs: Don't filter character value from ALLEGRO_EVENT_KEY_CHAR before calling AddInputCharacter().
// 2019-04-30: Renderer: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
// 2018-11-30: Platform: Added touchscreen support.
// 2018-11-30: Misc: Setting up io.BackendPlatformName/io.BackendRendererName so they can be displayed in the About Window.
// 2018-06-13: Platform: Added clipboard support (from Allegro 5.1.12).
// 2018-06-13: Renderer: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
// 2018-06-13: Renderer: Backup/restore transform and clipping rectangle.
// 2018-06-11: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
// 2018-04-18: Misc: Renamed file from imgui_impl_a5.cpp to imgui_impl_allegro5.cpp.
// 2018-04-18: Misc: Added support for 32-bit vertex indices to avoid conversion at runtime. Added imconfig_allegro5.h to enforce 32-bit indices when included from imgui.h.
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplAllegro5_RenderDrawData() in the .h file so you can call it yourself.
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
#include <stdint.h> // uint64_t
#include <cstring> // memcpy
#include "imgui.h"
#include "imgui_impl_allegro5.h"
// Allegro
#include <allegro5/allegro.h>
#include <allegro5/allegro_primitives.h>
#ifdef _WIN32
#include <allegro5/allegro_windows.h>
#endif
#define ALLEGRO_HAS_CLIPBOARD (ALLEGRO_VERSION_INT >= ((5 << 24) | (1 << 16) | (12 << 8))) // Clipboard only supported from Allegro 5.1.12
// Visual Studio warnings
#ifdef _MSC_VER
#pragma warning (disable: 4127) // condition expression is constant
#endif
// Allegro Data
struct ImGui_ImplAllegro5_Data
{
ALLEGRO_DISPLAY* Display;
ALLEGRO_BITMAP* Texture;
double Time;
ALLEGRO_MOUSE_CURSOR* MouseCursorInvisible;
ALLEGRO_VERTEX_DECL* VertexDecl;
char* ClipboardTextData;
ImGui_ImplAllegro5_Data() { memset(this, 0, sizeof(*this)); }
};
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
static ImGui_ImplAllegro5_Data* ImGui_ImplAllegro5_GetBackendData() { return ImGui::GetCurrentContext() ? (ImGui_ImplAllegro5_Data*)ImGui::GetIO().BackendPlatformUserData : NULL; }
struct ImDrawVertAllegro
{
ImVec2 pos;
ImVec2 uv;
ALLEGRO_COLOR col;
};
static void ImGui_ImplAllegro5_SetupRenderState(ImDrawData* draw_data)
{
// Setup blending
al_set_separate_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
// Setup orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right).
{
float L = draw_data->DisplayPos.x;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
float T = draw_data->DisplayPos.y;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
ALLEGRO_TRANSFORM transform;
al_identity_transform(&transform);
al_use_transform(&transform);
al_orthographic_transform(&transform, L, T, 1.0f, R, B, -1.0f);
al_use_projection_transform(&transform);
}
}
// Render function.
void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data)
{
// Avoid rendering when minimized
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
return;
// Backup Allegro state that will be modified
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
ALLEGRO_TRANSFORM last_transform = *al_get_current_transform();
ALLEGRO_TRANSFORM last_projection_transform = *al_get_current_projection_transform();
int last_clip_x, last_clip_y, last_clip_w, last_clip_h;
al_get_clipping_rectangle(&last_clip_x, &last_clip_y, &last_clip_w, &last_clip_h);
int last_blender_op, last_blender_src, last_blender_dst;
al_get_blender(&last_blender_op, &last_blender_src, &last_blender_dst);
// Setup desired render state
ImGui_ImplAllegro5_SetupRenderState(draw_data);
// Render command lists
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
// Allegro's implementation of al_draw_indexed_prim() for DX9 is completely broken. Unindex our buffers ourselves.
// FIXME-OPT: Unfortunately Allegro doesn't support 32-bit packed colors so we have to convert them to 4 float as well..
static ImVector<ImDrawVertAllegro> vertices;
vertices.resize(cmd_list->IdxBuffer.Size);
for (int i = 0; i < cmd_list->IdxBuffer.Size; i++)
{
const ImDrawVert* src_v = &cmd_list->VtxBuffer[cmd_list->IdxBuffer[i]];
ImDrawVertAllegro* dst_v = &vertices[i];
dst_v->pos = src_v->pos;
dst_v->uv = src_v->uv;
unsigned char* c = (unsigned char*)&src_v->col;
dst_v->col = al_map_rgba(c[0], c[1], c[2], c[3]);
}
const int* indices = NULL;
if (sizeof(ImDrawIdx) == 2)
{
// FIXME-OPT: Unfortunately Allegro doesn't support 16-bit indices.. You can '#define ImDrawIdx int' in imconfig.h to request Dear ImGui to output 32-bit indices.
// Otherwise, we convert them from 16-bit to 32-bit at runtime here, which works perfectly but is a little wasteful.
static ImVector<int> indices_converted;
indices_converted.resize(cmd_list->IdxBuffer.Size);
for (int i = 0; i < cmd_list->IdxBuffer.Size; ++i)
indices_converted[i] = (int)cmd_list->IdxBuffer.Data[i];
indices = indices_converted.Data;
}
else if (sizeof(ImDrawIdx) == 4)
{
indices = (const int*)cmd_list->IdxBuffer.Data;
}
// Render command lists
int idx_offset = 0;
ImVec2 clip_off = draw_data->DisplayPos;
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplAllegro5_SetupRenderState(draw_data);
else
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
continue;
// Apply scissor/clipping rectangle, Draw
ALLEGRO_BITMAP* texture = (ALLEGRO_BITMAP*)pcmd->GetTexID();
al_set_clipping_rectangle(clip_min.x, clip_min.y, clip_max.x - clip_min.x, clip_max.y - clip_min.y);
al_draw_prim(&vertices[0], bd->VertexDecl, texture, idx_offset, idx_offset + pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST);
}
idx_offset += pcmd->ElemCount;
}
}
// Restore modified Allegro state
al_set_blender(last_blender_op, last_blender_src, last_blender_dst);
al_set_clipping_rectangle(last_clip_x, last_clip_y, last_clip_w, last_clip_h);
al_use_transform(&last_transform);
al_use_projection_transform(&last_projection_transform);
}
bool ImGui_ImplAllegro5_CreateDeviceObjects()
{
// Build texture atlas
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
// Create texture
int flags = al_get_new_bitmap_flags();
int fmt = al_get_new_bitmap_format();
al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP | ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR);
al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE);
ALLEGRO_BITMAP* img = al_create_bitmap(width, height);
al_set_new_bitmap_flags(flags);
al_set_new_bitmap_format(fmt);
if (!img)
return false;
ALLEGRO_LOCKED_REGION* locked_img = al_lock_bitmap(img, al_get_bitmap_format(img), ALLEGRO_LOCK_WRITEONLY);
if (!locked_img)
{
al_destroy_bitmap(img);
return false;
}
memcpy(locked_img->data, pixels, sizeof(int) * width * height);
al_unlock_bitmap(img);
// Convert software texture to hardware texture.
ALLEGRO_BITMAP* cloned_img = al_clone_bitmap(img);
al_destroy_bitmap(img);
if (!cloned_img)
return false;
// Store our identifier
io.Fonts->SetTexID((void*)cloned_img);
bd->Texture = cloned_img;
// Create an invisible mouse cursor
// Because al_hide_mouse_cursor() seems to mess up with the actual inputs..
ALLEGRO_BITMAP* mouse_cursor = al_create_bitmap(8, 8);
bd->MouseCursorInvisible = al_create_mouse_cursor(mouse_cursor, 0, 0);
al_destroy_bitmap(mouse_cursor);
return true;
}
void ImGui_ImplAllegro5_InvalidateDeviceObjects()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
if (bd->Texture)
{
io.Fonts->SetTexID(NULL);
al_destroy_bitmap(bd->Texture);
bd->Texture = NULL;
}
if (bd->MouseCursorInvisible)
{
al_destroy_mouse_cursor(bd->MouseCursorInvisible);
bd->MouseCursorInvisible = NULL;
}
}
#if ALLEGRO_HAS_CLIPBOARD
static const char* ImGui_ImplAllegro5_GetClipboardText(void*)
{
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
if (bd->ClipboardTextData)
al_free(bd->ClipboardTextData);
bd->ClipboardTextData = al_get_clipboard_text(bd->Display);
return bd->ClipboardTextData;
}
static void ImGui_ImplAllegro5_SetClipboardText(void*, const char* text)
{
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
al_set_clipboard_text(bd->Display, text);
}
#endif
bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display)
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!");
// Setup backend capabilities flags
ImGui_ImplAllegro5_Data* bd = IM_NEW(ImGui_ImplAllegro5_Data)();
io.BackendPlatformUserData = (void*)bd;
io.BackendPlatformName = io.BackendRendererName = "imgui_impl_allegro5";
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
bd->Display = display;
// Create custom vertex declaration.
// Unfortunately Allegro doesn't support 32-bit packed colors so we have to convert them to 4 floats.
// We still use a custom declaration to use 'ALLEGRO_PRIM_TEX_COORD' instead of 'ALLEGRO_PRIM_TEX_COORD_PIXEL' else we can't do a reliable conversion.
ALLEGRO_VERTEX_ELEMENT elems[] =
{
{ ALLEGRO_PRIM_POSITION, ALLEGRO_PRIM_FLOAT_2, IM_OFFSETOF(ImDrawVertAllegro, pos) },
{ ALLEGRO_PRIM_TEX_COORD, ALLEGRO_PRIM_FLOAT_2, IM_OFFSETOF(ImDrawVertAllegro, uv) },
{ ALLEGRO_PRIM_COLOR_ATTR, 0, IM_OFFSETOF(ImDrawVertAllegro, col) },
{ 0, 0, 0 }
};
bd->VertexDecl = al_create_vertex_decl(elems, sizeof(ImDrawVertAllegro));
io.KeyMap[ImGuiKey_Tab] = ALLEGRO_KEY_TAB;
io.KeyMap[ImGuiKey_LeftArrow] = ALLEGRO_KEY_LEFT;
io.KeyMap[ImGuiKey_RightArrow] = ALLEGRO_KEY_RIGHT;
io.KeyMap[ImGuiKey_UpArrow] = ALLEGRO_KEY_UP;
io.KeyMap[ImGuiKey_DownArrow] = ALLEGRO_KEY_DOWN;
io.KeyMap[ImGuiKey_PageUp] = ALLEGRO_KEY_PGUP;
io.KeyMap[ImGuiKey_PageDown] = ALLEGRO_KEY_PGDN;
io.KeyMap[ImGuiKey_Home] = ALLEGRO_KEY_HOME;
io.KeyMap[ImGuiKey_End] = ALLEGRO_KEY_END;
io.KeyMap[ImGuiKey_Insert] = ALLEGRO_KEY_INSERT;
io.KeyMap[ImGuiKey_Delete] = ALLEGRO_KEY_DELETE;
io.KeyMap[ImGuiKey_Backspace] = ALLEGRO_KEY_BACKSPACE;
io.KeyMap[ImGuiKey_Space] = ALLEGRO_KEY_SPACE;
io.KeyMap[ImGuiKey_Enter] = ALLEGRO_KEY_ENTER;
io.KeyMap[ImGuiKey_Escape] = ALLEGRO_KEY_ESCAPE;
io.KeyMap[ImGuiKey_KeyPadEnter] = ALLEGRO_KEY_PAD_ENTER;
io.KeyMap[ImGuiKey_A] = ALLEGRO_KEY_A;
io.KeyMap[ImGuiKey_C] = ALLEGRO_KEY_C;
io.KeyMap[ImGuiKey_V] = ALLEGRO_KEY_V;
io.KeyMap[ImGuiKey_X] = ALLEGRO_KEY_X;
io.KeyMap[ImGuiKey_Y] = ALLEGRO_KEY_Y;
io.KeyMap[ImGuiKey_Z] = ALLEGRO_KEY_Z;
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
#if ALLEGRO_HAS_CLIPBOARD
io.SetClipboardTextFn = ImGui_ImplAllegro5_SetClipboardText;
io.GetClipboardTextFn = ImGui_ImplAllegro5_GetClipboardText;
io.ClipboardUserData = NULL;
#endif
return true;
}
void ImGui_ImplAllegro5_Shutdown()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
ImGui_ImplAllegro5_InvalidateDeviceObjects();
if (bd->VertexDecl)
al_destroy_vertex_decl(bd->VertexDecl);
if (bd->ClipboardTextData)
al_free(bd->ClipboardTextData);
io.BackendPlatformUserData = NULL;
io.BackendPlatformName = io.BackendRendererName = NULL;
IM_DELETE(bd);
}
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT* ev)
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
switch (ev->type)
{
case ALLEGRO_EVENT_MOUSE_AXES:
if (ev->mouse.display == bd->Display)
{
io.MouseWheel += ev->mouse.dz;
io.MouseWheelH -= ev->mouse.dw;
io.MousePos = ImVec2(ev->mouse.x, ev->mouse.y);
}
return true;
case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
if (ev->mouse.display == bd->Display && ev->mouse.button <= 5)
io.MouseDown[ev->mouse.button - 1] = (ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN);
return true;
case ALLEGRO_EVENT_TOUCH_MOVE:
if (ev->touch.display == bd->Display)
io.MousePos = ImVec2(ev->touch.x, ev->touch.y);
return true;
case ALLEGRO_EVENT_TOUCH_BEGIN:
case ALLEGRO_EVENT_TOUCH_END:
case ALLEGRO_EVENT_TOUCH_CANCEL:
if (ev->touch.display == bd->Display && ev->touch.primary)
io.MouseDown[0] = (ev->type == ALLEGRO_EVENT_TOUCH_BEGIN);
return true;
case ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY:
if (ev->mouse.display == bd->Display)
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
return true;
case ALLEGRO_EVENT_KEY_CHAR:
if (ev->keyboard.display == bd->Display)
if (ev->keyboard.unichar != 0)
io.AddInputCharacter((unsigned int)ev->keyboard.unichar);
return true;
case ALLEGRO_EVENT_KEY_DOWN:
case ALLEGRO_EVENT_KEY_UP:
if (ev->keyboard.display == bd->Display)
io.KeysDown[ev->keyboard.keycode] = (ev->type == ALLEGRO_EVENT_KEY_DOWN);
return true;
case ALLEGRO_EVENT_DISPLAY_SWITCH_OUT:
if (ev->display.source == bd->Display)
io.AddFocusEvent(false);
return true;
case ALLEGRO_EVENT_DISPLAY_SWITCH_IN:
if (ev->display.source == bd->Display)
{
io.AddFocusEvent(true);
#if defined(ALLEGRO_UNSTABLE)
al_clear_keyboard_state(bd->Display);
#endif
}
return true;
}
return false;
}
static void ImGui_ImplAllegro5_UpdateMouseCursor()
{
ImGuiIO& io = ImGui::GetIO();
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
return;
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
{
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
al_set_mouse_cursor(bd->Display, bd->MouseCursorInvisible);
}
else
{
ALLEGRO_SYSTEM_MOUSE_CURSOR cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT;
switch (imgui_cursor)
{
case ImGuiMouseCursor_TextInput: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_EDIT; break;
case ImGuiMouseCursor_ResizeAll: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_MOVE; break;
case ImGuiMouseCursor_ResizeNS: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_N; break;
case ImGuiMouseCursor_ResizeEW: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_E; break;
case ImGuiMouseCursor_ResizeNESW: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NE; break;
case ImGuiMouseCursor_ResizeNWSE: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NW; break;
case ImGuiMouseCursor_NotAllowed: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_UNAVAILABLE; break;
}
al_set_system_mouse_cursor(bd->Display, cursor_id);
}
}
void ImGui_ImplAllegro5_NewFrame()
{
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplAllegro5_Init()?");
if (!bd->Texture)
ImGui_ImplAllegro5_CreateDeviceObjects();
ImGuiIO& io = ImGui::GetIO();
// Setup display size (every frame to accommodate for window resizing)
int w, h;
w = al_get_display_width(bd->Display);
h = al_get_display_height(bd->Display);
io.DisplaySize = ImVec2((float)w, (float)h);
// Setup time step
double current_time = al_get_time();
io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
bd->Time = current_time;
// Setup inputs
ALLEGRO_KEYBOARD_STATE keys;
al_get_keyboard_state(&keys);
io.KeyCtrl = al_key_down(&keys, ALLEGRO_KEY_LCTRL) || al_key_down(&keys, ALLEGRO_KEY_RCTRL);
io.KeyShift = al_key_down(&keys, ALLEGRO_KEY_LSHIFT) || al_key_down(&keys, ALLEGRO_KEY_RSHIFT);
io.KeyAlt = al_key_down(&keys, ALLEGRO_KEY_ALT) || al_key_down(&keys, ALLEGRO_KEY_ALTGR);
io.KeySuper = al_key_down(&keys, ALLEGRO_KEY_LWIN) || al_key_down(&keys, ALLEGRO_KEY_RWIN);
ImGui_ImplAllegro5_UpdateMouseCursor();
}

View file

@ -1,31 +0,0 @@
// dear imgui: Renderer + Platform Backend for Allegro 5
// (Info: Allegro 5 is a cross-platform general purpose library for handling windows, inputs, graphics, etc.)
// Implemented features:
// [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Platform: Clipboard support (from Allegro 5.1.12)
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// Issues:
// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
// [ ] Platform: Missing gamepad support.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
struct ALLEGRO_DISPLAY;
union ALLEGRO_EVENT;
IMGUI_IMPL_API bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display);
IMGUI_IMPL_API void ImGui_ImplAllegro5_Shutdown();
IMGUI_IMPL_API void ImGui_ImplAllegro5_NewFrame();
IMGUI_IMPL_API void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data);
IMGUI_IMPL_API bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT* event);
// Use if you want to reset your rendering device without losing Dear ImGui state.
IMGUI_IMPL_API bool ImGui_ImplAllegro5_CreateDeviceObjects();
IMGUI_IMPL_API void ImGui_ImplAllegro5_InvalidateDeviceObjects();

View file

@ -1,187 +0,0 @@
// dear imgui: Platform Binding for Android native app
// This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3)
// Implemented features:
// [X] Platform: Keyboard arrays indexed using AKEYCODE_* codes, e.g. ImGui::IsKeyPressed(AKEYCODE_SPACE).
// Missing features:
// [ ] Platform: Clipboard support.
// [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
// Important:
// - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)
// - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446)
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-03-04: Initial version.
#include "imgui.h"
#include "imgui_impl_android.h"
#include <time.h>
#include <map>
#include <queue>
#include <android/native_window.h>
#include <android/input.h>
#include <android/keycodes.h>
#include <android/log.h>
// Android data
static double g_Time = 0.0;
static ANativeWindow* g_Window;
static char g_LogTag[] = "ImGuiExample";
static std::map<int32_t, std::queue<int32_t>> g_KeyEventQueues; // FIXME: Remove dependency on map and queue once we use upcoming input queue.
int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event)
{
ImGuiIO& io = ImGui::GetIO();
int32_t event_type = AInputEvent_getType(input_event);
switch (event_type)
{
case AINPUT_EVENT_TYPE_KEY:
{
int32_t event_key_code = AKeyEvent_getKeyCode(input_event);
int32_t event_action = AKeyEvent_getAction(input_event);
int32_t event_meta_state = AKeyEvent_getMetaState(input_event);
io.KeyCtrl = ((event_meta_state & AMETA_CTRL_ON) != 0);
io.KeyShift = ((event_meta_state & AMETA_SHIFT_ON) != 0);
io.KeyAlt = ((event_meta_state & AMETA_ALT_ON) != 0);
switch (event_action)
{
// FIXME: AKEY_EVENT_ACTION_DOWN and AKEY_EVENT_ACTION_UP occur at once as soon as a touch pointer
// goes up from a key. We use a simple key event queue/ and process one event per key per frame in
// ImGui_ImplAndroid_NewFrame()...or consider using IO queue, if suitable: https://github.com/ocornut/imgui/issues/2787
case AKEY_EVENT_ACTION_DOWN:
case AKEY_EVENT_ACTION_UP:
g_KeyEventQueues[event_key_code].push(event_action);
break;
default:
break;
}
break;
}
case AINPUT_EVENT_TYPE_MOTION:
{
int32_t event_action = AMotionEvent_getAction(input_event);
int32_t event_pointer_index = (event_action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
event_action &= AMOTION_EVENT_ACTION_MASK;
switch (event_action)
{
case AMOTION_EVENT_ACTION_DOWN:
case AMOTION_EVENT_ACTION_UP:
// Physical mouse buttons (and probably other physical devices) also invoke the actions AMOTION_EVENT_ACTION_DOWN/_UP,
// but we have to process them separately to identify the actual button pressed. This is done below via
// AMOTION_EVENT_ACTION_BUTTON_PRESS/_RELEASE. Here, we only process "FINGER" input (and "UNKNOWN", as a fallback).
if((AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_FINGER)
|| (AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_UNKNOWN))
{
io.MouseDown[0] = (event_action == AMOTION_EVENT_ACTION_DOWN);
io.MousePos = ImVec2(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index));
}
break;
case AMOTION_EVENT_ACTION_BUTTON_PRESS:
case AMOTION_EVENT_ACTION_BUTTON_RELEASE:
{
int32_t button_state = AMotionEvent_getButtonState(input_event);
io.MouseDown[0] = ((button_state & AMOTION_EVENT_BUTTON_PRIMARY) != 0);
io.MouseDown[1] = ((button_state & AMOTION_EVENT_BUTTON_SECONDARY) != 0);
io.MouseDown[2] = ((button_state & AMOTION_EVENT_BUTTON_TERTIARY) != 0);
}
break;
case AMOTION_EVENT_ACTION_HOVER_MOVE: // Hovering: Tool moves while NOT pressed (such as a physical mouse)
case AMOTION_EVENT_ACTION_MOVE: // Touch pointer moves while DOWN
io.MousePos = ImVec2(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index));
break;
case AMOTION_EVENT_ACTION_SCROLL:
io.MouseWheel = AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_VSCROLL, event_pointer_index);
io.MouseWheelH = AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_HSCROLL, event_pointer_index);
break;
default:
break;
}
}
return 1;
default:
break;
}
return 0;
}
bool ImGui_ImplAndroid_Init(ANativeWindow* window)
{
g_Window = window;
g_Time = 0.0;
// Setup backend capabilities flags
ImGuiIO& io = ImGui::GetIO();
io.BackendPlatformName = "imgui_impl_android";
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
io.KeyMap[ImGuiKey_Tab] = AKEYCODE_TAB;
io.KeyMap[ImGuiKey_LeftArrow] = AKEYCODE_DPAD_LEFT; // also covers physical keyboard arrow key
io.KeyMap[ImGuiKey_RightArrow] = AKEYCODE_DPAD_RIGHT; // also covers physical keyboard arrow key
io.KeyMap[ImGuiKey_UpArrow] = AKEYCODE_DPAD_UP; // also covers physical keyboard arrow key
io.KeyMap[ImGuiKey_DownArrow] = AKEYCODE_DPAD_DOWN; // also covers physical keyboard arrow key
io.KeyMap[ImGuiKey_PageUp] = AKEYCODE_PAGE_UP;
io.KeyMap[ImGuiKey_PageDown] = AKEYCODE_PAGE_DOWN;
io.KeyMap[ImGuiKey_Home] = AKEYCODE_MOVE_HOME;
io.KeyMap[ImGuiKey_End] = AKEYCODE_MOVE_END;
io.KeyMap[ImGuiKey_Insert] = AKEYCODE_INSERT;
io.KeyMap[ImGuiKey_Delete] = AKEYCODE_FORWARD_DEL;
io.KeyMap[ImGuiKey_Backspace] = AKEYCODE_DEL;
io.KeyMap[ImGuiKey_Space] = AKEYCODE_SPACE;
io.KeyMap[ImGuiKey_Enter] = AKEYCODE_ENTER;
io.KeyMap[ImGuiKey_Escape] = AKEYCODE_ESCAPE;
io.KeyMap[ImGuiKey_KeyPadEnter] = AKEYCODE_NUMPAD_ENTER;
io.KeyMap[ImGuiKey_A] = AKEYCODE_A;
io.KeyMap[ImGuiKey_C] = AKEYCODE_C;
io.KeyMap[ImGuiKey_V] = AKEYCODE_V;
io.KeyMap[ImGuiKey_X] = AKEYCODE_X;
io.KeyMap[ImGuiKey_Y] = AKEYCODE_Y;
io.KeyMap[ImGuiKey_Z] = AKEYCODE_Z;
return true;
}
void ImGui_ImplAndroid_Shutdown()
{
}
void ImGui_ImplAndroid_NewFrame()
{
ImGuiIO& io = ImGui::GetIO();
// Process queued key events
// FIXME: This is a workaround for multiple key event actions occurring at once (see above) and can be removed once we use upcoming input queue.
for (auto& key_queue : g_KeyEventQueues)
{
if (key_queue.second.empty())
continue;
io.KeysDown[key_queue.first] = (key_queue.second.front() == AKEY_EVENT_ACTION_DOWN);
key_queue.second.pop();
}
// Setup display size (every frame to accommodate for window resizing)
int32_t window_width = ANativeWindow_getWidth(g_Window);
int32_t window_height = ANativeWindow_getHeight(g_Window);
int display_width = window_width;
int display_height = window_height;
io.DisplaySize = ImVec2((float)window_width, (float)window_height);
if (window_width > 0 && window_height > 0)
io.DisplayFramebufferScale = ImVec2((float)display_width / window_width, (float)display_height / window_height);
// Setup time step
struct timespec current_timespec;
clock_gettime(CLOCK_MONOTONIC, &current_timespec);
double current_time = (double)(current_timespec.tv_sec) + (current_timespec.tv_nsec / 1000000000.0);
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f);
g_Time = current_time;
}

View file

@ -1,27 +0,0 @@
// dear imgui: Platform Binding for Android native app
// This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3)
// Implemented features:
// [X] Platform: Keyboard arrays indexed using AKEYCODE_* codes, e.g. ImGui::IsKeyPressed(AKEYCODE_SPACE).
// Missing features:
// [ ] Platform: Clipboard support.
// [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
// Important:
// - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)
// - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446)
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#pragma once
struct ANativeWindow;
struct AInputEvent;
IMGUI_IMPL_API bool ImGui_ImplAndroid_Init(ANativeWindow* window);
IMGUI_IMPL_API int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event);
IMGUI_IMPL_API void ImGui_ImplAndroid_Shutdown();
IMGUI_IMPL_API void ImGui_ImplAndroid_NewFrame();

View file

@ -1,577 +0,0 @@
// dear imgui: Renderer Backend for DirectX10
// This needs to be used along with a Platform Backend (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture backend. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
// 2021-05-19: DirectX10: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 2021-02-18: DirectX10: Change blending equation to preserve alpha in output buffer.
// 2019-07-21: DirectX10: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData().
// 2019-05-29: DirectX10: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
// 2019-04-30: DirectX10: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
// 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
// 2018-07-13: DirectX10: Fixed unreleased resources in Init and Shutdown functions.
// 2018-06-08: Misc: Extracted imgui_impl_dx10.cpp/.h away from the old combined DX10+Win32 example.
// 2018-06-08: DirectX10: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
// 2018-04-09: Misc: Fixed erroneous call to io.Fonts->ClearInputData() + ClearTexData() that was left in DX10 example but removed in 1.47 (Nov 2015) on other backends.
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX10_RenderDrawData() in the .h file so you can call it yourself.
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
// 2016-05-07: DirectX10: Disabling depth-write.
#include "imgui.h"
#include "imgui_impl_dx10.h"
// DirectX
#include <stdio.h>
#include <d3d10_1.h>
#include <d3d10.h>
#include <d3dcompiler.h>
#ifdef _MSC_VER
#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
#endif
// DirectX data
struct ImGui_ImplDX10_Data
{
ID3D10Device* pd3dDevice;
IDXGIFactory* pFactory;
ID3D10Buffer* pVB;
ID3D10Buffer* pIB;
ID3D10VertexShader* pVertexShader;
ID3D10InputLayout* pInputLayout;
ID3D10Buffer* pVertexConstantBuffer;
ID3D10PixelShader* pPixelShader;
ID3D10SamplerState* pFontSampler;
ID3D10ShaderResourceView* pFontTextureView;
ID3D10RasterizerState* pRasterizerState;
ID3D10BlendState* pBlendState;
ID3D10DepthStencilState* pDepthStencilState;
int VertexBufferSize;
int IndexBufferSize;
ImGui_ImplDX10_Data() { memset(this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
};
struct VERTEX_CONSTANT_BUFFER
{
float mvp[4][4];
};
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
static ImGui_ImplDX10_Data* ImGui_ImplDX10_GetBackendData()
{
return ImGui::GetCurrentContext() ? (ImGui_ImplDX10_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
}
// Functions
static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* ctx)
{
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
// Setup viewport
D3D10_VIEWPORT vp;
memset(&vp, 0, sizeof(D3D10_VIEWPORT));
vp.Width = (UINT)draw_data->DisplaySize.x;
vp.Height = (UINT)draw_data->DisplaySize.y;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = vp.TopLeftY = 0;
ctx->RSSetViewports(1, &vp);
// Bind shader and vertex buffers
unsigned int stride = sizeof(ImDrawVert);
unsigned int offset = 0;
ctx->IASetInputLayout(bd->pInputLayout);
ctx->IASetVertexBuffers(0, 1, &bd->pVB, &stride, &offset);
ctx->IASetIndexBuffer(bd->pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
ctx->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ctx->VSSetShader(bd->pVertexShader);
ctx->VSSetConstantBuffers(0, 1, &bd->pVertexConstantBuffer);
ctx->PSSetShader(bd->pPixelShader);
ctx->PSSetSamplers(0, 1, &bd->pFontSampler);
ctx->GSSetShader(NULL);
// Setup render state
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
ctx->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff);
ctx->OMSetDepthStencilState(bd->pDepthStencilState, 0);
ctx->RSSetState(bd->pRasterizerState);
}
// Render function
void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
{
// Avoid rendering when minimized
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
return;
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
ID3D10Device* ctx = bd->pd3dDevice;
// Create and grow vertex/index buffers if needed
if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount)
{
if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
bd->VertexBufferSize = draw_data->TotalVtxCount + 5000;
D3D10_BUFFER_DESC desc;
memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert);
desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
if (ctx->CreateBuffer(&desc, NULL, &bd->pVB) < 0)
return;
}
if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)
{
if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; }
bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
D3D10_BUFFER_DESC desc;
memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx);
desc.BindFlags = D3D10_BIND_INDEX_BUFFER;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
if (ctx->CreateBuffer(&desc, NULL, &bd->pIB) < 0)
return;
}
// Copy and convert all vertices into a single contiguous buffer
ImDrawVert* vtx_dst = NULL;
ImDrawIdx* idx_dst = NULL;
bd->pVB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&vtx_dst);
bd->pIB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&idx_dst);
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
vtx_dst += cmd_list->VtxBuffer.Size;
idx_dst += cmd_list->IdxBuffer.Size;
}
bd->pVB->Unmap();
bd->pIB->Unmap();
// Setup orthographic projection matrix into our constant buffer
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
{
void* mapped_resource;
if (bd->pVertexConstantBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
return;
VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource;
float L = draw_data->DisplayPos.x;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
float T = draw_data->DisplayPos.y;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
float mvp[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(&constant_buffer->mvp, mvp, sizeof(mvp));
bd->pVertexConstantBuffer->Unmap();
}
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
struct BACKUP_DX10_STATE
{
UINT ScissorRectsCount, ViewportsCount;
D3D10_RECT ScissorRects[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
D3D10_VIEWPORT Viewports[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
ID3D10RasterizerState* RS;
ID3D10BlendState* BlendState;
FLOAT BlendFactor[4];
UINT SampleMask;
UINT StencilRef;
ID3D10DepthStencilState* DepthStencilState;
ID3D10ShaderResourceView* PSShaderResource;
ID3D10SamplerState* PSSampler;
ID3D10PixelShader* PS;
ID3D10VertexShader* VS;
ID3D10GeometryShader* GS;
D3D10_PRIMITIVE_TOPOLOGY PrimitiveTopology;
ID3D10Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer;
UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
DXGI_FORMAT IndexBufferFormat;
ID3D10InputLayout* InputLayout;
};
BACKUP_DX10_STATE old = {};
old.ScissorRectsCount = old.ViewportsCount = D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);
ctx->RSGetViewports(&old.ViewportsCount, old.Viewports);
ctx->RSGetState(&old.RS);
ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask);
ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef);
ctx->PSGetShaderResources(0, 1, &old.PSShaderResource);
ctx->PSGetSamplers(0, 1, &old.PSSampler);
ctx->PSGetShader(&old.PS);
ctx->VSGetShader(&old.VS);
ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer);
ctx->GSGetShader(&old.GS);
ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology);
ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset);
ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset);
ctx->IAGetInputLayout(&old.InputLayout);
// Setup desired DX state
ImGui_ImplDX10_SetupRenderState(draw_data, ctx);
// Render command lists
// (Because we merged all buffers into a single one, we maintain our own offset into them)
int global_vtx_offset = 0;
int global_idx_offset = 0;
ImVec2 clip_off = draw_data->DisplayPos;
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplDX10_SetupRenderState(draw_data, ctx);
else
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
continue;
// Apply scissor/clipping rectangle
const D3D10_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
ctx->RSSetScissorRects(1, &r);
// Bind texture, Draw
ID3D10ShaderResourceView* texture_srv = (ID3D10ShaderResourceView*)pcmd->GetTexID();
ctx->PSSetShaderResources(0, 1, &texture_srv);
ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
}
}
global_idx_offset += cmd_list->IdxBuffer.Size;
global_vtx_offset += cmd_list->VtxBuffer.Size;
}
// Restore modified DX state
ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
ctx->RSSetViewports(old.ViewportsCount, old.Viewports);
ctx->RSSetState(old.RS); if (old.RS) old.RS->Release();
ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();
ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release();
ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release();
ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release();
ctx->PSSetShader(old.PS); if (old.PS) old.PS->Release();
ctx->VSSetShader(old.VS); if (old.VS) old.VS->Release();
ctx->GSSetShader(old.GS); if (old.GS) old.GS->Release();
ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release();
ctx->IASetPrimitiveTopology(old.PrimitiveTopology);
ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release();
ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release();
ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();
}
static void ImGui_ImplDX10_CreateFontsTexture()
{
// Build texture atlas
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
// Upload texture to graphics system
{
D3D10_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Width = width;
desc.Height = height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D10_USAGE_DEFAULT;
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
ID3D10Texture2D* pTexture = NULL;
D3D10_SUBRESOURCE_DATA subResource;
subResource.pSysMem = pixels;
subResource.SysMemPitch = desc.Width * 4;
subResource.SysMemSlicePitch = 0;
bd->pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
IM_ASSERT(pTexture != NULL);
// Create texture view
D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc;
ZeroMemory(&srv_desc, sizeof(srv_desc));
srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srv_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
srv_desc.Texture2D.MipLevels = desc.MipLevels;
srv_desc.Texture2D.MostDetailedMip = 0;
bd->pd3dDevice->CreateShaderResourceView(pTexture, &srv_desc, &bd->pFontTextureView);
pTexture->Release();
}
// Store our identifier
io.Fonts->SetTexID((ImTextureID)bd->pFontTextureView);
// Create texture sampler
{
D3D10_SAMPLER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR;
desc.AddressU = D3D10_TEXTURE_ADDRESS_WRAP;
desc.AddressV = D3D10_TEXTURE_ADDRESS_WRAP;
desc.AddressW = D3D10_TEXTURE_ADDRESS_WRAP;
desc.MipLODBias = 0.f;
desc.ComparisonFunc = D3D10_COMPARISON_ALWAYS;
desc.MinLOD = 0.f;
desc.MaxLOD = 0.f;
bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler);
}
}
bool ImGui_ImplDX10_CreateDeviceObjects()
{
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
if (!bd->pd3dDevice)
return false;
if (bd->pFontSampler)
ImGui_ImplDX10_InvalidateDeviceObjects();
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
// If you would like to use this DX10 sample code but remove this dependency you can:
// 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
// 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
// Create the vertex shader
{
static const char* vertexShader =
"cbuffer vertexBuffer : register(b0) \
{\
float4x4 ProjectionMatrix; \
};\
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 main(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;\
}";
ID3DBlob* vertexShaderBlob;
if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &vertexShaderBlob, NULL)))
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
if (bd->pd3dDevice->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &bd->pVertexShader) != S_OK)
{
vertexShaderBlob->Release();
return false;
}
// Create the input layout
D3D10_INPUT_ELEMENT_DESC local_layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, pos), D3D10_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, uv), D3D10_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), D3D10_INPUT_PER_VERTEX_DATA, 0 },
};
if (bd->pd3dDevice->CreateInputLayout(local_layout, 3, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &bd->pInputLayout) != S_OK)
{
vertexShaderBlob->Release();
return false;
}
vertexShaderBlob->Release();
// Create the constant buffer
{
D3D10_BUFFER_DESC desc;
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
bd->pd3dDevice->CreateBuffer(&desc, NULL, &bd->pVertexConstantBuffer);
}
}
// Create the pixel shader
{
static const char* pixelShader =
"struct PS_INPUT\
{\
float4 pos : SV_POSITION;\
float4 col : COLOR0;\
float2 uv : TEXCOORD0;\
};\
sampler sampler0;\
Texture2D texture0;\
\
float4 main(PS_INPUT input) : SV_Target\
{\
float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
return out_col; \
}";
ID3DBlob* pixelShaderBlob;
if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &pixelShaderBlob, NULL)))
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
if (bd->pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), &bd->pPixelShader) != S_OK)
{
pixelShaderBlob->Release();
return false;
}
pixelShaderBlob->Release();
}
// Create the blending setup
{
D3D10_BLEND_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.AlphaToCoverageEnable = false;
desc.BlendEnable[0] = true;
desc.SrcBlend = D3D10_BLEND_SRC_ALPHA;
desc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
desc.BlendOp = D3D10_BLEND_OP_ADD;
desc.SrcBlendAlpha = D3D10_BLEND_ONE;
desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
bd->pd3dDevice->CreateBlendState(&desc, &bd->pBlendState);
}
// Create the rasterizer state
{
D3D10_RASTERIZER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.FillMode = D3D10_FILL_SOLID;
desc.CullMode = D3D10_CULL_NONE;
desc.ScissorEnable = true;
desc.DepthClipEnable = true;
bd->pd3dDevice->CreateRasterizerState(&desc, &bd->pRasterizerState);
}
// Create depth-stencil State
{
D3D10_DEPTH_STENCIL_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.DepthEnable = false;
desc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ALL;
desc.DepthFunc = D3D10_COMPARISON_ALWAYS;
desc.StencilEnable = false;
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;
desc.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS;
desc.BackFace = desc.FrontFace;
bd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState);
}
ImGui_ImplDX10_CreateFontsTexture();
return true;
}
void ImGui_ImplDX10_InvalidateDeviceObjects()
{
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
if (!bd->pd3dDevice)
return;
if (bd->pFontSampler) { bd->pFontSampler->Release(); bd->pFontSampler = NULL; }
if (bd->pFontTextureView) { bd->pFontTextureView->Release(); bd->pFontTextureView = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well.
if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; }
if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = NULL; }
if (bd->pDepthStencilState) { bd->pDepthStencilState->Release(); bd->pDepthStencilState = NULL; }
if (bd->pRasterizerState) { bd->pRasterizerState->Release(); bd->pRasterizerState = NULL; }
if (bd->pPixelShader) { bd->pPixelShader->Release(); bd->pPixelShader = NULL; }
if (bd->pVertexConstantBuffer) { bd->pVertexConstantBuffer->Release(); bd->pVertexConstantBuffer = NULL; }
if (bd->pInputLayout) { bd->pInputLayout->Release(); bd->pInputLayout = NULL; }
if (bd->pVertexShader) { bd->pVertexShader->Release(); bd->pVertexShader = NULL; }
}
bool ImGui_ImplDX10_Init(ID3D10Device* device)
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
// Setup backend capabilities flags
ImGui_ImplDX10_Data* bd = IM_NEW(ImGui_ImplDX10_Data)();
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_dx10";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
// Get factory from device
IDXGIDevice* pDXGIDevice = NULL;
IDXGIAdapter* pDXGIAdapter = NULL;
IDXGIFactory* pFactory = NULL;
if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
{
bd->pd3dDevice = device;
bd->pFactory = pFactory;
}
if (pDXGIDevice) pDXGIDevice->Release();
if (pDXGIAdapter) pDXGIAdapter->Release();
bd->pd3dDevice->AddRef();
return true;
}
void ImGui_ImplDX10_Shutdown()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
ImGui_ImplDX10_InvalidateDeviceObjects();
if (bd->pFactory) { bd->pFactory->Release(); }
if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
io.BackendRendererName = NULL;
io.BackendRendererUserData = NULL;
IM_DELETE(bd);
}
void ImGui_ImplDX10_NewFrame()
{
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplDX10_Init()?");
if (!bd->pFontSampler)
ImGui_ImplDX10_CreateDeviceObjects();
}

View file

@ -1,25 +0,0 @@
// dear imgui: Renderer Backend for DirectX10
// This needs to be used along with a Platform Backend (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture backend. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
struct ID3D10Device;
IMGUI_IMPL_API bool ImGui_ImplDX10_Init(ID3D10Device* device);
IMGUI_IMPL_API void ImGui_ImplDX10_Shutdown();
IMGUI_IMPL_API void ImGui_ImplDX10_NewFrame();
IMGUI_IMPL_API void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data);
// Use if you want to reset your rendering device without losing Dear ImGui state.
IMGUI_IMPL_API void ImGui_ImplDX10_InvalidateDeviceObjects();
IMGUI_IMPL_API bool ImGui_ImplDX10_CreateDeviceObjects();

View file

@ -1,593 +0,0 @@
// dear imgui: Renderer Backend for DirectX11
// This needs to be used along with a Platform Backend (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
// 2021-05-19: DirectX11: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 2021-02-18: DirectX11: Change blending equation to preserve alpha in output buffer.
// 2019-08-01: DirectX11: Fixed code querying the Geometry Shader state (would generally error with Debug layer enabled).
// 2019-07-21: DirectX11: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData. Clearing Hull/Domain/Compute shaders without backup/restore.
// 2019-05-29: DirectX11: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
// 2019-04-30: DirectX11: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
// 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
// 2018-08-01: DirectX11: Querying for IDXGIFactory instead of IDXGIFactory1 to increase compatibility.
// 2018-07-13: DirectX11: Fixed unreleased resources in Init and Shutdown functions.
// 2018-06-08: Misc: Extracted imgui_impl_dx11.cpp/.h away from the old combined DX11+Win32 example.
// 2018-06-08: DirectX11: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX11_RenderDrawData() in the .h file so you can call it yourself.
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
// 2016-05-07: DirectX11: Disabling depth-write.
#include "imgui.h"
#include "imgui_impl_dx11.h"
// DirectX
#include <stdio.h>
#include <d3d11.h>
#include <d3dcompiler.h>
#ifdef _MSC_VER
#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
#endif
// DirectX11 data
struct ImGui_ImplDX11_Data
{
ID3D11Device* pd3dDevice;
ID3D11DeviceContext* pd3dDeviceContext;
IDXGIFactory* pFactory;
ID3D11Buffer* pVB;
ID3D11Buffer* pIB;
ID3D11VertexShader* pVertexShader;
ID3D11InputLayout* pInputLayout;
ID3D11Buffer* pVertexConstantBuffer;
ID3D11PixelShader* pPixelShader;
ID3D11SamplerState* pFontSampler;
ID3D11ShaderResourceView* pFontTextureView;
ID3D11RasterizerState* pRasterizerState;
ID3D11BlendState* pBlendState;
ID3D11DepthStencilState* pDepthStencilState;
int VertexBufferSize;
int IndexBufferSize;
ImGui_ImplDX11_Data() { memset(this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
};
struct VERTEX_CONSTANT_BUFFER
{
float mvp[4][4];
};
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
static ImGui_ImplDX11_Data* ImGui_ImplDX11_GetBackendData()
{
return ImGui::GetCurrentContext() ? (ImGui_ImplDX11_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
}
// Functions
static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceContext* ctx)
{
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
// Setup viewport
D3D11_VIEWPORT vp;
memset(&vp, 0, sizeof(D3D11_VIEWPORT));
vp.Width = draw_data->DisplaySize.x;
vp.Height = draw_data->DisplaySize.y;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = vp.TopLeftY = 0;
ctx->RSSetViewports(1, &vp);
// Setup shader and vertex buffers
unsigned int stride = sizeof(ImDrawVert);
unsigned int offset = 0;
ctx->IASetInputLayout(bd->pInputLayout);
ctx->IASetVertexBuffers(0, 1, &bd->pVB, &stride, &offset);
ctx->IASetIndexBuffer(bd->pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ctx->VSSetShader(bd->pVertexShader, NULL, 0);
ctx->VSSetConstantBuffers(0, 1, &bd->pVertexConstantBuffer);
ctx->PSSetShader(bd->pPixelShader, NULL, 0);
ctx->PSSetSamplers(0, 1, &bd->pFontSampler);
ctx->GSSetShader(NULL, NULL, 0);
ctx->HSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used..
ctx->DSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used..
ctx->CSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used..
// Setup blend state
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
ctx->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff);
ctx->OMSetDepthStencilState(bd->pDepthStencilState, 0);
ctx->RSSetState(bd->pRasterizerState);
}
// Render function
void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
{
// Avoid rendering when minimized
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
return;
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
ID3D11DeviceContext* ctx = bd->pd3dDeviceContext;
// Create and grow vertex/index buffers if needed
if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount)
{
if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
bd->VertexBufferSize = draw_data->TotalVtxCount + 5000;
D3D11_BUFFER_DESC desc;
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert);
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
if (bd->pd3dDevice->CreateBuffer(&desc, NULL, &bd->pVB) < 0)
return;
}
if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)
{
if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; }
bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
D3D11_BUFFER_DESC desc;
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx);
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
if (bd->pd3dDevice->CreateBuffer(&desc, NULL, &bd->pIB) < 0)
return;
}
// Upload vertex/index data into a single contiguous GPU buffer
D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource;
if (ctx->Map(bd->pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK)
return;
if (ctx->Map(bd->pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK)
return;
ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData;
ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData;
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
vtx_dst += cmd_list->VtxBuffer.Size;
idx_dst += cmd_list->IdxBuffer.Size;
}
ctx->Unmap(bd->pVB, 0);
ctx->Unmap(bd->pIB, 0);
// Setup orthographic projection matrix into our constant buffer
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
{
D3D11_MAPPED_SUBRESOURCE mapped_resource;
if (ctx->Map(bd->pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
return;
VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource.pData;
float L = draw_data->DisplayPos.x;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
float T = draw_data->DisplayPos.y;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
float mvp[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(&constant_buffer->mvp, mvp, sizeof(mvp));
ctx->Unmap(bd->pVertexConstantBuffer, 0);
}
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
struct BACKUP_DX11_STATE
{
UINT ScissorRectsCount, ViewportsCount;
D3D11_RECT ScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
ID3D11RasterizerState* RS;
ID3D11BlendState* BlendState;
FLOAT BlendFactor[4];
UINT SampleMask;
UINT StencilRef;
ID3D11DepthStencilState* DepthStencilState;
ID3D11ShaderResourceView* PSShaderResource;
ID3D11SamplerState* PSSampler;
ID3D11PixelShader* PS;
ID3D11VertexShader* VS;
ID3D11GeometryShader* GS;
UINT PSInstancesCount, VSInstancesCount, GSInstancesCount;
ID3D11ClassInstance *PSInstances[256], *VSInstances[256], *GSInstances[256]; // 256 is max according to PSSetShader documentation
D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology;
ID3D11Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer;
UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
DXGI_FORMAT IndexBufferFormat;
ID3D11InputLayout* InputLayout;
};
BACKUP_DX11_STATE old = {};
old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);
ctx->RSGetViewports(&old.ViewportsCount, old.Viewports);
ctx->RSGetState(&old.RS);
ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask);
ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef);
ctx->PSGetShaderResources(0, 1, &old.PSShaderResource);
ctx->PSGetSamplers(0, 1, &old.PSSampler);
old.PSInstancesCount = old.VSInstancesCount = old.GSInstancesCount = 256;
ctx->PSGetShader(&old.PS, old.PSInstances, &old.PSInstancesCount);
ctx->VSGetShader(&old.VS, old.VSInstances, &old.VSInstancesCount);
ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer);
ctx->GSGetShader(&old.GS, old.GSInstances, &old.GSInstancesCount);
ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology);
ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset);
ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset);
ctx->IAGetInputLayout(&old.InputLayout);
// Setup desired DX state
ImGui_ImplDX11_SetupRenderState(draw_data, ctx);
// Render command lists
// (Because we merged all buffers into a single one, we maintain our own offset into them)
int global_idx_offset = 0;
int global_vtx_offset = 0;
ImVec2 clip_off = draw_data->DisplayPos;
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback != NULL)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplDX11_SetupRenderState(draw_data, ctx);
else
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
continue;
// Apply scissor/clipping rectangle
const D3D11_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
ctx->RSSetScissorRects(1, &r);
// Bind texture, Draw
ID3D11ShaderResourceView* texture_srv = (ID3D11ShaderResourceView*)pcmd->GetTexID();
ctx->PSSetShaderResources(0, 1, &texture_srv);
ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
}
}
global_idx_offset += cmd_list->IdxBuffer.Size;
global_vtx_offset += cmd_list->VtxBuffer.Size;
}
// Restore modified DX state
ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
ctx->RSSetViewports(old.ViewportsCount, old.Viewports);
ctx->RSSetState(old.RS); if (old.RS) old.RS->Release();
ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();
ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release();
ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release();
ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release();
ctx->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount); if (old.PS) old.PS->Release();
for (UINT i = 0; i < old.PSInstancesCount; i++) if (old.PSInstances[i]) old.PSInstances[i]->Release();
ctx->VSSetShader(old.VS, old.VSInstances, old.VSInstancesCount); if (old.VS) old.VS->Release();
ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release();
ctx->GSSetShader(old.GS, old.GSInstances, old.GSInstancesCount); if (old.GS) old.GS->Release();
for (UINT i = 0; i < old.VSInstancesCount; i++) if (old.VSInstances[i]) old.VSInstances[i]->Release();
ctx->IASetPrimitiveTopology(old.PrimitiveTopology);
ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release();
ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release();
ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();
}
static void ImGui_ImplDX11_CreateFontsTexture()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
// Upload texture to graphics system
{
D3D11_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Width = width;
desc.Height = height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
ID3D11Texture2D* pTexture = NULL;
D3D11_SUBRESOURCE_DATA subResource;
subResource.pSysMem = pixels;
subResource.SysMemPitch = desc.Width * 4;
subResource.SysMemSlicePitch = 0;
bd->pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
IM_ASSERT(pTexture != NULL);
// Create texture view
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
ZeroMemory(&srvDesc, sizeof(srvDesc));
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Texture2D.MostDetailedMip = 0;
bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &bd->pFontTextureView);
pTexture->Release();
}
// Store our identifier
io.Fonts->SetTexID((ImTextureID)bd->pFontTextureView);
// Create texture sampler
{
D3D11_SAMPLER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
desc.MipLODBias = 0.f;
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
desc.MinLOD = 0.f;
desc.MaxLOD = 0.f;
bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler);
}
}
bool ImGui_ImplDX11_CreateDeviceObjects()
{
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
if (!bd->pd3dDevice)
return false;
if (bd->pFontSampler)
ImGui_ImplDX11_InvalidateDeviceObjects();
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
// If you would like to use this DX11 sample code but remove this dependency you can:
// 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
// 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
// Create the vertex shader
{
static const char* vertexShader =
"cbuffer vertexBuffer : register(b0) \
{\
float4x4 ProjectionMatrix; \
};\
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 main(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;\
}";
ID3DBlob* vertexShaderBlob;
if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &vertexShaderBlob, NULL)))
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
if (bd->pd3dDevice->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), NULL, &bd->pVertexShader) != S_OK)
{
vertexShaderBlob->Release();
return false;
}
// Create the input layout
D3D11_INPUT_ELEMENT_DESC local_layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
if (bd->pd3dDevice->CreateInputLayout(local_layout, 3, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &bd->pInputLayout) != S_OK)
{
vertexShaderBlob->Release();
return false;
}
vertexShaderBlob->Release();
// Create the constant buffer
{
D3D11_BUFFER_DESC desc;
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
bd->pd3dDevice->CreateBuffer(&desc, NULL, &bd->pVertexConstantBuffer);
}
}
// Create the pixel shader
{
static const char* pixelShader =
"struct PS_INPUT\
{\
float4 pos : SV_POSITION;\
float4 col : COLOR0;\
float2 uv : TEXCOORD0;\
};\
sampler sampler0;\
Texture2D texture0;\
\
float4 main(PS_INPUT input) : SV_Target\
{\
float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
return out_col; \
}";
ID3DBlob* pixelShaderBlob;
if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &pixelShaderBlob, NULL)))
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
if (bd->pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), NULL, &bd->pPixelShader) != S_OK)
{
pixelShaderBlob->Release();
return false;
}
pixelShaderBlob->Release();
}
// Create the blending setup
{
D3D11_BLEND_DESC desc;
ZeroMemory(&desc, 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_ONE;
desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
bd->pd3dDevice->CreateBlendState(&desc, &bd->pBlendState);
}
// Create the rasterizer state
{
D3D11_RASTERIZER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.FillMode = D3D11_FILL_SOLID;
desc.CullMode = D3D11_CULL_NONE;
desc.ScissorEnable = true;
desc.DepthClipEnable = true;
bd->pd3dDevice->CreateRasterizerState(&desc, &bd->pRasterizerState);
}
// Create depth-stencil State
{
D3D11_DEPTH_STENCIL_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.DepthEnable = false;
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
desc.StencilEnable = false;
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
desc.BackFace = desc.FrontFace;
bd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState);
}
ImGui_ImplDX11_CreateFontsTexture();
return true;
}
void ImGui_ImplDX11_InvalidateDeviceObjects()
{
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
if (!bd->pd3dDevice)
return;
if (bd->pFontSampler) { bd->pFontSampler->Release(); bd->pFontSampler = NULL; }
if (bd->pFontTextureView) { bd->pFontTextureView->Release(); bd->pFontTextureView = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied data->pFontTextureView to io.Fonts->TexID so let's clear that as well.
if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; }
if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = NULL; }
if (bd->pDepthStencilState) { bd->pDepthStencilState->Release(); bd->pDepthStencilState = NULL; }
if (bd->pRasterizerState) { bd->pRasterizerState->Release(); bd->pRasterizerState = NULL; }
if (bd->pPixelShader) { bd->pPixelShader->Release(); bd->pPixelShader = NULL; }
if (bd->pVertexConstantBuffer) { bd->pVertexConstantBuffer->Release(); bd->pVertexConstantBuffer = NULL; }
if (bd->pInputLayout) { bd->pInputLayout->Release(); bd->pInputLayout = NULL; }
if (bd->pVertexShader) { bd->pVertexShader->Release(); bd->pVertexShader = NULL; }
}
bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context)
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
// Setup backend capabilities flags
ImGui_ImplDX11_Data* bd = IM_NEW(ImGui_ImplDX11_Data)();
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_dx11";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
// Get factory from device
IDXGIDevice* pDXGIDevice = NULL;
IDXGIAdapter* pDXGIAdapter = NULL;
IDXGIFactory* pFactory = NULL;
if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
{
bd->pd3dDevice = device;
bd->pd3dDeviceContext = device_context;
bd->pFactory = pFactory;
}
if (pDXGIDevice) pDXGIDevice->Release();
if (pDXGIAdapter) pDXGIAdapter->Release();
bd->pd3dDevice->AddRef();
bd->pd3dDeviceContext->AddRef();
return true;
}
void ImGui_ImplDX11_Shutdown()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
ImGui_ImplDX11_InvalidateDeviceObjects();
if (bd->pFactory) { bd->pFactory->Release(); }
if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
if (bd->pd3dDeviceContext) { bd->pd3dDeviceContext->Release(); }
io.BackendRendererName = NULL;
io.BackendRendererUserData = NULL;
IM_DELETE(bd);
}
void ImGui_ImplDX11_NewFrame()
{
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplDX11_Init()?");
if (!bd->pFontSampler)
ImGui_ImplDX11_CreateDeviceObjects();
}

View file

@ -1,26 +0,0 @@
// dear imgui: Renderer Backend for DirectX11
// This needs to be used along with a Platform Backend (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
struct ID3D11Device;
struct ID3D11DeviceContext;
IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context);
IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown();
IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame();
IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data);
// Use if you want to reset your rendering device without losing Dear ImGui state.
IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects();
IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects();

View file

@ -1,745 +0,0 @@
// dear imgui: Renderer Backend for DirectX12
// This needs to be used along with a Platform Backend (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'.
// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*.
// To build this on 32-bit systems:
// - [Solution 1] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'ImTextureID=ImU64' (this is what we do in the 'example_win32_direct12/example_win32_direct12.vcxproj' project file)
// - [Solution 2] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'IMGUI_USER_CONFIG="my_imgui_config.h"' and inside 'my_imgui_config.h' add '#define ImTextureID ImU64' and as many other options as you like.
// - [Solution 3] IDE/msbuild: edit imconfig.h and add '#define ImTextureID ImU64' (prefer solution 2 to create your own config file!)
// - [Solution 4] command-line: add '/D ImTextureID=ImU64' to your cl.exe command-line (this is what we do in the example_win32_direct12/build_win32.bat file)
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
// 2021-05-19: DirectX12: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 2021-02-18: DirectX12: Change blending equation to preserve alpha in output buffer.
// 2021-01-11: DirectX12: Improve Windows 7 compatibility (for D3D12On7) by loading d3d12.dll dynamically.
// 2020-09-16: DirectX12: Avoid rendering calls with zero-sized scissor rectangle since it generates a validation layer warning.
// 2020-09-08: DirectX12: Clarified support for building on 32-bit systems by redefining ImTextureID.
// 2019-10-18: DirectX12: *BREAKING CHANGE* Added extra ID3D12DescriptorHeap parameter to ImGui_ImplDX12_Init() function.
// 2019-05-29: DirectX12: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
// 2019-04-30: DirectX12: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
// 2019-03-29: Misc: Various minor tidying up.
// 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
// 2018-06-12: DirectX12: Moved the ID3D12GraphicsCommandList* parameter from NewFrame() to RenderDrawData().
// 2018-06-08: Misc: Extracted imgui_impl_dx12.cpp/.h away from the old combined DX12+Win32 example.
// 2018-06-08: DirectX12: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle (to ease support for future multi-viewport).
// 2018-02-22: Merged into master with all Win32 code synchronized to other examples.
#include "imgui.h"
#include "imgui_impl_dx12.h"
// DirectX
#include <d3d12.h>
#include <dxgi1_4.h>
#include <d3dcompiler.h>
#ifdef _MSC_VER
#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
#endif
// DirectX data
struct ImGui_ImplDX12_RenderBuffers
{
ID3D12Resource* IndexBuffer;
ID3D12Resource* VertexBuffer;
int IndexBufferSize;
int VertexBufferSize;
};
struct ImGui_ImplDX12_Data
{
ID3D12Device* pd3dDevice;
ID3D12RootSignature* pRootSignature;
ID3D12PipelineState* pPipelineState;
DXGI_FORMAT RTVFormat;
ID3D12Resource* pFontTextureResource;
D3D12_CPU_DESCRIPTOR_HANDLE hFontSrvCpuDescHandle;
D3D12_GPU_DESCRIPTOR_HANDLE hFontSrvGpuDescHandle;
ImGui_ImplDX12_RenderBuffers* pFrameResources;
UINT numFramesInFlight;
UINT frameIndex;
ImGui_ImplDX12_Data() { memset(this, 0, sizeof(*this)); frameIndex = UINT_MAX; }
};
struct VERTEX_CONSTANT_BUFFER
{
float mvp[4][4];
};
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
static ImGui_ImplDX12_Data* ImGui_ImplDX12_GetBackendData()
{
return ImGui::GetCurrentContext() ? (ImGui_ImplDX12_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
}
// Functions
static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12GraphicsCommandList* ctx, ImGui_ImplDX12_RenderBuffers* fr)
{
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
// Setup orthographic projection matrix into our constant buffer
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right).
VERTEX_CONSTANT_BUFFER vertex_constant_buffer;
{
float L = draw_data->DisplayPos.x;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
float T = draw_data->DisplayPos.y;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
float mvp[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(&vertex_constant_buffer.mvp, mvp, sizeof(mvp));
}
// Setup viewport
D3D12_VIEWPORT vp;
memset(&vp, 0, sizeof(D3D12_VIEWPORT));
vp.Width = draw_data->DisplaySize.x;
vp.Height = draw_data->DisplaySize.y;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = vp.TopLeftY = 0.0f;
ctx->RSSetViewports(1, &vp);
// Bind shader and vertex buffers
unsigned int stride = sizeof(ImDrawVert);
unsigned int offset = 0;
D3D12_VERTEX_BUFFER_VIEW vbv;
memset(&vbv, 0, sizeof(D3D12_VERTEX_BUFFER_VIEW));
vbv.BufferLocation = fr->VertexBuffer->GetGPUVirtualAddress() + offset;
vbv.SizeInBytes = fr->VertexBufferSize * stride;
vbv.StrideInBytes = stride;
ctx->IASetVertexBuffers(0, 1, &vbv);
D3D12_INDEX_BUFFER_VIEW ibv;
memset(&ibv, 0, sizeof(D3D12_INDEX_BUFFER_VIEW));
ibv.BufferLocation = fr->IndexBuffer->GetGPUVirtualAddress();
ibv.SizeInBytes = fr->IndexBufferSize * sizeof(ImDrawIdx);
ibv.Format = sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
ctx->IASetIndexBuffer(&ibv);
ctx->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ctx->SetPipelineState(bd->pPipelineState);
ctx->SetGraphicsRootSignature(bd->pRootSignature);
ctx->SetGraphicsRoot32BitConstants(0, 16, &vertex_constant_buffer, 0);
// Setup blend factor
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
ctx->OMSetBlendFactor(blend_factor);
}
template<typename T>
static inline void SafeRelease(T*& res)
{
if (res)
res->Release();
res = NULL;
}
// Render function
void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* ctx)
{
// Avoid rendering when minimized
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
return;
// FIXME: I'm assuming that this only gets called once per frame!
// If not, we can't just re-allocate the IB or VB, we'll have to do a proper allocator.
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
bd->frameIndex = bd->frameIndex + 1;
ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[bd->frameIndex % bd->numFramesInFlight];
// Create and grow vertex/index buffers if needed
if (fr->VertexBuffer == NULL || fr->VertexBufferSize < draw_data->TotalVtxCount)
{
SafeRelease(fr->VertexBuffer);
fr->VertexBufferSize = draw_data->TotalVtxCount + 5000;
D3D12_HEAP_PROPERTIES props;
memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES));
props.Type = D3D12_HEAP_TYPE_UPLOAD;
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
D3D12_RESOURCE_DESC desc;
memset(&desc, 0, sizeof(D3D12_RESOURCE_DESC));
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
desc.Width = fr->VertexBufferSize * sizeof(ImDrawVert);
desc.Height = 1;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.Format = DXGI_FORMAT_UNKNOWN;
desc.SampleDesc.Count = 1;
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
if (bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&fr->VertexBuffer)) < 0)
return;
}
if (fr->IndexBuffer == NULL || fr->IndexBufferSize < draw_data->TotalIdxCount)
{
SafeRelease(fr->IndexBuffer);
fr->IndexBufferSize = draw_data->TotalIdxCount + 10000;
D3D12_HEAP_PROPERTIES props;
memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES));
props.Type = D3D12_HEAP_TYPE_UPLOAD;
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
D3D12_RESOURCE_DESC desc;
memset(&desc, 0, sizeof(D3D12_RESOURCE_DESC));
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
desc.Width = fr->IndexBufferSize * sizeof(ImDrawIdx);
desc.Height = 1;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.Format = DXGI_FORMAT_UNKNOWN;
desc.SampleDesc.Count = 1;
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
if (bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&fr->IndexBuffer)) < 0)
return;
}
// Upload vertex/index data into a single contiguous GPU buffer
void* vtx_resource, *idx_resource;
D3D12_RANGE range;
memset(&range, 0, sizeof(D3D12_RANGE));
if (fr->VertexBuffer->Map(0, &range, &vtx_resource) != S_OK)
return;
if (fr->IndexBuffer->Map(0, &range, &idx_resource) != S_OK)
return;
ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource;
ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource;
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
vtx_dst += cmd_list->VtxBuffer.Size;
idx_dst += cmd_list->IdxBuffer.Size;
}
fr->VertexBuffer->Unmap(0, &range);
fr->IndexBuffer->Unmap(0, &range);
// Setup desired DX state
ImGui_ImplDX12_SetupRenderState(draw_data, ctx, fr);
// Render command lists
// (Because we merged all buffers into a single one, we maintain our own offset into them)
int global_vtx_offset = 0;
int global_idx_offset = 0;
ImVec2 clip_off = draw_data->DisplayPos;
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback != NULL)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplDX12_SetupRenderState(draw_data, ctx, fr);
else
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
continue;
// Apply Scissor/clipping rectangle, Bind texture, Draw
const D3D12_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
D3D12_GPU_DESCRIPTOR_HANDLE texture_handle = {};
texture_handle.ptr = (UINT64)pcmd->GetTexID();
ctx->SetGraphicsRootDescriptorTable(1, texture_handle);
ctx->RSSetScissorRects(1, &r);
ctx->DrawIndexedInstanced(pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
}
}
global_idx_offset += cmd_list->IdxBuffer.Size;
global_vtx_offset += cmd_list->VtxBuffer.Size;
}
}
static void ImGui_ImplDX12_CreateFontsTexture()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
// Upload texture to graphics system
{
D3D12_HEAP_PROPERTIES props;
memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES));
props.Type = D3D12_HEAP_TYPE_DEFAULT;
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
D3D12_RESOURCE_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
desc.Alignment = 0;
desc.Width = width;
desc.Height = height;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
ID3D12Resource* pTexture = NULL;
bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
D3D12_RESOURCE_STATE_COPY_DEST, NULL, IID_PPV_ARGS(&pTexture));
UINT uploadPitch = (width * 4 + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u);
UINT uploadSize = height * uploadPitch;
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
desc.Alignment = 0;
desc.Width = uploadSize;
desc.Height = 1;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.Format = DXGI_FORMAT_UNKNOWN;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
props.Type = D3D12_HEAP_TYPE_UPLOAD;
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
ID3D12Resource* uploadBuffer = NULL;
HRESULT hr = bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&uploadBuffer));
IM_ASSERT(SUCCEEDED(hr));
void* mapped = NULL;
D3D12_RANGE range = { 0, uploadSize };
hr = uploadBuffer->Map(0, &range, &mapped);
IM_ASSERT(SUCCEEDED(hr));
for (int y = 0; y < height; y++)
memcpy((void*) ((uintptr_t) mapped + y * uploadPitch), pixels + y * width * 4, width * 4);
uploadBuffer->Unmap(0, &range);
D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
srcLocation.pResource = uploadBuffer;
srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
srcLocation.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srcLocation.PlacedFootprint.Footprint.Width = width;
srcLocation.PlacedFootprint.Footprint.Height = height;
srcLocation.PlacedFootprint.Footprint.Depth = 1;
srcLocation.PlacedFootprint.Footprint.RowPitch = uploadPitch;
D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
dstLocation.pResource = pTexture;
dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
dstLocation.SubresourceIndex = 0;
D3D12_RESOURCE_BARRIER barrier = {};
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition.pResource = pTexture;
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
ID3D12Fence* fence = NULL;
hr = bd->pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence));
IM_ASSERT(SUCCEEDED(hr));
HANDLE event = CreateEvent(0, 0, 0, 0);
IM_ASSERT(event != NULL);
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queueDesc.NodeMask = 1;
ID3D12CommandQueue* cmdQueue = NULL;
hr = bd->pd3dDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&cmdQueue));
IM_ASSERT(SUCCEEDED(hr));
ID3D12CommandAllocator* cmdAlloc = NULL;
hr = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc));
IM_ASSERT(SUCCEEDED(hr));
ID3D12GraphicsCommandList* cmdList = NULL;
hr = bd->pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc, NULL, IID_PPV_ARGS(&cmdList));
IM_ASSERT(SUCCEEDED(hr));
cmdList->CopyTextureRegion(&dstLocation, 0, 0, 0, &srcLocation, NULL);
cmdList->ResourceBarrier(1, &barrier);
hr = cmdList->Close();
IM_ASSERT(SUCCEEDED(hr));
cmdQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmdList);
hr = cmdQueue->Signal(fence, 1);
IM_ASSERT(SUCCEEDED(hr));
fence->SetEventOnCompletion(1, event);
WaitForSingleObject(event, INFINITE);
cmdList->Release();
cmdAlloc->Release();
cmdQueue->Release();
CloseHandle(event);
fence->Release();
uploadBuffer->Release();
// Create texture view
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
ZeroMemory(&srvDesc, sizeof(srvDesc));
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, bd->hFontSrvCpuDescHandle);
SafeRelease(bd->pFontTextureResource);
bd->pFontTextureResource = pTexture;
}
// Store our identifier
// READ THIS IF THE STATIC_ASSERT() TRIGGERS:
// - Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'.
// - This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*.
// [Solution 1] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'ImTextureID=ImU64' (this is what we do in the 'example_win32_direct12/example_win32_direct12.vcxproj' project file)
// [Solution 2] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'IMGUI_USER_CONFIG="my_imgui_config.h"' and inside 'my_imgui_config.h' add '#define ImTextureID ImU64' and as many other options as you like.
// [Solution 3] IDE/msbuild: edit imconfig.h and add '#define ImTextureID ImU64' (prefer solution 2 to create your own config file!)
// [Solution 4] command-line: add '/D ImTextureID=ImU64' to your cl.exe command-line (this is what we do in the example_win32_direct12/build_win32.bat file)
static_assert(sizeof(ImTextureID) >= sizeof(bd->hFontSrvGpuDescHandle.ptr), "Can't pack descriptor handle into TexID, 32-bit not supported yet.");
io.Fonts->SetTexID((ImTextureID)bd->hFontSrvGpuDescHandle.ptr);
}
bool ImGui_ImplDX12_CreateDeviceObjects()
{
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
if (!bd || !bd->pd3dDevice)
return false;
if (bd->pPipelineState)
ImGui_ImplDX12_InvalidateDeviceObjects();
// Create the root signature
{
D3D12_DESCRIPTOR_RANGE descRange = {};
descRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
descRange.NumDescriptors = 1;
descRange.BaseShaderRegister = 0;
descRange.RegisterSpace = 0;
descRange.OffsetInDescriptorsFromTableStart = 0;
D3D12_ROOT_PARAMETER param[2] = {};
param[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
param[0].Constants.ShaderRegister = 0;
param[0].Constants.RegisterSpace = 0;
param[0].Constants.Num32BitValues = 16;
param[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
param[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
param[1].DescriptorTable.NumDescriptorRanges = 1;
param[1].DescriptorTable.pDescriptorRanges = &descRange;
param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
D3D12_STATIC_SAMPLER_DESC staticSampler = {};
staticSampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
staticSampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
staticSampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
staticSampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
staticSampler.MipLODBias = 0.f;
staticSampler.MaxAnisotropy = 0;
staticSampler.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS;
staticSampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
staticSampler.MinLOD = 0.f;
staticSampler.MaxLOD = 0.f;
staticSampler.ShaderRegister = 0;
staticSampler.RegisterSpace = 0;
staticSampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
D3D12_ROOT_SIGNATURE_DESC desc = {};
desc.NumParameters = _countof(param);
desc.pParameters = param;
desc.NumStaticSamplers = 1;
desc.pStaticSamplers = &staticSampler;
desc.Flags =
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |
D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;
// Load d3d12.dll and D3D12SerializeRootSignature() function address dynamically to facilitate using with D3D12On7.
// See if any version of d3d12.dll is already loaded in the process. If so, give preference to that.
static HINSTANCE d3d12_dll = ::GetModuleHandleA("d3d12.dll");
if (d3d12_dll == NULL)
{
// Attempt to load d3d12.dll from local directories. This will only succeed if
// (1) the current OS is Windows 7, and
// (2) there exists a version of d3d12.dll for Windows 7 (D3D12On7) in one of the following directories.
// See https://github.com/ocornut/imgui/pull/3696 for details.
const char* localD3d12Paths[] = { ".\\d3d12.dll", ".\\d3d12on7\\d3d12.dll", ".\\12on7\\d3d12.dll" }; // A. current directory, B. used by some games, C. used in Microsoft D3D12On7 sample
for (int i = 0; i < IM_ARRAYSIZE(localD3d12Paths); i++)
if ((d3d12_dll = ::LoadLibraryA(localD3d12Paths[i])) != NULL)
break;
// If failed, we are on Windows >= 10.
if (d3d12_dll == NULL)
d3d12_dll = ::LoadLibraryA("d3d12.dll");
if (d3d12_dll == NULL)
return false;
}
PFN_D3D12_SERIALIZE_ROOT_SIGNATURE D3D12SerializeRootSignatureFn = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)::GetProcAddress(d3d12_dll, "D3D12SerializeRootSignature");
if (D3D12SerializeRootSignatureFn == NULL)
return false;
ID3DBlob* blob = NULL;
if (D3D12SerializeRootSignatureFn(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &blob, NULL) != S_OK)
return false;
bd->pd3dDevice->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(&bd->pRootSignature));
blob->Release();
}
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
// If you would like to use this DX12 sample code but remove this dependency you can:
// 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
// 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc;
memset(&psoDesc, 0, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
psoDesc.NodeMask = 1;
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
psoDesc.pRootSignature = bd->pRootSignature;
psoDesc.SampleMask = UINT_MAX;
psoDesc.NumRenderTargets = 1;
psoDesc.RTVFormats[0] = bd->RTVFormat;
psoDesc.SampleDesc.Count = 1;
psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
ID3DBlob* vertexShaderBlob;
ID3DBlob* pixelShaderBlob;
// Create the vertex shader
{
static const char* vertexShader =
"cbuffer vertexBuffer : register(b0) \
{\
float4x4 ProjectionMatrix; \
};\
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 main(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;\
}";
if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_5_0", 0, 0, &vertexShaderBlob, NULL)))
return false; // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
psoDesc.VS = { vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize() };
// Create the input layout
static D3D12_INPUT_ELEMENT_DESC local_layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, pos), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, uv), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
};
psoDesc.InputLayout = { local_layout, 3 };
}
// Create the pixel shader
{
static const char* pixelShader =
"struct PS_INPUT\
{\
float4 pos : SV_POSITION;\
float4 col : COLOR0;\
float2 uv : TEXCOORD0;\
};\
SamplerState sampler0 : register(s0);\
Texture2D texture0 : register(t0);\
\
float4 main(PS_INPUT input) : SV_Target\
{\
float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
return out_col; \
}";
if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_5_0", 0, 0, &pixelShaderBlob, NULL)))
{
vertexShaderBlob->Release();
return false; // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
}
psoDesc.PS = { pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize() };
}
// Create the blending setup
{
D3D12_BLEND_DESC& desc = psoDesc.BlendState;
desc.AlphaToCoverageEnable = false;
desc.RenderTarget[0].BlendEnable = true;
desc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
desc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
desc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
desc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
desc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
desc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
desc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
}
// Create the rasterizer state
{
D3D12_RASTERIZER_DESC& desc = psoDesc.RasterizerState;
desc.FillMode = D3D12_FILL_MODE_SOLID;
desc.CullMode = D3D12_CULL_MODE_NONE;
desc.FrontCounterClockwise = FALSE;
desc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
desc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
desc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
desc.DepthClipEnable = true;
desc.MultisampleEnable = FALSE;
desc.AntialiasedLineEnable = FALSE;
desc.ForcedSampleCount = 0;
desc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
}
// Create depth-stencil State
{
D3D12_DEPTH_STENCIL_DESC& desc = psoDesc.DepthStencilState;
desc.DepthEnable = false;
desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
desc.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
desc.StencilEnable = false;
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
desc.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
desc.BackFace = desc.FrontFace;
}
HRESULT result_pipeline_state = bd->pd3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&bd->pPipelineState));
vertexShaderBlob->Release();
pixelShaderBlob->Release();
if (result_pipeline_state != S_OK)
return false;
ImGui_ImplDX12_CreateFontsTexture();
return true;
}
void ImGui_ImplDX12_InvalidateDeviceObjects()
{
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
if (!bd || !bd->pd3dDevice)
return;
ImGuiIO& io = ImGui::GetIO();
SafeRelease(bd->pRootSignature);
SafeRelease(bd->pPipelineState);
SafeRelease(bd->pFontTextureResource);
io.Fonts->SetTexID(NULL); // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well.
for (UINT i = 0; i < bd->numFramesInFlight; i++)
{
ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[i];
SafeRelease(fr->IndexBuffer);
SafeRelease(fr->VertexBuffer);
}
}
bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* cbv_srv_heap,
D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle)
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
// Setup backend capabilities flags
ImGui_ImplDX12_Data* bd = IM_NEW(ImGui_ImplDX12_Data)();
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_dx12";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
bd->pd3dDevice = device;
bd->RTVFormat = rtv_format;
bd->hFontSrvCpuDescHandle = font_srv_cpu_desc_handle;
bd->hFontSrvGpuDescHandle = font_srv_gpu_desc_handle;
bd->pFrameResources = new ImGui_ImplDX12_RenderBuffers[num_frames_in_flight];
bd->numFramesInFlight = num_frames_in_flight;
bd->frameIndex = UINT_MAX;
IM_UNUSED(cbv_srv_heap); // Unused in master branch (will be used by multi-viewports)
// Create buffers with a default size (they will later be grown as needed)
for (int i = 0; i < num_frames_in_flight; i++)
{
ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[i];
fr->IndexBuffer = NULL;
fr->VertexBuffer = NULL;
fr->IndexBufferSize = 10000;
fr->VertexBufferSize = 5000;
}
return true;
}
void ImGui_ImplDX12_Shutdown()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
ImGui_ImplDX12_InvalidateDeviceObjects();
delete[] bd->pFrameResources;
io.BackendRendererName = NULL;
io.BackendRendererUserData = NULL;
IM_DELETE(bd);
}
void ImGui_ImplDX12_NewFrame()
{
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplDX12_Init()?");
if (!bd->pPipelineState)
ImGui_ImplDX12_CreateDeviceObjects();
}

View file

@ -1,49 +0,0 @@
// dear imgui: Renderer Backend for DirectX12
// This needs to be used along with a Platform Backend (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'.
// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*.
// This define is set in the example .vcxproj file and need to be replicated in your app or by adding it to your imconfig.h file.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
#ifdef _MSC_VER
#pragma warning (push)
#pragma warning (disable: 4471) // a forward declaration of an unscoped enumeration must have an underlying type
#endif
enum DXGI_FORMAT;
struct ID3D12Device;
struct ID3D12DescriptorHeap;
struct ID3D12GraphicsCommandList;
struct D3D12_CPU_DESCRIPTOR_HANDLE;
struct D3D12_GPU_DESCRIPTOR_HANDLE;
// cmd_list is the command list that the implementation will use to render imgui draw lists.
// Before calling the render function, caller must prepare cmd_list by resetting it and setting the appropriate
// render target and descriptor heap that contains font_srv_cpu_desc_handle/font_srv_gpu_desc_handle.
// font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture.
IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* cbv_srv_heap,
D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle);
IMGUI_IMPL_API void ImGui_ImplDX12_Shutdown();
IMGUI_IMPL_API void ImGui_ImplDX12_NewFrame();
IMGUI_IMPL_API void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* graphics_command_list);
// Use if you want to reset your rendering device without losing Dear ImGui state.
IMGUI_IMPL_API void ImGui_ImplDX12_InvalidateDeviceObjects();
IMGUI_IMPL_API bool ImGui_ImplDX12_CreateDeviceObjects();
#ifdef _MSC_VER
#pragma warning (pop)
#endif

View file

@ -1,377 +0,0 @@
// dear imgui: Renderer Backend for DirectX9
// This needs to be used along with a Platform Backend (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
// 2021-06-25: DirectX9: Explicitly disable texture state stages after >= 1.
// 2021-05-19: DirectX9: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 2021-04-23: DirectX9: Explicitly setting up more graphics states to increase compatibility with unusual non-default states.
// 2021-03-18: DirectX9: Calling IDirect3DStateBlock9::Capture() after CreateStateBlock() as a workaround for state restoring issues (see #3857).
// 2021-03-03: DirectX9: Added support for IMGUI_USE_BGRA_PACKED_COLOR in user's imconfig file.
// 2021-02-18: DirectX9: Change blending equation to preserve alpha in output buffer.
// 2019-05-29: DirectX9: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
// 2019-04-30: DirectX9: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
// 2019-03-29: Misc: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects().
// 2019-01-16: Misc: Disabled fog before drawing UI's. Fixes issue #2288.
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
// 2018-06-08: Misc: Extracted imgui_impl_dx9.cpp/.h away from the old combined DX9+Win32 example.
// 2018-06-08: DirectX9: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
// 2018-05-07: Render: Saving/restoring Transform because they don't seem to be included in the StateBlock. Setting shading mode to Gouraud.
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself.
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
#include "imgui.h"
#include "imgui_impl_dx9.h"
// DirectX
#include <d3d9.h>
// DirectX data
struct ImGui_ImplDX9_Data
{
LPDIRECT3DDEVICE9 pd3dDevice;
LPDIRECT3DVERTEXBUFFER9 pVB;
LPDIRECT3DINDEXBUFFER9 pIB;
LPDIRECT3DTEXTURE9 FontTexture;
int VertexBufferSize;
int IndexBufferSize;
ImGui_ImplDX9_Data() { memset(this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
};
struct CUSTOMVERTEX
{
float pos[3];
D3DCOLOR col;
float uv[2];
};
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
#ifdef IMGUI_USE_BGRA_PACKED_COLOR
#define IMGUI_COL_TO_DX9_ARGB(_COL) (_COL)
#else
#define IMGUI_COL_TO_DX9_ARGB(_COL) (((_COL) & 0xFF00FF00) | (((_COL) & 0xFF0000) >> 16) | (((_COL) & 0xFF) << 16))
#endif
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
static ImGui_ImplDX9_Data* ImGui_ImplDX9_GetBackendData()
{
return ImGui::GetCurrentContext() ? (ImGui_ImplDX9_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
}
// Functions
static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data)
{
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
// Setup viewport
D3DVIEWPORT9 vp;
vp.X = vp.Y = 0;
vp.Width = (DWORD)draw_data->DisplaySize.x;
vp.Height = (DWORD)draw_data->DisplaySize.y;
vp.MinZ = 0.0f;
vp.MaxZ = 1.0f;
bd->pd3dDevice->SetViewport(&vp);
// Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient)
bd->pd3dDevice->SetPixelShader(NULL);
bd->pd3dDevice->SetVertexShader(NULL);
bd->pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
bd->pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
bd->pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
bd->pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
bd->pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
bd->pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
bd->pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
bd->pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
bd->pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
bd->pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
bd->pd3dDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
bd->pd3dDevice->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);
bd->pd3dDevice->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA);
bd->pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
bd->pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
bd->pd3dDevice->SetRenderState(D3DRS_RANGEFOGENABLE, FALSE);
bd->pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE);
bd->pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
bd->pd3dDevice->SetRenderState(D3DRS_CLIPPING, TRUE);
bd->pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
bd->pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
bd->pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
// Setup orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
// Being agnostic of whether <d3dx9.h> or <DirectXMath.h> can be used, we aren't relying on D3DXMatrixIdentity()/D3DXMatrixOrthoOffCenterLH() or DirectX::XMMatrixIdentity()/DirectX::XMMatrixOrthographicOffCenterLH()
{
float L = draw_data->DisplayPos.x + 0.5f;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x + 0.5f;
float T = draw_data->DisplayPos.y + 0.5f;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y + 0.5f;
D3DMATRIX mat_identity = { { { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } } };
D3DMATRIX mat_projection =
{ { {
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,
(L+R)/(L-R), (T+B)/(B-T), 0.5f, 1.0f
} } };
bd->pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity);
bd->pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity);
bd->pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_projection);
}
}
// Render function.
void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
{
// Avoid rendering when minimized
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
return;
// Create and grow buffers if needed
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount)
{
if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
bd->VertexBufferSize = draw_data->TotalVtxCount + 5000;
if (bd->pd3dDevice->CreateVertexBuffer(bd->VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->pVB, NULL) < 0)
return;
}
if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)
{
if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; }
bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
if (bd->pd3dDevice->CreateIndexBuffer(bd->IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->pIB, NULL) < 0)
return;
}
// Backup the DX9 state
IDirect3DStateBlock9* d3d9_state_block = NULL;
if (bd->pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0)
return;
if (d3d9_state_block->Capture() < 0)
{
d3d9_state_block->Release();
return;
}
// Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to)
D3DMATRIX last_world, last_view, last_projection;
bd->pd3dDevice->GetTransform(D3DTS_WORLD, &last_world);
bd->pd3dDevice->GetTransform(D3DTS_VIEW, &last_view);
bd->pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection);
// Allocate buffers
CUSTOMVERTEX* vtx_dst;
ImDrawIdx* idx_dst;
if (bd->pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (void**)&vtx_dst, D3DLOCK_DISCARD) < 0)
{
d3d9_state_block->Release();
return;
}
if (bd->pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void**)&idx_dst, D3DLOCK_DISCARD) < 0)
{
bd->pVB->Unlock();
d3d9_state_block->Release();
return;
}
// Copy and convert all vertices into a single contiguous buffer, convert colors to DX9 default format.
// FIXME-OPT: This is a minor waste of resource, the ideal is to use imconfig.h and
// 1) to avoid repacking colors: #define IMGUI_USE_BGRA_PACKED_COLOR
// 2) to avoid repacking vertices: #define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; }
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
const ImDrawVert* vtx_src = cmd_list->VtxBuffer.Data;
for (int i = 0; i < cmd_list->VtxBuffer.Size; i++)
{
vtx_dst->pos[0] = vtx_src->pos.x;
vtx_dst->pos[1] = vtx_src->pos.y;
vtx_dst->pos[2] = 0.0f;
vtx_dst->col = IMGUI_COL_TO_DX9_ARGB(vtx_src->col);
vtx_dst->uv[0] = vtx_src->uv.x;
vtx_dst->uv[1] = vtx_src->uv.y;
vtx_dst++;
vtx_src++;
}
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
idx_dst += cmd_list->IdxBuffer.Size;
}
bd->pVB->Unlock();
bd->pIB->Unlock();
bd->pd3dDevice->SetStreamSource(0, bd->pVB, 0, sizeof(CUSTOMVERTEX));
bd->pd3dDevice->SetIndices(bd->pIB);
bd->pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
// Setup desired DX state
ImGui_ImplDX9_SetupRenderState(draw_data);
// Render command lists
// (Because we merged all buffers into a single one, we maintain our own offset into them)
int global_vtx_offset = 0;
int global_idx_offset = 0;
ImVec2 clip_off = draw_data->DisplayPos;
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback != NULL)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplDX9_SetupRenderState(draw_data);
else
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
continue;
// Apply Scissor/clipping rectangle, Bind texture, Draw
const RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
const LPDIRECT3DTEXTURE9 texture = (LPDIRECT3DTEXTURE9)pcmd->GetTexID();
bd->pd3dDevice->SetTexture(0, texture);
bd->pd3dDevice->SetScissorRect(&r);
bd->pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, pcmd->VtxOffset + global_vtx_offset, 0, (UINT)cmd_list->VtxBuffer.Size, pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3);
}
}
global_idx_offset += cmd_list->IdxBuffer.Size;
global_vtx_offset += cmd_list->VtxBuffer.Size;
}
// Restore the DX9 transform
bd->pd3dDevice->SetTransform(D3DTS_WORLD, &last_world);
bd->pd3dDevice->SetTransform(D3DTS_VIEW, &last_view);
bd->pd3dDevice->SetTransform(D3DTS_PROJECTION, &last_projection);
// Restore the DX9 state
d3d9_state_block->Apply();
d3d9_state_block->Release();
}
bool ImGui_ImplDX9_Init(IDirect3DDevice9* device)
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
// Setup backend capabilities flags
ImGui_ImplDX9_Data* bd = IM_NEW(ImGui_ImplDX9_Data)();
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_dx9";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
bd->pd3dDevice = device;
bd->pd3dDevice->AddRef();
return true;
}
void ImGui_ImplDX9_Shutdown()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
ImGui_ImplDX9_InvalidateDeviceObjects();
if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
io.BackendRendererName = NULL;
io.BackendRendererUserData = NULL;
IM_DELETE(bd);
}
static bool ImGui_ImplDX9_CreateFontsTexture()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
unsigned char* pixels;
int width, height, bytes_per_pixel;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel);
// Convert RGBA32 to BGRA32 (because RGBA32 is not well supported by DX9 devices)
#ifndef IMGUI_USE_BGRA_PACKED_COLOR
if (io.Fonts->TexPixelsUseColors)
{
ImU32* dst_start = (ImU32*)ImGui::MemAlloc((size_t)width * height * bytes_per_pixel);
for (ImU32* src = (ImU32*)pixels, *dst = dst_start, *dst_end = dst_start + (size_t)width * height; dst < dst_end; src++, dst++)
*dst = IMGUI_COL_TO_DX9_ARGB(*src);
pixels = (unsigned char*)dst_start;
}
#endif
// Upload texture to graphics system
bd->FontTexture = NULL;
if (bd->pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bd->FontTexture, NULL) < 0)
return false;
D3DLOCKED_RECT tex_locked_rect;
if (bd->FontTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK)
return false;
for (int y = 0; y < height; y++)
memcpy((unsigned char*)tex_locked_rect.pBits + (size_t)tex_locked_rect.Pitch * y, pixels + (size_t)width * bytes_per_pixel * y, (size_t)width * bytes_per_pixel);
bd->FontTexture->UnlockRect(0);
// Store our identifier
io.Fonts->SetTexID((ImTextureID)bd->FontTexture);
#ifndef IMGUI_USE_BGRA_PACKED_COLOR
if (io.Fonts->TexPixelsUseColors)
ImGui::MemFree(pixels);
#endif
return true;
}
bool ImGui_ImplDX9_CreateDeviceObjects()
{
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
if (!bd || !bd->pd3dDevice)
return false;
if (!ImGui_ImplDX9_CreateFontsTexture())
return false;
return true;
}
void ImGui_ImplDX9_InvalidateDeviceObjects()
{
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
if (!bd || !bd->pd3dDevice)
return;
if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; }
if (bd->FontTexture) { bd->FontTexture->Release(); bd->FontTexture = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well.
}
void ImGui_ImplDX9_NewFrame()
{
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplDX9_Init()?");
if (!bd->FontTexture)
ImGui_ImplDX9_CreateDeviceObjects();
}

View file

@ -1,25 +0,0 @@
// dear imgui: Renderer Backend for DirectX9
// This needs to be used along with a Platform Backend (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
struct IDirect3DDevice9;
IMGUI_IMPL_API bool ImGui_ImplDX9_Init(IDirect3DDevice9* device);
IMGUI_IMPL_API void ImGui_ImplDX9_Shutdown();
IMGUI_IMPL_API void ImGui_ImplDX9_NewFrame();
IMGUI_IMPL_API void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data);
// Use if you want to reset your rendering device without losing Dear ImGui state.
IMGUI_IMPL_API bool ImGui_ImplDX9_CreateDeviceObjects();
IMGUI_IMPL_API void ImGui_ImplDX9_InvalidateDeviceObjects();

View file

@ -1,453 +0,0 @@
// dear imgui: Platform Backend for GLFW
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
// (Requires: GLFW 3.1+)
// Implemented features:
// [X] Platform: Clipboard support.
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-08-17: *BREAKING CHANGE*: Now using glfwSetWindowFocusCallback() to calling io.AddFocusEvent(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() and forward it to the backend via ImGui_ImplGlfw_WindowFocusCallback().
// 2021-07-29: *BREAKING CHANGE*: Now using glfwSetCursorEnterCallback(). MousePos is correctly reported when the host platform window is hovered but not focused. If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() callback and forward it to the backend via ImGui_ImplGlfw_CursorEnterCallback().
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
// 2020-01-17: Inputs: Disable error callback while assigning mouse cursors because some X11 setup don't have them and it generates errors.
// 2019-12-05: Inputs: Added support for new mouse cursors added in GLFW 3.4+ (resizing cursors, not allowed cursor).
// 2019-10-18: Misc: Previously installed user callbacks are now restored on shutdown.
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
// 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them.
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
// 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples.
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()).
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
// 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set.
// 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
#include "imgui.h"
#include "imgui_impl_glfw.h"
// GLFW
#include <GLFW/glfw3.h>
#ifdef _WIN32
#undef APIENTRY
#define GLFW_EXPOSE_NATIVE_WIN32
#include <GLFW/glfw3native.h> // for glfwGetWin32Window
#endif
#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING
#define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED
#define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity
#define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale
#define GLFW_HAS_VULKAN (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface
#ifdef GLFW_RESIZE_NESW_CURSOR // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released?
#define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR
#else
#define GLFW_HAS_NEW_CURSORS (0)
#endif
// GLFW data
enum GlfwClientApi
{
GlfwClientApi_Unknown,
GlfwClientApi_OpenGL,
GlfwClientApi_Vulkan
};
struct ImGui_ImplGlfw_Data
{
GLFWwindow* Window;
GlfwClientApi ClientApi;
double Time;
GLFWwindow* MouseWindow;
bool MouseJustPressed[ImGuiMouseButton_COUNT];
GLFWcursor* MouseCursors[ImGuiMouseCursor_COUNT];
bool InstalledCallbacks;
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
GLFWwindowfocusfun PrevUserCallbackWindowFocus;
GLFWcursorenterfun PrevUserCallbackCursorEnter;
GLFWmousebuttonfun PrevUserCallbackMousebutton;
GLFWscrollfun PrevUserCallbackScroll;
GLFWkeyfun PrevUserCallbackKey;
GLFWcharfun PrevUserCallbackChar;
GLFWmonitorfun PrevUserCallbackMonitor;
ImGui_ImplGlfw_Data() { memset(this, 0, sizeof(*this)); }
};
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
// - Because glfwPollEvents() process all windows and some events may be called outside of it, you will need to register your own callbacks
// (passing install_callbacks=false in ImGui_ImplGlfw_InitXXX functions), set the current dear imgui context and then call our callbacks.
// - Otherwise we may need to store a GLFWWindow* -> ImGuiContext* map and handle this in the backend, adding a little bit of extra complexity to it.
// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData()
{
return ImGui::GetCurrentContext() ? (ImGui_ImplGlfw_Data*)ImGui::GetIO().BackendPlatformUserData : NULL;
}
// Functions
static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
{
return glfwGetClipboardString((GLFWwindow*)user_data);
}
static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
{
glfwSetClipboardString((GLFWwindow*)user_data, text);
}
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackMousebutton != NULL && window == bd->Window)
bd->PrevUserCallbackMousebutton(window, button, action, mods);
if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(bd->MouseJustPressed))
bd->MouseJustPressed[button] = true;
}
void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackScroll != NULL && window == bd->Window)
bd->PrevUserCallbackScroll(window, xoffset, yoffset);
ImGuiIO& io = ImGui::GetIO();
io.MouseWheelH += (float)xoffset;
io.MouseWheel += (float)yoffset;
}
void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackKey != NULL && window == bd->Window)
bd->PrevUserCallbackKey(window, key, scancode, action, mods);
ImGuiIO& io = ImGui::GetIO();
if (key >= 0 && key < IM_ARRAYSIZE(io.KeysDown))
{
if (action == GLFW_PRESS)
io.KeysDown[key] = true;
if (action == GLFW_RELEASE)
io.KeysDown[key] = false;
}
// Modifiers are not reliable across systems
io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
#ifdef _WIN32
io.KeySuper = false;
#else
io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
#endif
}
void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackWindowFocus != NULL && window == bd->Window)
bd->PrevUserCallbackWindowFocus(window, focused);
ImGuiIO& io = ImGui::GetIO();
io.AddFocusEvent(focused != 0);
}
void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackCursorEnter != NULL && window == bd->Window)
bd->PrevUserCallbackCursorEnter(window, entered);
if (entered)
bd->MouseWindow = window;
if (!entered && bd->MouseWindow == window)
bd->MouseWindow = NULL;
}
void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackChar != NULL && window == bd->Window)
bd->PrevUserCallbackChar(window, c);
ImGuiIO& io = ImGui::GetIO();
io.AddInputCharacter(c);
}
void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int)
{
// Unused in 'master' branch but 'docking' branch will use this, so we declare it ahead of it so if you have to install callbacks you can install this one too.
}
static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!");
// Setup backend capabilities flags
ImGui_ImplGlfw_Data* bd = IM_NEW(ImGui_ImplGlfw_Data)();
io.BackendPlatformUserData = (void*)bd;
io.BackendPlatformName = "imgui_impl_glfw";
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
bd->Window = window;
bd->Time = 0.0;
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT;
io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE;
io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER;
io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
io.ClipboardUserData = bd->Window;
#if defined(_WIN32)
io.ImeWindowHandle = (void*)glfwGetWin32Window(bd->Window);
#endif
// Create mouse cursors
// (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,
// GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting.
// Missing cursors will return NULL and our _UpdateMouseCursor() function will use the Arrow cursor instead.)
GLFWerrorfun prev_error_callback = glfwSetErrorCallback(NULL);
bd->MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
bd->MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
bd->MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
#if GLFW_HAS_NEW_CURSORS
bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR);
bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR);
bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR);
bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR);
#else
bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
#endif
glfwSetErrorCallback(prev_error_callback);
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
bd->PrevUserCallbackWindowFocus = NULL;
bd->PrevUserCallbackMousebutton = NULL;
bd->PrevUserCallbackScroll = NULL;
bd->PrevUserCallbackKey = NULL;
bd->PrevUserCallbackChar = NULL;
bd->PrevUserCallbackMonitor = NULL;
if (install_callbacks)
{
bd->InstalledCallbacks = true;
bd->PrevUserCallbackWindowFocus = glfwSetWindowFocusCallback(window, ImGui_ImplGlfw_WindowFocusCallback);
bd->PrevUserCallbackCursorEnter = glfwSetCursorEnterCallback(window, ImGui_ImplGlfw_CursorEnterCallback);
bd->PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
bd->PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
bd->PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
bd->PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
bd->PrevUserCallbackMonitor = glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
}
bd->ClientApi = client_api;
return true;
}
bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks)
{
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL);
}
bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks)
{
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan);
}
bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks)
{
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Unknown);
}
void ImGui_ImplGlfw_Shutdown()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->InstalledCallbacks)
{
glfwSetWindowFocusCallback(bd->Window, bd->PrevUserCallbackWindowFocus);
glfwSetCursorEnterCallback(bd->Window, bd->PrevUserCallbackCursorEnter);
glfwSetMouseButtonCallback(bd->Window, bd->PrevUserCallbackMousebutton);
glfwSetScrollCallback(bd->Window, bd->PrevUserCallbackScroll);
glfwSetKeyCallback(bd->Window, bd->PrevUserCallbackKey);
glfwSetCharCallback(bd->Window, bd->PrevUserCallbackChar);
glfwSetMonitorCallback(bd->PrevUserCallbackMonitor);
}
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
glfwDestroyCursor(bd->MouseCursors[cursor_n]);
io.BackendPlatformName = NULL;
io.BackendPlatformUserData = NULL;
IM_DELETE(bd);
}
static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
ImGuiIO& io = ImGui::GetIO();
const ImVec2 mouse_pos_prev = io.MousePos;
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
// Update mouse buttons
// (if a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame)
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
{
io.MouseDown[i] = bd->MouseJustPressed[i] || glfwGetMouseButton(bd->Window, i) != 0;
bd->MouseJustPressed[i] = false;
}
#ifdef __EMSCRIPTEN__
const bool focused = true;
#else
const bool focused = glfwGetWindowAttrib(bd->Window, GLFW_FOCUSED) != 0;
#endif
GLFWwindow* mouse_window = (bd->MouseWindow == bd->Window || focused) ? bd->Window : NULL;
// Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
if (io.WantSetMousePos && focused)
glfwSetCursorPos(bd->Window, (double)mouse_pos_prev.x, (double)mouse_pos_prev.y);
// Set Dear ImGui mouse position from OS position
if (mouse_window != NULL)
{
double mouse_x, mouse_y;
glfwGetCursorPos(mouse_window, &mouse_x, &mouse_y);
io.MousePos = ImVec2((float)mouse_x, (float)mouse_y);
}
}
static void ImGui_ImplGlfw_UpdateMouseCursor()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(bd->Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
return;
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
{
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
glfwSetInputMode(bd->Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
}
else
{
// Show OS mouse cursor
// FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
glfwSetCursor(bd->Window, bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
glfwSetInputMode(bd->Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
}
}
static void ImGui_ImplGlfw_UpdateGamepads()
{
ImGuiIO& io = ImGui::GetIO();
memset(io.NavInputs, 0, sizeof(io.NavInputs));
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
return;
// Update gamepad inputs
#define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; }
#define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; }
int axes_count = 0, buttons_count = 0;
const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count);
const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count);
MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A
MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B
MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X
MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y
MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left
MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right
MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up
MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down
MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB
MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB
MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB
MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB
MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f);
MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f);
MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f);
MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f);
#undef MAP_BUTTON
#undef MAP_ANALOG
if (axes_count > 0 && buttons_count > 0)
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
else
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
}
void ImGui_ImplGlfw_NewFrame()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplGlfw_InitForXXX()?");
// Setup display size (every frame to accommodate for window resizing)
int w, h;
int display_w, display_h;
glfwGetWindowSize(bd->Window, &w, &h);
glfwGetFramebufferSize(bd->Window, &display_w, &display_h);
io.DisplaySize = ImVec2((float)w, (float)h);
if (w > 0 && h > 0)
io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
// Setup time step
double current_time = glfwGetTime();
io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
bd->Time = current_time;
ImGui_ImplGlfw_UpdateMousePosAndButtons();
ImGui_ImplGlfw_UpdateMouseCursor();
// Update game controllers (if enabled and available)
ImGui_ImplGlfw_UpdateGamepads();
}

View file

@ -1,41 +0,0 @@
// dear imgui: Platform Backend for GLFW
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
// Implemented features:
// [X] Platform: Clipboard support.
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW.
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// About GLSL version:
// The 'glsl_version' initialization parameter defaults to "#version 150" if NULL.
// Only override if your GL version doesn't handle this GLSL version. Keep NULL if unsure!
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
struct GLFWwindow;
struct GLFWmonitor;
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks);
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks);
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks);
IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
// GLFW callbacks
// - When calling Init with 'install_callbacks=true': GLFW callbacks will be installed for you. They will call user's previously installed callbacks, if any.
// - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call those function yourself from your own GLFW callbacks.
IMGUI_IMPL_API void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused);
IMGUI_IMPL_API void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered);
IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c);
IMGUI_IMPL_API void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor* monitor, int event);

View file

@ -1,217 +0,0 @@
// dear imgui: Platform Backend for GLUT/FreeGLUT
// This needs to be used along with a Renderer (e.g. OpenGL2)
// !!! GLUT/FreeGLUT IS OBSOLETE PREHISTORIC SOFTWARE. Using GLUT is not recommended unless you really miss the 90's. !!!
// !!! If someone or something is teaching you GLUT today, you are being abused. Please show some resistance. !!!
// !!! Nowadays, prefer using GLFW or SDL instead!
// Issues:
// [ ] Platform: GLUT is unable to distinguish e.g. Backspace from CTRL+H or TAB from CTRL+I
// [ ] Platform: Missing mouse cursor shape/visibility support.
// [ ] Platform: Missing clipboard support (not supported by Glut).
// [ ] Platform: Missing gamepad support.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2019-04-03: Misc: Renamed imgui_impl_freeglut.cpp/.h to imgui_impl_glut.cpp/.h.
// 2019-03-25: Misc: Made io.DeltaTime always above zero.
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
// 2018-03-22: Added GLUT Platform binding.
#include "imgui.h"
#include "imgui_impl_glut.h"
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/freeglut.h>
#endif
#ifdef _MSC_VER
#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
#endif
static int g_Time = 0; // Current time, in milliseconds
bool ImGui_ImplGLUT_Init()
{
ImGuiIO& io = ImGui::GetIO();
#ifdef FREEGLUT
io.BackendPlatformName = "imgui_impl_glut (freeglut)";
#else
io.BackendPlatformName = "imgui_impl_glut";
#endif
g_Time = 0;
// Glut has 1 function for characters and one for "special keys". We map the characters in the 0..255 range and the keys above.
io.KeyMap[ImGuiKey_Tab] = '\t'; // == 9 == CTRL+I
io.KeyMap[ImGuiKey_LeftArrow] = 256 + GLUT_KEY_LEFT;
io.KeyMap[ImGuiKey_RightArrow] = 256 + GLUT_KEY_RIGHT;
io.KeyMap[ImGuiKey_UpArrow] = 256 + GLUT_KEY_UP;
io.KeyMap[ImGuiKey_DownArrow] = 256 + GLUT_KEY_DOWN;
io.KeyMap[ImGuiKey_PageUp] = 256 + GLUT_KEY_PAGE_UP;
io.KeyMap[ImGuiKey_PageDown] = 256 + GLUT_KEY_PAGE_DOWN;
io.KeyMap[ImGuiKey_Home] = 256 + GLUT_KEY_HOME;
io.KeyMap[ImGuiKey_End] = 256 + GLUT_KEY_END;
io.KeyMap[ImGuiKey_Insert] = 256 + GLUT_KEY_INSERT;
io.KeyMap[ImGuiKey_Delete] = 127;
io.KeyMap[ImGuiKey_Backspace] = 8; // == CTRL+H
io.KeyMap[ImGuiKey_Space] = ' ';
io.KeyMap[ImGuiKey_Enter] = 13; // == CTRL+M
io.KeyMap[ImGuiKey_Escape] = 27;
io.KeyMap[ImGuiKey_KeyPadEnter] = 13; // == CTRL+M
io.KeyMap[ImGuiKey_A] = 'A';
io.KeyMap[ImGuiKey_C] = 'C';
io.KeyMap[ImGuiKey_V] = 'V';
io.KeyMap[ImGuiKey_X] = 'X';
io.KeyMap[ImGuiKey_Y] = 'Y';
io.KeyMap[ImGuiKey_Z] = 'Z';
return true;
}
void ImGui_ImplGLUT_InstallFuncs()
{
glutReshapeFunc(ImGui_ImplGLUT_ReshapeFunc);
glutMotionFunc(ImGui_ImplGLUT_MotionFunc);
glutPassiveMotionFunc(ImGui_ImplGLUT_MotionFunc);
glutMouseFunc(ImGui_ImplGLUT_MouseFunc);
#ifdef __FREEGLUT_EXT_H__
glutMouseWheelFunc(ImGui_ImplGLUT_MouseWheelFunc);
#endif
glutKeyboardFunc(ImGui_ImplGLUT_KeyboardFunc);
glutKeyboardUpFunc(ImGui_ImplGLUT_KeyboardUpFunc);
glutSpecialFunc(ImGui_ImplGLUT_SpecialFunc);
glutSpecialUpFunc(ImGui_ImplGLUT_SpecialUpFunc);
}
void ImGui_ImplGLUT_Shutdown()
{
}
void ImGui_ImplGLUT_NewFrame()
{
// Setup time step
ImGuiIO& io = ImGui::GetIO();
int current_time = glutGet(GLUT_ELAPSED_TIME);
int delta_time_ms = (current_time - g_Time);
if (delta_time_ms <= 0)
delta_time_ms = 1;
io.DeltaTime = delta_time_ms / 1000.0f;
g_Time = current_time;
// Start the frame
ImGui::NewFrame();
}
static void ImGui_ImplGLUT_UpdateKeyboardMods()
{
ImGuiIO& io = ImGui::GetIO();
int mods = glutGetModifiers();
io.KeyCtrl = (mods & GLUT_ACTIVE_CTRL) != 0;
io.KeyShift = (mods & GLUT_ACTIVE_SHIFT) != 0;
io.KeyAlt = (mods & GLUT_ACTIVE_ALT) != 0;
}
void ImGui_ImplGLUT_KeyboardFunc(unsigned char c, int x, int y)
{
// Send character to imgui
//printf("char_down_func %d '%c'\n", c, c);
ImGuiIO& io = ImGui::GetIO();
if (c >= 32)
io.AddInputCharacter((unsigned int)c);
// Store letters in KeysDown[] array as both uppercase and lowercase + Handle GLUT translating CTRL+A..CTRL+Z as 1..26.
// This is a hacky mess but GLUT is unable to distinguish e.g. a TAB key from CTRL+I so this is probably the best we can do here.
if (c >= 1 && c <= 26)
io.KeysDown[c] = io.KeysDown[c - 1 + 'a'] = io.KeysDown[c - 1 + 'A'] = true;
else if (c >= 'a' && c <= 'z')
io.KeysDown[c] = io.KeysDown[c - 'a' + 'A'] = true;
else if (c >= 'A' && c <= 'Z')
io.KeysDown[c] = io.KeysDown[c - 'A' + 'a'] = true;
else
io.KeysDown[c] = true;
ImGui_ImplGLUT_UpdateKeyboardMods();
(void)x; (void)y; // Unused
}
void ImGui_ImplGLUT_KeyboardUpFunc(unsigned char c, int x, int y)
{
//printf("char_up_func %d '%c'\n", c, c);
ImGuiIO& io = ImGui::GetIO();
if (c >= 1 && c <= 26)
io.KeysDown[c] = io.KeysDown[c - 1 + 'a'] = io.KeysDown[c - 1 + 'A'] = false;
else if (c >= 'a' && c <= 'z')
io.KeysDown[c] = io.KeysDown[c - 'a' + 'A'] = false;
else if (c >= 'A' && c <= 'Z')
io.KeysDown[c] = io.KeysDown[c - 'A' + 'a'] = false;
else
io.KeysDown[c] = false;
ImGui_ImplGLUT_UpdateKeyboardMods();
(void)x; (void)y; // Unused
}
void ImGui_ImplGLUT_SpecialFunc(int key, int x, int y)
{
//printf("key_down_func %d\n", key);
ImGuiIO& io = ImGui::GetIO();
if (key + 256 < IM_ARRAYSIZE(io.KeysDown))
io.KeysDown[key + 256] = true;
ImGui_ImplGLUT_UpdateKeyboardMods();
(void)x; (void)y; // Unused
}
void ImGui_ImplGLUT_SpecialUpFunc(int key, int x, int y)
{
//printf("key_up_func %d\n", key);
ImGuiIO& io = ImGui::GetIO();
if (key + 256 < IM_ARRAYSIZE(io.KeysDown))
io.KeysDown[key + 256] = false;
ImGui_ImplGLUT_UpdateKeyboardMods();
(void)x; (void)y; // Unused
}
void ImGui_ImplGLUT_MouseFunc(int glut_button, int state, int x, int y)
{
ImGuiIO& io = ImGui::GetIO();
io.MousePos = ImVec2((float)x, (float)y);
int button = -1;
if (glut_button == GLUT_LEFT_BUTTON) button = 0;
if (glut_button == GLUT_RIGHT_BUTTON) button = 1;
if (glut_button == GLUT_MIDDLE_BUTTON) button = 2;
if (button != -1 && state == GLUT_DOWN)
io.MouseDown[button] = true;
if (button != -1 && state == GLUT_UP)
io.MouseDown[button] = false;
}
#ifdef __FREEGLUT_EXT_H__
void ImGui_ImplGLUT_MouseWheelFunc(int button, int dir, int x, int y)
{
ImGuiIO& io = ImGui::GetIO();
io.MousePos = ImVec2((float)x, (float)y);
if (dir > 0)
io.MouseWheel += 1.0;
else if (dir < 0)
io.MouseWheel -= 1.0;
(void)button; // Unused
}
#endif
void ImGui_ImplGLUT_ReshapeFunc(int w, int h)
{
ImGuiIO& io = ImGui::GetIO();
io.DisplaySize = ImVec2((float)w, (float)h);
}
void ImGui_ImplGLUT_MotionFunc(int x, int y)
{
ImGuiIO& io = ImGui::GetIO();
io.MousePos = ImVec2((float)x, (float)y);
}

View file

@ -1,37 +0,0 @@
// dear imgui: Platform Backend for GLUT/FreeGLUT
// This needs to be used along with a Renderer (e.g. OpenGL2)
// !!! GLUT/FreeGLUT IS OBSOLETE PREHISTORIC SOFTWARE. Using GLUT is not recommended unless you really miss the 90's. !!!
// !!! If someone or something is teaching you GLUT today, you are being abused. Please show some resistance. !!!
// !!! Nowadays, prefer using GLFW or SDL instead!
// Issues:
// [ ] Platform: GLUT is unable to distinguish e.g. Backspace from CTRL+H or TAB from CTRL+I
// [ ] Platform: Missing mouse cursor shape/visibility support.
// [ ] Platform: Missing clipboard support (not supported by Glut).
// [ ] Platform: Missing gamepad support.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
IMGUI_IMPL_API bool ImGui_ImplGLUT_Init();
IMGUI_IMPL_API void ImGui_ImplGLUT_InstallFuncs();
IMGUI_IMPL_API void ImGui_ImplGLUT_Shutdown();
IMGUI_IMPL_API void ImGui_ImplGLUT_NewFrame();
// You can call ImGui_ImplGLUT_InstallFuncs() to get all those functions installed automatically,
// or call them yourself from your own GLUT handlers. We are using the same weird names as GLUT for consistency..
//---------------------------------------- GLUT name --------------------------------------------- Decent Name ---------
IMGUI_IMPL_API void ImGui_ImplGLUT_ReshapeFunc(int w, int h); // ~ ResizeFunc
IMGUI_IMPL_API void ImGui_ImplGLUT_MotionFunc(int x, int y); // ~ MouseMoveFunc
IMGUI_IMPL_API void ImGui_ImplGLUT_MouseFunc(int button, int state, int x, int y); // ~ MouseButtonFunc
IMGUI_IMPL_API void ImGui_ImplGLUT_MouseWheelFunc(int button, int dir, int x, int y); // ~ MouseWheelFunc
IMGUI_IMPL_API void ImGui_ImplGLUT_KeyboardFunc(unsigned char c, int x, int y); // ~ CharPressedFunc
IMGUI_IMPL_API void ImGui_ImplGLUT_KeyboardUpFunc(unsigned char c, int x, int y); // ~ CharReleasedFunc
IMGUI_IMPL_API void ImGui_ImplGLUT_SpecialFunc(int key, int x, int y); // ~ KeyPressedFunc
IMGUI_IMPL_API void ImGui_ImplGLUT_SpecialUpFunc(int key, int x, int y); // ~ KeyReleasedFunc

View file

@ -1,318 +0,0 @@
// dear imgui: Renderer + Platform Backend for Marmalade + IwGx
// Marmalade code: Copyright (C) 2015 by Giovanni Zito (this file is part of Dear ImGui)
// Implemented features:
// [X] Renderer: User texture binding. Use 'CIwTexture*' as ImTextureID. Read the FAQ about ImTextureID!
// Missing features:
// [ ] Renderer: Clipping rectangles are not honored.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-05-19: Renderer: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
// 2018-11-30: Misc: Setting up io.BackendPlatformName/io.BackendRendererName so they can be displayed in the About Window.
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_Marmalade_RenderDrawData() in the .h file so you can call it yourself.
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
#include "imgui.h"
#include "imgui_impl_marmalade.h"
#include <s3eClipboard.h>
#include <s3ePointer.h>
#include <s3eKeyboard.h>
#include <IwTexture.h>
#include <IwGx.h>
// Data
static double g_Time = 0.0f;
static bool g_MousePressed[3] = { false, false, false };
static CIwTexture* g_FontTexture = NULL;
static char* g_ClipboardText = NULL;
static bool g_osdKeyboardEnabled = false;
// use this setting to scale the interface - e.g. on device you could use 2 or 3 scale factor
static ImVec2 g_RenderScale = ImVec2(1.0f, 1.0f);
// Render function.
void ImGui_Marmalade_RenderDrawData(ImDrawData* draw_data)
{
// Avoid rendering when minimized
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
return;
// Render command lists
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;
const int nVert = cmd_list->VtxBuffer.Size;
CIwFVec2* pVertStream = IW_GX_ALLOC(CIwFVec2, nVert);
CIwFVec2* pUVStream = IW_GX_ALLOC(CIwFVec2, nVert);
CIwColour* pColStream = IW_GX_ALLOC(CIwColour, nVert);
for (int i = 0; i < nVert; i++)
{
// FIXME-OPT: optimize multiplication on GPU using vertex shader/projection matrix.
pVertStream[i].x = cmd_list->VtxBuffer[i].pos.x * g_RenderScale.x;
pVertStream[i].y = cmd_list->VtxBuffer[i].pos.y * g_RenderScale.y;
pUVStream[i].x = cmd_list->VtxBuffer[i].uv.x;
pUVStream[i].y = cmd_list->VtxBuffer[i].uv.y;
pColStream[i] = cmd_list->VtxBuffer[i].col;
}
IwGxSetVertStreamScreenSpace(pVertStream, nVert);
IwGxSetUVStream(pUVStream);
IwGxSetColStream(pColStream, nVert);
IwGxSetNormStream(0);
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback)
{
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
// FIXME: Not honoring ClipRect fields.
CIwMaterial* pCurrentMaterial = IW_GX_ALLOC_MATERIAL();
pCurrentMaterial->SetShadeMode(CIwMaterial::SHADE_FLAT);
pCurrentMaterial->SetCullMode(CIwMaterial::CULL_NONE);
pCurrentMaterial->SetFiltering(false);
pCurrentMaterial->SetAlphaMode(CIwMaterial::ALPHA_BLEND);
pCurrentMaterial->SetDepthWriteMode(CIwMaterial::DEPTH_WRITE_NORMAL);
pCurrentMaterial->SetAlphaTestMode(CIwMaterial::ALPHATEST_DISABLED);
pCurrentMaterial->SetTexture((CIwTexture*)pcmd->GetTexID());
IwGxSetMaterial(pCurrentMaterial);
IwGxDrawPrims(IW_GX_TRI_LIST, (uint16*)idx_buffer, pcmd->ElemCount);
}
idx_buffer += pcmd->ElemCount;
}
IwGxFlush();
}
// TODO: restore modified state (i.e. mvp matrix)
}
static const char* ImGui_Marmalade_GetClipboardText(void* /*user_data*/)
{
if (!s3eClipboardAvailable())
return NULL;
if (int size = s3eClipboardGetText(NULL, 0))
{
if (g_ClipboardText)
delete[] g_ClipboardText;
g_ClipboardText = new char[size];
g_ClipboardText[0] = '\0';
s3eClipboardGetText(g_ClipboardText, size);
}
return g_ClipboardText;
}
static void ImGui_Marmalade_SetClipboardText(void* /*user_data*/, const char* text)
{
if (s3eClipboardAvailable())
s3eClipboardSetText(text);
}
int32 ImGui_Marmalade_PointerButtonEventCallback(void* system_data, void* user_data)
{
// pEvent->m_Button is of type s3ePointerButton and indicates which mouse
// button was pressed. For touchscreen this should always have the value
// S3E_POINTER_BUTTON_SELECT
s3ePointerEvent* pEvent = (s3ePointerEvent*)system_data;
if (pEvent->m_Pressed == 1)
{
if (pEvent->m_Button == S3E_POINTER_BUTTON_LEFTMOUSE)
g_MousePressed[0] = true;
if (pEvent->m_Button == S3E_POINTER_BUTTON_RIGHTMOUSE)
g_MousePressed[1] = true;
if (pEvent->m_Button == S3E_POINTER_BUTTON_MIDDLEMOUSE)
g_MousePressed[2] = true;
if (pEvent->m_Button == S3E_POINTER_BUTTON_MOUSEWHEELUP)
io.MouseWheel += pEvent->m_y;
if (pEvent->m_Button == S3E_POINTER_BUTTON_MOUSEWHEELDOWN)
io.MouseWheel += pEvent->m_y;
}
return 0;
}
int32 ImGui_Marmalade_KeyCallback(void* system_data, void* user_data)
{
ImGuiIO& io = ImGui::GetIO();
s3eKeyboardEvent* e = (s3eKeyboardEvent*)system_data;
if (e->m_Pressed == 1)
io.KeysDown[e->m_Key] = true;
if (e->m_Pressed == 0)
io.KeysDown[e->m_Key] = false;
io.KeyCtrl = s3eKeyboardGetState(s3eKeyLeftControl) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightControl) == S3E_KEY_STATE_DOWN;
io.KeyShift = s3eKeyboardGetState(s3eKeyLeftShift) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightShift) == S3E_KEY_STATE_DOWN;
io.KeyAlt = s3eKeyboardGetState(s3eKeyLeftAlt) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightAlt) == S3E_KEY_STATE_DOWN;
io.KeySuper = s3eKeyboardGetState(s3eKeyLeftWindows) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightWindows) == S3E_KEY_STATE_DOWN;
return 0;
}
int32 ImGui_Marmalade_CharCallback(void* system_data, void* user_data)
{
ImGuiIO& io = ImGui::GetIO();
s3eKeyboardCharEvent* e = (s3eKeyboardCharEvent*)system_data;
io.AddInputCharacter((unsigned int)e->m_Char);
return 0;
}
bool ImGui_Marmalade_CreateDeviceObjects()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
// Upload texture to graphics system
g_FontTexture = new CIwTexture();
g_FontTexture->SetModifiable(true);
CIwImage& image = g_FontTexture->GetImage();
image.SetFormat(CIwImage::ARGB_8888);
image.SetWidth(width);
image.SetHeight(height);
image.SetBuffers(); // allocates and own buffers
image.ReadTexels(pixels);
g_FontTexture->SetMipMapping(false);
g_FontTexture->SetFiltering(false);
g_FontTexture->Upload();
// Store our identifier
io.Fonts->SetTexID((ImTextureID)g_FontTexture);
return true;
}
void ImGui_Marmalade_InvalidateDeviceObjects()
{
if (g_ClipboardText)
{
delete[] g_ClipboardText;
g_ClipboardText = NULL;
}
if (g_FontTexture)
{
ImGui::GetIO().Fonts->SetTexID(0);
delete g_FontTexture;
g_FontTexture = NULL;
}
}
bool ImGui_Marmalade_Init(bool install_callbacks)
{
ImGuiIO& io = ImGui::GetIO();
io.BackendPlatformName = io.BackendRendererName = "imgui_impl_marmalade";
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
io.KeyMap[ImGuiKey_Tab] = s3eKeyTab
io.KeyMap[ImGuiKey_LeftArrow] = s3eKeyLeft;
io.KeyMap[ImGuiKey_RightArrow] = s3eKeyRight;
io.KeyMap[ImGuiKey_UpArrow] = s3eKeyUp;
io.KeyMap[ImGuiKey_DownArrow] = s3eKeyDown;
io.KeyMap[ImGuiKey_PageUp] = s3eKeyPageUp;
io.KeyMap[ImGuiKey_PageDown] = s3eKeyPageDown;
io.KeyMap[ImGuiKey_Home] = s3eKeyHome;
io.KeyMap[ImGuiKey_End] = s3eKeyEnd;
io.KeyMap[ImGuiKey_Insert] = s3eKeyInsert;
io.KeyMap[ImGuiKey_Delete] = s3eKeyDelete;
io.KeyMap[ImGuiKey_Backspace] = s3eKeyBackspace;
io.KeyMap[ImGuiKey_Space] = s3eKeySpace;
io.KeyMap[ImGuiKey_Enter] = s3eKeyEnter;
io.KeyMap[ImGuiKey_Escape] = s3eKeyEsc;
io.KeyMap[ImGuiKey_KeyPadEnter] = s3eKeyNumPadEnter;
io.KeyMap[ImGuiKey_A] = s3eKeyA;
io.KeyMap[ImGuiKey_C] = s3eKeyC;
io.KeyMap[ImGuiKey_V] = s3eKeyV;
io.KeyMap[ImGuiKey_X] = s3eKeyX;
io.KeyMap[ImGuiKey_Y] = s3eKeyY;
io.KeyMap[ImGuiKey_Z] = s3eKeyZ;
io.SetClipboardTextFn = ImGui_Marmalade_SetClipboardText;
io.GetClipboardTextFn = ImGui_Marmalade_GetClipboardText;
if (install_callbacks)
{
s3ePointerRegister(S3E_POINTER_BUTTON_EVENT, ImGui_Marmalade_PointerButtonEventCallback, 0);
s3eKeyboardRegister(S3E_KEYBOARD_KEY_EVENT, ImGui_Marmalade_KeyCallback, 0);
s3eKeyboardRegister(S3E_KEYBOARD_CHAR_EVENT, ImGui_Marmalade_CharCallback, 0);
}
return true;
}
void ImGui_Marmalade_Shutdown()
{
ImGui_Marmalade_InvalidateDeviceObjects();
}
void ImGui_Marmalade_NewFrame()
{
if (!g_FontTexture)
ImGui_Marmalade_CreateDeviceObjects();
ImGuiIO& io = ImGui::GetIO();
// Setup display size (every frame to accommodate for window resizing)
int w = IwGxGetScreenWidth(), h = IwGxGetScreenHeight();
io.DisplaySize = ImVec2((float)w, (float)h);
// For retina display or other situations where window coordinates are different from framebuffer coordinates. User storage only, presently not used by ImGui.
io.DisplayFramebufferScale = g_scale;
// Setup time step
double current_time = s3eTimerGetUST() / 1000.0f;
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f);
g_Time = current_time;
double mouse_x, mouse_y;
mouse_x = s3ePointerGetX();
mouse_y = s3ePointerGetY();
io.MousePos = ImVec2((float)mouse_x / g_scale.x, (float)mouse_y / g_scale.y); // Mouse position (set to -FLT_MAX,-FLT_MAX if no mouse / on another screen, etc.)
for (int i = 0; i < 3; i++)
{
io.MouseDown[i] = g_MousePressed[i] || s3ePointerGetState((s3ePointerButton)i) != S3E_POINTER_STATE_UP; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
g_MousePressed[i] = false;
}
// TODO: Hide OS mouse cursor if ImGui is drawing it
// s3ePointerSetInt(S3E_POINTER_HIDE_CURSOR,(io.MouseDrawCursor ? 0 : 1));
// Show/hide OSD keyboard
if (io.WantTextInput)
{
// Some text input widget is active?
if (!g_osdKeyboardEnabled)
{
g_osdKeyboardEnabled = true;
s3eKeyboardSetInt(S3E_KEYBOARD_GET_CHAR, 1); // show OSD keyboard
}
}
else
{
// No text input widget is active
if (g_osdKeyboardEnabled)
{
g_osdKeyboardEnabled = false;
s3eKeyboardSetInt(S3E_KEYBOARD_GET_CHAR, 0); // hide OSD keyboard
}
}
}

View file

@ -1,28 +0,0 @@
// dear imgui: Renderer + Platform Backend for Marmalade + IwGx
// Marmalade code: Copyright (C) 2015 by Giovanni Zito (this file is part of Dear ImGui)
// Implemented features:
// [X] Renderer: User texture binding. Use 'CIwTexture*' as ImTextureID. Read the FAQ about ImTextureID!
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
IMGUI_IMPL_API bool ImGui_Marmalade_Init(bool install_callbacks);
IMGUI_IMPL_API void ImGui_Marmalade_Shutdown();
IMGUI_IMPL_API void ImGui_Marmalade_NewFrame();
IMGUI_IMPL_API void ImGui_Marmalade_RenderDrawData(ImDrawData* draw_data);
// Use if you want to reset your rendering device without losing Dear ImGui state.
IMGUI_IMPL_API void ImGui_Marmalade_InvalidateDeviceObjects();
IMGUI_IMPL_API bool ImGui_Marmalade_CreateDeviceObjects();
// Callbacks (installed by default if you enable 'install_callbacks' during initialization)
// You can also handle inputs yourself and use those as a reference.
IMGUI_IMPL_API int32 ImGui_Marmalade_PointerButtonEventCallback(void* system_data, void* user_data);
IMGUI_IMPL_API int32 ImGui_Marmalade_KeyCallback(void* system_data, void* user_data);
IMGUI_IMPL_API int32 ImGui_Marmalade_CharCallback(void* system_data, void* user_data);

View file

@ -1,29 +0,0 @@
// dear imgui: Renderer Backend for Metal
// This needs to be used along with a Platform Backend (e.g. OSX)
// Implemented features:
// [X] Renderer: User texture binding. Use 'MTLTexture' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#include "imgui.h" // IMGUI_IMPL_API
@class MTLRenderPassDescriptor;
@protocol MTLDevice, MTLCommandBuffer, MTLRenderCommandEncoder;
IMGUI_IMPL_API bool ImGui_ImplMetal_Init(id<MTLDevice> device);
IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown();
IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor);
IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,
id<MTLCommandBuffer> commandBuffer,
id<MTLRenderCommandEncoder> commandEncoder);
// Called by Init/NewFrame/Shutdown
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateFontsTexture(id<MTLDevice> device);
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyFontsTexture();
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> device);
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects();

View file

@ -1,556 +0,0 @@
// dear imgui: Renderer Backend for Metal
// This needs to be used along with a Platform Backend (e.g. OSX)
// Implemented features:
// [X] Renderer: User texture binding. Use 'MTLTexture' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-08-24: Metal: Fixed a crash when clipping rect larger than framebuffer is submitted. (#4464)
// 2021-05-19: Metal: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 2021-02-18: Metal: Change blending equation to preserve alpha in output buffer.
// 2021-01-25: Metal: Fixed texture storage mode when building on Mac Catalyst.
// 2019-05-29: Metal: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
// 2019-04-30: Metal: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
// 2019-02-11: Metal: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
// 2018-07-05: Metal: Added new Metal backend implementation.
#include "imgui.h"
#include "imgui_impl_metal.h"
#import <Metal/Metal.h>
// #import <QuartzCore/CAMetalLayer.h> // Not supported in XCode 9.2. Maybe a macro to detect the SDK version can be used (something like #if MACOS_SDK >= 10.13 ...)
#import <simd/simd.h>
#pragma mark - Support classes
// A wrapper around a MTLBuffer object that knows the last time it was reused
@interface MetalBuffer : NSObject
@property (nonatomic, strong) id<MTLBuffer> buffer;
@property (nonatomic, assign) NSTimeInterval lastReuseTime;
- (instancetype)initWithBuffer:(id<MTLBuffer>)buffer;
@end
// An object that encapsulates the data necessary to uniquely identify a
// render pipeline state. These are used as cache keys.
@interface FramebufferDescriptor : NSObject<NSCopying>
@property (nonatomic, assign) unsigned long sampleCount;
@property (nonatomic, assign) MTLPixelFormat colorPixelFormat;
@property (nonatomic, assign) MTLPixelFormat depthPixelFormat;
@property (nonatomic, assign) MTLPixelFormat stencilPixelFormat;
- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor *)renderPassDescriptor;
@end
// A singleton that stores long-lived objects that are needed by the Metal
// renderer backend. Stores the render pipeline state cache and the default
// font texture, and manages the reusable buffer cache.
@interface MetalContext : NSObject
@property (nonatomic, strong) id<MTLDepthStencilState> depthStencilState;
@property (nonatomic, strong) FramebufferDescriptor *framebufferDescriptor; // framebuffer descriptor for current frame; transient
@property (nonatomic, strong) NSMutableDictionary *renderPipelineStateCache; // pipeline cache; keyed on framebuffer descriptors
@property (nonatomic, strong, nullable) id<MTLTexture> fontTexture;
@property (nonatomic, strong) NSMutableArray<MetalBuffer *> *bufferCache;
@property (nonatomic, assign) NSTimeInterval lastBufferCachePurge;
- (void)makeDeviceObjectsWithDevice:(id<MTLDevice>)device;
- (void)makeFontTextureWithDevice:(id<MTLDevice>)device;
- (MetalBuffer *)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device;
- (void)enqueueReusableBuffer:(MetalBuffer *)buffer;
- (id<MTLRenderPipelineState>)renderPipelineStateForFrameAndDevice:(id<MTLDevice>)device;
- (void)emptyRenderPipelineStateCache;
- (void)setupRenderState:(ImDrawData *)drawData
commandBuffer:(id<MTLCommandBuffer>)commandBuffer
commandEncoder:(id<MTLRenderCommandEncoder>)commandEncoder
renderPipelineState:(id<MTLRenderPipelineState>)renderPipelineState
vertexBuffer:(MetalBuffer *)vertexBuffer
vertexBufferOffset:(size_t)vertexBufferOffset;
- (void)renderDrawData:(ImDrawData *)drawData
commandBuffer:(id<MTLCommandBuffer>)commandBuffer
commandEncoder:(id<MTLRenderCommandEncoder>)commandEncoder;
@end
static MetalContext *g_sharedMetalContext = nil;
#pragma mark - ImGui API implementation
bool ImGui_ImplMetal_Init(id<MTLDevice> device)
{
ImGuiIO& io = ImGui::GetIO();
io.BackendRendererName = "imgui_impl_metal";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
g_sharedMetalContext = [[MetalContext alloc] init];
});
ImGui_ImplMetal_CreateDeviceObjects(device);
return true;
}
void ImGui_ImplMetal_Shutdown()
{
ImGui_ImplMetal_DestroyDeviceObjects();
}
void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor *renderPassDescriptor)
{
IM_ASSERT(g_sharedMetalContext != nil && "No Metal context. Did you call ImGui_ImplMetal_Init() ?");
g_sharedMetalContext.framebufferDescriptor = [[FramebufferDescriptor alloc] initWithRenderPassDescriptor:renderPassDescriptor];
}
// Metal Render function.
void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id<MTLCommandBuffer> commandBuffer, id<MTLRenderCommandEncoder> commandEncoder)
{
[g_sharedMetalContext renderDrawData:draw_data commandBuffer:commandBuffer commandEncoder:commandEncoder];
}
bool ImGui_ImplMetal_CreateFontsTexture(id<MTLDevice> device)
{
[g_sharedMetalContext makeFontTextureWithDevice:device];
ImGuiIO& io = ImGui::GetIO();
io.Fonts->SetTexID((__bridge void *)g_sharedMetalContext.fontTexture); // ImTextureID == void*
return (g_sharedMetalContext.fontTexture != nil);
}
void ImGui_ImplMetal_DestroyFontsTexture()
{
ImGuiIO& io = ImGui::GetIO();
g_sharedMetalContext.fontTexture = nil;
io.Fonts->SetTexID(nullptr);
}
bool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> device)
{
[g_sharedMetalContext makeDeviceObjectsWithDevice:device];
ImGui_ImplMetal_CreateFontsTexture(device);
return true;
}
void ImGui_ImplMetal_DestroyDeviceObjects()
{
ImGui_ImplMetal_DestroyFontsTexture();
[g_sharedMetalContext emptyRenderPipelineStateCache];
}
#pragma mark - MetalBuffer implementation
@implementation MetalBuffer
- (instancetype)initWithBuffer:(id<MTLBuffer>)buffer
{
if ((self = [super init]))
{
_buffer = buffer;
_lastReuseTime = [NSDate date].timeIntervalSince1970;
}
return self;
}
@end
#pragma mark - FramebufferDescriptor implementation
@implementation FramebufferDescriptor
- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor *)renderPassDescriptor
{
if ((self = [super init]))
{
_sampleCount = renderPassDescriptor.colorAttachments[0].texture.sampleCount;
_colorPixelFormat = renderPassDescriptor.colorAttachments[0].texture.pixelFormat;
_depthPixelFormat = renderPassDescriptor.depthAttachment.texture.pixelFormat;
_stencilPixelFormat = renderPassDescriptor.stencilAttachment.texture.pixelFormat;
}
return self;
}
- (nonnull id)copyWithZone:(nullable NSZone *)zone
{
FramebufferDescriptor *copy = [[FramebufferDescriptor allocWithZone:zone] init];
copy.sampleCount = self.sampleCount;
copy.colorPixelFormat = self.colorPixelFormat;
copy.depthPixelFormat = self.depthPixelFormat;
copy.stencilPixelFormat = self.stencilPixelFormat;
return copy;
}
- (NSUInteger)hash
{
NSUInteger sc = _sampleCount & 0x3;
NSUInteger cf = _colorPixelFormat & 0x3FF;
NSUInteger df = _depthPixelFormat & 0x3FF;
NSUInteger sf = _stencilPixelFormat & 0x3FF;
NSUInteger hash = (sf << 22) | (df << 12) | (cf << 2) | sc;
return hash;
}
- (BOOL)isEqual:(id)object
{
FramebufferDescriptor *other = object;
if (![other isKindOfClass:[FramebufferDescriptor class]])
return NO;
return other.sampleCount == self.sampleCount &&
other.colorPixelFormat == self.colorPixelFormat &&
other.depthPixelFormat == self.depthPixelFormat &&
other.stencilPixelFormat == self.stencilPixelFormat;
}
@end
#pragma mark - MetalContext implementation
@implementation MetalContext
- (instancetype)init {
if ((self = [super init]))
{
_renderPipelineStateCache = [NSMutableDictionary dictionary];
_bufferCache = [NSMutableArray array];
_lastBufferCachePurge = [NSDate date].timeIntervalSince1970;
}
return self;
}
- (void)makeDeviceObjectsWithDevice:(id<MTLDevice>)device
{
MTLDepthStencilDescriptor *depthStencilDescriptor = [[MTLDepthStencilDescriptor alloc] init];
depthStencilDescriptor.depthWriteEnabled = NO;
depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways;
self.depthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDescriptor];
}
// We are retrieving and uploading the font atlas as a 4-channels RGBA texture here.
// In theory we could call GetTexDataAsAlpha8() and upload a 1-channel texture to save on memory access bandwidth.
// However, using a shader designed for 1-channel texture would make it less obvious to use the ImTextureID facility to render users own textures.
// You can make that change in your implementation.
- (void)makeFontTextureWithDevice:(id<MTLDevice>)device
{
ImGuiIO &io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
width:(NSUInteger)width
height:(NSUInteger)height
mipmapped:NO];
textureDescriptor.usage = MTLTextureUsageShaderRead;
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
textureDescriptor.storageMode = MTLStorageModeManaged;
#else
textureDescriptor.storageMode = MTLStorageModeShared;
#endif
id <MTLTexture> texture = [device newTextureWithDescriptor:textureDescriptor];
[texture replaceRegion:MTLRegionMake2D(0, 0, (NSUInteger)width, (NSUInteger)height) mipmapLevel:0 withBytes:pixels bytesPerRow:(NSUInteger)width * 4];
self.fontTexture = texture;
}
- (MetalBuffer *)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device
{
NSTimeInterval now = [NSDate date].timeIntervalSince1970;
// Purge old buffers that haven't been useful for a while
if (now - self.lastBufferCachePurge > 1.0)
{
NSMutableArray *survivors = [NSMutableArray array];
for (MetalBuffer *candidate in self.bufferCache)
{
if (candidate.lastReuseTime > self.lastBufferCachePurge)
{
[survivors addObject:candidate];
}
}
self.bufferCache = [survivors mutableCopy];
self.lastBufferCachePurge = now;
}
// See if we have a buffer we can reuse
MetalBuffer *bestCandidate = nil;
for (MetalBuffer *candidate in self.bufferCache)
if (candidate.buffer.length >= length && (bestCandidate == nil || bestCandidate.lastReuseTime > candidate.lastReuseTime))
bestCandidate = candidate;
if (bestCandidate != nil)
{
[self.bufferCache removeObject:bestCandidate];
bestCandidate.lastReuseTime = now;
return bestCandidate;
}
// No luck; make a new buffer
id<MTLBuffer> backing = [device newBufferWithLength:length options:MTLResourceStorageModeShared];
return [[MetalBuffer alloc] initWithBuffer:backing];
}
- (void)enqueueReusableBuffer:(MetalBuffer *)buffer
{
[self.bufferCache addObject:buffer];
}
- (_Nullable id<MTLRenderPipelineState>)renderPipelineStateForFrameAndDevice:(id<MTLDevice>)device
{
// Try to retrieve a render pipeline state that is compatible with the framebuffer config for this frame
// The hit rate for this cache should be very near 100%.
id<MTLRenderPipelineState> renderPipelineState = self.renderPipelineStateCache[self.framebufferDescriptor];
if (renderPipelineState == nil)
{
// No luck; make a new render pipeline state
renderPipelineState = [self _renderPipelineStateForFramebufferDescriptor:self.framebufferDescriptor device:device];
// Cache render pipeline state for later reuse
self.renderPipelineStateCache[self.framebufferDescriptor] = renderPipelineState;
}
return renderPipelineState;
}
- (id<MTLRenderPipelineState>)_renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor *)descriptor device:(id<MTLDevice>)device
{
NSError *error = nil;
NSString *shaderSource = @""
"#include <metal_stdlib>\n"
"using namespace metal;\n"
"\n"
"struct Uniforms {\n"
" float4x4 projectionMatrix;\n"
"};\n"
"\n"
"struct VertexIn {\n"
" float2 position [[attribute(0)]];\n"
" float2 texCoords [[attribute(1)]];\n"
" uchar4 color [[attribute(2)]];\n"
"};\n"
"\n"
"struct VertexOut {\n"
" float4 position [[position]];\n"
" float2 texCoords;\n"
" float4 color;\n"
"};\n"
"\n"
"vertex VertexOut vertex_main(VertexIn in [[stage_in]],\n"
" constant Uniforms &uniforms [[buffer(1)]]) {\n"
" VertexOut out;\n"
" out.position = uniforms.projectionMatrix * float4(in.position, 0, 1);\n"
" out.texCoords = in.texCoords;\n"
" out.color = float4(in.color) / float4(255.0);\n"
" return out;\n"
"}\n"
"\n"
"fragment half4 fragment_main(VertexOut in [[stage_in]],\n"
" texture2d<half, access::sample> texture [[texture(0)]]) {\n"
" constexpr sampler linearSampler(coord::normalized, min_filter::linear, mag_filter::linear, mip_filter::linear);\n"
" half4 texColor = texture.sample(linearSampler, in.texCoords);\n"
" return half4(in.color) * texColor;\n"
"}\n";
id<MTLLibrary> library = [device newLibraryWithSource:shaderSource options:nil error:&error];
if (library == nil)
{
NSLog(@"Error: failed to create Metal library: %@", error);
return nil;
}
id<MTLFunction> vertexFunction = [library newFunctionWithName:@"vertex_main"];
id<MTLFunction> fragmentFunction = [library newFunctionWithName:@"fragment_main"];
if (vertexFunction == nil || fragmentFunction == nil)
{
NSLog(@"Error: failed to find Metal shader functions in library: %@", error);
return nil;
}
MTLVertexDescriptor *vertexDescriptor = [MTLVertexDescriptor vertexDescriptor];
vertexDescriptor.attributes[0].offset = IM_OFFSETOF(ImDrawVert, pos);
vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2; // position
vertexDescriptor.attributes[0].bufferIndex = 0;
vertexDescriptor.attributes[1].offset = IM_OFFSETOF(ImDrawVert, uv);
vertexDescriptor.attributes[1].format = MTLVertexFormatFloat2; // texCoords
vertexDescriptor.attributes[1].bufferIndex = 0;
vertexDescriptor.attributes[2].offset = IM_OFFSETOF(ImDrawVert, col);
vertexDescriptor.attributes[2].format = MTLVertexFormatUChar4; // color
vertexDescriptor.attributes[2].bufferIndex = 0;
vertexDescriptor.layouts[0].stepRate = 1;
vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
vertexDescriptor.layouts[0].stride = sizeof(ImDrawVert);
MTLRenderPipelineDescriptor *pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
pipelineDescriptor.vertexFunction = vertexFunction;
pipelineDescriptor.fragmentFunction = fragmentFunction;
pipelineDescriptor.vertexDescriptor = vertexDescriptor;
pipelineDescriptor.sampleCount = self.framebufferDescriptor.sampleCount;
pipelineDescriptor.colorAttachments[0].pixelFormat = self.framebufferDescriptor.colorPixelFormat;
pipelineDescriptor.colorAttachments[0].blendingEnabled = YES;
pipelineDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
pipelineDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
pipelineDescriptor.depthAttachmentPixelFormat = self.framebufferDescriptor.depthPixelFormat;
pipelineDescriptor.stencilAttachmentPixelFormat = self.framebufferDescriptor.stencilPixelFormat;
id<MTLRenderPipelineState> renderPipelineState = [device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error];
if (error != nil)
{
NSLog(@"Error: failed to create Metal pipeline state: %@", error);
}
return renderPipelineState;
}
- (void)emptyRenderPipelineStateCache
{
[self.renderPipelineStateCache removeAllObjects];
}
- (void)setupRenderState:(ImDrawData *)drawData
commandBuffer:(id<MTLCommandBuffer>)commandBuffer
commandEncoder:(id<MTLRenderCommandEncoder>)commandEncoder
renderPipelineState:(id<MTLRenderPipelineState>)renderPipelineState
vertexBuffer:(MetalBuffer *)vertexBuffer
vertexBufferOffset:(size_t)vertexBufferOffset
{
[commandEncoder setCullMode:MTLCullModeNone];
[commandEncoder setDepthStencilState:g_sharedMetalContext.depthStencilState];
// Setup viewport, orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to
// draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps.
MTLViewport viewport =
{
.originX = 0.0,
.originY = 0.0,
.width = (double)(drawData->DisplaySize.x * drawData->FramebufferScale.x),
.height = (double)(drawData->DisplaySize.y * drawData->FramebufferScale.y),
.znear = 0.0,
.zfar = 1.0
};
[commandEncoder setViewport:viewport];
float L = drawData->DisplayPos.x;
float R = drawData->DisplayPos.x + drawData->DisplaySize.x;
float T = drawData->DisplayPos.y;
float B = drawData->DisplayPos.y + drawData->DisplaySize.y;
float N = (float)viewport.znear;
float F = (float)viewport.zfar;
const float ortho_projection[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, 1/(F-N), 0.0f },
{ (R+L)/(L-R), (T+B)/(B-T), N/(F-N), 1.0f },
};
[commandEncoder setVertexBytes:&ortho_projection length:sizeof(ortho_projection) atIndex:1];
[commandEncoder setRenderPipelineState:renderPipelineState];
[commandEncoder setVertexBuffer:vertexBuffer.buffer offset:0 atIndex:0];
[commandEncoder setVertexBufferOffset:vertexBufferOffset atIndex:0];
}
- (void)renderDrawData:(ImDrawData *)drawData
commandBuffer:(id<MTLCommandBuffer>)commandBuffer
commandEncoder:(id<MTLRenderCommandEncoder>)commandEncoder
{
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
int fb_width = (int)(drawData->DisplaySize.x * drawData->FramebufferScale.x);
int fb_height = (int)(drawData->DisplaySize.y * drawData->FramebufferScale.y);
if (fb_width <= 0 || fb_height <= 0 || drawData->CmdListsCount == 0)
return;
id<MTLRenderPipelineState> renderPipelineState = [self renderPipelineStateForFrameAndDevice:commandBuffer.device];
size_t vertexBufferLength = (size_t)drawData->TotalVtxCount * sizeof(ImDrawVert);
size_t indexBufferLength = (size_t)drawData->TotalIdxCount * sizeof(ImDrawIdx);
MetalBuffer* vertexBuffer = [self dequeueReusableBufferOfLength:vertexBufferLength device:commandBuffer.device];
MetalBuffer* indexBuffer = [self dequeueReusableBufferOfLength:indexBufferLength device:commandBuffer.device];
[self setupRenderState:drawData commandBuffer:commandBuffer commandEncoder:commandEncoder renderPipelineState:renderPipelineState vertexBuffer:vertexBuffer vertexBufferOffset:0];
// Will project scissor/clipping rectangles into framebuffer space
ImVec2 clip_off = drawData->DisplayPos; // (0,0) unless using multi-viewports
ImVec2 clip_scale = drawData->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
// Render command lists
size_t vertexBufferOffset = 0;
size_t indexBufferOffset = 0;
for (int n = 0; n < drawData->CmdListsCount; n++)
{
const ImDrawList* cmd_list = drawData->CmdLists[n];
memcpy((char *)vertexBuffer.buffer.contents + vertexBufferOffset, cmd_list->VtxBuffer.Data, (size_t)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
memcpy((char *)indexBuffer.buffer.contents + indexBufferOffset, cmd_list->IdxBuffer.Data, (size_t)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
[self setupRenderState:drawData commandBuffer:commandBuffer commandEncoder:commandEncoder renderPipelineState:renderPipelineState vertexBuffer:vertexBuffer vertexBufferOffset:vertexBufferOffset];
else
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
// Clamp to viewport as setScissorRect() won't accept values that are off bounds
if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
continue;
// Apply scissor/clipping rectangle
MTLScissorRect scissorRect =
{
.x = NSUInteger(clip_min.x),
.y = NSUInteger(clip_min.y),
.width = NSUInteger(clip_max.x - clip_min.x),
.height = NSUInteger(clip_max.y - clip_min.y)
};
[commandEncoder setScissorRect:scissorRect];
// Bind texture, Draw
if (ImTextureID tex_id = pcmd->GetTexID())
[commandEncoder setFragmentTexture:(__bridge id<MTLTexture>)(tex_id) atIndex:0];
[commandEncoder setVertexBufferOffset:(vertexBufferOffset + pcmd->VtxOffset * sizeof(ImDrawVert)) atIndex:0];
[commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
indexCount:pcmd->ElemCount
indexType:sizeof(ImDrawIdx) == 2 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32
indexBuffer:indexBuffer.buffer
indexBufferOffset:indexBufferOffset + pcmd->IdxOffset * sizeof(ImDrawIdx)];
}
}
vertexBufferOffset += (size_t)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert);
indexBufferOffset += (size_t)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx);
}
__weak id weakSelf = self;
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer>)
{
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf enqueueReusableBuffer:vertexBuffer];
[weakSelf enqueueReusableBuffer:indexBuffer];
});
}];
}
@end

View file

@ -1,284 +0,0 @@
// dear imgui: Renderer Backend for OpenGL2 (legacy OpenGL, fixed pipeline)
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
// Implemented features:
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)**
// **Prefer using the code in imgui_impl_opengl3.cpp**
// This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read.
// If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more
// complicated, will require your code to reset every single OpenGL attributes to their initial state, and might
// confuse your GPU driver.
// The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API.
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
// 2021-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 2021-01-03: OpenGL: Backup, setup and restore GL_SHADE_MODEL state, disable GL_STENCIL_TEST and disable GL_NORMAL_ARRAY client state to increase compatibility with legacy OpenGL applications.
// 2020-01-23: OpenGL: Backup, setup and restore GL_TEXTURE_ENV to increase compatibility with legacy OpenGL applications.
// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
// 2018-08-03: OpenGL: Disabling/restoring GL_LIGHTING and GL_COLOR_MATERIAL to increase compatibility with legacy OpenGL applications.
// 2018-06-08: Misc: Extracted imgui_impl_opengl2.cpp/.h away from the old combined GLFW/SDL+OpenGL2 examples.
// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplOpenGL2_RenderDrawData() in the .h file so you can call it yourself.
// 2017-09-01: OpenGL: Save and restore current polygon mode.
// 2016-09-10: OpenGL: Uploading font texture as RGBA32 to increase compatibility with users shaders (not ideal).
// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.
#include "imgui.h"
#include "imgui_impl_opengl2.h"
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
#include <stddef.h> // intptr_t
#else
#include <stdint.h> // intptr_t
#endif
// Include OpenGL header (without an OpenGL loader) requires a bit of fiddling
#if defined(_WIN32) && !defined(APIENTRY)
#define APIENTRY __stdcall // It is customary to use APIENTRY for OpenGL function pointer declarations on all platforms. Additionally, the Windows OpenGL header needs APIENTRY.
#endif
#if defined(_WIN32) && !defined(WINGDIAPI)
#define WINGDIAPI __declspec(dllimport) // Some Windows OpenGL headers need this
#endif
#if defined(__APPLE__)
#define GL_SILENCE_DEPRECATION
#include <OpenGL/gl.h>
#else
#include <GL/gl.h>
#endif
struct ImGui_ImplOpenGL2_Data
{
GLuint FontTexture;
ImGui_ImplOpenGL2_Data() { memset(this, 0, sizeof(*this)); }
};
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
static ImGui_ImplOpenGL2_Data* ImGui_ImplOpenGL2_GetBackendData()
{
return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL2_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
}
// Functions
bool ImGui_ImplOpenGL2_Init()
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
// Setup backend capabilities flags
ImGui_ImplOpenGL2_Data* bd = IM_NEW(ImGui_ImplOpenGL2_Data)();
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_opengl2";
return true;
}
void ImGui_ImplOpenGL2_Shutdown()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData();
ImGui_ImplOpenGL2_DestroyDeviceObjects();
io.BackendRendererName = NULL;
io.BackendRendererUserData = NULL;
IM_DELETE(bd);
}
void ImGui_ImplOpenGL2_NewFrame()
{
ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData();
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplOpenGL2_Init()?");
if (!bd->FontTexture)
ImGui_ImplOpenGL2_CreateDeviceObjects();
}
static void ImGui_ImplOpenGL2_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height)
{
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill.
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // In order to composite our output buffer we need to preserve alpha
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glDisable(GL_LIGHTING);
glDisable(GL_COLOR_MATERIAL);
glEnable(GL_SCISSOR_TEST);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glEnable(GL_TEXTURE_2D);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glShadeModel(GL_SMOOTH);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
// If you are using this code with non-legacy OpenGL header/contexts (which you should not, prefer using imgui_impl_opengl3.cpp!!),
// you may need to backup/reset/restore other state, e.g. for current shader using the commented lines below.
// (DO NOT MODIFY THIS FILE! Add the code in your calling function)
// GLint last_program;
// glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
// glUseProgram(0);
// ImGui_ImplOpenGL2_RenderDrawData(...);
// glUseProgram(last_program)
// There are potentially many more states you could need to clear/setup that we can't access from default headers.
// e.g. glBindBuffer(GL_ARRAY_BUFFER, 0), glDisable(GL_TEXTURE_CUBE_MAP).
// Setup viewport, orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(draw_data->DisplayPos.x, draw_data->DisplayPos.x + draw_data->DisplaySize.x, draw_data->DisplayPos.y + draw_data->DisplaySize.y, draw_data->DisplayPos.y, -1.0f, +1.0f);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
}
// OpenGL2 Render function.
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
// This is in order to be able to run within an OpenGL engine that doesn't do so.
void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data)
{
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
if (fb_width == 0 || fb_height == 0)
return;
// Backup GL state
GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
GLint last_shade_model; glGetIntegerv(GL_SHADE_MODEL, &last_shade_model);
GLint last_tex_env_mode; glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &last_tex_env_mode);
glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
// Setup desired GL state
ImGui_ImplOpenGL2_SetupRenderState(draw_data, fb_width, fb_height);
// Will project scissor/clipping rectangles into framebuffer space
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
// Render command lists
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;
const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;
glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, pos)));
glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, uv)));
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, col)));
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplOpenGL2_SetupRenderState(draw_data, fb_width, fb_height);
else
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
continue;
// Apply scissor/clipping rectangle (Y is inverted in OpenGL)
glScissor((int)clip_min.x, (int)(fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y));
// Bind texture, Draw
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID());
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer);
}
idx_buffer += pcmd->ElemCount;
}
}
// Restore modified GL state
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glBindTexture(GL_TEXTURE_2D, (GLuint)last_texture);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPopAttrib();
glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]); glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1]);
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
glShadeModel(last_shade_model);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, last_tex_env_mode);
}
bool ImGui_ImplOpenGL2_CreateFontsTexture()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
// Upload texture to graphics system
GLint last_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGenTextures(1, &bd->FontTexture);
glBindTexture(GL_TEXTURE_2D, bd->FontTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// Store our identifier
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
// Restore state
glBindTexture(GL_TEXTURE_2D, last_texture);
return true;
}
void ImGui_ImplOpenGL2_DestroyFontsTexture()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData();
if (bd->FontTexture)
{
glDeleteTextures(1, &bd->FontTexture);
io.Fonts->SetTexID(0);
bd->FontTexture = 0;
}
}
bool ImGui_ImplOpenGL2_CreateDeviceObjects()
{
return ImGui_ImplOpenGL2_CreateFontsTexture();
}
void ImGui_ImplOpenGL2_DestroyDeviceObjects()
{
ImGui_ImplOpenGL2_DestroyFontsTexture();
}

View file

@ -1,32 +0,0 @@
// dear imgui: Renderer Backend for OpenGL2 (legacy OpenGL, fixed pipeline)
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
// Implemented features:
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)**
// **Prefer using the code in imgui_impl_opengl3.cpp**
// This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read.
// If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more
// complicated, will require your code to reset every single OpenGL attributes to their initial state, and might
// confuse your GPU driver.
// The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API.
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
IMGUI_IMPL_API bool ImGui_ImplOpenGL2_Init();
IMGUI_IMPL_API void ImGui_ImplOpenGL2_Shutdown();
IMGUI_IMPL_API void ImGui_ImplOpenGL2_NewFrame();
IMGUI_IMPL_API void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data);
// Called by Init/NewFrame/Shutdown
IMGUI_IMPL_API bool ImGui_ImplOpenGL2_CreateFontsTexture();
IMGUI_IMPL_API void ImGui_ImplOpenGL2_DestroyFontsTexture();
IMGUI_IMPL_API bool ImGui_ImplOpenGL2_CreateDeviceObjects();
IMGUI_IMPL_API void ImGui_ImplOpenGL2_DestroyDeviceObjects();

View file

@ -1,777 +0,0 @@
// dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
// - Desktop GL: 2.x 3.x 4.x
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
// Implemented features:
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-08-23: OpenGL: Fixed ES 3.0 shader ("#version 300 es") use normal precision floats to avoid wobbly rendering at HD resolutions.
// 2021-08-19: OpenGL: Embed and use our own minimal GL loader (imgui_impl_opengl3_loader.h), removing requirement and support for third-party loader.
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
// 2021-06-25: OpenGL: Use OES_vertex_array extension on Emscripten + backup/restore current state.
// 2021-06-21: OpenGL: Destroy individual vertex/fragment shader objects right after they are linked into the main shader.
// 2021-05-24: OpenGL: Access GL_CLIP_ORIGIN when "GL_ARB_clip_control" extension is detected, inside of just OpenGL 4.5 version.
// 2021-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 2021-04-06: OpenGL: Don't try to read GL_CLIP_ORIGIN unless we're OpenGL 4.5 or greater.
// 2021-02-18: OpenGL: Change blending equation to preserve alpha in output buffer.
// 2021-01-03: OpenGL: Backup, setup and restore GL_STENCIL_TEST state.
// 2020-10-23: OpenGL: Backup, setup and restore GL_PRIMITIVE_RESTART state.
// 2020-10-15: OpenGL: Use glGetString(GL_VERSION) instead of glGetIntegerv(GL_MAJOR_VERSION, ...) when the later returns zero (e.g. Desktop GL 2.x)
// 2020-09-17: OpenGL: Fix to avoid compiling/calling glBindSampler() on ES or pre 3.3 context which have the defines set by a loader.
// 2020-07-10: OpenGL: Added support for glad2 OpenGL loader.
// 2020-05-08: OpenGL: Made default GLSL version 150 (instead of 130) on OSX.
// 2020-04-21: OpenGL: Fixed handling of glClipControl(GL_UPPER_LEFT) by inverting projection matrix.
// 2020-04-12: OpenGL: Fixed context version check mistakenly testing for 4.0+ instead of 3.2+ to enable ImGuiBackendFlags_RendererHasVtxOffset.
// 2020-03-24: OpenGL: Added support for glbinding 2.x OpenGL loader.
// 2020-01-07: OpenGL: Added support for glbinding 3.x OpenGL loader.
// 2019-10-25: OpenGL: Using a combination of GL define and runtime GL version to decide whether to use glDrawElementsBaseVertex(). Fix building with pre-3.2 GL loaders.
// 2019-09-22: OpenGL: Detect default GL loader using __has_include compiler facility.
// 2019-09-16: OpenGL: Tweak initialization code to allow application calling ImGui_ImplOpenGL3_CreateFontsTexture() before the first NewFrame() call.
// 2019-05-29: OpenGL: Desktop GL only: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
// 2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop.
// 2019-03-15: OpenGL: Added a GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early.
// 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0).
// 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader.
// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
// 2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450).
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
// 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT) / GL_CLIP_ORIGIN.
// 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used.
// 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES".
// 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation.
// 2018-07-10: OpenGL: Support for more GLSL versions (based on the GLSL version string). Added error output when shaders fail to compile/link.
// 2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples.
// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
// 2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state.
// 2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a NULL pointer.
// 2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. "#version 150".
// 2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context.
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself.
// 2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150.
// 2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode.
// 2017-05-01: OpenGL: Fixed save and restore of current blend func state.
// 2017-05-01: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE.
// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.
// 2016-07-29: OpenGL: Explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it. (#752)
//----------------------------------------
// OpenGL GLSL GLSL
// version version string
//----------------------------------------
// 2.0 110 "#version 110"
// 2.1 120 "#version 120"
// 3.0 130 "#version 130"
// 3.1 140 "#version 140"
// 3.2 150 "#version 150"
// 3.3 330 "#version 330 core"
// 4.0 400 "#version 400 core"
// 4.1 410 "#version 410 core"
// 4.2 420 "#version 410 core"
// 4.3 430 "#version 430 core"
// ES 2.0 100 "#version 100" = WebGL 1.0
// ES 3.0 300 "#version 300 es" = WebGL 2.0
//----------------------------------------
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "imgui.h"
#include "imgui_impl_opengl3.h"
#include <stdio.h>
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
#include <stddef.h> // intptr_t
#else
#include <stdint.h> // intptr_t
#endif
// GL includes
#if defined(IMGUI_IMPL_OPENGL_ES2)
#include <GLES2/gl2.h>
#if defined(__EMSCRIPTEN__)
#ifndef GL_GLEXT_PROTOTYPES
#define GL_GLEXT_PROTOTYPES
#endif
#include <GLES2/gl2ext.h>
#endif
#elif defined(IMGUI_IMPL_OPENGL_ES3)
#if defined(__APPLE__)
#include <TargetConditionals.h>
#endif
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
#include <OpenGLES/ES3/gl.h> // Use GL ES 3
#else
#include <GLES3/gl3.h> // Use GL ES 3
#endif
#elif !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
// Helper libraries are often used for this purpose! Here we are using our own minimal custom loader based on gl3w.
// In the rest of your app/engine, you can use another loader of your choice (gl3w, glew, glad, glbinding, glext, glLoadGen, etc.).
// If you happen to be developing a new feature for this backend (imgui_impl_opengl3.cpp):
// - You may need to regenerate imgui_impl_opengl3_loader.h to add new symbols. See https://github.com/dearimgui/gl3w_stripped
// - You can temporarily use an unstripped version. See https://github.com/dearimgui/gl3w_stripped/releases
// Changes to this backend using new APIs should be accompanied by a regenerated stripped loader version.
#define IMGL3W_IMPL
#include "imgui_impl_opengl3_loader.h"
#endif
// Vertex arrays are not supported on ES2/WebGL1 unless Emscripten which uses an extension
#ifndef IMGUI_IMPL_OPENGL_ES2
#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
#elif defined(__EMSCRIPTEN__)
#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
#define glBindVertexArray glBindVertexArrayOES
#define glGenVertexArrays glGenVertexArraysOES
#define glDeleteVertexArrays glDeleteVertexArraysOES
#define GL_VERTEX_ARRAY_BINDING GL_VERTEX_ARRAY_BINDING_OES
#endif
// Desktop GL 2.0+ has glPolygonMode() which GL ES and WebGL don't have.
#ifdef GL_POLYGON_MODE
#define IMGUI_IMPL_HAS_POLYGON_MODE
#endif
// Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have.
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_2)
#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
#endif
// Desktop GL 3.3+ has glBindSampler()
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_3)
#define IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
#endif
// Desktop GL 3.1+ has GL_PRIMITIVE_RESTART state
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_1)
#define IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
#endif
// Desktop GL use extension detection
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3)
#define IMGUI_IMPL_OPENGL_MAY_HAVE_EXTENSIONS
#endif
// OpenGL Data
struct ImGui_ImplOpenGL3_Data
{
GLuint GlVersion; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
char GlslVersionString[32]; // Specified by user or detected based on compile time GL settings.
GLuint FontTexture;
GLuint ShaderHandle;
GLint AttribLocationTex; // Uniforms location
GLint AttribLocationProjMtx;
GLuint AttribLocationVtxPos; // Vertex attributes location
GLuint AttribLocationVtxUV;
GLuint AttribLocationVtxColor;
unsigned int VboHandle, ElementsHandle;
bool HasClipOrigin;
ImGui_ImplOpenGL3_Data() { memset(this, 0, sizeof(*this)); }
};
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
static ImGui_ImplOpenGL3_Data* ImGui_ImplOpenGL3_GetBackendData()
{
return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL3_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
}
// Functions
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
// Initialize our loader
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
if (imgl3wInit() != 0)
{
fprintf(stderr, "Failed to initialize OpenGL loader!\n");
return false;
}
#endif
// Setup backend capabilities flags
ImGui_ImplOpenGL3_Data* bd = IM_NEW(ImGui_ImplOpenGL3_Data)();
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_opengl3";
// Query for GL version (e.g. 320 for GL 3.2)
#if !defined(IMGUI_IMPL_OPENGL_ES2)
GLint major = 0;
GLint minor = 0;
glGetIntegerv(GL_MAJOR_VERSION, &major);
glGetIntegerv(GL_MINOR_VERSION, &minor);
if (major == 0 && minor == 0)
{
// Query GL_VERSION in desktop GL 2.x, the string will start with "<major>.<minor>"
const char* gl_version = (const char*)glGetString(GL_VERSION);
sscanf(gl_version, "%d.%d", &major, &minor);
}
bd->GlVersion = (GLuint)(major * 100 + minor * 10);
#else
bd->GlVersion = 200; // GLES 2
#endif
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
if (bd->GlVersion >= 320)
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
#endif
// Store GLSL version string so we can refer to it later in case we recreate shaders.
// Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure.
if (glsl_version == NULL)
{
#if defined(IMGUI_IMPL_OPENGL_ES2)
glsl_version = "#version 100";
#elif defined(IMGUI_IMPL_OPENGL_ES3)
glsl_version = "#version 300 es";
#elif defined(__APPLE__)
glsl_version = "#version 150";
#else
glsl_version = "#version 130";
#endif
}
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(bd->GlslVersionString));
strcpy(bd->GlslVersionString, glsl_version);
strcat(bd->GlslVersionString, "\n");
// Make an arbitrary GL call (we don't actually need the result)
// IF YOU GET A CRASH HERE: it probably means the OpenGL function loader didn't do its job. Let us know!
GLint current_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);
// Detect extensions we support
bd->HasClipOrigin = (bd->GlVersion >= 450);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_EXTENSIONS
GLint num_extensions = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
for (GLint i = 0; i < num_extensions; i++)
{
const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, i);
if (extension != NULL && strcmp(extension, "GL_ARB_clip_control") == 0)
bd->HasClipOrigin = true;
}
#endif
return true;
}
void ImGui_ImplOpenGL3_Shutdown()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
ImGui_ImplOpenGL3_DestroyDeviceObjects();
io.BackendRendererName = NULL;
io.BackendRendererUserData = NULL;
IM_DELETE(bd);
}
void ImGui_ImplOpenGL3_NewFrame()
{
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplOpenGL3_Init()?");
if (!bd->ShaderHandle)
ImGui_ImplOpenGL3_CreateDeviceObjects();
}
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
{
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glEnable(GL_SCISSOR_TEST);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
if (bd->GlVersion >= 310)
glDisable(GL_PRIMITIVE_RESTART);
#endif
#ifdef IMGUI_IMPL_HAS_POLYGON_MODE
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
#endif
// Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
#if defined(GL_CLIP_ORIGIN)
bool clip_origin_lower_left = true;
if (bd->HasClipOrigin)
{
GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&current_clip_origin);
if (current_clip_origin == GL_UPPER_LEFT)
clip_origin_lower_left = false;
}
#endif
// Setup viewport, orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
float L = draw_data->DisplayPos.x;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
float T = draw_data->DisplayPos.y;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
#if defined(GL_CLIP_ORIGIN)
if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left
#endif
const float ortho_projection[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, -1.0f, 0.0f },
{ (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f },
};
glUseProgram(bd->ShaderHandle);
glUniform1i(bd->AttribLocationTex, 0);
glUniformMatrix4fv(bd->AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
if (bd->GlVersion >= 330)
glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
#endif
(void)vertex_array_object;
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
glBindVertexArray(vertex_array_object);
#endif
// Bind vertex/index buffers and setup attributes for ImDrawVert
glBindBuffer(GL_ARRAY_BUFFER, bd->VboHandle);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bd->ElementsHandle);
glEnableVertexAttribArray(bd->AttribLocationVtxPos);
glEnableVertexAttribArray(bd->AttribLocationVtxUV);
glEnableVertexAttribArray(bd->AttribLocationVtxColor);
glVertexAttribPointer(bd->AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos));
glVertexAttribPointer(bd->AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv));
glVertexAttribPointer(bd->AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col));
}
// OpenGL3 Render function.
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
// This is in order to be able to run within an OpenGL engine that doesn't do so.
void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
{
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
if (fb_width <= 0 || fb_height <= 0)
return;
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
// Backup GL state
GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
glActiveTexture(GL_TEXTURE0);
GLuint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&last_program);
GLuint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&last_texture);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
GLuint last_sampler; if (bd->GlVersion >= 330) { glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&last_sampler); } else { last_sampler = 0; }
#endif
GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer);
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
GLuint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&last_vertex_array_object);
#endif
#ifdef IMGUI_IMPL_HAS_POLYGON_MODE
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
#endif
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb);
GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb);
GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha);
GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha);
GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb);
GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha);
GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
GLboolean last_enable_stencil_test = glIsEnabled(GL_STENCIL_TEST);
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
GLboolean last_enable_primitive_restart = (bd->GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE;
#endif
// Setup desired GL state
// Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
// The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
GLuint vertex_array_object = 0;
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
glGenVertexArrays(1, &vertex_array_object);
#endif
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
// Will project scissor/clipping rectangles into framebuffer space
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
// Render command lists
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
// Upload vertex/index buffers
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW);
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback != NULL)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
else
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
continue;
// Apply scissor/clipping rectangle (Y is inverted in OpenGL)
glScissor((int)clip_min.x, (int)(fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y));
// Bind texture, Draw
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID());
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
if (bd->GlVersion >= 320)
glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset);
else
#endif
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)));
}
}
}
// Destroy the temporary VAO
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
glDeleteVertexArrays(1, &vertex_array_object);
#endif
// Restore modified GL state
glUseProgram(last_program);
glBindTexture(GL_TEXTURE_2D, last_texture);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
if (bd->GlVersion >= 330)
glBindSampler(0, last_sampler);
#endif
glActiveTexture(last_active_texture);
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
glBindVertexArray(last_vertex_array_object);
#endif
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
if (last_enable_stencil_test) glEnable(GL_STENCIL_TEST); else glDisable(GL_STENCIL_TEST);
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
if (bd->GlVersion >= 310) { if (last_enable_primitive_restart) glEnable(GL_PRIMITIVE_RESTART); else glDisable(GL_PRIMITIVE_RESTART); }
#endif
#ifdef IMGUI_IMPL_HAS_POLYGON_MODE
glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
#endif
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
(void)bd; // Not all compilation paths use this
}
bool ImGui_ImplOpenGL3_CreateFontsTexture()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
// Build texture atlas
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
// Upload texture to graphics system
GLint last_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGenTextures(1, &bd->FontTexture);
glBindTexture(GL_TEXTURE_2D, bd->FontTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
#ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// Store our identifier
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
// Restore state
glBindTexture(GL_TEXTURE_2D, last_texture);
return true;
}
void ImGui_ImplOpenGL3_DestroyFontsTexture()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
if (bd->FontTexture)
{
glDeleteTextures(1, &bd->FontTexture);
io.Fonts->SetTexID(0);
bd->FontTexture = 0;
}
}
// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file.
static bool CheckShader(GLuint handle, const char* desc)
{
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
GLint status = 0, log_length = 0;
glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
if ((GLboolean)status == GL_FALSE)
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s! With GLSL: %s\n", desc, bd->GlslVersionString);
if (log_length > 1)
{
ImVector<char> buf;
buf.resize((int)(log_length + 1));
glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
fprintf(stderr, "%s\n", buf.begin());
}
return (GLboolean)status == GL_TRUE;
}
// If you get an error please report on GitHub. You may try different GL context version or GLSL version.
static bool CheckProgram(GLuint handle, const char* desc)
{
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
GLint status = 0, log_length = 0;
glGetProgramiv(handle, GL_LINK_STATUS, &status);
glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
if ((GLboolean)status == GL_FALSE)
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! With GLSL %s\n", desc, bd->GlslVersionString);
if (log_length > 1)
{
ImVector<char> buf;
buf.resize((int)(log_length + 1));
glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
fprintf(stderr, "%s\n", buf.begin());
}
return (GLboolean)status == GL_TRUE;
}
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
{
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
// Backup GL state
GLint last_texture, last_array_buffer;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
GLint last_vertex_array;
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
#endif
// Parse GLSL version string
int glsl_version = 130;
sscanf(bd->GlslVersionString, "#version %d", &glsl_version);
const GLchar* vertex_shader_glsl_120 =
"uniform mat4 ProjMtx;\n"
"attribute vec2 Position;\n"
"attribute vec2 UV;\n"
"attribute vec4 Color;\n"
"varying vec2 Frag_UV;\n"
"varying vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" Frag_UV = UV;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
"}\n";
const GLchar* vertex_shader_glsl_130 =
"uniform mat4 ProjMtx;\n"
"in vec2 Position;\n"
"in vec2 UV;\n"
"in vec4 Color;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" Frag_UV = UV;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
"}\n";
const GLchar* vertex_shader_glsl_300_es =
"precision highp float;\n"
"layout (location = 0) in vec2 Position;\n"
"layout (location = 1) in vec2 UV;\n"
"layout (location = 2) in vec4 Color;\n"
"uniform mat4 ProjMtx;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" Frag_UV = UV;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
"}\n";
const GLchar* vertex_shader_glsl_410_core =
"layout (location = 0) in vec2 Position;\n"
"layout (location = 1) in vec2 UV;\n"
"layout (location = 2) in vec4 Color;\n"
"uniform mat4 ProjMtx;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" Frag_UV = UV;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
"}\n";
const GLchar* fragment_shader_glsl_120 =
"#ifdef GL_ES\n"
" precision mediump float;\n"
"#endif\n"
"uniform sampler2D Texture;\n"
"varying vec2 Frag_UV;\n"
"varying vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n"
"}\n";
const GLchar* fragment_shader_glsl_130 =
"uniform sampler2D Texture;\n"
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"out vec4 Out_Color;\n"
"void main()\n"
"{\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
const GLchar* fragment_shader_glsl_300_es =
"precision mediump float;\n"
"uniform sampler2D Texture;\n"
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"layout (location = 0) out vec4 Out_Color;\n"
"void main()\n"
"{\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
const GLchar* fragment_shader_glsl_410_core =
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"uniform sampler2D Texture;\n"
"layout (location = 0) out vec4 Out_Color;\n"
"void main()\n"
"{\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
// Select shaders matching our GLSL versions
const GLchar* vertex_shader = NULL;
const GLchar* fragment_shader = NULL;
if (glsl_version < 130)
{
vertex_shader = vertex_shader_glsl_120;
fragment_shader = fragment_shader_glsl_120;
}
else if (glsl_version >= 410)
{
vertex_shader = vertex_shader_glsl_410_core;
fragment_shader = fragment_shader_glsl_410_core;
}
else if (glsl_version == 300)
{
vertex_shader = vertex_shader_glsl_300_es;
fragment_shader = fragment_shader_glsl_300_es;
}
else
{
vertex_shader = vertex_shader_glsl_130;
fragment_shader = fragment_shader_glsl_130;
}
// Create shaders
const GLchar* vertex_shader_with_version[2] = { bd->GlslVersionString, vertex_shader };
GLuint vert_handle = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vert_handle, 2, vertex_shader_with_version, NULL);
glCompileShader(vert_handle);
CheckShader(vert_handle, "vertex shader");
const GLchar* fragment_shader_with_version[2] = { bd->GlslVersionString, fragment_shader };
GLuint frag_handle = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(frag_handle, 2, fragment_shader_with_version, NULL);
glCompileShader(frag_handle);
CheckShader(frag_handle, "fragment shader");
// Link
bd->ShaderHandle = glCreateProgram();
glAttachShader(bd->ShaderHandle, vert_handle);
glAttachShader(bd->ShaderHandle, frag_handle);
glLinkProgram(bd->ShaderHandle);
CheckProgram(bd->ShaderHandle, "shader program");
glDetachShader(bd->ShaderHandle, vert_handle);
glDetachShader(bd->ShaderHandle, frag_handle);
glDeleteShader(vert_handle);
glDeleteShader(frag_handle);
bd->AttribLocationTex = glGetUniformLocation(bd->ShaderHandle, "Texture");
bd->AttribLocationProjMtx = glGetUniformLocation(bd->ShaderHandle, "ProjMtx");
bd->AttribLocationVtxPos = (GLuint)glGetAttribLocation(bd->ShaderHandle, "Position");
bd->AttribLocationVtxUV = (GLuint)glGetAttribLocation(bd->ShaderHandle, "UV");
bd->AttribLocationVtxColor = (GLuint)glGetAttribLocation(bd->ShaderHandle, "Color");
// Create buffers
glGenBuffers(1, &bd->VboHandle);
glGenBuffers(1, &bd->ElementsHandle);
ImGui_ImplOpenGL3_CreateFontsTexture();
// Restore modified GL state
glBindTexture(GL_TEXTURE_2D, last_texture);
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
glBindVertexArray(last_vertex_array);
#endif
return true;
}
void ImGui_ImplOpenGL3_DestroyDeviceObjects()
{
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
if (bd->VboHandle) { glDeleteBuffers(1, &bd->VboHandle); bd->VboHandle = 0; }
if (bd->ElementsHandle) { glDeleteBuffers(1, &bd->ElementsHandle); bd->ElementsHandle = 0; }
if (bd->ShaderHandle) { glDeleteProgram(bd->ShaderHandle); bd->ShaderHandle = 0; }
ImGui_ImplOpenGL3_DestroyFontsTexture();
}

View file

@ -1,55 +0,0 @@
// dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
// - Desktop GL: 2.x 3.x 4.x
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
// Implemented features:
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// About GLSL version:
// The 'glsl_version' initialization parameter should be NULL (default) or a "#version XXX" string.
// On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es"
// Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp.
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
// Backend API
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = NULL);
IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown();
IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame();
IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data);
// (Optional) Called by Init/NewFrame/Shutdown
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture();
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture();
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects();
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
// Specific OpenGL ES versions
//#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten
//#define IMGUI_IMPL_OPENGL_ES3 // Auto-detected on iOS/Android
// You can explicitly select GLES2 or GLES3 API by using one of the '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
#if !defined(IMGUI_IMPL_OPENGL_ES2) \
&& !defined(IMGUI_IMPL_OPENGL_ES3)
// Try to detect GLES on matching platforms
#if defined(__APPLE__)
#include <TargetConditionals.h>
#endif
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__))
#define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es"
#elif defined(__EMSCRIPTEN__)
#define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100"
#else
// Otherwise imgui_impl_opengl3_loader.h will be used.
#endif
#endif

View file

@ -1,752 +0,0 @@
//-----------------------------------------------------------------------------
// About imgui_impl_opengl3_loader.h:
//
// We embed our own OpenGL loader to not require user to provide their own or to have to use ours,
// which proved to be endless problems for users.
// Our loader is custom-generated, based on gl3w but automatically filtered to only include
// enums/functions that we use in our imgui_impl_opengl3.cpp source file in order to be small.
//
// YOU SHOULD NOT NEED TO INCLUDE/USE THIS DIRECTLY. THIS IS USED BY imgui_impl_opengl3.cpp ONLY.
// THE REST OF YOUR APP SHOULD USE A DIFFERENT GL LOADER: ANY GL LOADER OF YOUR CHOICE.
//
// Regenerate with:
// python gl3w_gen.py --output ../imgui/backends/imgui_impl_opengl3_loader.h --ref ../imgui/backends/imgui_impl_opengl3.cpp ./extra_symbols.txt
//
// More info:
// https://github.com/dearimgui/gl3w_stripped
// https://github.com/ocornut/imgui/issues/4445
//-----------------------------------------------------------------------------
/*
* This file was generated with gl3w_gen.py, part of imgl3w
* (hosted at https://github.com/dearimgui/gl3w_stripped)
*
* 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.
*/
#ifndef __gl3w_h_
#define __gl3w_h_
// Adapted from KHR/khrplatform.h to avoid including entire file.
#ifndef __khrplatform_h_
typedef float khronos_float_t;
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;
#ifdef _WIN64
typedef signed long long int khronos_intptr_t;
typedef signed long long int khronos_ssize_t;
#else
typedef signed long int khronos_intptr_t;
typedef signed long int khronos_ssize_t;
#endif
#if defined(_MSC_VER) && !defined(__clang__)
typedef signed __int64 khronos_int64_t;
typedef unsigned __int64 khronos_uint64_t;
#elif (defined(__clang__) || defined(__GNUC__)) && (__cplusplus < 201100)
#include <stdint.h>
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#else
typedef signed long long khronos_int64_t;
typedef unsigned long long khronos_uint64_t;
#endif
#endif // __khrplatform_h_
#ifndef __gl_glcorearb_h_
#define __gl_glcorearb_h_ 1
#ifdef __cplusplus
extern "C" {
#endif
/*
** Copyright 2013-2020 The Khronos Group Inc.
** SPDX-License-Identifier: MIT
**
** This header is generated from the Khronos OpenGL / OpenGL ES XML
** API Registry. The current version of the Registry, generator scripts
** used to make the header, and the header can be found at
** https://github.com/KhronosGroup/OpenGL-Registry
*/
#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#include <windows.h>
#endif
#ifndef APIENTRY
#define APIENTRY
#endif
#ifndef APIENTRYP
#define APIENTRYP APIENTRY *
#endif
#ifndef GLAPI
#define GLAPI extern
#endif
/* glcorearb.h is for use with OpenGL core profile implementations.
** It should should be placed in the same directory as gl.h and
** included as <GL/glcorearb.h>.
**
** glcorearb.h includes only APIs in the latest OpenGL core profile
** implementation together with APIs in newer ARB extensions which
** can be supported by the core profile. It does not, and never will
** include functionality removed from the core profile, such as
** fixed-function vertex and fragment processing.
**
** Do not #include both <GL/glcorearb.h> and either of <GL/gl.h> or
** <GL/glext.h> in the same source file.
*/
/* Generated C header for:
* API: gl
* Profile: core
* Versions considered: .*
* Versions emitted: .*
* Default extensions included: glcore
* Additional extensions included: _nomatch_^
* Extensions removed: _nomatch_^
*/
#ifndef GL_VERSION_1_0
typedef void GLvoid;
typedef unsigned int GLenum;
typedef khronos_float_t GLfloat;
typedef int GLint;
typedef int GLsizei;
typedef unsigned int GLbitfield;
typedef double GLdouble;
typedef unsigned int GLuint;
typedef unsigned char GLboolean;
typedef khronos_uint8_t GLubyte;
#define GL_COLOR_BUFFER_BIT 0x00004000
#define GL_FALSE 0
#define GL_TRUE 1
#define GL_TRIANGLES 0x0004
#define GL_ONE 1
#define GL_SRC_ALPHA 0x0302
#define GL_ONE_MINUS_SRC_ALPHA 0x0303
#define GL_FRONT_AND_BACK 0x0408
#define GL_POLYGON_MODE 0x0B40
#define GL_CULL_FACE 0x0B44
#define GL_DEPTH_TEST 0x0B71
#define GL_STENCIL_TEST 0x0B90
#define GL_VIEWPORT 0x0BA2
#define GL_BLEND 0x0BE2
#define GL_SCISSOR_BOX 0x0C10
#define GL_SCISSOR_TEST 0x0C11
#define GL_UNPACK_ROW_LENGTH 0x0CF2
#define GL_PACK_ALIGNMENT 0x0D05
#define GL_TEXTURE_2D 0x0DE1
#define GL_UNSIGNED_BYTE 0x1401
#define GL_UNSIGNED_SHORT 0x1403
#define GL_UNSIGNED_INT 0x1405
#define GL_FLOAT 0x1406
#define GL_RGBA 0x1908
#define GL_FILL 0x1B02
#define GL_VERSION 0x1F02
#define GL_EXTENSIONS 0x1F03
#define GL_LINEAR 0x2601
#define GL_TEXTURE_MAG_FILTER 0x2800
#define GL_TEXTURE_MIN_FILTER 0x2801
typedef void (APIENTRYP PFNGLPOLYGONMODEPROC) (GLenum face, GLenum mode);
typedef void (APIENTRYP PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param);
typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
typedef void (APIENTRYP PFNGLCLEARPROC) (GLbitfield mask);
typedef void (APIENTRYP PFNGLCLEARCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
typedef void (APIENTRYP PFNGLDISABLEPROC) (GLenum cap);
typedef void (APIENTRYP PFNGLENABLEPROC) (GLenum cap);
typedef void (APIENTRYP PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param);
typedef void (APIENTRYP PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
typedef GLenum (APIENTRYP PFNGLGETERRORPROC) (void);
typedef void (APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *data);
typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGPROC) (GLenum name);
typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC) (GLenum cap);
typedef void (APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
#ifdef GL_GLEXT_PROTOTYPES
GLAPI void APIENTRY glPolygonMode (GLenum face, GLenum mode);
GLAPI void APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
GLAPI void APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
GLAPI void APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
GLAPI void APIENTRY glClear (GLbitfield mask);
GLAPI void APIENTRY glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
GLAPI void APIENTRY glDisable (GLenum cap);
GLAPI void APIENTRY glEnable (GLenum cap);
GLAPI void APIENTRY glPixelStorei (GLenum pname, GLint param);
GLAPI void APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
GLAPI GLenum APIENTRY glGetError (void);
GLAPI void APIENTRY glGetIntegerv (GLenum pname, GLint *data);
GLAPI const GLubyte *APIENTRY glGetString (GLenum name);
GLAPI GLboolean APIENTRY glIsEnabled (GLenum cap);
GLAPI void APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
#endif
#endif /* GL_VERSION_1_0 */
#ifndef GL_VERSION_1_1
typedef khronos_float_t GLclampf;
typedef double GLclampd;
#define GL_TEXTURE_BINDING_2D 0x8069
typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices);
typedef void (APIENTRYP PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture);
typedef void (APIENTRYP PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures);
typedef void (APIENTRYP PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures);
#ifdef GL_GLEXT_PROTOTYPES
GLAPI void APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices);
GLAPI void APIENTRY glBindTexture (GLenum target, GLuint texture);
GLAPI void APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures);
GLAPI void APIENTRY glGenTextures (GLsizei n, GLuint *textures);
#endif
#endif /* GL_VERSION_1_1 */
#ifndef GL_VERSION_1_3
#define GL_TEXTURE0 0x84C0
#define GL_ACTIVE_TEXTURE 0x84E0
typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
#ifdef GL_GLEXT_PROTOTYPES
GLAPI void APIENTRY glActiveTexture (GLenum texture);
#endif
#endif /* GL_VERSION_1_3 */
#ifndef GL_VERSION_1_4
#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_FUNC_ADD 0x8006
typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode);
#ifdef GL_GLEXT_PROTOTYPES
GLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
GLAPI void APIENTRY glBlendEquation (GLenum mode);
#endif
#endif /* GL_VERSION_1_4 */
#ifndef GL_VERSION_1_5
typedef khronos_ssize_t GLsizeiptr;
typedef khronos_intptr_t GLintptr;
#define GL_ARRAY_BUFFER 0x8892
#define GL_ELEMENT_ARRAY_BUFFER 0x8893
#define GL_ARRAY_BUFFER_BINDING 0x8894
#define GL_STREAM_DRAW 0x88E0
typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
#ifdef GL_GLEXT_PROTOTYPES
GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer);
GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers);
GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers);
GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
#endif
#endif /* GL_VERSION_1_5 */
#ifndef GL_VERSION_2_0
typedef char GLchar;
typedef khronos_int16_t GLshort;
typedef khronos_int8_t GLbyte;
typedef khronos_uint16_t GLushort;
#define GL_BLEND_EQUATION_RGB 0x8009
#define GL_BLEND_EQUATION_ALPHA 0x883D
#define GL_FRAGMENT_SHADER 0x8B30
#define GL_VERTEX_SHADER 0x8B31
#define GL_COMPILE_STATUS 0x8B81
#define GL_LINK_STATUS 0x8B82
#define GL_INFO_LOG_LENGTH 0x8B84
#define GL_CURRENT_PROGRAM 0x8B8D
#define GL_UPPER_LEFT 0x8CA2
typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);
typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader);
typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void);
typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);
typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader);
typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);
typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);
typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);
typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
#ifdef GL_GLEXT_PROTOTYPES
GLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
GLAPI void APIENTRY glAttachShader (GLuint program, GLuint shader);
GLAPI void APIENTRY glCompileShader (GLuint shader);
GLAPI GLuint APIENTRY glCreateProgram (void);
GLAPI GLuint APIENTRY glCreateShader (GLenum type);
GLAPI void APIENTRY glDeleteProgram (GLuint program);
GLAPI void APIENTRY glDeleteShader (GLuint shader);
GLAPI void APIENTRY glDetachShader (GLuint program, GLuint shader);
GLAPI void APIENTRY glEnableVertexAttribArray (GLuint index);
GLAPI GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name);
GLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params);
GLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
GLAPI void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params);
GLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
GLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name);
GLAPI void APIENTRY glLinkProgram (GLuint program);
GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
GLAPI void APIENTRY glUseProgram (GLuint program);
GLAPI void APIENTRY glUniform1i (GLint location, GLint v0);
GLAPI void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
#endif
#endif /* GL_VERSION_2_0 */
#ifndef GL_VERSION_3_0
typedef khronos_uint16_t GLhalf;
#define GL_MAJOR_VERSION 0x821B
#define GL_MINOR_VERSION 0x821C
#define GL_NUM_EXTENSIONS 0x821D
#define GL_FRAMEBUFFER_SRGB 0x8DB9
#define GL_VERTEX_ARRAY_BINDING 0x85B5
typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data);
typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data);
typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index);
typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array);
typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays);
typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);
#ifdef GL_GLEXT_PROTOTYPES
GLAPI const GLubyte *APIENTRY glGetStringi (GLenum name, GLuint index);
GLAPI void APIENTRY glBindVertexArray (GLuint array);
GLAPI void APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays);
GLAPI void APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays);
#endif
#endif /* GL_VERSION_3_0 */
#ifndef GL_VERSION_3_1
#define GL_VERSION_3_1 1
#define GL_PRIMITIVE_RESTART 0x8F9D
#endif /* GL_VERSION_3_1 */
#ifndef GL_VERSION_3_2
#define GL_VERSION_3_2 1
typedef struct __GLsync *GLsync;
typedef khronos_uint64_t GLuint64;
typedef khronos_int64_t GLint64;
typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data);
#ifdef GL_GLEXT_PROTOTYPES
GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
#endif
#endif /* GL_VERSION_3_2 */
#ifndef GL_VERSION_3_3
#define GL_VERSION_3_3 1
#define GL_SAMPLER_BINDING 0x8919
typedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler);
#ifdef GL_GLEXT_PROTOTYPES
GLAPI void APIENTRY glBindSampler (GLuint unit, GLuint sampler);
#endif
#endif /* GL_VERSION_3_3 */
#ifndef GL_VERSION_4_1
typedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data);
typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data);
#endif /* GL_VERSION_4_1 */
#ifndef GL_VERSION_4_3
typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
#endif /* GL_VERSION_4_3 */
#ifndef GL_VERSION_4_5
#define GL_CLIP_ORIGIN 0x935C
typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint *param);
typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI64_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint64 *param);
#endif /* GL_VERSION_4_5 */
#ifndef GL_ARB_bindless_texture
typedef khronos_uint64_t GLuint64EXT;
#endif /* GL_ARB_bindless_texture */
#ifndef GL_ARB_cl_event
struct _cl_context;
struct _cl_event;
#endif /* GL_ARB_cl_event */
#ifndef GL_ARB_clip_control
#define GL_ARB_clip_control 1
#endif /* GL_ARB_clip_control */
#ifndef GL_ARB_debug_output
typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
#endif /* GL_ARB_debug_output */
#ifndef GL_EXT_EGL_image_storage
typedef void *GLeglImageOES;
#endif /* GL_EXT_EGL_image_storage */
#ifndef GL_EXT_direct_state_access
typedef void (APIENTRYP PFNGLGETFLOATI_VEXTPROC) (GLenum pname, GLuint index, GLfloat *params);
typedef void (APIENTRYP PFNGLGETDOUBLEI_VEXTPROC) (GLenum pname, GLuint index, GLdouble *params);
typedef void (APIENTRYP PFNGLGETPOINTERI_VEXTPROC) (GLenum pname, GLuint index, void **params);
typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param);
typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, void **param);
#endif /* GL_EXT_direct_state_access */
#ifndef GL_NV_draw_vulkan_image
typedef void (APIENTRY *GLVULKANPROCNV)(void);
#endif /* GL_NV_draw_vulkan_image */
#ifndef GL_NV_gpu_shader5
typedef khronos_int64_t GLint64EXT;
#endif /* GL_NV_gpu_shader5 */
#ifndef GL_NV_vertex_buffer_unified_memory
typedef void (APIENTRYP PFNGLGETINTEGERUI64I_VNVPROC) (GLenum value, GLuint index, GLuint64EXT *result);
#endif /* GL_NV_vertex_buffer_unified_memory */
#ifdef __cplusplus
}
#endif
#endif
#ifndef GL3W_API
#define GL3W_API
#endif
#ifndef __gl_h_
#define __gl_h_
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define GL3W_OK 0
#define GL3W_ERROR_INIT -1
#define GL3W_ERROR_LIBRARY_OPEN -2
#define GL3W_ERROR_OPENGL_VERSION -3
typedef void (*GL3WglProc)(void);
typedef GL3WglProc (*GL3WGetProcAddressProc)(const char *proc);
/* gl3w api */
GL3W_API int imgl3wInit(void);
GL3W_API int imgl3wInit2(GL3WGetProcAddressProc proc);
GL3W_API int imgl3wIsSupported(int major, int minor);
GL3W_API GL3WglProc imgl3wGetProcAddress(const char *proc);
/* gl3w internal state */
union GL3WProcs {
GL3WglProc ptr[53];
struct {
PFNGLACTIVETEXTUREPROC ActiveTexture;
PFNGLATTACHSHADERPROC AttachShader;
PFNGLBINDBUFFERPROC BindBuffer;
PFNGLBINDSAMPLERPROC BindSampler;
PFNGLBINDTEXTUREPROC BindTexture;
PFNGLBINDVERTEXARRAYPROC BindVertexArray;
PFNGLBLENDEQUATIONPROC BlendEquation;
PFNGLBLENDEQUATIONSEPARATEPROC BlendEquationSeparate;
PFNGLBLENDFUNCSEPARATEPROC BlendFuncSeparate;
PFNGLBUFFERDATAPROC BufferData;
PFNGLCLEARPROC Clear;
PFNGLCLEARCOLORPROC ClearColor;
PFNGLCOMPILESHADERPROC CompileShader;
PFNGLCREATEPROGRAMPROC CreateProgram;
PFNGLCREATESHADERPROC CreateShader;
PFNGLDELETEBUFFERSPROC DeleteBuffers;
PFNGLDELETEPROGRAMPROC DeleteProgram;
PFNGLDELETESHADERPROC DeleteShader;
PFNGLDELETETEXTURESPROC DeleteTextures;
PFNGLDELETEVERTEXARRAYSPROC DeleteVertexArrays;
PFNGLDETACHSHADERPROC DetachShader;
PFNGLDISABLEPROC Disable;
PFNGLDRAWELEMENTSPROC DrawElements;
PFNGLDRAWELEMENTSBASEVERTEXPROC DrawElementsBaseVertex;
PFNGLENABLEPROC Enable;
PFNGLENABLEVERTEXATTRIBARRAYPROC EnableVertexAttribArray;
PFNGLGENBUFFERSPROC GenBuffers;
PFNGLGENTEXTURESPROC GenTextures;
PFNGLGENVERTEXARRAYSPROC GenVertexArrays;
PFNGLGETATTRIBLOCATIONPROC GetAttribLocation;
PFNGLGETERRORPROC GetError;
PFNGLGETINTEGERVPROC GetIntegerv;
PFNGLGETPROGRAMINFOLOGPROC GetProgramInfoLog;
PFNGLGETPROGRAMIVPROC GetProgramiv;
PFNGLGETSHADERINFOLOGPROC GetShaderInfoLog;
PFNGLGETSHADERIVPROC GetShaderiv;
PFNGLGETSTRINGPROC GetString;
PFNGLGETSTRINGIPROC GetStringi;
PFNGLGETUNIFORMLOCATIONPROC GetUniformLocation;
PFNGLISENABLEDPROC IsEnabled;
PFNGLLINKPROGRAMPROC LinkProgram;
PFNGLPIXELSTOREIPROC PixelStorei;
PFNGLPOLYGONMODEPROC PolygonMode;
PFNGLREADPIXELSPROC ReadPixels;
PFNGLSCISSORPROC Scissor;
PFNGLSHADERSOURCEPROC ShaderSource;
PFNGLTEXIMAGE2DPROC TexImage2D;
PFNGLTEXPARAMETERIPROC TexParameteri;
PFNGLUNIFORM1IPROC Uniform1i;
PFNGLUNIFORMMATRIX4FVPROC UniformMatrix4fv;
PFNGLUSEPROGRAMPROC UseProgram;
PFNGLVERTEXATTRIBPOINTERPROC VertexAttribPointer;
PFNGLVIEWPORTPROC Viewport;
} gl;
};
GL3W_API extern union GL3WProcs imgl3wProcs;
/* OpenGL functions */
#define glActiveTexture imgl3wProcs.gl.ActiveTexture
#define glAttachShader imgl3wProcs.gl.AttachShader
#define glBindBuffer imgl3wProcs.gl.BindBuffer
#define glBindSampler imgl3wProcs.gl.BindSampler
#define glBindTexture imgl3wProcs.gl.BindTexture
#define glBindVertexArray imgl3wProcs.gl.BindVertexArray
#define glBlendEquation imgl3wProcs.gl.BlendEquation
#define glBlendEquationSeparate imgl3wProcs.gl.BlendEquationSeparate
#define glBlendFuncSeparate imgl3wProcs.gl.BlendFuncSeparate
#define glBufferData imgl3wProcs.gl.BufferData
#define glClear imgl3wProcs.gl.Clear
#define glClearColor imgl3wProcs.gl.ClearColor
#define glCompileShader imgl3wProcs.gl.CompileShader
#define glCreateProgram imgl3wProcs.gl.CreateProgram
#define glCreateShader imgl3wProcs.gl.CreateShader
#define glDeleteBuffers imgl3wProcs.gl.DeleteBuffers
#define glDeleteProgram imgl3wProcs.gl.DeleteProgram
#define glDeleteShader imgl3wProcs.gl.DeleteShader
#define glDeleteTextures imgl3wProcs.gl.DeleteTextures
#define glDeleteVertexArrays imgl3wProcs.gl.DeleteVertexArrays
#define glDetachShader imgl3wProcs.gl.DetachShader
#define glDisable imgl3wProcs.gl.Disable
#define glDrawElements imgl3wProcs.gl.DrawElements
#define glDrawElementsBaseVertex imgl3wProcs.gl.DrawElementsBaseVertex
#define glEnable imgl3wProcs.gl.Enable
#define glEnableVertexAttribArray imgl3wProcs.gl.EnableVertexAttribArray
#define glGenBuffers imgl3wProcs.gl.GenBuffers
#define glGenTextures imgl3wProcs.gl.GenTextures
#define glGenVertexArrays imgl3wProcs.gl.GenVertexArrays
#define glGetAttribLocation imgl3wProcs.gl.GetAttribLocation
#define glGetError imgl3wProcs.gl.GetError
#define glGetIntegerv imgl3wProcs.gl.GetIntegerv
#define glGetProgramInfoLog imgl3wProcs.gl.GetProgramInfoLog
#define glGetProgramiv imgl3wProcs.gl.GetProgramiv
#define glGetShaderInfoLog imgl3wProcs.gl.GetShaderInfoLog
#define glGetShaderiv imgl3wProcs.gl.GetShaderiv
#define glGetString imgl3wProcs.gl.GetString
#define glGetStringi imgl3wProcs.gl.GetStringi
#define glGetUniformLocation imgl3wProcs.gl.GetUniformLocation
#define glIsEnabled imgl3wProcs.gl.IsEnabled
#define glLinkProgram imgl3wProcs.gl.LinkProgram
#define glPixelStorei imgl3wProcs.gl.PixelStorei
#define glPolygonMode imgl3wProcs.gl.PolygonMode
#define glReadPixels imgl3wProcs.gl.ReadPixels
#define glScissor imgl3wProcs.gl.Scissor
#define glShaderSource imgl3wProcs.gl.ShaderSource
#define glTexImage2D imgl3wProcs.gl.TexImage2D
#define glTexParameteri imgl3wProcs.gl.TexParameteri
#define glUniform1i imgl3wProcs.gl.Uniform1i
#define glUniformMatrix4fv imgl3wProcs.gl.UniformMatrix4fv
#define glUseProgram imgl3wProcs.gl.UseProgram
#define glVertexAttribPointer imgl3wProcs.gl.VertexAttribPointer
#define glViewport imgl3wProcs.gl.Viewport
#ifdef __cplusplus
}
#endif
#endif
#ifdef IMGL3W_IMPL
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#if defined(_WIN32)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#include <windows.h>
static HMODULE libgl;
typedef PROC(__stdcall* GL3WglGetProcAddr)(LPCSTR);
static GL3WglGetProcAddr wgl_get_proc_address;
static int open_libgl(void)
{
libgl = LoadLibraryA("opengl32.dll");
if (!libgl)
return GL3W_ERROR_LIBRARY_OPEN;
wgl_get_proc_address = (GL3WglGetProcAddr)GetProcAddress(libgl, "wglGetProcAddress");
return GL3W_OK;
}
static void close_libgl(void) { FreeLibrary(libgl); }
static GL3WglProc get_proc(const char *proc)
{
GL3WglProc res;
res = (GL3WglProc)wgl_get_proc_address(proc);
if (!res)
res = (GL3WglProc)GetProcAddress(libgl, proc);
return res;
}
#elif defined(__APPLE__)
#include <dlfcn.h>
static void *libgl;
static int open_libgl(void)
{
libgl = dlopen("/System/Library/Frameworks/OpenGL.framework/OpenGL", RTLD_LAZY | RTLD_LOCAL);
if (!libgl)
return GL3W_ERROR_LIBRARY_OPEN;
return GL3W_OK;
}
static void close_libgl(void) { dlclose(libgl); }
static GL3WglProc get_proc(const char *proc)
{
GL3WglProc res;
*(void **)(&res) = dlsym(libgl, proc);
return res;
}
#else
#include <dlfcn.h>
static void *libgl;
static GL3WglProc (*glx_get_proc_address)(const GLubyte *);
static int open_libgl(void)
{
libgl = dlopen("libGL.so.1", RTLD_LAZY | RTLD_LOCAL);
if (!libgl)
return GL3W_ERROR_LIBRARY_OPEN;
*(void **)(&glx_get_proc_address) = dlsym(libgl, "glXGetProcAddressARB");
return GL3W_OK;
}
static void close_libgl(void) { dlclose(libgl); }
static GL3WglProc get_proc(const char *proc)
{
GL3WglProc res;
res = glx_get_proc_address((const GLubyte *)proc);
if (!res)
*(void **)(&res) = dlsym(libgl, proc);
return res;
}
#endif
static struct { int major, minor; } version;
static int parse_version(void)
{
if (!glGetIntegerv)
return GL3W_ERROR_INIT;
glGetIntegerv(GL_MAJOR_VERSION, &version.major);
glGetIntegerv(GL_MINOR_VERSION, &version.minor);
if (version.major < 3)
return GL3W_ERROR_OPENGL_VERSION;
return GL3W_OK;
}
static void load_procs(GL3WGetProcAddressProc proc);
int imgl3wInit(void)
{
int res = open_libgl();
if (res)
return res;
atexit(close_libgl);
return imgl3wInit2(get_proc);
}
int imgl3wInit2(GL3WGetProcAddressProc proc)
{
load_procs(proc);
return parse_version();
}
int imgl3wIsSupported(int major, int minor)
{
if (major < 3)
return 0;
if (version.major == major)
return version.minor >= minor;
return version.major >= major;
}
GL3WglProc imgl3wGetProcAddress(const char *proc) { return get_proc(proc); }
static const char *proc_names[] = {
"glActiveTexture",
"glAttachShader",
"glBindBuffer",
"glBindSampler",
"glBindTexture",
"glBindVertexArray",
"glBlendEquation",
"glBlendEquationSeparate",
"glBlendFuncSeparate",
"glBufferData",
"glClear",
"glClearColor",
"glCompileShader",
"glCreateProgram",
"glCreateShader",
"glDeleteBuffers",
"glDeleteProgram",
"glDeleteShader",
"glDeleteTextures",
"glDeleteVertexArrays",
"glDetachShader",
"glDisable",
"glDrawElements",
"glDrawElementsBaseVertex",
"glEnable",
"glEnableVertexAttribArray",
"glGenBuffers",
"glGenTextures",
"glGenVertexArrays",
"glGetAttribLocation",
"glGetError",
"glGetIntegerv",
"glGetProgramInfoLog",
"glGetProgramiv",
"glGetShaderInfoLog",
"glGetShaderiv",
"glGetString",
"glGetStringi",
"glGetUniformLocation",
"glIsEnabled",
"glLinkProgram",
"glPixelStorei",
"glPolygonMode",
"glReadPixels",
"glScissor",
"glShaderSource",
"glTexImage2D",
"glTexParameteri",
"glUniform1i",
"glUniformMatrix4fv",
"glUseProgram",
"glVertexAttribPointer",
"glViewport",
};
GL3W_API union GL3WProcs imgl3wProcs;
static void load_procs(GL3WGetProcAddressProc proc)
{
size_t i;
for (i = 0; i < ARRAY_SIZE(proc_names); i++)
imgl3wProcs.ptr[i] = proc(proc_names[i]);
}
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,24 +0,0 @@
// dear imgui: Platform Backend for OSX / Cocoa
// This needs to be used along with a Renderer (e.g. OpenGL2, OpenGL3, Vulkan, Metal..)
// [ALPHA] Early backend, not well tested. If you want a portable application, prefer using the GLFW or SDL platform Backends on Mac.
// Implemented features:
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend).
// Issues:
// [ ] Platform: Keys are all generally very broken. Best using [event keycode] and not [event characters]..
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#include "imgui.h" // IMGUI_IMPL_API
@class NSEvent;
@class NSView;
IMGUI_IMPL_API bool ImGui_ImplOSX_Init();
IMGUI_IMPL_API void ImGui_ImplOSX_Shutdown();
IMGUI_IMPL_API void ImGui_ImplOSX_NewFrame(NSView* _Nullable view);
IMGUI_IMPL_API bool ImGui_ImplOSX_HandleEvent(NSEvent* _Nonnull event, NSView* _Nullable view);

View file

@ -1,369 +0,0 @@
// dear imgui: Platform Backend for OSX / Cocoa
// This needs to be used along with a Renderer (e.g. OpenGL2, OpenGL3, Vulkan, Metal..)
// [ALPHA] Early backend, not well tested. If you want a portable application, prefer using the GLFW or SDL platform Backends on Mac.
// Implemented features:
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend).
// Issues:
// [ ] Platform: Keys are all generally very broken. Best using [event keycode] and not [event characters]..
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#include "imgui.h"
#include "imgui_impl_osx.h"
#import <Cocoa/Cocoa.h>
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-08-17: Calling io.AddFocusEvent() on NSApplicationDidBecomeActiveNotification/NSApplicationDidResignActiveNotification events.
// 2021-06-23: Inputs: Added a fix for shortcuts using CTRL key instead of CMD key.
// 2021-04-19: Inputs: Added a fix for keys remaining stuck in pressed state when CMD-tabbing into different application.
// 2021-01-27: Inputs: Added a fix for mouse position not being reported when mouse buttons other than left one are down.
// 2020-10-28: Inputs: Added a fix for handling keypad-enter key.
// 2020-05-25: Inputs: Added a fix for missing trackpad clicks when done with "soft tap".
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
// 2019-10-11: Inputs: Fix using Backspace key.
// 2019-07-21: Re-added clipboard handlers as they are not enabled by default in core imgui.cpp (reverted 2019-05-18 change).
// 2019-05-28: Inputs: Added mouse cursor shape and visibility support.
// 2019-05-18: Misc: Removed clipboard handlers as they are now supported by core imgui.cpp.
// 2019-05-11: Inputs: Don't filter character values before calling AddInputCharacter() apart from 0xF700..0xFFFF range.
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
// 2018-07-07: Initial version.
@class ImFocusObserver;
// Data
static CFAbsoluteTime g_Time = 0.0;
static NSCursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = {};
static bool g_MouseCursorHidden = false;
static bool g_MouseJustPressed[ImGuiMouseButton_COUNT] = {};
static bool g_MouseDown[ImGuiMouseButton_COUNT] = {};
static ImFocusObserver* g_FocusObserver = NULL;
// Undocumented methods for creating cursors.
@interface NSCursor()
+ (id)_windowResizeNorthWestSouthEastCursor;
+ (id)_windowResizeNorthEastSouthWestCursor;
+ (id)_windowResizeNorthSouthCursor;
+ (id)_windowResizeEastWestCursor;
@end
static void resetKeys()
{
ImGuiIO& io = ImGui::GetIO();
memset(io.KeysDown, 0, sizeof(io.KeysDown));
io.KeyCtrl = io.KeyShift = io.KeyAlt = io.KeySuper = false;
}
@interface ImFocusObserver : NSObject
- (void)onApplicationBecomeActive:(NSNotification*)aNotification;
- (void)onApplicationBecomeInactive:(NSNotification*)aNotification;
@end
@implementation ImFocusObserver
- (void)onApplicationBecomeActive:(NSNotification*)aNotification
{
ImGuiIO& io = ImGui::GetIO();
io.AddFocusEvent(true);
}
- (void)onApplicationBecomeInactive:(NSNotification*)aNotification
{
ImGuiIO& io = ImGui::GetIO();
io.AddFocusEvent(false);
// Unfocused applications do not receive input events, therefore we must manually
// release any pressed keys when application loses focus, otherwise they would remain
// stuck in a pressed state. https://github.com/ocornut/imgui/issues/3832
resetKeys();
}
@end
// Functions
bool ImGui_ImplOSX_Init()
{
ImGuiIO& io = ImGui::GetIO();
// Setup backend capabilities flags
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
//io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
//io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
//io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can set io.MouseHoveredViewport correctly (optional, not easy)
io.BackendPlatformName = "imgui_impl_osx";
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeyDown[] array.
const int offset_for_function_keys = 256 - 0xF700;
io.KeyMap[ImGuiKey_Tab] = '\t';
io.KeyMap[ImGuiKey_LeftArrow] = NSLeftArrowFunctionKey + offset_for_function_keys;
io.KeyMap[ImGuiKey_RightArrow] = NSRightArrowFunctionKey + offset_for_function_keys;
io.KeyMap[ImGuiKey_UpArrow] = NSUpArrowFunctionKey + offset_for_function_keys;
io.KeyMap[ImGuiKey_DownArrow] = NSDownArrowFunctionKey + offset_for_function_keys;
io.KeyMap[ImGuiKey_PageUp] = NSPageUpFunctionKey + offset_for_function_keys;
io.KeyMap[ImGuiKey_PageDown] = NSPageDownFunctionKey + offset_for_function_keys;
io.KeyMap[ImGuiKey_Home] = NSHomeFunctionKey + offset_for_function_keys;
io.KeyMap[ImGuiKey_End] = NSEndFunctionKey + offset_for_function_keys;
io.KeyMap[ImGuiKey_Insert] = NSInsertFunctionKey + offset_for_function_keys;
io.KeyMap[ImGuiKey_Delete] = NSDeleteFunctionKey + offset_for_function_keys;
io.KeyMap[ImGuiKey_Backspace] = 127;
io.KeyMap[ImGuiKey_Space] = 32;
io.KeyMap[ImGuiKey_Enter] = 13;
io.KeyMap[ImGuiKey_Escape] = 27;
io.KeyMap[ImGuiKey_KeyPadEnter] = 3;
io.KeyMap[ImGuiKey_A] = 'A';
io.KeyMap[ImGuiKey_C] = 'C';
io.KeyMap[ImGuiKey_V] = 'V';
io.KeyMap[ImGuiKey_X] = 'X';
io.KeyMap[ImGuiKey_Y] = 'Y';
io.KeyMap[ImGuiKey_Z] = 'Z';
// Load cursors. Some of them are undocumented.
g_MouseCursorHidden = false;
g_MouseCursors[ImGuiMouseCursor_Arrow] = [NSCursor arrowCursor];
g_MouseCursors[ImGuiMouseCursor_TextInput] = [NSCursor IBeamCursor];
g_MouseCursors[ImGuiMouseCursor_ResizeAll] = [NSCursor closedHandCursor];
g_MouseCursors[ImGuiMouseCursor_Hand] = [NSCursor pointingHandCursor];
g_MouseCursors[ImGuiMouseCursor_NotAllowed] = [NSCursor operationNotAllowedCursor];
g_MouseCursors[ImGuiMouseCursor_ResizeNS] = [NSCursor respondsToSelector:@selector(_windowResizeNorthSouthCursor)] ? [NSCursor _windowResizeNorthSouthCursor] : [NSCursor resizeUpDownCursor];
g_MouseCursors[ImGuiMouseCursor_ResizeEW] = [NSCursor respondsToSelector:@selector(_windowResizeEastWestCursor)] ? [NSCursor _windowResizeEastWestCursor] : [NSCursor resizeLeftRightCursor];
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = [NSCursor respondsToSelector:@selector(_windowResizeNorthEastSouthWestCursor)] ? [NSCursor _windowResizeNorthEastSouthWestCursor] : [NSCursor closedHandCursor];
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = [NSCursor respondsToSelector:@selector(_windowResizeNorthWestSouthEastCursor)] ? [NSCursor _windowResizeNorthWestSouthEastCursor] : [NSCursor closedHandCursor];
// Note that imgui.cpp also include default OSX clipboard handlers which can be enabled
// by adding '#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS' in imconfig.h and adding '-framework ApplicationServices' to your linker command-line.
// Since we are already in ObjC land here, it is easy for us to add a clipboard handler using the NSPasteboard api.
io.SetClipboardTextFn = [](void*, const char* str) -> void
{
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
[pasteboard declareTypes:[NSArray arrayWithObject:NSPasteboardTypeString] owner:nil];
[pasteboard setString:[NSString stringWithUTF8String:str] forType:NSPasteboardTypeString];
};
io.GetClipboardTextFn = [](void*) -> const char*
{
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
NSString* available = [pasteboard availableTypeFromArray: [NSArray arrayWithObject:NSPasteboardTypeString]];
if (![available isEqualToString:NSPasteboardTypeString])
return NULL;
NSString* string = [pasteboard stringForType:NSPasteboardTypeString];
if (string == nil)
return NULL;
const char* string_c = (const char*)[string UTF8String];
size_t string_len = strlen(string_c);
static ImVector<char> s_clipboard;
s_clipboard.resize((int)string_len + 1);
strcpy(s_clipboard.Data, string_c);
return s_clipboard.Data;
};
g_FocusObserver = [[ImFocusObserver alloc] init];
[[NSNotificationCenter defaultCenter] addObserver:g_FocusObserver
selector:@selector(onApplicationBecomeActive:)
name:NSApplicationDidBecomeActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:g_FocusObserver
selector:@selector(onApplicationBecomeInactive:)
name:NSApplicationDidResignActiveNotification
object:nil];
return true;
}
void ImGui_ImplOSX_Shutdown()
{
g_FocusObserver = NULL;
}
static void ImGui_ImplOSX_UpdateMouseCursorAndButtons()
{
// Update buttons
ImGuiIO& io = ImGui::GetIO();
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
{
// If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
io.MouseDown[i] = g_MouseJustPressed[i] || g_MouseDown[i];
g_MouseJustPressed[i] = false;
}
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
return;
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
{
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
if (!g_MouseCursorHidden)
{
g_MouseCursorHidden = true;
[NSCursor hide];
}
}
else
{
// Show OS mouse cursor
[g_MouseCursors[g_MouseCursors[imgui_cursor] ? imgui_cursor : ImGuiMouseCursor_Arrow] set];
if (g_MouseCursorHidden)
{
g_MouseCursorHidden = false;
[NSCursor unhide];
}
}
}
void ImGui_ImplOSX_NewFrame(NSView* view)
{
// Setup display size
ImGuiIO& io = ImGui::GetIO();
if (view)
{
const float dpi = (float)[view.window backingScaleFactor];
io.DisplaySize = ImVec2((float)view.bounds.size.width, (float)view.bounds.size.height);
io.DisplayFramebufferScale = ImVec2(dpi, dpi);
}
// Setup time step
if (g_Time == 0.0)
g_Time = CFAbsoluteTimeGetCurrent();
CFAbsoluteTime current_time = CFAbsoluteTimeGetCurrent();
io.DeltaTime = (float)(current_time - g_Time);
g_Time = current_time;
ImGui_ImplOSX_UpdateMouseCursorAndButtons();
}
static int mapCharacterToKey(int c)
{
if (c >= 'a' && c <= 'z')
return c - 'a' + 'A';
if (c == 25) // SHIFT+TAB -> TAB
return 9;
if (c >= 0 && c < 256)
return c;
if (c >= 0xF700 && c < 0xF700 + 256)
return c - 0xF700 + 256;
return -1;
}
bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view)
{
ImGuiIO& io = ImGui::GetIO();
if (event.type == NSEventTypeLeftMouseDown || event.type == NSEventTypeRightMouseDown || event.type == NSEventTypeOtherMouseDown)
{
int button = (int)[event buttonNumber];
if (button >= 0 && button < IM_ARRAYSIZE(g_MouseDown))
g_MouseDown[button] = g_MouseJustPressed[button] = true;
return io.WantCaptureMouse;
}
if (event.type == NSEventTypeLeftMouseUp || event.type == NSEventTypeRightMouseUp || event.type == NSEventTypeOtherMouseUp)
{
int button = (int)[event buttonNumber];
if (button >= 0 && button < IM_ARRAYSIZE(g_MouseDown))
g_MouseDown[button] = false;
return io.WantCaptureMouse;
}
if (event.type == NSEventTypeMouseMoved || event.type == NSEventTypeLeftMouseDragged || event.type == NSEventTypeRightMouseDragged || event.type == NSEventTypeOtherMouseDragged)
{
NSPoint mousePoint = event.locationInWindow;
mousePoint = [view convertPoint:mousePoint fromView:nil];
mousePoint = NSMakePoint(mousePoint.x, view.bounds.size.height - mousePoint.y);
io.MousePos = ImVec2((float)mousePoint.x, (float)mousePoint.y);
}
if (event.type == NSEventTypeScrollWheel)
{
double wheel_dx = 0.0;
double wheel_dy = 0.0;
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6)
{
wheel_dx = [event scrollingDeltaX];
wheel_dy = [event scrollingDeltaY];
if ([event hasPreciseScrollingDeltas])
{
wheel_dx *= 0.1;
wheel_dy *= 0.1;
}
}
else
#endif // MAC_OS_X_VERSION_MAX_ALLOWED
{
wheel_dx = [event deltaX];
wheel_dy = [event deltaY];
}
if (fabs(wheel_dx) > 0.0)
io.MouseWheelH += (float)wheel_dx * 0.1f;
if (fabs(wheel_dy) > 0.0)
io.MouseWheel += (float)wheel_dy * 0.1f;
return io.WantCaptureMouse;
}
// FIXME: All the key handling is wrong and broken. Refer to GLFW's cocoa_init.mm and cocoa_window.mm.
if (event.type == NSEventTypeKeyDown)
{
NSString* str = [event characters];
NSUInteger len = [str length];
for (NSUInteger i = 0; i < len; i++)
{
int c = [str characterAtIndex:i];
if (!io.KeySuper && !(c >= 0xF700 && c <= 0xFFFF) && c != 127)
io.AddInputCharacter((unsigned int)c);
// We must reset in case we're pressing a sequence of special keys while keeping the command pressed
int key = mapCharacterToKey(c);
if (key != -1 && key < 256 && !io.KeySuper)
resetKeys();
if (key != -1)
io.KeysDown[key] = true;
}
return io.WantCaptureKeyboard;
}
if (event.type == NSEventTypeKeyUp)
{
NSString* str = [event characters];
NSUInteger len = [str length];
for (NSUInteger i = 0; i < len; i++)
{
int c = [str characterAtIndex:i];
int key = mapCharacterToKey(c);
if (key != -1)
io.KeysDown[key] = false;
}
return io.WantCaptureKeyboard;
}
if (event.type == NSEventTypeFlagsChanged)
{
unsigned int flags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
bool oldKeyCtrl = io.KeyCtrl;
bool oldKeyShift = io.KeyShift;
bool oldKeyAlt = io.KeyAlt;
bool oldKeySuper = io.KeySuper;
io.KeyCtrl = flags & NSEventModifierFlagControl;
io.KeyShift = flags & NSEventModifierFlagShift;
io.KeyAlt = flags & NSEventModifierFlagOption;
io.KeySuper = flags & NSEventModifierFlagCommand;
// We must reset them as we will not receive any keyUp event if they where pressed with a modifier
if ((oldKeyShift && !io.KeyShift) || (oldKeyCtrl && !io.KeyCtrl) || (oldKeyAlt && !io.KeyAlt) || (oldKeySuper && !io.KeySuper))
resetKeys();
return io.WantCaptureKeyboard;
}
return false;
}

Some files were not shown because too many files have changed in this diff Show more