begin cleanup from other project
This commit is contained in:
commit
9e47fdd28e
35
.gitignore
vendored
Normal file
35
.gitignore
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
|
||||
tview
|
91
Makefile
Normal file
91
Makefile
Normal file
@ -0,0 +1,91 @@
|
||||
#
|
||||
# Cross Platform Makefile
|
||||
# Compatible with MSYS2/MINGW, Ubuntu 14.04.1 and Mac OS X
|
||||
#
|
||||
# You will need SDL2 (http://www.libsdl.org):
|
||||
# Linux:
|
||||
# apt-get install libsdl2-dev
|
||||
# Mac OS X:
|
||||
# brew install sdl2
|
||||
# MSYS2:
|
||||
# pacman -S mingw-w64-i686-SDL2
|
||||
#
|
||||
|
||||
#CXX = g++
|
||||
#CXX = clang++
|
||||
|
||||
EXE = ppdnode
|
||||
IMGUI_DIR = lib
|
||||
SOURCES = main.cpp
|
||||
SOURCES += $(wildcard $(IMGUI_DIR)/*.cpp)
|
||||
SOURCES += $(wildcard $(IMGUI_DIR)/backends/*.cpp)
|
||||
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
|
||||
UNAME_S := $(shell uname -s)
|
||||
LINUX_GL_LIBS = -lGL
|
||||
|
||||
CXXFLAGS = -std=c++20 -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends
|
||||
CXXFLAGS += -g -DIMGUI_DEFINE_MATH_OPERATORS -Ofast
|
||||
LIBS =
|
||||
|
||||
##---------------------------------------------------------------------
|
||||
## OPENGL ES
|
||||
##---------------------------------------------------------------------
|
||||
|
||||
## This assumes a GL ES library available in the system, e.g. libGLESv2.so
|
||||
# CXXFLAGS += -DIMGUI_IMPL_OPENGL_ES2
|
||||
# LINUX_GL_LIBS = -lGLESv2
|
||||
## If you're on a Raspberry Pi and want to use the legacy drivers,
|
||||
## use the following instead:
|
||||
# LINUX_GL_LIBS = -L/opt/vc/lib -lbrcmGLESv2
|
||||
|
||||
##---------------------------------------------------------------------
|
||||
## BUILD FLAGS PER PLATFORM
|
||||
##---------------------------------------------------------------------
|
||||
|
||||
ifeq ($(UNAME_S), Linux) #LINUX
|
||||
ECHO_MESSAGE = "Linux"
|
||||
LIBS += $(LINUX_GL_LIBS) -ldl `sdl2-config --libs`
|
||||
|
||||
CXXFLAGS += `sdl2-config --cflags`
|
||||
CFLAGS = $(CXXFLAGS)
|
||||
endif
|
||||
|
||||
ifeq ($(UNAME_S), Darwin) #APPLE
|
||||
ECHO_MESSAGE = "Mac OS X"
|
||||
LIBS += -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo `sdl2-config --libs`
|
||||
LIBS += -L/usr/local/lib -L/opt/local/lib
|
||||
|
||||
CXXFLAGS += `sdl2-config --cflags`
|
||||
CXXFLAGS += -I/usr/local/include -I/opt/local/include
|
||||
CFLAGS = $(CXXFLAGS)
|
||||
endif
|
||||
|
||||
ifeq ($(OS), Windows_NT)
|
||||
ECHO_MESSAGE = "MinGW"
|
||||
LIBS += -lgdi32 -lopengl32 -limm32 `pkg-config --static --libs sdl2`
|
||||
|
||||
CXXFLAGS += `pkg-config --cflags sdl2`
|
||||
CFLAGS = $(CXXFLAGS)
|
||||
endif
|
||||
|
||||
##---------------------------------------------------------------------
|
||||
## BUILD RULES
|
||||
##---------------------------------------------------------------------
|
||||
|
||||
%.o:%.cpp
|
||||
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
%.o:$(IMGUI_DIR)/%.cpp
|
||||
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
%.o:$(IMGUI_DIR)/backends/%.cpp
|
||||
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
all: $(EXE)
|
||||
@echo Build complete for $(ECHO_MESSAGE)
|
||||
|
||||
$(EXE): $(OBJS)
|
||||
$(CXX) -o $@ $^ $(CXXFLAGS) $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -f $(EXE) $(OBJS)
|
92
Makefile.emscripten
Normal file
92
Makefile.emscripten
Normal file
@ -0,0 +1,92 @@
|
||||
#
|
||||
# Makefile to use with SDL+emscripten
|
||||
# See https://emscripten.org/docs/getting_started/downloads.html
|
||||
# for installation instructions.
|
||||
#
|
||||
# This Makefile assumes you have loaded emscripten's environment.
|
||||
# (On Windows, you may need to execute emsdk_env.bat or encmdprompt.bat ahead)
|
||||
#
|
||||
# Running `make -f Makefile.emscripten` will produce three files:
|
||||
# - web/index.html
|
||||
# - web/index.js
|
||||
# - web/index.wasm
|
||||
#
|
||||
# All three are needed to run the demo.
|
||||
|
||||
CC = emcc
|
||||
CXX = em++
|
||||
WEB_DIR = web
|
||||
EXE = $(WEB_DIR)/index.html
|
||||
IMGUI_DIR = lib
|
||||
SOURCES = main.cpp
|
||||
SOURCES += $(wildcard $(IMGUI_DIR)/*.cpp)
|
||||
SOURCES += $(wildcard $(IMGUI_DIR)/backends/*.cpp)
|
||||
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
|
||||
UNAME_S := $(shell uname -s)
|
||||
CPPFLAGS = -std=c++20 -DIMGUI_DEFINE_MATH_OPERATORS
|
||||
LDFLAGS =
|
||||
EMS =
|
||||
|
||||
##---------------------------------------------------------------------
|
||||
## EMSCRIPTEN OPTIONS
|
||||
##---------------------------------------------------------------------
|
||||
|
||||
# ("EMS" options gets added to both CPPFLAGS and LDFLAGS, whereas some options are for linker only)
|
||||
EMS += -s USE_SDL=2 -flto -O2
|
||||
EMS += -s DISABLE_EXCEPTION_CATCHING=1
|
||||
LDFLAGS += -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s NO_EXIT_RUNTIME=0 -s ASSERTIONS=1 -sEXPORTED_FUNCTIONS=[_main,_malloc,_free] -sEXPORTED_RUNTIME_METHODS=[ccall]
|
||||
|
||||
# Uncomment next line to fix possible rendering bugs with Emscripten version older then 1.39.0 (https://github.com/ocornut/imgui/issues/2877)
|
||||
#EMS += -s BINARYEN_TRAP_MODE=clamp
|
||||
#EMS += -s SAFE_HEAP=1 ## Adds overhead
|
||||
|
||||
# Emscripten allows preloading a file or folder to be accessible at runtime.
|
||||
# The Makefile for this example project suggests embedding the misc/fonts/ folder into our application, it will then be accessible as "/fonts"
|
||||
# See documentation for more details: https://emscripten.org/docs/porting/files/packaging_files.html
|
||||
# (Default value is 0. Set to 1 to enable file-system and include the misc/fonts/ folder as part of the build.)
|
||||
USE_FILE_SYSTEM ?= 0
|
||||
ifeq ($(USE_FILE_SYSTEM), 0)
|
||||
LDFLAGS += -s NO_FILESYSTEM=1
|
||||
CPPFLAGS += -DIMGUI_DISABLE_FILE_FUNCTIONS
|
||||
endif
|
||||
ifeq ($(USE_FILE_SYSTEM), 1)
|
||||
LDFLAGS += --no-heap-copy --preload-file ../../misc/fonts@/fonts
|
||||
endif
|
||||
|
||||
##---------------------------------------------------------------------
|
||||
## FINAL BUILD FLAGS
|
||||
##---------------------------------------------------------------------
|
||||
|
||||
CPPFLAGS += -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends
|
||||
#CPPFLAGS += -g
|
||||
CPPFLAGS += -Os $(EMS)
|
||||
LDFLAGS += --shell-file lib/emscripten/shell_minimal.html
|
||||
LDFLAGS += $(EMS)
|
||||
|
||||
##---------------------------------------------------------------------
|
||||
## BUILD RULES
|
||||
##---------------------------------------------------------------------
|
||||
|
||||
%.o:%.cpp
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
%.o:$(IMGUI_DIR)/%.cpp
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
%.o:$(IMGUI_DIR)/backends/%.cpp
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
all: $(EXE)
|
||||
@echo Build complete for $(EXE)
|
||||
|
||||
$(WEB_DIR):
|
||||
mkdir $@
|
||||
|
||||
serve: all
|
||||
python3 -m http.server -d $(WEB_DIR)
|
||||
|
||||
$(EXE): clean $(OBJS) $(WEB_DIR)
|
||||
$(CXX) -o $@ $(OBJS) $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJS) $(WEB_DIR)
|
57
README.md
Normal file
57
README.md
Normal file
@ -0,0 +1,57 @@
|
||||
|
||||
# How to Build
|
||||
|
||||
## Windows with Visual Studio's IDE
|
||||
|
||||
Use the provided project file (.vcxproj). Add to solution (imgui_examples.sln) if necessary.
|
||||
|
||||
## Windows with Visual Studio's CLI
|
||||
|
||||
Use build_win32.bat or directly:
|
||||
```
|
||||
set SDL2_DIR=path_to_your_sdl2_folder
|
||||
cl /Zi /MD /utf-8 /I.. /I..\.. /I%SDL2_DIR%\include main.cpp ..\..\backends\imgui_impl_sdl2.cpp ..\..\backends\imgui_impl_opengl3.cpp ..\..\imgui*.cpp /FeDebug/example_sdl2_opengl3.exe /FoDebug/ /link /libpath:%SDL2_DIR%\lib\x86 SDL2.lib SDL2main.lib opengl32.lib /subsystem:console
|
||||
# ^^ include paths ^^ source files ^^ output exe ^^ output dir ^^ libraries
|
||||
# or for 64-bit:
|
||||
cl /Zi /MD /utf-8 /I.. /I..\.. /I%SDL2_DIR%\include main.cpp ..\..\backends\imgui_impl_sdl2.cpp ..\..\backends\imgui_impl_opengl3.cpp ..\..\imgui*.cpp /FeDebug/example_sdl2_opengl3.exe /FoDebug/ /link /libpath:%SDL2_DIR%\lib\x64 SDL2.lib SDL2main.lib opengl32.lib /subsystem:console
|
||||
```
|
||||
|
||||
## Linux and similar Unixes
|
||||
|
||||
Use our Makefile or directly:
|
||||
```
|
||||
c++ `sdl2-config --cflags` -I .. -I ../.. -I ../../backends
|
||||
main.cpp ../../backends/imgui_impl_sdl2.cpp ../../backends/imgui_impl_opengl3.cpp ../../imgui*.cpp
|
||||
`sdl2-config --libs` -lGL -ldl
|
||||
```
|
||||
|
||||
## macOS
|
||||
|
||||
Use our Makefile or directly:
|
||||
```
|
||||
brew install sdl2
|
||||
c++ `sdl2-config --cflags` -I .. -I ../.. -I ../../backends
|
||||
main.cpp ../../backends/imgui_impl_sdl2.cpp ../../backends/imgui_impl_opengl3.cpp ../../imgui*.cpp
|
||||
`sdl2-config --libs` -framework OpenGl -framework CoreFoundation
|
||||
```
|
||||
|
||||
## Emscripten
|
||||
|
||||
**Building**
|
||||
|
||||
You need to install Emscripten from https://emscripten.org/docs/getting_started/downloads.html, and have the environment variables set, as described in https://emscripten.org/docs/getting_started/downloads.html#installation-instructions
|
||||
|
||||
- Depending on your configuration, in Windows you may need to run `emsdk/emsdk_env.bat` in your console to access the Emscripten command-line tools.
|
||||
- You may also refer to our [Continuous Integration setup](https://github.com/ocornut/imgui/tree/master/.github/workflows) for Emscripten setup.
|
||||
- Then build using `make -f Makefile.emscripten` while in the current directory.
|
||||
|
||||
**Running an Emscripten project**
|
||||
|
||||
To run on a local machine:
|
||||
- `make -f Makefile.emscripten serve` will use Python3 to spawn a local webserver, you can then browse http://localhost:8000 to access your build.
|
||||
- Otherwise, generally you will need a local webserver. Quoting [https://emscripten.org/docs/getting_started](https://emscripten.org/docs/getting_started/Tutorial.html#generating-html):<br>
|
||||
_"Unfortunately several browsers (including Chrome, Safari, and Internet Explorer) do not support file:// [XHR](https://emscripten.org/docs/site/glossary.html#term-xhr) requests, and can’t load extra files needed by the HTML (like a .wasm file, or packaged file data as mentioned lower down). For these browsers you’ll need to serve the files using a [local webserver](https://emscripten.org/docs/getting_started/FAQ.html#faq-local-webserver) and then open http://localhost:8000/hello.html."_
|
||||
- Emscripten SDK has a handy `emrun` command: `emrun web/index.html --browser firefox` which will spawn a temporary local webserver (in Firefox). See https://emscripten.org/docs/compiling/Running-html-files-with-emrun.html for details.
|
||||
- You may use Python 3 builtin webserver: `python -m http.server -d web` (this is what `make serve` uses).
|
||||
- You may use Python 2 builtin webserver: `cd web && python -m SimpleHTTPServer`.
|
||||
- If you are accessing the files over a network, certain browsers, such as Firefox, will restrict Gamepad API access to secure contexts only (e.g. https only).
|
8
build_win32.bat
Normal file
8
build_win32.bat
Normal file
@ -0,0 +1,8 @@
|
||||
@REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler.
|
||||
@set OUT_DIR=Debug
|
||||
@set OUT_EXE=example_sdl2_opengl3
|
||||
@set INCLUDES=/I..\.. /I..\..\backends /I%SDL2_DIR%\include
|
||||
@set SOURCES=main.cpp ..\..\backends\imgui_impl_sdl2.cpp ..\..\backends\imgui_impl_opengl3.cpp ..\..\imgui*.cpp
|
||||
@set LIBS=/LIBPATH:%SDL2_DIR%\lib\x86 SDL2.lib SDL2main.lib opengl32.lib shell32.lib
|
||||
mkdir %OUT_DIR%
|
||||
cl /nologo /Zi /MD /utf-8 %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console
|
97
emscripten_browser_file.h
Normal file
97
emscripten_browser_file.h
Normal file
@ -0,0 +1,97 @@
|
||||
#ifndef EMSCRIPTEN_UPLOAD_FILE_H_INCLUDED
|
||||
#define EMSCRIPTEN_UPLOAD_FILE_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <emscripten.h>
|
||||
|
||||
#define _EM_JS_INLINE(ret, c_name, js_name, params, code) \
|
||||
extern "C" { \
|
||||
ret c_name params EM_IMPORT(js_name); \
|
||||
EMSCRIPTEN_KEEPALIVE \
|
||||
__attribute__((section("em_js"), aligned(1))) inline char __em_js__##js_name[] = \
|
||||
#params "<::>" code; \
|
||||
}
|
||||
|
||||
#define EM_JS_INLINE(ret, name, params, ...) _EM_JS_INLINE(ret, name, name, params, #__VA_ARGS__)
|
||||
|
||||
namespace emscripten_browser_file {
|
||||
|
||||
/////////////////////////////////// Interface //////////////////////////////////
|
||||
|
||||
using upload_handler = void(*)(std::string const&, std::string const&, std::string_view buffer, void*);
|
||||
|
||||
inline void upload(std::string const &accept_types, upload_handler callback, void *callback_data = nullptr);
|
||||
inline void download(std::string const &filename, std::string const &mime_type, std::string_view buffer);
|
||||
|
||||
///////////////////////////////// Implementation ///////////////////////////////
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmissing-variable-declarations"
|
||||
EM_JS_INLINE(void, upload, (char const *accept_types, upload_handler callback, void *callback_data), {
|
||||
/// Prompt the browser to open the file selector dialogue, and pass the file to the given handler
|
||||
/// Accept-types are in the format ".png,.jpeg,.jpg" as per https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept
|
||||
/// Upload handler callback signature is:
|
||||
/// void my_handler(std::string const &filename, std::string const &mime_type, std::string_view buffer, void *callback_data = nullptr);
|
||||
globalThis["open_file"] = function(e) {
|
||||
const file_reader = new FileReader();
|
||||
file_reader.onload = (event) => {
|
||||
const uint8Arr = new Uint8Array(event.target.result);
|
||||
const data_ptr = Module["_malloc"](uint8Arr.length);
|
||||
const data_on_heap = new Uint8Array(Module["HEAPU8"].buffer, data_ptr, uint8Arr.length);
|
||||
data_on_heap.set(uint8Arr);
|
||||
Module["ccall"]('upload_file_return', 'number', ['string', 'string', 'number', 'number', 'number', 'number'], [event.target.filename, event.target.mime_type, data_on_heap.byteOffset, uint8Arr.length, callback, callback_data]);
|
||||
Module["_free"](data_ptr);
|
||||
};
|
||||
file_reader.filename = e.target.files[0].name;
|
||||
file_reader.mime_type = e.target.files[0].type;
|
||||
file_reader.readAsArrayBuffer(e.target.files[0]);
|
||||
};
|
||||
|
||||
var file_selector = document.createElement('input');
|
||||
file_selector.setAttribute('type', 'file');
|
||||
file_selector.setAttribute('onchange', 'globalThis["open_file"](event)');
|
||||
file_selector.setAttribute('accept', UTF8ToString(accept_types));
|
||||
file_selector.click();
|
||||
});
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
inline void upload(std::string const &accept_types, upload_handler callback, void *callback_data) {
|
||||
/// C++ wrapper for javascript upload call
|
||||
upload(accept_types.c_str(), callback, callback_data);
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmissing-variable-declarations"
|
||||
EM_JS_INLINE(void, download, (char const *filename, char const *mime_type, void const *buffer, size_t buffer_size), {
|
||||
/// Offer a buffer in memory as a file to download, specifying download filename and mime type
|
||||
var a = document.createElement('a');
|
||||
a.download = UTF8ToString(filename);
|
||||
a.href = URL.createObjectURL(new Blob([new Uint8Array(Module["HEAPU8"].buffer, buffer, buffer_size)], {type: UTF8ToString(mime_type)}));
|
||||
a.click();
|
||||
});
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
inline void download(std::string const &filename, std::string const &mime_type, std::string_view buffer) {
|
||||
/// C++ wrapper for javascript download call, accepting a string_view
|
||||
download(filename.c_str(), mime_type.c_str(), buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
extern "C" {
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE inline int upload_file_return(char const *filename, char const *mime_type, char *buffer, size_t buffer_size, upload_handler callback, void *callback_data);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE inline int upload_file_return(char const *filename, char const *mime_type, char *buffer, size_t buffer_size, upload_handler callback, void *callback_data) {
|
||||
/// Load a file - this function is called from javascript when the file upload is activated
|
||||
callback(filename, mime_type, {buffer, buffer_size}, callback_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // EMSCRIPTEN_UPLOAD_FILE_H_INCLUDED
|
187
example_sdl2_opengl3.vcxproj
Normal file
187
example_sdl2_opengl3.vcxproj
Normal file
@ -0,0 +1,187 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{BBAEB705-1669-40F3-8567-04CF6A991F4C}</ProjectGuid>
|
||||
<RootNamespace>example_sdl2_opengl3</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<OutDir>$(ProjectDir)$(Configuration)\</OutDir>
|
||||
<IntDir>$(ProjectDir)$(Configuration)\</IntDir>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutDir>$(ProjectDir)$(Configuration)\</OutDir>
|
||||
<IntDir>$(ProjectDir)$(Configuration)\</IntDir>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<OutDir>$(ProjectDir)$(Configuration)\</OutDir>
|
||||
<IntDir>$(ProjectDir)$(Configuration)\</IntDir>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>$(ProjectDir)$(Configuration)\</OutDir>
|
||||
<IntDir>$(ProjectDir)$(Configuration)\</IntDir>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\..;..\..\backends;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>%SDL2_DIR%\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>opengl32.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<IgnoreSpecificDefaultLibraries>msvcrt.lib</IgnoreSpecificDefaultLibraries>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\..;..\..\backends;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>%SDL2_DIR%\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>opengl32.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<IgnoreSpecificDefaultLibraries>msvcrt.lib</IgnoreSpecificDefaultLibraries>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>..\..;..\..\backends;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalLibraryDirectories>%SDL2_DIR%\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>opengl32.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<IgnoreSpecificDefaultLibraries>
|
||||
</IgnoreSpecificDefaultLibraries>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>..\..;..\..\backends;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalLibraryDirectories>%SDL2_DIR%\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>opengl32.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<IgnoreSpecificDefaultLibraries>
|
||||
</IgnoreSpecificDefaultLibraries>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\imgui.cpp" />
|
||||
<ClCompile Include="..\..\imgui_demo.cpp" />
|
||||
<ClCompile Include="..\..\imgui_draw.cpp" />
|
||||
<ClCompile Include="..\..\imgui_tables.cpp" />
|
||||
<ClCompile Include="..\..\imgui_widgets.cpp" />
|
||||
<ClCompile Include="..\..\backends\imgui_impl_sdl2.cpp" />
|
||||
<ClCompile Include="..\..\backends\imgui_impl_opengl3.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\imconfig.h" />
|
||||
<ClInclude Include="..\..\imgui.h" />
|
||||
<ClInclude Include="..\..\imgui_internal.h" />
|
||||
<ClInclude Include="..\..\backends\imgui_impl_sdl2.h" />
|
||||
<ClInclude Include="..\..\backends\imgui_impl_opengl3.h" />
|
||||
<ClInclude Include="..\..\backends\imgui_impl_opengl3_loader.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\misc\debuggers\imgui.natstepfilter" />
|
||||
<None Include="..\..\misc\debuggers\imgui.natvis" />
|
||||
<None Include="..\README.txt" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
67
example_sdl2_opengl3.vcxproj.filters
Normal file
67
example_sdl2_opengl3.vcxproj.filters
Normal file
@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="imgui">
|
||||
<UniqueIdentifier>{20b90ce4-7fcb-4731-b9a0-075f875de82d}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="sources">
|
||||
<UniqueIdentifier>{f18ab499-84e1-499f-8eff-9754361e0e52}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\imgui.cpp">
|
||||
<Filter>imgui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\imgui_demo.cpp">
|
||||
<Filter>imgui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\imgui_draw.cpp">
|
||||
<Filter>imgui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="main.cpp">
|
||||
<Filter>sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\backends\imgui_impl_sdl2.cpp">
|
||||
<Filter>sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\backends\imgui_impl_opengl3.cpp">
|
||||
<Filter>sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\imgui_tables.cpp">
|
||||
<Filter>imgui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\imgui_widgets.cpp">
|
||||
<Filter>imgui</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\imconfig.h">
|
||||
<Filter>imgui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\imgui.h">
|
||||
<Filter>imgui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\imgui_internal.h">
|
||||
<Filter>imgui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\backends\imgui_impl_sdl2.h">
|
||||
<Filter>sources</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\backends\imgui_impl_opengl3.h">
|
||||
<Filter>sources</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\backends\imgui_impl_opengl3_loader.h">
|
||||
<Filter>sources</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\README.txt" />
|
||||
<None Include="..\..\misc\debuggers\imgui.natvis">
|
||||
<Filter>imgui</Filter>
|
||||
</None>
|
||||
<None Include="..\..\misc\debuggers\imgui.natstepfilter">
|
||||
<Filter>imgui</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
10
imgui.ini
Normal file
10
imgui.ini
Normal file
@ -0,0 +1,10 @@
|
||||
[Window][Debug##Default]
|
||||
Pos=-3,-3
|
||||
Size=400,400
|
||||
Collapsed=0
|
||||
|
||||
[Window][viewport_container]
|
||||
Pos=0,0
|
||||
Size=1101,598
|
||||
Collapsed=0
|
||||
|
378
lib/ImNodeFlow.cpp
Executable file
378
lib/ImNodeFlow.cpp
Executable file
@ -0,0 +1,378 @@
|
||||
#include "ImNodeFlow.h"
|
||||
|
||||
namespace ImFlow {
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// LINK
|
||||
|
||||
void Link::update() {
|
||||
ImVec2 start = m_left->pinPoint();
|
||||
ImVec2 end = m_right->pinPoint();
|
||||
float thickness = m_left->getStyle()->extra.link_thickness;
|
||||
bool mouseClickState = m_inf->getSingleUseClick();
|
||||
|
||||
if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl) &&
|
||||
ImGui::IsMouseClicked(ImGuiMouseButton_Left))
|
||||
m_selected = false;
|
||||
|
||||
if (smart_bezier_collider(ImGui::GetMousePos(), start, end, 2.5)) {
|
||||
m_hovered = true;
|
||||
thickness = m_left->getStyle()->extra.link_hovered_thickness;
|
||||
if (mouseClickState) {
|
||||
m_inf->consumeSingleUseClick();
|
||||
m_selected = true;
|
||||
}
|
||||
} else {
|
||||
m_hovered = false;
|
||||
}
|
||||
|
||||
if (m_selected)
|
||||
smart_bezier(start, end, m_left->getStyle()->extra.outline_color,
|
||||
thickness +
|
||||
m_left->getStyle()->extra.link_selected_outline_thickness);
|
||||
smart_bezier(start, end, m_left->getStyle()->color, thickness);
|
||||
|
||||
if (m_selected && ImGui::IsKeyPressed(ImGuiKey_Delete, false))
|
||||
m_right->deleteLink();
|
||||
}
|
||||
|
||||
Link::~Link() { m_left->deleteLink(); }
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// BASE NODE
|
||||
|
||||
bool BaseNode::isHovered() {
|
||||
ImVec2 paddingTL = {m_style->padding.x, m_style->padding.y};
|
||||
ImVec2 paddingBR = {m_style->padding.z, m_style->padding.w};
|
||||
return ImGui::IsMouseHoveringRect(
|
||||
m_inf->grid2screen(m_pos - paddingTL),
|
||||
m_inf->grid2screen(m_pos + m_size + paddingBR));
|
||||
}
|
||||
|
||||
void BaseNode::update() {
|
||||
ImDrawList *draw_list = ImGui::GetWindowDrawList();
|
||||
ImGui::PushID(this);
|
||||
bool mouseClickState = m_inf->getSingleUseClick();
|
||||
ImVec2 offset = m_inf->grid2screen({0.f, 0.f});
|
||||
ImVec2 paddingTL = {m_style->padding.x, m_style->padding.y};
|
||||
ImVec2 paddingBR = {m_style->padding.z, m_style->padding.w};
|
||||
|
||||
draw_list->ChannelsSetCurrent(1); // Foreground
|
||||
ImGui::SetCursorScreenPos(offset + m_pos);
|
||||
|
||||
ImGui::BeginGroup();
|
||||
|
||||
// Header
|
||||
ImGui::BeginGroup();
|
||||
ImGui::TextColored(m_style->header_title_color, m_title.c_str());
|
||||
ImGui::Spacing();
|
||||
ImGui::EndGroup();
|
||||
float headerH = ImGui::GetItemRectSize().y;
|
||||
float titleW = ImGui::GetItemRectSize().x;
|
||||
|
||||
// Inputs
|
||||
ImGui::BeginGroup();
|
||||
for (auto &p : m_ins) {
|
||||
p->setPos(ImGui::GetCursorPos());
|
||||
p->update();
|
||||
}
|
||||
for (auto &p : m_dynamicIns) {
|
||||
if (p.first == 1) {
|
||||
p.second->setPos(ImGui::GetCursorPos());
|
||||
p.second->update();
|
||||
p.first = 0;
|
||||
}
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
ImGui::SameLine();
|
||||
|
||||
// Content
|
||||
ImGui::BeginGroup();
|
||||
draw();
|
||||
ImGui::Dummy(ImVec2(0.f, 0.f));
|
||||
ImGui::EndGroup();
|
||||
ImGui::SameLine();
|
||||
|
||||
// Outputs
|
||||
float maxW = 0.0f;
|
||||
for (auto &p : m_outs) {
|
||||
float w = p->calcWidth();
|
||||
if (w > maxW)
|
||||
maxW = w;
|
||||
}
|
||||
for (auto &p : m_dynamicOuts) {
|
||||
float w = p.second->calcWidth();
|
||||
if (w > maxW)
|
||||
maxW = w;
|
||||
}
|
||||
ImGui::BeginGroup();
|
||||
for (auto &p : m_outs) {
|
||||
// FIXME: This looks horrible
|
||||
if ((m_pos + ImVec2(titleW, 0) + m_inf->getGrid().scroll()).x <
|
||||
ImGui::GetCursorPos().x + ImGui::GetWindowPos().x + maxW)
|
||||
p->setPos(ImGui::GetCursorPos() + ImGui::GetWindowPos() +
|
||||
ImVec2(maxW - p->calcWidth(), 0.f));
|
||||
else
|
||||
p->setPos(ImVec2((m_pos + ImVec2(titleW - p->calcWidth(), 0) +
|
||||
m_inf->getGrid().scroll())
|
||||
.x,
|
||||
ImGui::GetCursorPos().y + ImGui::GetWindowPos().y));
|
||||
p->update();
|
||||
}
|
||||
for (auto &p : m_dynamicOuts) {
|
||||
// FIXME: This looks horrible
|
||||
if ((m_pos + ImVec2(titleW, 0) + m_inf->getGrid().scroll()).x <
|
||||
ImGui::GetCursorPos().x + ImGui::GetWindowPos().x + maxW)
|
||||
p.second->setPos(ImGui::GetCursorPos() + ImGui::GetWindowPos() +
|
||||
ImVec2(maxW - p.second->calcWidth(), 0.f));
|
||||
else
|
||||
p.second->setPos(
|
||||
ImVec2((m_pos + ImVec2(titleW - p.second->calcWidth(), 0) +
|
||||
m_inf->getGrid().scroll())
|
||||
.x,
|
||||
ImGui::GetCursorPos().y + ImGui::GetWindowPos().y));
|
||||
p.second->update();
|
||||
p.first -= 1;
|
||||
}
|
||||
|
||||
ImGui::EndGroup();
|
||||
|
||||
ImGui::EndGroup();
|
||||
m_size = ImGui::GetItemRectSize();
|
||||
ImVec2 headerSize = ImVec2(m_size.x + paddingBR.x, headerH);
|
||||
|
||||
// Background
|
||||
draw_list->ChannelsSetCurrent(0);
|
||||
draw_list->AddRectFilled(offset + m_pos - paddingTL,
|
||||
offset + m_pos + m_size + paddingBR, m_style->bg,
|
||||
m_style->radius);
|
||||
draw_list->AddRectFilled(offset + m_pos - paddingTL,
|
||||
offset + m_pos + headerSize, m_style->header_bg,
|
||||
m_style->radius, ImDrawFlags_RoundCornersTop);
|
||||
|
||||
ImU32 col = m_style->border_color;
|
||||
float thickness = m_style->border_thickness;
|
||||
ImVec2 ptl = paddingTL;
|
||||
ImVec2 pbr = paddingBR;
|
||||
if (m_selected) {
|
||||
col = m_style->border_selected_color;
|
||||
thickness = m_style->border_selected_thickness;
|
||||
}
|
||||
if (thickness < 0.f) {
|
||||
ptl.x -= thickness / 2;
|
||||
ptl.y -= thickness / 2;
|
||||
pbr.x -= thickness / 2;
|
||||
pbr.y -= thickness / 2;
|
||||
thickness *= -1.f;
|
||||
}
|
||||
draw_list->AddRect(offset + m_pos - ptl, offset + m_pos + m_size + pbr, col,
|
||||
m_style->radius, 0, thickness);
|
||||
|
||||
if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl) &&
|
||||
ImGui::IsMouseClicked(ImGuiMouseButton_Left) &&
|
||||
!m_inf->on_selected_node())
|
||||
selected(false);
|
||||
|
||||
if (isHovered()) {
|
||||
m_inf->hoveredNode(this);
|
||||
if (mouseClickState) {
|
||||
selected(true);
|
||||
m_inf->consumeSingleUseClick();
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_Delete) && !ImGui::IsAnyItemActive() &&
|
||||
isSelected())
|
||||
destroy();
|
||||
|
||||
bool onHeader = ImGui::IsMouseHoveringRect(offset + m_pos - paddingTL,
|
||||
offset + m_pos + headerSize);
|
||||
if (onHeader && mouseClickState) {
|
||||
m_inf->consumeSingleUseClick();
|
||||
m_dragged = true;
|
||||
m_inf->draggingNode(true);
|
||||
}
|
||||
if (m_dragged || (m_selected && m_inf->isNodeDragged())) {
|
||||
float step =
|
||||
m_inf->getStyle().grid_size / m_inf->getStyle().grid_subdivisions;
|
||||
m_posTarget += ImGui::GetIO().MouseDelta;
|
||||
// "Slam" The position
|
||||
m_pos.x = round(m_posTarget.x / step) * step;
|
||||
m_pos.y = round(m_posTarget.y / step) * step;
|
||||
|
||||
if (ImGui::IsMouseReleased(ImGuiMouseButton_Left)) {
|
||||
m_dragged = false;
|
||||
m_inf->draggingNode(false);
|
||||
m_posTarget = m_pos;
|
||||
}
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
||||
// Resolve output pins values
|
||||
for (auto &p : m_outs)
|
||||
p->resolve();
|
||||
for (auto &p : m_dynamicOuts)
|
||||
p.second->resolve();
|
||||
|
||||
// Deleting dead pins
|
||||
m_dynamicIns.erase(
|
||||
std::remove_if(m_dynamicIns.begin(), m_dynamicIns.end(),
|
||||
[](const std::pair<int, std::shared_ptr<Pin>> &p) {
|
||||
return p.first == 0;
|
||||
}),
|
||||
m_dynamicIns.end());
|
||||
m_dynamicOuts.erase(
|
||||
std::remove_if(m_dynamicOuts.begin(), m_dynamicOuts.end(),
|
||||
[](const std::pair<int, std::shared_ptr<Pin>> &p) {
|
||||
return p.first == 0;
|
||||
}),
|
||||
m_dynamicOuts.end());
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// HANDLER
|
||||
|
||||
int ImNodeFlow::m_instances = 0;
|
||||
|
||||
bool ImNodeFlow::on_selected_node() {
|
||||
return std::any_of(m_nodes.begin(), m_nodes.end(), [](const auto &n) {
|
||||
return n.second->isSelected() && n.second->isHovered();
|
||||
});
|
||||
}
|
||||
|
||||
bool ImNodeFlow::on_free_space() {
|
||||
return std::all_of(m_nodes.begin(), m_nodes.end(),
|
||||
[](const auto &n) { return !n.second->isHovered(); }) &&
|
||||
std::all_of(m_links.begin(), m_links.end(),
|
||||
[](const auto &l) { return !l.lock()->isHovered(); });
|
||||
}
|
||||
|
||||
ImVec2 ImNodeFlow::screen2grid(const ImVec2 &p) {
|
||||
if (ImGui::GetCurrentContext() == m_context.getRawContext())
|
||||
return p - m_context.scroll();
|
||||
else
|
||||
return p - m_context.origin() - m_context.scroll() * m_context.scale();
|
||||
}
|
||||
|
||||
ImVec2 ImNodeFlow::grid2screen(const ImVec2 &p) {
|
||||
if (ImGui::GetCurrentContext() == m_context.getRawContext())
|
||||
return p + m_context.scroll();
|
||||
else
|
||||
return p + m_context.origin() + m_context.scroll() * m_context.scale();
|
||||
}
|
||||
|
||||
void ImNodeFlow::addLink(std::shared_ptr<Link> &link) {
|
||||
m_links.push_back(link);
|
||||
}
|
||||
|
||||
void ImNodeFlow::update() {
|
||||
// Updating looping stuff
|
||||
m_hovering = nullptr;
|
||||
m_hoveredNode = nullptr;
|
||||
m_draggingNode = m_draggingNodeNext;
|
||||
m_singleUseClick = ImGui::IsMouseClicked(ImGuiMouseButton_Left);
|
||||
|
||||
// Create child canvas
|
||||
m_context.begin();
|
||||
|
||||
ImDrawList *draw_list = ImGui::GetWindowDrawList();
|
||||
|
||||
// Display grid
|
||||
ImVec2 win_pos = ImGui::GetCursorScreenPos();
|
||||
ImVec2 canvas_sz = ImGui::GetWindowSize();
|
||||
for (float x = fmodf(m_context.scroll().x, m_style.grid_size);
|
||||
x < canvas_sz.x; x += m_style.grid_size)
|
||||
draw_list->AddLine(ImVec2(x, 0.0f) + win_pos,
|
||||
ImVec2(x, canvas_sz.y) + win_pos, m_style.colors.grid);
|
||||
for (float y = fmodf(m_context.scroll().y, m_style.grid_size);
|
||||
y < canvas_sz.y; y += m_style.grid_size)
|
||||
draw_list->AddLine(ImVec2(0.0f, y) + win_pos,
|
||||
ImVec2(canvas_sz.x, y) + win_pos, m_style.colors.grid);
|
||||
for (float x = fmodf(m_context.scroll().x,
|
||||
m_style.grid_size / m_style.grid_subdivisions);
|
||||
x < canvas_sz.x; x += m_style.grid_size / m_style.grid_subdivisions)
|
||||
draw_list->AddLine(ImVec2(x, 0.0f) + win_pos,
|
||||
ImVec2(x, canvas_sz.y) + win_pos,
|
||||
m_style.colors.subGrid);
|
||||
for (float y = fmodf(m_context.scroll().y,
|
||||
m_style.grid_size / m_style.grid_subdivisions);
|
||||
y < canvas_sz.y; y += m_style.grid_size / m_style.grid_subdivisions)
|
||||
draw_list->AddLine(ImVec2(0.0f, y) + win_pos,
|
||||
ImVec2(canvas_sz.x, y) + win_pos,
|
||||
m_style.colors.subGrid);
|
||||
|
||||
// Update and draw nodes
|
||||
// TODO: I don't like this
|
||||
draw_list->ChannelsSplit(2);
|
||||
for (auto &node : m_nodes) {
|
||||
node.second->update();
|
||||
}
|
||||
std::erase_if(m_nodes, [](const auto &n) { return n.second->toDestroy(); });
|
||||
draw_list->ChannelsMerge();
|
||||
for (auto &node : m_nodes) {
|
||||
node.second->updatePublicStatus();
|
||||
}
|
||||
|
||||
// Update and draw links
|
||||
for (auto &l : m_links) {
|
||||
if (!l.expired())
|
||||
l.lock()->update();
|
||||
}
|
||||
|
||||
// Links drop-off
|
||||
if (m_dragOut && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) {
|
||||
if (!m_hovering) {
|
||||
if (on_free_space() && m_droppedLinkPopUp) {
|
||||
if (m_droppedLinkPupUpComboKey == ImGuiKey_None ||
|
||||
ImGui::IsKeyDown(m_droppedLinkPupUpComboKey)) {
|
||||
m_droppedLinkLeft = m_dragOut;
|
||||
ImGui::OpenPopup("DroppedLinkPopUp");
|
||||
}
|
||||
}
|
||||
} else
|
||||
m_dragOut->createLink(m_hovering);
|
||||
}
|
||||
|
||||
// Links drag-out
|
||||
if (!m_draggingNode && m_hovering && !m_dragOut &&
|
||||
ImGui::IsMouseClicked(ImGuiMouseButton_Left))
|
||||
m_dragOut = m_hovering;
|
||||
if (m_dragOut) {
|
||||
if (m_dragOut->getType() == PinType_Output)
|
||||
smart_bezier(m_dragOut->pinPoint(), ImGui::GetMousePos(),
|
||||
m_dragOut->getStyle()->color,
|
||||
m_dragOut->getStyle()->extra.link_dragged_thickness);
|
||||
else
|
||||
smart_bezier(ImGui::GetMousePos(), m_dragOut->pinPoint(),
|
||||
m_dragOut->getStyle()->color,
|
||||
m_dragOut->getStyle()->extra.link_dragged_thickness);
|
||||
|
||||
if (ImGui::IsMouseReleased(ImGuiMouseButton_Left))
|
||||
m_dragOut = nullptr;
|
||||
}
|
||||
|
||||
// Right-click PopUp
|
||||
if (m_rightClickPopUp && ImGui::IsMouseClicked(ImGuiMouseButton_Right) &&
|
||||
ImGui::IsWindowHovered()) {
|
||||
m_hoveredNodeAux = m_hoveredNode;
|
||||
ImGui::OpenPopup("RightClickPopUp");
|
||||
}
|
||||
if (ImGui::BeginPopup("RightClickPopUp")) {
|
||||
m_rightClickPopUp(m_hoveredNodeAux);
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
// Dropped Link PopUp
|
||||
if (ImGui::BeginPopup("DroppedLinkPopUp")) {
|
||||
m_droppedLinkPopUp(m_droppedLinkLeft);
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
// Removing dead Links
|
||||
m_links.erase(
|
||||
std::remove_if(m_links.begin(), m_links.end(),
|
||||
[](const std::weak_ptr<Link> &l) { return l.expired(); }),
|
||||
m_links.end());
|
||||
|
||||
m_context.end();
|
||||
}
|
||||
} // namespace ImFlow
|
1318
lib/ImNodeFlow.h
Executable file
1318
lib/ImNodeFlow.h
Executable file
File diff suppressed because it is too large
Load Diff
347
lib/ImNodeFlow.inl
Executable file
347
lib/ImNodeFlow.inl
Executable file
@ -0,0 +1,347 @@
|
||||
#pragma once
|
||||
|
||||
#include "ImNodeFlow.h"
|
||||
|
||||
namespace ImFlow
|
||||
{
|
||||
inline void smart_bezier(const ImVec2& p1, const ImVec2& p2, ImU32 color, float thickness)
|
||||
{
|
||||
ImDrawList* dl = ImGui::GetWindowDrawList();
|
||||
float distance = sqrt(pow((p2.x - p1.x), 2.f) + pow((p2.y - p1.y), 2.f));
|
||||
float delta = distance * 0.45f;
|
||||
if (p2.x < p1.x) delta += 0.2f * (p1.x - p2.x);
|
||||
// float vert = (p2.x < p1.x - 20.f) ? 0.062f * distance * (p2.y - p1.y) * 0.005f : 0.f;
|
||||
float vert = 0.f;
|
||||
ImVec2 p22 = p2 - ImVec2(delta, vert);
|
||||
if (p2.x < p1.x - 50.f) delta *= -1.f;
|
||||
ImVec2 p11 = p1 + ImVec2(delta, vert);
|
||||
dl->AddBezierCubic(p1, p11, p22, p2, color, thickness);
|
||||
}
|
||||
|
||||
inline bool smart_bezier_collider(const ImVec2& p, const ImVec2& p1, const ImVec2& p2, float radius)
|
||||
{
|
||||
float distance = sqrt(pow((p2.x - p1.x), 2.f) + pow((p2.y - p1.y), 2.f));
|
||||
float delta = distance * 0.45f;
|
||||
if (p2.x < p1.x) delta += 0.2f * (p1.x - p2.x);
|
||||
// float vert = (p2.x < p1.x - 20.f) ? 0.062f * distance * (p2.y - p1.y) * 0.005f : 0.f;
|
||||
float vert = 0.f;
|
||||
ImVec2 p22 = p2 - ImVec2(delta, vert);
|
||||
if (p2.x < p1.x - 50.f) delta *= -1.f;
|
||||
ImVec2 p11 = p1 + ImVec2(delta, vert);
|
||||
return ImProjectOnCubicBezier(p, p1, p11, p22, p2).Distance < radius;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// HANDLER
|
||||
|
||||
template<typename T, typename... Params>
|
||||
std::shared_ptr<T> ImNodeFlow::addNode(const ImVec2& pos, Params&&... args)
|
||||
{
|
||||
static_assert(std::is_base_of<BaseNode, T>::value, "Pushed type is not a subclass of BaseNode!");
|
||||
|
||||
std::shared_ptr<T> n = std::make_shared<T>(std::forward<Params>(args)...);
|
||||
n->setPos(pos);
|
||||
n->setHandler(this);
|
||||
if (!n->getStyle())
|
||||
n->setStyle(NodeStyle::cyan());
|
||||
|
||||
auto uid = reinterpret_cast<uintptr_t>(n.get());
|
||||
n->setUID(uid);
|
||||
m_nodes[uid] = n;
|
||||
return n;
|
||||
}
|
||||
|
||||
template<typename T, typename... Params>
|
||||
std::shared_ptr<T> ImNodeFlow::placeNodeAt(const ImVec2& pos, Params&&... args)
|
||||
{
|
||||
return addNode<T>(screen2grid(pos), std::forward<Params>(args)...);
|
||||
}
|
||||
|
||||
template<typename T, typename... Params>
|
||||
std::shared_ptr<T> ImNodeFlow::placeNode(Params&&... args)
|
||||
{
|
||||
return placeNodeAt<T>(ImGui::GetMousePos(), std::forward<Params>(args)...);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// BASE NODE
|
||||
|
||||
template<typename T>
|
||||
std::shared_ptr<InPin<T>> BaseNode::addIN(const std::string& name, T defReturn, ConnectionFilter filter, std::shared_ptr<PinStyle> style)
|
||||
{
|
||||
return addIN_uid(name, name, defReturn, filter, std::move(style));
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
std::shared_ptr<InPin<T>> BaseNode::addIN_uid(const U& uid, const std::string& name, T defReturn, ConnectionFilter filter, std::shared_ptr<PinStyle> style)
|
||||
{
|
||||
PinUID h = std::hash<U>{}(uid);
|
||||
auto p = std::make_shared<InPin<T>>(h, name, filter, this, defReturn, &m_inf, std::move(style));
|
||||
m_ins.emplace_back(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
void BaseNode::dropIN(const U& uid)
|
||||
{
|
||||
PinUID h = std::hash<U>{}(uid);
|
||||
for (auto it = m_ins.begin(); it != m_ins.end(); it++)
|
||||
{
|
||||
if (it->get()->getUid() == h)
|
||||
{
|
||||
m_ins.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void BaseNode::dropIN(const char* uid)
|
||||
{
|
||||
dropIN<std::string>(uid);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T& BaseNode::showIN(const std::string& name, T defReturn, ConnectionFilter filter, std::shared_ptr<PinStyle> style)
|
||||
{
|
||||
return showIN_uid(name, name, defReturn, filter, std::move(style));
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
const T& BaseNode::showIN_uid(const U& uid, const std::string& name, T defReturn, ConnectionFilter filter, std::shared_ptr<PinStyle> style)
|
||||
{
|
||||
PinUID h = std::hash<U>{}(uid);
|
||||
for (std::pair<int, std::shared_ptr<Pin>>& p : m_dynamicIns)
|
||||
{
|
||||
if (p.second->getUid() == h)
|
||||
{
|
||||
p.first = 1;
|
||||
return static_cast<InPin<T>*>(p.second.get())->val();
|
||||
}
|
||||
}
|
||||
|
||||
m_dynamicIns.emplace_back(std::make_pair(1, std::make_shared<InPin<T>>(h, name, filter, this, defReturn, &m_inf, std::move(style))));
|
||||
return static_cast<InPin<T>*>(m_dynamicIns.back().second.get())->val();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::shared_ptr<OutPin<T>> BaseNode::addOUT(const std::string& name, ConnectionFilter filter, std::shared_ptr<PinStyle> style)
|
||||
{
|
||||
return addOUT_uid<T>(name, name, filter, std::move(style));
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
std::shared_ptr<OutPin<T>> BaseNode::addOUT_uid(const U& uid, const std::string& name, ConnectionFilter filter, std::shared_ptr<PinStyle> style)
|
||||
{
|
||||
PinUID h = std::hash<U>{}(uid);
|
||||
auto p = std::make_shared<OutPin<T>>(h, name, filter, this, &m_inf, std::move(style));
|
||||
m_outs.emplace_back(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
void BaseNode::dropOUT(const U& uid)
|
||||
{
|
||||
PinUID h = std::hash<U>{}(uid);
|
||||
for (auto it = m_outs.begin(); it != m_outs.end(); it++)
|
||||
{
|
||||
if (it->get()->getUid() == h)
|
||||
{
|
||||
m_outs.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void BaseNode::dropOUT(const char* uid)
|
||||
{
|
||||
dropOUT<std::string>(uid);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void BaseNode::showOUT(const std::string& name, std::function<T()> behaviour, ConnectionFilter filter, std::shared_ptr<PinStyle> style)
|
||||
{
|
||||
showOUT_uid<T>(name, name, std::move(behaviour), filter, std::move(style));
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
void BaseNode::showOUT_uid(const U& uid, const std::string& name, std::function<T()> behaviour, ConnectionFilter filter, std::shared_ptr<PinStyle> style)
|
||||
{
|
||||
PinUID h = std::hash<U>{}(uid);
|
||||
for (std::pair<int, std::shared_ptr<Pin>>& p : m_dynamicOuts)
|
||||
{
|
||||
if (p.second->getUid() == h)
|
||||
{
|
||||
p.first = 2;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_dynamicOuts.emplace_back(std::make_pair(2, std::make_shared<OutPin<T>>(h, name, filter, this, &m_inf, std::move(style))));
|
||||
static_cast<OutPin<T>*>(m_dynamicOuts.back().second.get())->behaviour(std::move(behaviour));
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
const T& BaseNode::getInVal(const U& uid)
|
||||
{
|
||||
PinUID h = std::hash<U>{}(uid);
|
||||
auto it = std::find_if(m_ins.begin(), m_ins.end(), [&h](std::shared_ptr<Pin>& p)
|
||||
{ return p->getUid() == h; });
|
||||
assert(it != m_ins.end() && "Pin UID not found!");
|
||||
return static_cast<InPin<T>*>(it->get())->val();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T& BaseNode::getInVal(const char* uid)
|
||||
{
|
||||
return getInVal<T, std::string>(uid);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
Pin* BaseNode::inPin(const U& uid)
|
||||
{
|
||||
PinUID h = std::hash<U>{}(uid);
|
||||
auto it = std::find_if(m_ins.begin(), m_ins.end(), [&h](std::shared_ptr<Pin>& p)
|
||||
{ return p->getUid() == h; });
|
||||
assert(it != m_ins.end() && "Pin UID not found!");
|
||||
return it->get();
|
||||
}
|
||||
|
||||
inline Pin* BaseNode::inPin(const char* uid)
|
||||
{
|
||||
return inPin<std::string>(uid);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
Pin* BaseNode::outPin(const U& uid)
|
||||
{
|
||||
PinUID h = std::hash<U>{}(uid);
|
||||
auto it = std::find_if(m_outs.begin(), m_outs.end(), [&h](std::shared_ptr<Pin>& p)
|
||||
{ return p->getUid() == h; });
|
||||
assert(it != m_outs.end() && "Pin UID not found!");
|
||||
return it->get();
|
||||
}
|
||||
|
||||
inline Pin* BaseNode::outPin(const char* uid)
|
||||
{
|
||||
return outPin<std::string>(uid);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// PIN
|
||||
|
||||
inline void Pin::drawSocket()
|
||||
{
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
ImVec2 tl = pinPoint() - ImVec2(m_style->socket_radius, m_style->socket_radius);
|
||||
ImVec2 br = pinPoint() + ImVec2(m_style->socket_radius, m_style->socket_radius);
|
||||
|
||||
if (isConnected())
|
||||
draw_list->AddCircleFilled(pinPoint(), m_style->socket_connected_radius, m_style->color, m_style->socket_shape);
|
||||
else
|
||||
{
|
||||
if (ImGui::IsItemHovered() || ImGui::IsMouseHoveringRect(tl, br))
|
||||
draw_list->AddCircle(pinPoint(), m_style->socket_hovered_radius, m_style->color, m_style->socket_shape, m_style->socket_thickness);
|
||||
else
|
||||
draw_list->AddCircle(pinPoint(), m_style->socket_radius, m_style->color, m_style->socket_shape, m_style->socket_thickness);
|
||||
}
|
||||
|
||||
if (ImGui::IsMouseHoveringRect(tl, br))
|
||||
(*m_inf)->hovering(this);
|
||||
}
|
||||
|
||||
inline void Pin::drawDecoration()
|
||||
{
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
|
||||
if (ImGui::IsItemHovered())
|
||||
draw_list->AddRectFilled(m_pos - m_style->extra.padding, m_pos + m_size + m_style->extra.padding, m_style->extra.bg_hover_color, m_style->extra.bg_radius);
|
||||
else
|
||||
draw_list->AddRectFilled(m_pos - m_style->extra.padding, m_pos + m_size + m_style->extra.padding, m_style->extra.bg_color, m_style->extra.bg_radius);
|
||||
draw_list->AddRect(m_pos - m_style->extra.padding, m_pos + m_size + m_style->extra.padding, m_style->extra.border_color, m_style->extra.bg_radius, 0, m_style->extra.border_thickness);
|
||||
}
|
||||
|
||||
inline void Pin::update()
|
||||
{
|
||||
// Custom rendering
|
||||
if (m_renderer)
|
||||
{
|
||||
ImGui::BeginGroup();
|
||||
m_renderer(this);
|
||||
ImGui::EndGroup();
|
||||
m_size = ImGui::GetItemRectSize();
|
||||
if (ImGui::IsItemHovered())
|
||||
(*m_inf)->hovering(this);
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::SetCursorPos(m_pos);
|
||||
ImGui::Text(m_name.c_str());
|
||||
m_size = ImGui::GetItemRectSize();
|
||||
|
||||
drawDecoration();
|
||||
drawSocket();
|
||||
|
||||
if (ImGui::IsItemHovered())
|
||||
(*m_inf)->hovering(this);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// IN PIN
|
||||
|
||||
template<class T>
|
||||
const T& InPin<T>::val()
|
||||
{
|
||||
if(!m_link)
|
||||
return m_emptyVal;
|
||||
|
||||
return reinterpret_cast<OutPin<T>*>(m_link->left())->val();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void InPin<T>::createLink(Pin *other)
|
||||
{
|
||||
if (other == this || other->getType() == PinType_Input || (m_parent == other->getParent() && (m_filter & ConnectionFilter_SameNode) == 0))
|
||||
return;
|
||||
|
||||
if (!((m_filter & other->getFilter()) != 0 || m_filter == ConnectionFilter_None || other->getFilter() == ConnectionFilter_None)) // Check Filter
|
||||
return;
|
||||
|
||||
if (m_link && m_link->left() == other)
|
||||
{
|
||||
m_link.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
m_link = std::make_shared<Link>(other, this, (*m_inf));
|
||||
other->setLink(m_link);
|
||||
(*m_inf)->addLink(m_link);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// OUT PIN
|
||||
|
||||
template<class T>
|
||||
const T &OutPin<T>::val() { return m_val; }
|
||||
|
||||
template<class T>
|
||||
void OutPin<T>::createLink(ImFlow::Pin *other)
|
||||
{
|
||||
if (other == this || other->getType() == PinType_Output)
|
||||
return;
|
||||
|
||||
other->createLink(this);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void OutPin<T>::setLink(std::shared_ptr<Link>& link)
|
||||
{
|
||||
m_links.emplace_back(link);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void OutPin<T>::deleteLink()
|
||||
{
|
||||
m_links.erase(std::remove_if(m_links.begin(), m_links.end(),
|
||||
[](const std::weak_ptr<Link>& l) { return l.expired(); }), m_links.end());
|
||||
}
|
||||
}
|
1196
lib/backends/imgui_impl_opengl3.cpp
Normal file
1196
lib/backends/imgui_impl_opengl3.cpp
Normal file
File diff suppressed because it is too large
Load Diff
79
lib/backends/imgui_impl_opengl3.h
Normal file
79
lib/backends/imgui_impl_opengl3.h
Normal file
@ -0,0 +1,79 @@
|
||||
// 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: Large
|
||||
// meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only).
|
||||
// [X] Renderer: Multi-viewport support (multiple windows). Enable with
|
||||
// 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// About WebGL/ES:
|
||||
// - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define
|
||||
// IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES.
|
||||
// - This is done automatically on iOS, Android and Emscripten targets.
|
||||
// - For other targets, the define needs to be visible from the
|
||||
// imgui_impl_opengl3.cpp compilation unit. If unsure, define globally or in
|
||||
// imconfig.h.
|
||||
|
||||
// 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. Learn about Dear ImGui:
|
||||
// - FAQ https://dearimgui.com/faq
|
||||
// - Getting Started https://dearimgui.com/getting-started
|
||||
// - Documentation https://dearimgui.com/docs (same as your local docs/
|
||||
// folder).
|
||||
// - Introduction, links and more at the top of imgui.cpp
|
||||
|
||||
// About GLSL version:
|
||||
// The 'glsl_version' initialization parameter should be nullptr (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
|
||||
#ifndef IMGUI_DISABLE
|
||||
|
||||
// Backend API
|
||||
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char *glsl_version = nullptr);
|
||||
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__) || defined(__amigaos4__)
|
||||
#define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100"
|
||||
#else
|
||||
// Otherwise imgui_impl_opengl3_loader.h will be used.
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
816
lib/backends/imgui_impl_opengl3_loader.h
Normal file
816
lib/backends/imgui_impl_opengl3_loader.h
Normal file
@ -0,0 +1,816 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//
|
||||
// IF YOU GET BUILD ERRORS IN THIS FILE (commonly macro redefinitions or function redefinitions):
|
||||
// IT LIKELY MEANS THAT YOU ARE BUILDING 'imgui_impl_opengl3.cpp' OR INCUDING 'imgui_impl_opengl3_loader.h'
|
||||
// IN THE SAME COMPILATION UNIT AS ONE OF YOUR FILE WHICH IS USING A THIRD-PARTY OPENGL LOADER.
|
||||
// (e.g. COULD HAPPEN IF YOU ARE DOING A UNITY/JUMBO BUILD, OR INCLUDING .CPP FILES FROM OTHERS)
|
||||
// YOU SHOULD NOT BUILD BOTH IN THE SAME COMPILATION UNIT.
|
||||
// BUT IF YOU REALLY WANT TO, you can '#define IMGUI_IMPL_OPENGL_LOADER_CUSTOM' and imgui_impl_opengl3.cpp
|
||||
// WILL NOT BE USING OUR LOADER, AND INSTEAD EXPECT ANOTHER/YOUR LOADER TO BE AVAILABLE IN THE COMPILATION UNIT.
|
||||
//
|
||||
// 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 0x0404
|
||||
#define GL_BACK 0x0405
|
||||
#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_VENDOR 0x1F00
|
||||
#define GL_RENDERER 0x1F01
|
||||
#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 PFNGLFLUSHPROC) (void);
|
||||
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 glFlush (void);
|
||||
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_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
|
||||
#define GL_STREAM_DRAW 0x88E0
|
||||
#define GL_PIXEL_UNPACK_BUFFER 0x88EC
|
||||
#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF
|
||||
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);
|
||||
typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
|
||||
#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);
|
||||
GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
|
||||
#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_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
|
||||
#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
|
||||
#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
|
||||
#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
|
||||
#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
|
||||
#define GL_BLEND_EQUATION_ALPHA 0x883D
|
||||
#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
|
||||
#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 PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index);
|
||||
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 PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params);
|
||||
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer);
|
||||
typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program);
|
||||
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 glDisableVertexAttribArray (GLuint index);
|
||||
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 glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params);
|
||||
GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void **pointer);
|
||||
GLAPI GLboolean APIENTRY glIsProgram (GLuint program);
|
||||
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;
|
||||
#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
|
||||
#define GL_CONTEXT_PROFILE_MASK 0x9126
|
||||
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 ImGL3WProcs {
|
||||
GL3WglProc ptr[59];
|
||||
struct {
|
||||
PFNGLACTIVETEXTUREPROC ActiveTexture;
|
||||
PFNGLATTACHSHADERPROC AttachShader;
|
||||
PFNGLBINDBUFFERPROC BindBuffer;
|
||||
PFNGLBINDSAMPLERPROC BindSampler;
|
||||
PFNGLBINDTEXTUREPROC BindTexture;
|
||||
PFNGLBINDVERTEXARRAYPROC BindVertexArray;
|
||||
PFNGLBLENDEQUATIONPROC BlendEquation;
|
||||
PFNGLBLENDEQUATIONSEPARATEPROC BlendEquationSeparate;
|
||||
PFNGLBLENDFUNCSEPARATEPROC BlendFuncSeparate;
|
||||
PFNGLBUFFERDATAPROC BufferData;
|
||||
PFNGLBUFFERSUBDATAPROC BufferSubData;
|
||||
PFNGLCLEARPROC Clear;
|
||||
PFNGLCLEARCOLORPROC ClearColor;
|
||||
PFNGLCOMPILESHADERPROC CompileShader;
|
||||
PFNGLCREATEPROGRAMPROC CreateProgram;
|
||||
PFNGLCREATESHADERPROC CreateShader;
|
||||
PFNGLDELETEBUFFERSPROC DeleteBuffers;
|
||||
PFNGLDELETEPROGRAMPROC DeleteProgram;
|
||||
PFNGLDELETESHADERPROC DeleteShader;
|
||||
PFNGLDELETETEXTURESPROC DeleteTextures;
|
||||
PFNGLDELETEVERTEXARRAYSPROC DeleteVertexArrays;
|
||||
PFNGLDETACHSHADERPROC DetachShader;
|
||||
PFNGLDISABLEPROC Disable;
|
||||
PFNGLDISABLEVERTEXATTRIBARRAYPROC DisableVertexAttribArray;
|
||||
PFNGLDRAWELEMENTSPROC DrawElements;
|
||||
PFNGLDRAWELEMENTSBASEVERTEXPROC DrawElementsBaseVertex;
|
||||
PFNGLENABLEPROC Enable;
|
||||
PFNGLENABLEVERTEXATTRIBARRAYPROC EnableVertexAttribArray;
|
||||
PFNGLFLUSHPROC Flush;
|
||||
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;
|
||||
PFNGLGETVERTEXATTRIBPOINTERVPROC GetVertexAttribPointerv;
|
||||
PFNGLGETVERTEXATTRIBIVPROC GetVertexAttribiv;
|
||||
PFNGLISENABLEDPROC IsEnabled;
|
||||
PFNGLISPROGRAMPROC IsProgram;
|
||||
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 ImGL3WProcs 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 glBufferSubData imgl3wProcs.gl.BufferSubData
|
||||
#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 glDisableVertexAttribArray imgl3wProcs.gl.DisableVertexAttribArray
|
||||
#define glDrawElements imgl3wProcs.gl.DrawElements
|
||||
#define glDrawElementsBaseVertex imgl3wProcs.gl.DrawElementsBaseVertex
|
||||
#define glEnable imgl3wProcs.gl.Enable
|
||||
#define glEnableVertexAttribArray imgl3wProcs.gl.EnableVertexAttribArray
|
||||
#define glFlush imgl3wProcs.gl.Flush
|
||||
#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 glGetVertexAttribPointerv imgl3wProcs.gl.GetVertexAttribPointerv
|
||||
#define glGetVertexAttribiv imgl3wProcs.gl.GetVertexAttribiv
|
||||
#define glIsEnabled imgl3wProcs.gl.IsEnabled
|
||||
#define glIsProgram imgl3wProcs.gl.IsProgram
|
||||
#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 GL3W_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)
|
||||
{
|
||||
// While most systems use libGL.so.1, NetBSD seems to use that libGL.so.3. See https://github.com/ocornut/imgui/issues/6983
|
||||
libgl = dlopen("libGL.so", RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!libgl)
|
||||
libgl = dlopen("libGL.so.1", RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!libgl)
|
||||
libgl = dlopen("libGL.so.3", 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 == 0 && version.minor == 0)
|
||||
{
|
||||
// Query GL_VERSION in desktop GL 2.x, the string will start with "<major>.<minor>"
|
||||
if (const char* gl_version = (const char*)glGetString(GL_VERSION))
|
||||
sscanf(gl_version, "%d.%d", &version.major, &version.minor);
|
||||
}
|
||||
if (version.major < 2)
|
||||
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 < 2)
|
||||
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",
|
||||
"glBufferSubData",
|
||||
"glClear",
|
||||
"glClearColor",
|
||||
"glCompileShader",
|
||||
"glCreateProgram",
|
||||
"glCreateShader",
|
||||
"glDeleteBuffers",
|
||||
"glDeleteProgram",
|
||||
"glDeleteShader",
|
||||
"glDeleteTextures",
|
||||
"glDeleteVertexArrays",
|
||||
"glDetachShader",
|
||||
"glDisable",
|
||||
"glDisableVertexAttribArray",
|
||||
"glDrawElements",
|
||||
"glDrawElementsBaseVertex",
|
||||
"glEnable",
|
||||
"glEnableVertexAttribArray",
|
||||
"glFlush",
|
||||
"glGenBuffers",
|
||||
"glGenTextures",
|
||||
"glGenVertexArrays",
|
||||
"glGetAttribLocation",
|
||||
"glGetError",
|
||||
"glGetIntegerv",
|
||||
"glGetProgramInfoLog",
|
||||
"glGetProgramiv",
|
||||
"glGetShaderInfoLog",
|
||||
"glGetShaderiv",
|
||||
"glGetString",
|
||||
"glGetStringi",
|
||||
"glGetUniformLocation",
|
||||
"glGetVertexAttribPointerv",
|
||||
"glGetVertexAttribiv",
|
||||
"glIsEnabled",
|
||||
"glIsProgram",
|
||||
"glLinkProgram",
|
||||
"glPixelStorei",
|
||||
"glPolygonMode",
|
||||
"glReadPixels",
|
||||
"glScissor",
|
||||
"glShaderSource",
|
||||
"glTexImage2D",
|
||||
"glTexParameteri",
|
||||
"glUniform1i",
|
||||
"glUniformMatrix4fv",
|
||||
"glUseProgram",
|
||||
"glVertexAttribPointer",
|
||||
"glViewport",
|
||||
};
|
||||
|
||||
GL3W_API union ImGL3WProcs imgl3wProcs;
|
||||
|
||||
static void load_procs(GL3WGetProcAddressProc proc)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < GL3W_ARRAY_SIZE(proc_names); i++)
|
||||
imgl3wProcs.ptr[i] = proc(proc_names[i]);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
1472
lib/backends/imgui_impl_sdl2.cpp
Normal file
1472
lib/backends/imgui_impl_sdl2.cpp
Normal file
File diff suppressed because it is too large
Load Diff
70
lib/backends/imgui_impl_sdl2.h
Normal file
70
lib/backends/imgui_impl_sdl2.h
Normal file
@ -0,0 +1,70 @@
|
||||
// dear imgui: Platform Backend for SDL2
|
||||
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3,
|
||||
// Vulkan..) (Info: SDL2 is a cross-platform general purpose library for
|
||||
// handling windows, inputs, graphics context creation, etc.)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Clipboard support.
|
||||
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen.
|
||||
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent()
|
||||
// function. Pass ImGuiKey values to all key functions e.g.
|
||||
// ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values will also
|
||||
// be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] [X] Platform:
|
||||
// Gamepad support. Enabled with 'io.ConfigFlags |=
|
||||
// ImGuiConfigFlags_NavEnableGamepad'. [X] Platform: Mouse cursor shape and
|
||||
// visibility. Disable with 'io.ConfigFlags |=
|
||||
// ImGuiConfigFlags_NoMouseCursorChange'. [X] Platform: Multi-viewport support
|
||||
// (multiple windows). Enable with 'io.ConfigFlags |=
|
||||
// ImGuiConfigFlags_ViewportsEnable'.
|
||||
// Issues:
|
||||
// [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel
|
||||
// events (at least under Windows). [ ] Platform: Multi-viewport:
|
||||
// ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has
|
||||
// no effect (minor). [x] Platform: Basic IME support. App needs to call
|
||||
// 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!.
|
||||
|
||||
// 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. Learn about Dear ImGui:
|
||||
// - FAQ https://dearimgui.com/faq
|
||||
// - Getting Started https://dearimgui.com/getting-started
|
||||
// - Documentation https://dearimgui.com/docs (same as your local docs/
|
||||
// folder).
|
||||
// - Introduction, links and more at the top of imgui.cpp
|
||||
|
||||
#pragma once
|
||||
#include "../imgui.h" // IMGUI_IMPL_API
|
||||
#ifndef IMGUI_DISABLE
|
||||
|
||||
struct SDL_Window;
|
||||
struct SDL_Renderer;
|
||||
struct _SDL_GameController;
|
||||
typedef union SDL_Event SDL_Event;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window *window,
|
||||
void *sdl_gl_context);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window *window);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window *window);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForMetal(SDL_Window *window);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window *window,
|
||||
SDL_Renderer *renderer);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOther(SDL_Window *window);
|
||||
IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame();
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event *event);
|
||||
|
||||
// Gamepad selection automatically starts in AutoFirst mode, picking first
|
||||
// available SDL_Gamepad. You may override this. When using manual mode, caller
|
||||
// is responsible for opening/closing gamepad.
|
||||
enum ImGui_ImplSDL2_GamepadMode {
|
||||
ImGui_ImplSDL2_GamepadMode_AutoFirst,
|
||||
ImGui_ImplSDL2_GamepadMode_AutoAll,
|
||||
ImGui_ImplSDL2_GamepadMode_Manual
|
||||
};
|
||||
IMGUI_IMPL_API void ImGui_ImplSDL2_SetGamepadMode(
|
||||
ImGui_ImplSDL2_GamepadMode mode,
|
||||
struct _SDL_GameController **manual_gamepads_array = NULL,
|
||||
int manual_gamepads_count = -1);
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
198
lib/context_wrapper.h
Executable file
198
lib/context_wrapper.h
Executable file
@ -0,0 +1,198 @@
|
||||
#pragma once
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_internal.h"
|
||||
|
||||
inline static void CopyIOEvents(ImGuiContext *src, ImGuiContext *dst,
|
||||
ImVec2 origin, float scale) {
|
||||
dst->InputEventsQueue = src->InputEventsTrail;
|
||||
for (ImGuiInputEvent &e : dst->InputEventsQueue) {
|
||||
if (e.Type == ImGuiInputEventType_MousePos) {
|
||||
e.MousePos.PosX = (e.MousePos.PosX - origin.x) / scale;
|
||||
e.MousePos.PosY = (e.MousePos.PosY - origin.y) / scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline static void AppendDrawData(ImDrawList *src, ImVec2 origin, float scale) {
|
||||
// TODO optimize if vtx_start == 0 || if idx_start == 0
|
||||
ImDrawList *dl = ImGui::GetWindowDrawList();
|
||||
const int vtx_start = dl->VtxBuffer.size();
|
||||
const int idx_start = dl->IdxBuffer.size();
|
||||
dl->VtxBuffer.resize(dl->VtxBuffer.size() + src->VtxBuffer.size());
|
||||
dl->IdxBuffer.resize(dl->IdxBuffer.size() + src->IdxBuffer.size());
|
||||
dl->CmdBuffer.reserve(dl->CmdBuffer.size() + src->CmdBuffer.size());
|
||||
dl->_VtxWritePtr = dl->VtxBuffer.Data + vtx_start;
|
||||
dl->_IdxWritePtr = dl->IdxBuffer.Data + idx_start;
|
||||
const ImDrawVert *vtx_read = src->VtxBuffer.Data;
|
||||
const ImDrawIdx *idx_read = src->IdxBuffer.Data;
|
||||
for (int i = 0, c = src->VtxBuffer.size(); i < c; ++i) {
|
||||
dl->_VtxWritePtr[i].uv = vtx_read[i].uv;
|
||||
dl->_VtxWritePtr[i].col = vtx_read[i].col;
|
||||
dl->_VtxWritePtr[i].pos = vtx_read[i].pos * scale + origin;
|
||||
}
|
||||
for (int i = 0, c = src->IdxBuffer.size(); i < c; ++i) {
|
||||
dl->_IdxWritePtr[i] = idx_read[i] + vtx_start;
|
||||
}
|
||||
for (auto cmd : src->CmdBuffer) {
|
||||
cmd.IdxOffset += idx_start;
|
||||
IM_ASSERT(cmd.VtxOffset == 0);
|
||||
cmd.ClipRect.x = cmd.ClipRect.x * scale + origin.x;
|
||||
cmd.ClipRect.y = cmd.ClipRect.y * scale + origin.y;
|
||||
cmd.ClipRect.z = cmd.ClipRect.z * scale + origin.x;
|
||||
cmd.ClipRect.w = cmd.ClipRect.w * scale + origin.y;
|
||||
dl->CmdBuffer.push_back(cmd);
|
||||
}
|
||||
|
||||
dl->_VtxCurrentIdx += src->VtxBuffer.size();
|
||||
dl->_VtxWritePtr = dl->VtxBuffer.Data + dl->VtxBuffer.size();
|
||||
dl->_IdxWritePtr = dl->IdxBuffer.Data + dl->IdxBuffer.size();
|
||||
}
|
||||
|
||||
struct ContainedContextConfig {
|
||||
bool extra_window_wrapper = false;
|
||||
ImVec2 size = {0.f, 0.f};
|
||||
ImU32 color = IM_COL32_WHITE;
|
||||
bool zoom_enabled = true;
|
||||
float zoom_min = 0.3f;
|
||||
float zoom_max = 2.f;
|
||||
float zoom_divisions = 10.f;
|
||||
float zoom_smoothness = 5.f;
|
||||
float default_zoom = 1.f;
|
||||
ImGuiKey reset_zoom_key = ImGuiKey_R;
|
||||
ImGuiMouseButton scroll_button = ImGuiMouseButton_Middle;
|
||||
};
|
||||
|
||||
class ContainedContext {
|
||||
public:
|
||||
~ContainedContext();
|
||||
ContainedContextConfig &config() { return m_config; }
|
||||
void begin();
|
||||
void end();
|
||||
[[nodiscard]] float scale() const { return m_scale; }
|
||||
[[nodiscard]] const ImVec2 &origin() const { return m_origin; }
|
||||
[[nodiscard]] bool hovered() const { return m_hovered; }
|
||||
[[nodiscard]] const ImVec2 &scroll() const { return m_scroll; }
|
||||
ImGuiContext *getRawContext() { return m_ctx; }
|
||||
|
||||
private:
|
||||
ContainedContextConfig m_config;
|
||||
|
||||
ImVec2 m_origin;
|
||||
ImVec2 m_pos;
|
||||
ImGuiContext *m_ctx = nullptr;
|
||||
ImGuiContext *m_original_ctx = nullptr;
|
||||
|
||||
bool m_anyWindowHovered = false;
|
||||
bool m_anyItemActive = false;
|
||||
bool m_hovered = false;
|
||||
|
||||
float m_scale = m_config.default_zoom, m_scaleTarget = m_config.default_zoom;
|
||||
ImVec2 m_scroll = {0.f, 0.f}, m_scrollTarget = {0.f, 0.f};
|
||||
};
|
||||
|
||||
inline ContainedContext::~ContainedContext() {
|
||||
if (m_ctx)
|
||||
ImGui::DestroyContext(m_ctx);
|
||||
}
|
||||
|
||||
inline void ContainedContext::begin() {
|
||||
ImGui::PushID(this);
|
||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, m_config.color);
|
||||
ImGui::BeginChild("view_port", m_config.size, 0, ImGuiWindowFlags_NoMove);
|
||||
ImGui::PopStyleColor();
|
||||
// m_size = ImGui::GetWindowSize();
|
||||
m_pos = ImGui::GetWindowPos();
|
||||
|
||||
ImVec2 size = ImGui::GetContentRegionAvail();
|
||||
m_origin = ImGui::GetCursorScreenPos();
|
||||
m_original_ctx = ImGui::GetCurrentContext();
|
||||
const ImGuiStyle &orig_style = ImGui::GetStyle();
|
||||
if (!m_ctx)
|
||||
m_ctx = ImGui::CreateContext(ImGui::GetIO().Fonts);
|
||||
ImGui::SetCurrentContext(m_ctx);
|
||||
ImGuiStyle &new_style = ImGui::GetStyle();
|
||||
new_style = orig_style;
|
||||
|
||||
CopyIOEvents(m_original_ctx, m_ctx, m_origin, m_scale);
|
||||
|
||||
ImGui::GetIO().DisplaySize = size / m_scale;
|
||||
ImGui::GetIO().ConfigInputTrickleEventQueue = false;
|
||||
ImGui::NewFrame();
|
||||
|
||||
if (!m_config.extra_window_wrapper)
|
||||
return;
|
||||
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Appearing);
|
||||
ImGui::SetNextWindowSize(ImGui::GetMainViewport()->WorkSize);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
|
||||
ImGui::Begin("viewport_container", nullptr,
|
||||
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBackground |
|
||||
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar |
|
||||
ImGuiWindowFlags_NoScrollWithMouse);
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
|
||||
inline void ContainedContext::end() {
|
||||
m_anyWindowHovered = ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow);
|
||||
if (m_config.extra_window_wrapper && ImGui::IsWindowHovered())
|
||||
m_anyWindowHovered = false;
|
||||
|
||||
m_anyItemActive = ImGui::IsAnyItemActive();
|
||||
|
||||
if (m_config.extra_window_wrapper)
|
||||
ImGui::End();
|
||||
|
||||
ImGui::Render();
|
||||
|
||||
ImDrawData *draw_data = ImGui::GetDrawData();
|
||||
|
||||
ImGui::SetCurrentContext(m_original_ctx);
|
||||
m_original_ctx = nullptr;
|
||||
|
||||
for (int i = 0; i < draw_data->CmdListsCount; ++i)
|
||||
AppendDrawData(draw_data->CmdLists[i], m_origin, m_scale);
|
||||
|
||||
m_hovered = ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows) &&
|
||||
!m_anyWindowHovered;
|
||||
|
||||
// Zooming
|
||||
if (m_config.zoom_enabled && m_hovered && ImGui::GetIO().MouseWheel != 0.f) {
|
||||
m_scaleTarget += ImGui::GetIO().MouseWheel / m_config.zoom_divisions;
|
||||
m_scaleTarget =
|
||||
m_scaleTarget < m_config.zoom_min ? m_config.zoom_min : m_scaleTarget;
|
||||
m_scaleTarget =
|
||||
m_scaleTarget > m_config.zoom_max ? m_config.zoom_max : m_scaleTarget;
|
||||
|
||||
if (m_config.zoom_smoothness == 0.f) {
|
||||
m_scroll += (ImGui::GetMousePos() - m_pos) / m_scaleTarget -
|
||||
(ImGui::GetMousePos() - m_pos) / m_scale;
|
||||
m_scale = m_scaleTarget;
|
||||
}
|
||||
}
|
||||
if (abs(m_scaleTarget - m_scale) >= 0.015f / m_config.zoom_smoothness) {
|
||||
float cs = (m_scaleTarget - m_scale) / m_config.zoom_smoothness;
|
||||
m_scroll += (ImGui::GetMousePos() - m_pos) / (m_scale + cs) -
|
||||
(ImGui::GetMousePos() - m_pos) / m_scale;
|
||||
m_scale += (m_scaleTarget - m_scale) / m_config.zoom_smoothness;
|
||||
|
||||
if (abs(m_scaleTarget - m_scale) < 0.015f / m_config.zoom_smoothness) {
|
||||
m_scroll += (ImGui::GetMousePos() - m_pos) / m_scaleTarget -
|
||||
(ImGui::GetMousePos() - m_pos) / m_scale;
|
||||
m_scale = m_scaleTarget;
|
||||
}
|
||||
}
|
||||
|
||||
// Zoom reset
|
||||
if (ImGui::IsKeyPressed(m_config.reset_zoom_key, false))
|
||||
m_scaleTarget = m_config.default_zoom;
|
||||
|
||||
// Scrolling
|
||||
if (m_hovered && !m_anyItemActive &&
|
||||
ImGui::IsMouseDragging(m_config.scroll_button, 0.f)) {
|
||||
m_scroll += ImGui::GetIO().MouseDelta / m_scale;
|
||||
m_scrollTarget = m_scroll;
|
||||
}
|
||||
|
||||
ImGui::EndChild();
|
||||
ImGui::PopID();
|
||||
}
|
37
lib/emscripten/emscripten_mainloop_stub.h
Normal file
37
lib/emscripten/emscripten_mainloop_stub.h
Normal file
@ -0,0 +1,37 @@
|
||||
// What does this file solves?
|
||||
// - Since Dear ImGui 1.00 we took pride that most of our examples applications had their entire
|
||||
// main-loop inside the main() function. That's because:
|
||||
// - It makes the examples easier to read, keeping the code sequential.
|
||||
// - It permit the use of local variables, making it easier to try things and perform quick
|
||||
// changes when someone needs to quickly test something (vs having to structure the example
|
||||
// in order to pass data around). This is very important because people use those examples
|
||||
// to craft easy-to-past repro when they want to discuss features or report issues.
|
||||
// - It conveys at a glance that this is a no-BS framework, it won't take your main loop away from you.
|
||||
// - It is generally nice and elegant.
|
||||
// - However, comes Emscripten... it is a wonderful and magical tech but it requires a "main loop" function.
|
||||
// - Only some of our examples would run on Emscripten. Typically the ones rendering with GL or WGPU ones.
|
||||
// - I tried to refactor those examples but felt it was problematic that other examples didn't follow the
|
||||
// same layout. Why would the SDL+GL example be structured one way and the SGL+DX11 be structured differently?
|
||||
// Especially as we are trying hard to convey that using a Dear ImGui backend in an *existing application*
|
||||
// should requires only a few dozens lines of code, and this should be consistent and symmetrical for all backends.
|
||||
// - So the next logical step was to refactor all examples to follow that layout of using a "main loop" function.
|
||||
// This worked, but it made us lose all the nice things we had...
|
||||
|
||||
// Since only about 3 examples really need to run with Emscripten, here's our solution:
|
||||
// - Use some weird macros and capturing lambda to turn a loop in main() into a function.
|
||||
// - Hide all that crap in this file so it doesn't make our examples unusually ugly.
|
||||
// As a stance and principle of Dear ImGui development we don't use C++ headers and we don't
|
||||
// want to suggest to the newcomer that we would ever use C++ headers as this would affect
|
||||
// the initial judgment of many of our target audience.
|
||||
// - Technique is based on this idea: https://github.com/ocornut/imgui/pull/2492/
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten.h>
|
||||
#include <functional>
|
||||
static std::function<void()> MainLoopForEmscriptenP;
|
||||
static void MainLoopForEmscripten() { MainLoopForEmscriptenP(); }
|
||||
#define EMSCRIPTEN_MAINLOOP_BEGIN MainLoopForEmscriptenP = [&]()
|
||||
#define EMSCRIPTEN_MAINLOOP_END ; emscripten_set_main_loop(MainLoopForEmscripten, 0, true)
|
||||
#else
|
||||
#define EMSCRIPTEN_MAINLOOP_BEGIN
|
||||
#define EMSCRIPTEN_MAINLOOP_END
|
||||
#endif
|
65
lib/emscripten/shell_minimal.html
Normal file
65
lib/emscripten/shell_minimal.html
Normal file
@ -0,0 +1,65 @@
|
||||
<!doctype html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"/>
|
||||
<title>Image Flow Editor</title>
|
||||
<style>
|
||||
body { margin: 0; background-color: black }
|
||||
/* FIXME: with our GLFW example this block seems to break resizing and io.DisplaySize gets stuck */
|
||||
.emscripten {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
margin: 0px;
|
||||
border: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
image-rendering: optimizeSpeed;
|
||||
image-rendering: -moz-crisp-edges;
|
||||
image-rendering: -o-crisp-edges;
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
image-rendering: optimize-contrast;
|
||||
image-rendering: crisp-edges;
|
||||
image-rendering: pixelated;
|
||||
-ms-interpolation-mode: nearest-neighbor;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
|
||||
<script type='text/javascript'>
|
||||
var Module = {
|
||||
preRun: [],
|
||||
postRun: [],
|
||||
print: (function() {
|
||||
return function(text) {
|
||||
text = Array.prototype.slice.call(arguments).join(' ');
|
||||
console.log(text);
|
||||
};
|
||||
})(),
|
||||
printErr: function(text) {
|
||||
text = Array.prototype.slice.call(arguments).join(' ');
|
||||
console.error(text);
|
||||
},
|
||||
canvas: (function() {
|
||||
var canvas = document.getElementById('canvas');
|
||||
//canvas.addEventListener("webglcontextlost", function(e) { alert('FIXME: WebGL context lost, please reload the page'); e.preventDefault(); }, false);
|
||||
return canvas;
|
||||
})(),
|
||||
setStatus: function(text) {
|
||||
console.log("status: " + text);
|
||||
},
|
||||
monitorRunDependencies: function(left) {
|
||||
// no run dependencies to log
|
||||
}
|
||||
};
|
||||
window.onerror = function() {
|
||||
console.log("onerror: " + event);
|
||||
};
|
||||
</script>
|
||||
{{{ SCRIPT }}}
|
||||
</body>
|
||||
</html>
|
97
lib/emscripten_browser_file.h
Normal file
97
lib/emscripten_browser_file.h
Normal file
@ -0,0 +1,97 @@
|
||||
#ifndef EMSCRIPTEN_UPLOAD_FILE_H_INCLUDED
|
||||
#define EMSCRIPTEN_UPLOAD_FILE_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <emscripten.h>
|
||||
|
||||
#define _EM_JS_INLINE(ret, c_name, js_name, params, code) \
|
||||
extern "C" { \
|
||||
ret c_name params EM_IMPORT(js_name); \
|
||||
EMSCRIPTEN_KEEPALIVE \
|
||||
__attribute__((section("em_js"), aligned(1))) inline char __em_js__##js_name[] = \
|
||||
#params "<::>" code; \
|
||||
}
|
||||
|
||||
#define EM_JS_INLINE(ret, name, params, ...) _EM_JS_INLINE(ret, name, name, params, #__VA_ARGS__)
|
||||
|
||||
namespace emscripten_browser_file {
|
||||
|
||||
/////////////////////////////////// Interface //////////////////////////////////
|
||||
|
||||
using upload_handler = void(*)(std::string const&, std::string const&, std::string_view buffer, void*);
|
||||
|
||||
inline void upload(std::string const &accept_types, upload_handler callback, void *callback_data = nullptr);
|
||||
inline void download(std::string const &filename, std::string const &mime_type, std::string_view buffer);
|
||||
|
||||
///////////////////////////////// Implementation ///////////////////////////////
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmissing-variable-declarations"
|
||||
EM_JS_INLINE(void, upload, (char const *accept_types, upload_handler callback, void *callback_data), {
|
||||
/// Prompt the browser to open the file selector dialogue, and pass the file to the given handler
|
||||
/// Accept-types are in the format ".png,.jpeg,.jpg" as per https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept
|
||||
/// Upload handler callback signature is:
|
||||
/// void my_handler(std::string const &filename, std::string const &mime_type, std::string_view buffer, void *callback_data = nullptr);
|
||||
globalThis["open_file"] = function(e) {
|
||||
const file_reader = new FileReader();
|
||||
file_reader.onload = (event) => {
|
||||
const uint8Arr = new Uint8Array(event.target.result);
|
||||
const data_ptr = Module["_malloc"](uint8Arr.length);
|
||||
const data_on_heap = new Uint8Array(Module["HEAPU8"].buffer, data_ptr, uint8Arr.length);
|
||||
data_on_heap.set(uint8Arr);
|
||||
Module["ccall"]('upload_file_return', 'number', ['string', 'string', 'number', 'number', 'number', 'number'], [event.target.filename, event.target.mime_type, data_on_heap.byteOffset, uint8Arr.length, callback, callback_data]);
|
||||
Module["_free"](data_ptr);
|
||||
};
|
||||
file_reader.filename = e.target.files[0].name;
|
||||
file_reader.mime_type = e.target.files[0].type;
|
||||
file_reader.readAsArrayBuffer(e.target.files[0]);
|
||||
};
|
||||
|
||||
var file_selector = document.createElement('input');
|
||||
file_selector.setAttribute('type', 'file');
|
||||
file_selector.setAttribute('onchange', 'globalThis["open_file"](event)');
|
||||
file_selector.setAttribute('accept', UTF8ToString(accept_types));
|
||||
file_selector.click();
|
||||
});
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
inline void upload(std::string const &accept_types, upload_handler callback, void *callback_data) {
|
||||
/// C++ wrapper for javascript upload call
|
||||
upload(accept_types.c_str(), callback, callback_data);
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmissing-variable-declarations"
|
||||
EM_JS_INLINE(void, download, (char const *filename, char const *mime_type, void const *buffer, size_t buffer_size), {
|
||||
/// Offer a buffer in memory as a file to download, specifying download filename and mime type
|
||||
var a = document.createElement('a');
|
||||
a.download = UTF8ToString(filename);
|
||||
a.href = URL.createObjectURL(new Blob([new Uint8Array(Module["HEAPU8"].buffer, buffer, buffer_size)], {type: UTF8ToString(mime_type)}));
|
||||
a.click();
|
||||
});
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
inline void download(std::string const &filename, std::string const &mime_type, std::string_view buffer) {
|
||||
/// C++ wrapper for javascript download call, accepting a string_view
|
||||
download(filename.c_str(), mime_type.c_str(), buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
extern "C" {
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE inline int upload_file_return(char const *filename, char const *mime_type, char *buffer, size_t buffer_size, upload_handler callback, void *callback_data);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE inline int upload_file_return(char const *filename, char const *mime_type, char *buffer, size_t buffer_size, upload_handler callback, void *callback_data) {
|
||||
/// Load a file - this function is called from javascript when the file upload is activated
|
||||
callback(filename, mime_type, {buffer, buffer_size}, callback_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // EMSCRIPTEN_UPLOAD_FILE_H_INCLUDED
|
47
lib/image_model.h
Normal file
47
lib/image_model.h
Normal file
@ -0,0 +1,47 @@
|
||||
#include "imgui.h"
|
||||
#include <sstream>
|
||||
#include <string_view>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <SDL2/SDL.h>
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
#include <SDL2/SDL_opengles.h>
|
||||
#else
|
||||
#include <SDL2/SDL_opengl.h>
|
||||
#endif
|
||||
#else
|
||||
#include <SDL.h>
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
#include <SDL_opengles2.h>
|
||||
#else
|
||||
#include <SDL_opengl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class ImageBundle {
|
||||
public:
|
||||
int width;
|
||||
int height;
|
||||
int channels;
|
||||
ImTextureID texture;
|
||||
GLuint *glTextureID;
|
||||
std::string_view raw_buffer;
|
||||
uint8_t *image;
|
||||
bool loaded;
|
||||
std::string fname;
|
||||
|
||||
ImageBundle() {
|
||||
fname = "";
|
||||
loaded = false;
|
||||
}
|
||||
|
||||
float aspectRatio() { return (float)width / (float)height; }
|
||||
|
||||
int calcResizedWidth(int newHeight) {
|
||||
return (int)((float)newHeight * (1.0 / aspectRatio()));
|
||||
}
|
||||
|
||||
int calcResizedHeight(int newWidth) {
|
||||
return (int)((float)newWidth * (aspectRatio()));
|
||||
}
|
||||
};
|
131
lib/imconfig.h
Normal file
131
lib/imconfig.h
Normal file
@ -0,0 +1,131 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// DEAR IMGUI COMPILE-TIME OPTIONS
|
||||
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
|
||||
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
|
||||
//-----------------------------------------------------------------------------
|
||||
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
|
||||
// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
|
||||
//-----------------------------------------------------------------------------
|
||||
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
|
||||
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
|
||||
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
|
||||
// Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
//---- Define assertion handler. Defaults to calling assert().
|
||||
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
|
||||
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
|
||||
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
|
||||
|
||||
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
|
||||
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
|
||||
// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
|
||||
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
|
||||
//#define IMGUI_API __declspec( dllexport )
|
||||
//#define IMGUI_API __declspec( dllimport )
|
||||
|
||||
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
|
||||
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87+ disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This is automatically done by IMGUI_DISABLE_OBSOLETE_FUNCTIONS.
|
||||
|
||||
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
|
||||
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
|
||||
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
|
||||
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
|
||||
//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowIDStackToolWindow() will be empty.
|
||||
|
||||
//---- Don't implement some functions to reduce linkage requirements.
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
|
||||
//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
|
||||
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME).
|
||||
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
|
||||
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
|
||||
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
|
||||
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
|
||||
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
|
||||
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
|
||||
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
|
||||
|
||||
//---- Include imgui_user.h at the end of imgui.h as a convenience
|
||||
// May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included.
|
||||
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||
//#define IMGUI_USER_H_FILENAME "my_folder/my_imgui_user.h"
|
||||
|
||||
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
|
||||
//#define IMGUI_USE_BGRA_PACKED_COLOR
|
||||
|
||||
//---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
|
||||
//#define IMGUI_USE_WCHAR32
|
||||
|
||||
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
|
||||
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
|
||||
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
|
||||
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
|
||||
//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if IMGUI_USE_STB_SPRINTF is defined.
|
||||
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
||||
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
||||
//#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined.
|
||||
|
||||
//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
|
||||
// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
|
||||
//#define IMGUI_USE_STB_SPRINTF
|
||||
|
||||
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
|
||||
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
|
||||
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
|
||||
//#define IMGUI_ENABLE_FREETYPE
|
||||
|
||||
//---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT)
|
||||
// Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided).
|
||||
// Only works in combination with IMGUI_ENABLE_FREETYPE.
|
||||
// (implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
|
||||
//#define IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||
|
||||
//---- Use stb_truetype to build and rasterize the font atlas (default)
|
||||
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
|
||||
//#define IMGUI_ENABLE_STB_TRUETYPE
|
||||
|
||||
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
|
||||
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
|
||||
/*
|
||||
#define IM_VEC2_CLASS_EXTRA \
|
||||
constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \
|
||||
operator MyVec2() const { return MyVec2(x,y); }
|
||||
|
||||
#define IM_VEC4_CLASS_EXTRA \
|
||||
constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \
|
||||
operator MyVec4() const { return MyVec4(x,y,z,w); }
|
||||
*/
|
||||
//---- ...Or use Dear ImGui's own very basic math operators.
|
||||
//#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
|
||||
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
|
||||
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
|
||||
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
|
||||
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
|
||||
//#define ImDrawIdx unsigned int
|
||||
|
||||
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
|
||||
//struct ImDrawList;
|
||||
//struct ImDrawCmd;
|
||||
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
|
||||
//#define ImDrawCallback MyImDrawCallback
|
||||
|
||||
//---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase)
|
||||
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
|
||||
//#define IM_DEBUG_BREAK IM_ASSERT(0)
|
||||
//#define IM_DEBUG_BREAK __debugbreak()
|
||||
|
||||
//---- Debug Tools: Enable slower asserts
|
||||
//#define IMGUI_DEBUG_PARANOID
|
||||
|
||||
//---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files)
|
||||
/*
|
||||
namespace ImGui
|
||||
{
|
||||
void MyFunction(const char* name, MyMatrix44* mtx);
|
||||
}
|
||||
*/
|
1068
lib/imfilebrowser.h
Normal file
1068
lib/imfilebrowser.h
Normal file
File diff suppressed because it is too large
Load Diff
21577
lib/imgui.cpp
Normal file
21577
lib/imgui.cpp
Normal file
File diff suppressed because it is too large
Load Diff
3582
lib/imgui.h
Normal file
3582
lib/imgui.h
Normal file
File diff suppressed because it is too large
Load Diff
144
lib/imgui_bezier_math.h
Executable file
144
lib/imgui_bezier_math.h
Executable file
@ -0,0 +1,144 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// VERSION 0.1
|
||||
//
|
||||
// LICENSE
|
||||
// This software is dual-licensed to the public domain and under the following
|
||||
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||
// publish, and distribute this file as you see fit.
|
||||
//
|
||||
// CREDITS
|
||||
// Written by Michal Cichon
|
||||
//------------------------------------------------------------------------------
|
||||
# ifndef __IMGUI_BEZIER_MATH_H__
|
||||
# define __IMGUI_BEZIER_MATH_H__
|
||||
# pragma once
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
# include "imgui_extra_math.h"
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
struct ImCubicBezierPointsT
|
||||
{
|
||||
T P0;
|
||||
T P1;
|
||||
T P2;
|
||||
T P3;
|
||||
};
|
||||
using ImCubicBezierPoints = ImCubicBezierPointsT<ImVec2>;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Low-level Bezier curve sampling.
|
||||
template <typename T> inline T ImLinearBezier(const T& p0, const T& p1, float t);
|
||||
template <typename T> inline T ImLinearBezierDt(const T& p0, const T& p1, float t);
|
||||
template <typename T> inline T ImQuadraticBezier(const T& p0, const T& p1, const T& p2, float t);
|
||||
template <typename T> inline T ImQuadraticBezierDt(const T& p0, const T& p1, const T& p2, float t);
|
||||
template <typename T> inline T ImCubicBezier(const T& p0, const T& p1, const T& p2, const T& p3, float t);
|
||||
template <typename T> inline T ImCubicBezierDt(const T& p0, const T& p1, const T& p2, const T& p3, float t);
|
||||
|
||||
|
||||
// High-level Bezier sampling, automatically collapse to lower level Bezier curves if control points overlap.
|
||||
template <typename T> inline T ImCubicBezierSample(const T& p0, const T& p1, const T& p2, const T& p3, float t);
|
||||
template <typename T> inline T ImCubicBezierSample(const ImCubicBezierPointsT<T>& curve, float t);
|
||||
template <typename T> inline T ImCubicBezierTangent(const T& p0, const T& p1, const T& p2, const T& p3, float t);
|
||||
template <typename T> inline T ImCubicBezierTangent(const ImCubicBezierPointsT<T>& curve, float t);
|
||||
|
||||
|
||||
// Calculate approximate length of Cubic Bezier curve.
|
||||
template <typename T> inline float ImCubicBezierLength(const T& p0, const T& p1, const T& p2, const T& p3);
|
||||
template <typename T> inline float ImCubicBezierLength(const ImCubicBezierPointsT<T>& curve);
|
||||
|
||||
|
||||
// Splits Cubic Bezier curve into two curves.
|
||||
template <typename T>
|
||||
struct ImCubicBezierSplitResultT
|
||||
{
|
||||
ImCubicBezierPointsT<T> Left;
|
||||
ImCubicBezierPointsT<T> Right;
|
||||
};
|
||||
using ImCubicBezierSplitResult = ImCubicBezierSplitResultT<ImVec2>;
|
||||
|
||||
template <typename T> inline ImCubicBezierSplitResultT<T> ImCubicBezierSplit(const T& p0, const T& p1, const T& p2, const T& p3, float t);
|
||||
template <typename T> inline ImCubicBezierSplitResultT<T> ImCubicBezierSplit(const ImCubicBezierPointsT<T>& curve, float t);
|
||||
|
||||
|
||||
// Returns bounding rectangle of Cubic Bezier curve.
|
||||
inline ImRect ImCubicBezierBoundingRect(const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3);
|
||||
inline ImRect ImCubicBezierBoundingRect(const ImCubicBezierPoints& curve);
|
||||
|
||||
|
||||
// Project point on Cubic Bezier curve.
|
||||
struct ImProjectResult
|
||||
{
|
||||
ImVec2 Point; // Point on curve
|
||||
float Time; // [0 - 1]
|
||||
float Distance; // Distance to curve
|
||||
};
|
||||
|
||||
inline ImProjectResult ImProjectOnCubicBezier(const ImVec2& p, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const int subdivisions = 100);
|
||||
inline ImProjectResult ImProjectOnCubicBezier(const ImVec2& p, const ImCubicBezierPoints& curve, const int subdivisions = 100);
|
||||
|
||||
|
||||
// Calculate intersection between line and a Cubic Bezier curve.
|
||||
struct ImCubicBezierIntersectResult
|
||||
{
|
||||
int Count;
|
||||
ImVec2 Points[3];
|
||||
};
|
||||
|
||||
inline ImCubicBezierIntersectResult ImCubicBezierLineIntersect(const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& a0, const ImVec2& a1);
|
||||
inline ImCubicBezierIntersectResult ImCubicBezierLineIntersect(const ImCubicBezierPoints& curve, const ImLine& line);
|
||||
|
||||
|
||||
// Adaptive Cubic Bezier subdivision.
|
||||
enum ImCubicBezierSubdivideFlags
|
||||
{
|
||||
ImCubicBezierSubdivide_None = 0,
|
||||
ImCubicBezierSubdivide_SkipFirst = 1
|
||||
};
|
||||
|
||||
struct ImCubicBezierSubdivideSample
|
||||
{
|
||||
ImVec2 Point;
|
||||
ImVec2 Tangent;
|
||||
};
|
||||
|
||||
using ImCubicBezierSubdivideCallback = void (*)(const ImCubicBezierSubdivideSample& p, void* user_pointer);
|
||||
|
||||
inline void ImCubicBezierSubdivide(ImCubicBezierSubdivideCallback callback, void* user_pointer, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float tess_tol = -1.0f, ImCubicBezierSubdivideFlags flags = ImCubicBezierSubdivide_None);
|
||||
inline void ImCubicBezierSubdivide(ImCubicBezierSubdivideCallback callback, void* user_pointer, const ImCubicBezierPoints& curve, float tess_tol = -1.0f, ImCubicBezierSubdivideFlags flags = ImCubicBezierSubdivide_None);
|
||||
|
||||
|
||||
// F has signature void(const ImCubicBezierSubdivideSample& p)
|
||||
template <typename F> inline void ImCubicBezierSubdivide(F& callback, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float tess_tol = -1.0f, ImCubicBezierSubdivideFlags flags = ImCubicBezierSubdivide_None);
|
||||
template <typename F> inline void ImCubicBezierSubdivide(F& callback, const ImCubicBezierPoints& curve, float tess_tol = -1.0f, ImCubicBezierSubdivideFlags flags = ImCubicBezierSubdivide_None);
|
||||
|
||||
// Fixed step Cubic Bezier subdivision.
|
||||
struct ImCubicBezierFixedStepSample
|
||||
{
|
||||
float T;
|
||||
float Length;
|
||||
ImVec2 Point;
|
||||
bool BreakSearch;
|
||||
};
|
||||
|
||||
using ImCubicBezierFixedStepCallback = void (*)(ImCubicBezierFixedStepSample& sample, void* user_pointer);
|
||||
|
||||
inline void ImCubicBezierFixedStep(ImCubicBezierFixedStepCallback callback, void* user_pointer, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float step, bool overshoot = false, float max_value_error = 1e-3f, float max_t_error = 1e-5f);
|
||||
inline void ImCubicBezierFixedStep(ImCubicBezierFixedStepCallback callback, void* user_pointer, const ImCubicBezierPoints& curve, float step, bool overshoot = false, float max_value_error = 1e-3f, float max_t_error = 1e-5f);
|
||||
|
||||
|
||||
// F has signature void(const ImCubicBezierFixedStepSample& p)
|
||||
template <typename F> inline void ImCubicBezierFixedStep(F& callback, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float step, bool overshoot = false, float max_value_error = 1e-3f, float max_t_error = 1e-5f);
|
||||
template <typename F> inline void ImCubicBezierFixedStep(F& callback, const ImCubicBezierPoints& curve, float step, bool overshoot = false, float max_value_error = 1e-3f, float max_t_error = 1e-5f);
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
# include "imgui_bezier_math.inl"
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
# endif // __IMGUI_BEZIER_MATH_H__
|
675
lib/imgui_bezier_math.inl
Executable file
675
lib/imgui_bezier_math.inl
Executable file
@ -0,0 +1,675 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// VERSION 0.1
|
||||
//
|
||||
// LICENSE
|
||||
// This software is dual-licensed to the public domain and under the following
|
||||
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||
// publish, and distribute this file as you see fit.
|
||||
//
|
||||
// CREDITS
|
||||
// Written by Michal Cichon
|
||||
//------------------------------------------------------------------------------
|
||||
# ifndef __IMGUI_BEZIER_MATH_INL__
|
||||
# define __IMGUI_BEZIER_MATH_INL__
|
||||
# pragma once
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
# include "imgui_bezier_math.h"
|
||||
# include <map> // used in ImCubicBezierFixedStep
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
inline T ImLinearBezier(const T& p0, const T& p1, float t)
|
||||
{
|
||||
return p0 + t * (p1 - p0);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T ImLinearBezierDt(const T& p0, const T& p1, float t)
|
||||
{
|
||||
IM_UNUSED(t);
|
||||
|
||||
return p1 - p0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T ImQuadraticBezier(const T& p0, const T& p1, const T& p2, float t)
|
||||
{
|
||||
const auto a = 1 - t;
|
||||
|
||||
return a * a * p0 + 2 * t * a * p1 + t * t * p2;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T ImQuadraticBezierDt(const T& p0, const T& p1, const T& p2, float t)
|
||||
{
|
||||
return 2 * (1 - t) * (p1 - p0) + 2 * t * (p2 - p1);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T ImCubicBezier(const T& p0, const T& p1, const T& p2, const T& p3, float t)
|
||||
{
|
||||
const auto a = 1 - t;
|
||||
const auto b = a * a * a;
|
||||
const auto c = t * t * t;
|
||||
|
||||
return b * p0 + 3 * t * a * a * p1 + 3 * t * t * a * p2 + c * p3;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T ImCubicBezierDt(const T& p0, const T& p1, const T& p2, const T& p3, float t)
|
||||
{
|
||||
const auto a = 1 - t;
|
||||
const auto b = a * a;
|
||||
const auto c = t * t;
|
||||
const auto d = 2 * t * a;
|
||||
|
||||
return -3 * p0 * b + 3 * p1 * (b - d) + 3 * p2 * (d - c) + 3 * p3 * c;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T ImCubicBezierSample(const T& p0, const T& p1, const T& p2, const T& p3, float t)
|
||||
{
|
||||
const auto cp0_zero = ImLengthSqr(p1 - p0) < 1e-5f;
|
||||
const auto cp1_zero = ImLengthSqr(p3 - p2) < 1e-5f;
|
||||
|
||||
if (cp0_zero && cp1_zero)
|
||||
return ImLinearBezier(p0, p3, t);
|
||||
else if (cp0_zero)
|
||||
return ImQuadraticBezier(p0, p2, p3, t);
|
||||
else if (cp1_zero)
|
||||
return ImQuadraticBezier(p0, p1, p3, t);
|
||||
else
|
||||
return ImCubicBezier(p0, p1, p2, p3, t);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T ImCubicBezierSample(const ImCubicBezierPointsT<T>& curve, float t)
|
||||
{
|
||||
return ImCubicBezierSample(curve.P0, curve.P1, curve.P2, curve.P3, t);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T ImCubicBezierTangent(const T& p0, const T& p1, const T& p2, const T& p3, float t)
|
||||
{
|
||||
const auto cp0_zero = ImLengthSqr(p1 - p0) < 1e-5f;
|
||||
const auto cp1_zero = ImLengthSqr(p3 - p2) < 1e-5f;
|
||||
|
||||
if (cp0_zero && cp1_zero)
|
||||
return ImLinearBezierDt(p0, p3, t);
|
||||
else if (cp0_zero)
|
||||
return ImQuadraticBezierDt(p0, p2, p3, t);
|
||||
else if (cp1_zero)
|
||||
return ImQuadraticBezierDt(p0, p1, p3, t);
|
||||
else
|
||||
return ImCubicBezierDt(p0, p1, p2, p3, t);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T ImCubicBezierTangent(const ImCubicBezierPointsT<T>& curve, float t)
|
||||
{
|
||||
return ImCubicBezierTangent(curve.P0, curve.P1, curve.P2, curve.P3, t);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline float ImCubicBezierLength(const T& p0, const T& p1, const T& p2, const T& p3)
|
||||
{
|
||||
// Legendre-Gauss abscissae with n=24 (x_i values, defined at i=n as the roots of the nth order Legendre polynomial Pn(x))
|
||||
static const float t_values[] =
|
||||
{
|
||||
-0.0640568928626056260850430826247450385909f,
|
||||
0.0640568928626056260850430826247450385909f,
|
||||
-0.1911188674736163091586398207570696318404f,
|
||||
0.1911188674736163091586398207570696318404f,
|
||||
-0.3150426796961633743867932913198102407864f,
|
||||
0.3150426796961633743867932913198102407864f,
|
||||
-0.4337935076260451384870842319133497124524f,
|
||||
0.4337935076260451384870842319133497124524f,
|
||||
-0.5454214713888395356583756172183723700107f,
|
||||
0.5454214713888395356583756172183723700107f,
|
||||
-0.6480936519369755692524957869107476266696f,
|
||||
0.6480936519369755692524957869107476266696f,
|
||||
-0.7401241915785543642438281030999784255232f,
|
||||
0.7401241915785543642438281030999784255232f,
|
||||
-0.8200019859739029219539498726697452080761f,
|
||||
0.8200019859739029219539498726697452080761f,
|
||||
-0.8864155270044010342131543419821967550873f,
|
||||
0.8864155270044010342131543419821967550873f,
|
||||
-0.9382745520027327585236490017087214496548f,
|
||||
0.9382745520027327585236490017087214496548f,
|
||||
-0.9747285559713094981983919930081690617411f,
|
||||
0.9747285559713094981983919930081690617411f,
|
||||
-0.9951872199970213601799974097007368118745f,
|
||||
0.9951872199970213601799974097007368118745f
|
||||
};
|
||||
|
||||
// Legendre-Gauss weights with n=24 (w_i values, defined by a function linked to in the Bezier primer article)
|
||||
static const float c_values[] =
|
||||
{
|
||||
0.1279381953467521569740561652246953718517f,
|
||||
0.1279381953467521569740561652246953718517f,
|
||||
0.1258374563468282961213753825111836887264f,
|
||||
0.1258374563468282961213753825111836887264f,
|
||||
0.1216704729278033912044631534762624256070f,
|
||||
0.1216704729278033912044631534762624256070f,
|
||||
0.1155056680537256013533444839067835598622f,
|
||||
0.1155056680537256013533444839067835598622f,
|
||||
0.1074442701159656347825773424466062227946f,
|
||||
0.1074442701159656347825773424466062227946f,
|
||||
0.0976186521041138882698806644642471544279f,
|
||||
0.0976186521041138882698806644642471544279f,
|
||||
0.0861901615319532759171852029837426671850f,
|
||||
0.0861901615319532759171852029837426671850f,
|
||||
0.0733464814110803057340336152531165181193f,
|
||||
0.0733464814110803057340336152531165181193f,
|
||||
0.0592985849154367807463677585001085845412f,
|
||||
0.0592985849154367807463677585001085845412f,
|
||||
0.0442774388174198061686027482113382288593f,
|
||||
0.0442774388174198061686027482113382288593f,
|
||||
0.0285313886289336631813078159518782864491f,
|
||||
0.0285313886289336631813078159518782864491f,
|
||||
0.0123412297999871995468056670700372915759f,
|
||||
0.0123412297999871995468056670700372915759f
|
||||
};
|
||||
|
||||
static_assert(sizeof(t_values) / sizeof(*t_values) == sizeof(c_values) / sizeof(*c_values), "");
|
||||
|
||||
auto arc = [p0, p1, p2, p3](float t)
|
||||
{
|
||||
const auto p = ImCubicBezierDt(p0, p1, p2, p3, t);
|
||||
const auto l = ImLength(p);
|
||||
return l;
|
||||
};
|
||||
|
||||
const auto z = 0.5f;
|
||||
const auto n = sizeof(t_values) / sizeof(*t_values);
|
||||
|
||||
auto accumulator = 0.0f;
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
const auto t = z * t_values[i] + z;
|
||||
accumulator += c_values[i] * arc(t);
|
||||
}
|
||||
|
||||
return z * accumulator;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline float ImCubicBezierLength(const ImCubicBezierPointsT<T>& curve)
|
||||
{
|
||||
return ImCubicBezierLength(curve.P0, curve.P1, curve.P2, curve.P3);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline ImCubicBezierSplitResultT<T> ImCubicBezierSplit(const T& p0, const T& p1, const T& p2, const T& p3, float t)
|
||||
{
|
||||
const auto z1 = t;
|
||||
const auto z2 = z1 * z1;
|
||||
const auto z3 = z1 * z1 * z1;
|
||||
const auto s1 = z1 - 1;
|
||||
const auto s2 = s1 * s1;
|
||||
const auto s3 = s1 * s1 * s1;
|
||||
|
||||
return ImCubicBezierSplitResultT<T>
|
||||
{
|
||||
ImCubicBezierPointsT<T>
|
||||
{
|
||||
p0,
|
||||
z1 * p1 - s1 * p0,
|
||||
z2 * p2 - 2 * z1 * s1 * p1 + s2 * p0,
|
||||
z3 * p3 - 3 * z2 * s1 * p2 + 3 * z1 * s2 * p1 - s3 * p0
|
||||
},
|
||||
ImCubicBezierPointsT<T>
|
||||
{
|
||||
z3 * p0 - 3 * z2 * s1 * p1 + 3 * z1 * s2 * p2 - s3 * p3,
|
||||
z2 * p1 - 2 * z1 * s1 * p2 + s2 * p3,
|
||||
z1 * p2 - s1 * p3,
|
||||
p3,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline ImCubicBezierSplitResultT<T> ImCubicBezierSplit(const ImCubicBezierPointsT<T>& curve, float t)
|
||||
{
|
||||
return ImCubicBezierSplit(curve.P0, curve.P1, curve.P2, curve.P3, t);
|
||||
}
|
||||
|
||||
inline ImRect ImCubicBezierBoundingRect(const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3)
|
||||
{
|
||||
auto a = 3 * p3 - 9 * p2 + 9 * p1 - 3 * p0;
|
||||
auto b = 6 * p0 - 12 * p1 + 6 * p2;
|
||||
auto c = 3 * p1 - 3 * p0;
|
||||
auto delta_squared = ImMul(b, b) - 4 * ImMul(a, c);
|
||||
|
||||
auto tl = ImMin(p0, p3);
|
||||
auto rb = ImMax(p0, p3);
|
||||
|
||||
# define IM_VEC2_INDEX(v, i) *(&v.x + i)
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
if (IM_VEC2_INDEX(a, i) == 0.0f)
|
||||
continue;
|
||||
|
||||
if (IM_VEC2_INDEX(delta_squared, i) >= 0)
|
||||
{
|
||||
auto delta = ImSqrt(IM_VEC2_INDEX(delta_squared, i));
|
||||
|
||||
auto t0 = (-IM_VEC2_INDEX(b, i) + delta) / (2 * IM_VEC2_INDEX(a, i));
|
||||
if (t0 > 0 && t0 < 1)
|
||||
{
|
||||
auto p = ImCubicBezier(IM_VEC2_INDEX(p0, i), IM_VEC2_INDEX(p1, i), IM_VEC2_INDEX(p2, i), IM_VEC2_INDEX(p3, i), t0);
|
||||
IM_VEC2_INDEX(tl, i) = ImMin(IM_VEC2_INDEX(tl, i), p);
|
||||
IM_VEC2_INDEX(rb, i) = ImMax(IM_VEC2_INDEX(rb, i), p);
|
||||
}
|
||||
|
||||
auto t1 = (-IM_VEC2_INDEX(b, i) - delta) / (2 * IM_VEC2_INDEX(a, i));
|
||||
if (t1 > 0 && t1 < 1)
|
||||
{
|
||||
auto p = ImCubicBezier(IM_VEC2_INDEX(p0, i), IM_VEC2_INDEX(p1, i), IM_VEC2_INDEX(p2, i), IM_VEC2_INDEX(p3, i), t1);
|
||||
IM_VEC2_INDEX(tl, i) = ImMin(IM_VEC2_INDEX(tl, i), p);
|
||||
IM_VEC2_INDEX(rb, i) = ImMax(IM_VEC2_INDEX(rb, i), p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# undef IM_VEC2_INDEX
|
||||
|
||||
return ImRect(tl, rb);
|
||||
}
|
||||
|
||||
inline ImRect ImCubicBezierBoundingRect(const ImCubicBezierPoints& curve)
|
||||
{
|
||||
return ImCubicBezierBoundingRect(curve.P0, curve.P1, curve.P2, curve.P3);
|
||||
}
|
||||
|
||||
inline ImProjectResult ImProjectOnCubicBezier(const ImVec2& point, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const int subdivisions)
|
||||
{
|
||||
// http://pomax.github.io/bezierinfo/#projections
|
||||
|
||||
const float epsilon = 1e-5f;
|
||||
const float fixed_step = 1.0f / static_cast<float>(subdivisions - 1);
|
||||
|
||||
ImProjectResult result;
|
||||
result.Point = point;
|
||||
result.Time = 0.0f;
|
||||
result.Distance = FLT_MAX;
|
||||
|
||||
// Step 1: Coarse check
|
||||
for (int i = 0; i < subdivisions; ++i)
|
||||
{
|
||||
auto t = i * fixed_step;
|
||||
auto p = ImCubicBezier(p0, p1, p2, p3, t);
|
||||
auto s = point - p;
|
||||
auto d = ImDot(s, s);
|
||||
|
||||
if (d < result.Distance)
|
||||
{
|
||||
result.Point = p;
|
||||
result.Time = t;
|
||||
result.Distance = d;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.Time == 0.0f || ImFabs(result.Time - 1.0f) <= epsilon)
|
||||
{
|
||||
result.Distance = ImSqrt(result.Distance);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Step 2: Fine check
|
||||
auto left = result.Time - fixed_step;
|
||||
auto right = result.Time + fixed_step;
|
||||
auto step = fixed_step * 0.1f;
|
||||
|
||||
for (auto t = left; t < right + step; t += step)
|
||||
{
|
||||
auto p = ImCubicBezier(p0, p1, p2, p3, t);
|
||||
auto s = point - p;
|
||||
auto d = ImDot(s, s);
|
||||
|
||||
if (d < result.Distance)
|
||||
{
|
||||
result.Point = p;
|
||||
result.Time = t;
|
||||
result.Distance = d;
|
||||
}
|
||||
}
|
||||
|
||||
result.Distance = ImSqrt(result.Distance);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline ImProjectResult ImProjectOnCubicBezier(const ImVec2& p, const ImCubicBezierPoints& curve, const int subdivisions)
|
||||
{
|
||||
return ImProjectOnCubicBezier(p, curve.P0, curve.P1, curve.P2, curve.P3, subdivisions);
|
||||
}
|
||||
|
||||
inline ImCubicBezierIntersectResult ImCubicBezierLineIntersect(const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& a0, const ImVec2& a1)
|
||||
{
|
||||
auto cubic_roots = [](float a, float b, float c, float d, float* roots) -> int
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
auto sign = [](float x) -> float { return x < 0 ? -1.0f : 1.0f; };
|
||||
|
||||
auto A = b / a;
|
||||
auto B = c / a;
|
||||
auto C = d / a;
|
||||
|
||||
auto Q = (3 * B - ImPow(A, 2)) / 9;
|
||||
auto R = (9 * A * B - 27 * C - 2 * ImPow(A, 3)) / 54;
|
||||
auto D = ImPow(Q, 3) + ImPow(R, 2); // polynomial discriminant
|
||||
|
||||
if (D >= 0) // complex or duplicate roots
|
||||
{
|
||||
auto S = sign(R + ImSqrt(D)) * ImPow(ImFabs(R + ImSqrt(D)), (1.0f / 3.0f));
|
||||
auto T = sign(R - ImSqrt(D)) * ImPow(ImFabs(R - ImSqrt(D)), (1.0f / 3.0f));
|
||||
|
||||
roots[0] = -A / 3 + (S + T); // real root
|
||||
roots[1] = -A / 3 - (S + T) / 2; // real part of complex root
|
||||
roots[2] = -A / 3 - (S + T) / 2; // real part of complex root
|
||||
auto Im = ImFabs(ImSqrt(3) * (S - T) / 2); // complex part of root pair
|
||||
|
||||
// discard complex roots
|
||||
if (Im != 0)
|
||||
count = 1;
|
||||
else
|
||||
count = 3;
|
||||
}
|
||||
else // distinct real roots
|
||||
{
|
||||
auto th = ImAcos(R / ImSqrt(-ImPow(Q, 3)));
|
||||
|
||||
roots[0] = 2 * ImSqrt(-Q) * ImCos(th / 3) - A / 3;
|
||||
roots[1] = 2 * ImSqrt(-Q) * ImCos((th + 2 * IM_PI) / 3) - A / 3;
|
||||
roots[2] = 2 * ImSqrt(-Q) * ImCos((th + 4 * IM_PI) / 3) - A / 3;
|
||||
|
||||
count = 3;
|
||||
}
|
||||
|
||||
return count;
|
||||
};
|
||||
|
||||
// https://github.com/kaishiqi/Geometric-Bezier/blob/master/GeometricBezier/src/kaishiqi/geometric/intersection/Intersection.as
|
||||
//
|
||||
// Start with Bezier using Bernstein polynomials for weighting functions:
|
||||
// (1-t^3)P0 + 3t(1-t)^2P1 + 3t^2(1-t)P2 + t^3P3
|
||||
//
|
||||
// Expand and collect terms to form linear combinations of original Bezier
|
||||
// controls. This ends up with a vector cubic in t:
|
||||
// (-P0+3P1-3P2+P3)t^3 + (3P0-6P1+3P2)t^2 + (-3P0+3P1)t + P0
|
||||
// /\ /\ /\ /\
|
||||
// || || || ||
|
||||
// c3 c2 c1 c0
|
||||
|
||||
// Calculate the coefficients
|
||||
auto c3 = -p0 + 3 * p1 - 3 * p2 + p3;
|
||||
auto c2 = 3 * p0 - 6 * p1 + 3 * p2;
|
||||
auto c1 = -3 * p0 + 3 * p1;
|
||||
auto c0 = p0;
|
||||
|
||||
// Convert line to normal form: ax + by + c = 0
|
||||
auto a = a1.y - a0.y;
|
||||
auto b = a0.x - a1.x;
|
||||
auto c = a0.x * (a0.y - a1.y) + a0.y * (a1.x - a0.x);
|
||||
|
||||
// Rotate each cubic coefficient using line for new coordinate system?
|
||||
// Find roots of rotated cubic
|
||||
float roots[3];
|
||||
auto rootCount = cubic_roots(
|
||||
a * c3.x + b * c3.y,
|
||||
a * c2.x + b * c2.y,
|
||||
a * c1.x + b * c1.y,
|
||||
a * c0.x + b * c0.y + c,
|
||||
roots);
|
||||
|
||||
// Any roots in closed interval [0,1] are intersections on Bezier, but
|
||||
// might not be on the line segment.
|
||||
// Find intersections and calculate point coordinates
|
||||
|
||||
auto min = ImMin(a0, a1);
|
||||
auto max = ImMax(a0, a1);
|
||||
|
||||
ImCubicBezierIntersectResult result;
|
||||
auto points = result.Points;
|
||||
|
||||
for (int i = 0; i < rootCount; ++i)
|
||||
{
|
||||
auto root = roots[i];
|
||||
|
||||
if (0 <= root && root <= 1)
|
||||
{
|
||||
// We're within the Bezier curve
|
||||
// Find point on Bezier
|
||||
auto p = ImCubicBezier(p0, p1, p2, p3, root);
|
||||
|
||||
// See if point is on line segment
|
||||
// Had to make special cases for vertical and horizontal lines due
|
||||
// to slight errors in calculation of p00
|
||||
if (a0.x == a1.x)
|
||||
{
|
||||
if (min.y <= p.y && p.y <= max.y)
|
||||
*points++ = p;
|
||||
}
|
||||
else if (a0.y == a1.y)
|
||||
{
|
||||
if (min.x <= p.x && p.x <= max.x)
|
||||
*points++ = p;
|
||||
}
|
||||
else if (p.x >= min.x && p.y >= min.y && p.x <= max.x && p.y <= max.y)
|
||||
{
|
||||
*points++ = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.Count = static_cast<int>(points - result.Points);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline ImCubicBezierIntersectResult ImCubicBezierLineIntersect(const ImCubicBezierPoints& curve, const ImLine& line)
|
||||
{
|
||||
return ImCubicBezierLineIntersect(curve.P0, curve.P1, curve.P2, curve.P3, line.A, line.B);
|
||||
}
|
||||
|
||||
inline void ImCubicBezierSubdivide(ImCubicBezierSubdivideCallback callback, void* user_pointer, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float tess_tol, ImCubicBezierSubdivideFlags flags)
|
||||
{
|
||||
return ImCubicBezierSubdivide(callback, user_pointer, ImCubicBezierPoints{ p0, p1, p2, p3 }, tess_tol, flags);
|
||||
}
|
||||
|
||||
inline void ImCubicBezierSubdivide(ImCubicBezierSubdivideCallback callback, void* user_pointer, const ImCubicBezierPoints& curve, float tess_tol, ImCubicBezierSubdivideFlags flags)
|
||||
{
|
||||
struct Tesselator
|
||||
{
|
||||
ImCubicBezierSubdivideCallback Callback;
|
||||
void* UserPointer;
|
||||
float TesselationTollerance;
|
||||
ImCubicBezierSubdivideFlags Flags;
|
||||
|
||||
void Commit(const ImVec2& p, const ImVec2& t)
|
||||
{
|
||||
ImCubicBezierSubdivideSample sample;
|
||||
sample.Point = p;
|
||||
sample.Tangent = t;
|
||||
Callback(sample, UserPointer);
|
||||
}
|
||||
|
||||
void Subdivide(const ImCubicBezierPoints& curve, int level = 0)
|
||||
{
|
||||
float dx = curve.P3.x - curve.P0.x;
|
||||
float dy = curve.P3.y - curve.P0.y;
|
||||
float d2 = ((curve.P1.x - curve.P3.x) * dy - (curve.P1.y - curve.P3.y) * dx);
|
||||
float d3 = ((curve.P2.x - curve.P3.x) * dy - (curve.P2.y - curve.P3.y) * dx);
|
||||
d2 = (d2 >= 0) ? d2 : -d2;
|
||||
d3 = (d3 >= 0) ? d3 : -d3;
|
||||
if ((d2 + d3) * (d2 + d3) < TesselationTollerance * (dx * dx + dy * dy))
|
||||
{
|
||||
Commit(curve.P3, ImCubicBezierTangent(curve, 1.0f));
|
||||
}
|
||||
else if (level < 10)
|
||||
{
|
||||
const auto p12 = (curve.P0 + curve.P1) * 0.5f;
|
||||
const auto p23 = (curve.P1 + curve.P2) * 0.5f;
|
||||
const auto p34 = (curve.P2 + curve.P3) * 0.5f;
|
||||
const auto p123 = (p12 + p23) * 0.5f;
|
||||
const auto p234 = (p23 + p34) * 0.5f;
|
||||
const auto p1234 = (p123 + p234) * 0.5f;
|
||||
|
||||
Subdivide(ImCubicBezierPoints { curve.P0, p12, p123, p1234 }, level + 1);
|
||||
Subdivide(ImCubicBezierPoints { p1234, p234, p34, curve.P3 }, level + 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (tess_tol < 0)
|
||||
tess_tol = 1.118f; // sqrtf(1.25f)
|
||||
|
||||
Tesselator tesselator;
|
||||
tesselator.Callback = callback;
|
||||
tesselator.UserPointer = user_pointer;
|
||||
tesselator.TesselationTollerance = tess_tol * tess_tol;
|
||||
tesselator.Flags = flags;
|
||||
|
||||
if (!(tesselator.Flags & ImCubicBezierSubdivide_SkipFirst))
|
||||
tesselator.Commit(curve.P0, ImCubicBezierTangent(curve, 0.0f));
|
||||
|
||||
tesselator.Subdivide(curve, 0);
|
||||
}
|
||||
|
||||
template <typename F> inline void ImCubicBezierSubdivide(F& callback, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float tess_tol, ImCubicBezierSubdivideFlags flags)
|
||||
{
|
||||
auto handler = [](const ImCubicBezierSubdivideSample& p, void* user_pointer)
|
||||
{
|
||||
auto& callback = *reinterpret_cast<F*>(user_pointer);
|
||||
callback(p);
|
||||
};
|
||||
|
||||
ImCubicBezierSubdivide(handler, &callback, ImCubicBezierPoints{ p0, p1, p2, p3 }, tess_tol, flags);
|
||||
}
|
||||
|
||||
template <typename F> inline void ImCubicBezierSubdivide(F& callback, const ImCubicBezierPoints& curve, float tess_tol, ImCubicBezierSubdivideFlags flags)
|
||||
{
|
||||
auto handler = [](const ImCubicBezierSubdivideSample& p, void* user_pointer)
|
||||
{
|
||||
auto& callback = *reinterpret_cast<F*>(user_pointer);
|
||||
callback(p);
|
||||
};
|
||||
|
||||
ImCubicBezierSubdivide(handler, &callback, curve, tess_tol, flags);
|
||||
}
|
||||
|
||||
inline void ImCubicBezierFixedStep(ImCubicBezierFixedStepCallback callback, void* user_pointer, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float step, bool overshoot, float max_value_error, float max_t_error)
|
||||
{
|
||||
if (step <= 0.0f || !callback || max_value_error <= 0 || max_t_error <= 0)
|
||||
return;
|
||||
|
||||
ImCubicBezierFixedStepSample sample;
|
||||
sample.T = 0.0f;
|
||||
sample.Length = 0.0f;
|
||||
sample.Point = p0;
|
||||
sample.BreakSearch = false;
|
||||
|
||||
callback(sample, user_pointer);
|
||||
if (sample.BreakSearch)
|
||||
return;
|
||||
|
||||
const auto total_length = ImCubicBezierLength(p0, p1, p2, p3);
|
||||
const auto point_count = static_cast<int>(total_length / step) + (overshoot ? 2 : 1);
|
||||
const auto t_min = 0.0f;
|
||||
const auto t_max = step * point_count / total_length;
|
||||
const auto t_0 = (t_min + t_max) * 0.5f;
|
||||
|
||||
// #todo: replace map with ImVector + binary search
|
||||
std::map<float, float> cache;
|
||||
for (int point_index = 1; point_index < point_count; ++point_index)
|
||||
{
|
||||
const auto targetLength = point_index * step;
|
||||
|
||||
float t_start = t_min;
|
||||
float t_end = t_max;
|
||||
float t = t_0;
|
||||
|
||||
float t_best = t;
|
||||
float error_best = total_length;
|
||||
|
||||
while (true)
|
||||
{
|
||||
auto cacheIt = cache.find(t);
|
||||
if (cacheIt == cache.end())
|
||||
{
|
||||
const auto front = ImCubicBezierSplit(p0, p1, p2, p3, t).Left;
|
||||
const auto split_length = ImCubicBezierLength(front);
|
||||
|
||||
cacheIt = cache.emplace(t, split_length).first;
|
||||
}
|
||||
|
||||
const auto length = cacheIt->second;
|
||||
const auto error = targetLength - length;
|
||||
|
||||
if (error < error_best)
|
||||
{
|
||||
error_best = error;
|
||||
t_best = t;
|
||||
}
|
||||
|
||||
if (ImFabs(error) <= max_value_error || ImFabs(t_start - t_end) <= max_t_error)
|
||||
{
|
||||
sample.T = t;
|
||||
sample.Length = length;
|
||||
sample.Point = ImCubicBezier(p0, p1, p2, p3, t);
|
||||
|
||||
callback(sample, user_pointer);
|
||||
if (sample.BreakSearch)
|
||||
return;
|
||||
|
||||
break;
|
||||
}
|
||||
else if (error < 0.0f)
|
||||
t_end = t;
|
||||
else // if (error > 0.0f)
|
||||
t_start = t;
|
||||
|
||||
t = (t_start + t_end) * 0.5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void ImCubicBezierFixedStep(ImCubicBezierFixedStepCallback callback, void* user_pointer, const ImCubicBezierPoints& curve, float step, bool overshoot, float max_value_error, float max_t_error)
|
||||
{
|
||||
ImCubicBezierFixedStep(callback, user_pointer, curve.P0, curve.P1, curve.P2, curve.P3, step, overshoot, max_value_error, max_t_error);
|
||||
}
|
||||
|
||||
// F has signature void(const ImCubicBezierFixedStepSample& p)
|
||||
template <typename F>
|
||||
inline void ImCubicBezierFixedStep(F& callback, const ImVec2& p0, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float step, bool overshoot, float max_value_error, float max_t_error)
|
||||
{
|
||||
auto handler = [](ImCubicBezierFixedStepSample& sample, void* user_pointer)
|
||||
{
|
||||
auto& callback = *reinterpret_cast<F*>(user_pointer);
|
||||
callback(sample);
|
||||
};
|
||||
|
||||
ImCubicBezierFixedStep(handler, &callback, p0, p1, p2, p3, step, overshoot, max_value_error, max_t_error);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
inline void ImCubicBezierFixedStep(F& callback, const ImCubicBezierPoints& curve, float step, bool overshoot, float max_value_error, float max_t_error)
|
||||
{
|
||||
auto handler = [](ImCubicBezierFixedStepSample& sample, void* user_pointer)
|
||||
{
|
||||
auto& callback = *reinterpret_cast<F*>(user_pointer);
|
||||
callback(sample);
|
||||
};
|
||||
|
||||
ImCubicBezierFixedStep(handler, &callback, curve.P0, curve.P1, curve.P2, curve.P3, step, overshoot, max_value_error, max_t_error);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
# endif // __IMGUI_BEZIER_MATH_INL__
|
8861
lib/imgui_demo.cpp
Normal file
8861
lib/imgui_demo.cpp
Normal file
File diff suppressed because it is too large
Load Diff
4644
lib/imgui_draw.cpp
Normal file
4644
lib/imgui_draw.cpp
Normal file
File diff suppressed because it is too large
Load Diff
68
lib/imgui_extra_math.h
Executable file
68
lib/imgui_extra_math.h
Executable file
@ -0,0 +1,68 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// VERSION 0.9.1
|
||||
//
|
||||
// LICENSE
|
||||
// This software is dual-licensed to the public domain and under the following
|
||||
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||
// publish, and distribute this file as you see fit.
|
||||
//
|
||||
// CREDITS
|
||||
// Written by Michal Cichon
|
||||
//------------------------------------------------------------------------------
|
||||
#ifndef __IMGUI_EXTRA_MATH_H__
|
||||
#define __IMGUI_EXTRA_MATH_H__
|
||||
#pragma once
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
#ifndef IMGUI_DEFINE_MATH_OPERATORS
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#endif
|
||||
#include "imgui.h"
|
||||
#include "imgui_internal.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
struct ImLine {
|
||||
ImVec2 A, B;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
#if IMGUI_VERSION_NUM < 19002
|
||||
inline bool operator==(const ImVec2 &lhs, const ImVec2 &rhs);
|
||||
inline bool operator!=(const ImVec2 &lhs, const ImVec2 &rhs);
|
||||
#endif
|
||||
inline ImVec2 operator*(const float lhs, const ImVec2 &rhs);
|
||||
#if IMGUI_VERSION_NUM < 18955
|
||||
inline ImVec2 operator-(const ImVec2 &lhs);
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
inline float ImLength(float v);
|
||||
inline float ImLength(const ImVec2 &v);
|
||||
inline float ImLengthSqr(float v);
|
||||
inline ImVec2 ImNormalized(const ImVec2 &v);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
inline bool ImRect_IsEmpty(const ImRect &rect);
|
||||
inline ImVec2 ImRect_ClosestPoint(const ImRect &rect, const ImVec2 &p,
|
||||
bool snap_to_edge);
|
||||
inline ImVec2 ImRect_ClosestPoint(const ImRect &rect, const ImVec2 &p,
|
||||
bool snap_to_edge, float radius);
|
||||
inline ImVec2 ImRect_ClosestPoint(const ImRect &rect, const ImRect &b);
|
||||
inline ImLine ImRect_ClosestLine(const ImRect &rect_a, const ImRect &rect_b);
|
||||
inline ImLine ImRect_ClosestLine(const ImRect &rect_a, const ImRect &rect_b,
|
||||
float radius_a, float radius_b);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
namespace ImEasing {
|
||||
|
||||
template <typename V, typename T> inline V EaseOutQuad(V b, V c, T t) {
|
||||
return b - c * (t * (t - 2));
|
||||
}
|
||||
|
||||
} // namespace ImEasing
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
#include "imgui_extra_math.inl"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
#endif // __IMGUI_EXTRA_MATH_H__
|
193
lib/imgui_extra_math.inl
Executable file
193
lib/imgui_extra_math.inl
Executable file
@ -0,0 +1,193 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// VERSION 0.9.1
|
||||
//
|
||||
// LICENSE
|
||||
// This software is dual-licensed to the public domain and under the following
|
||||
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||
// publish, and distribute this file as you see fit.
|
||||
//
|
||||
// CREDITS
|
||||
// Written by Michal Cichon
|
||||
//------------------------------------------------------------------------------
|
||||
# ifndef __IMGUI_EXTRA_MATH_INL__
|
||||
# define __IMGUI_EXTRA_MATH_INL__
|
||||
# pragma once
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
# include "imgui_extra_math.h"
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
# if IMGUI_VERSION_NUM < 19002
|
||||
inline bool operator==(const ImVec2& lhs, const ImVec2& rhs)
|
||||
{
|
||||
return lhs.x == rhs.x && lhs.y == rhs.y;
|
||||
}
|
||||
|
||||
inline bool operator!=(const ImVec2& lhs, const ImVec2& rhs)
|
||||
{
|
||||
return lhs.x != rhs.x || lhs.y != rhs.y;
|
||||
}
|
||||
# endif
|
||||
|
||||
inline ImVec2 operator*(const float lhs, const ImVec2& rhs)
|
||||
{
|
||||
return ImVec2(lhs * rhs.x, lhs * rhs.y);
|
||||
}
|
||||
|
||||
# if IMGUI_VERSION_NUM < 18955
|
||||
inline ImVec2 operator-(const ImVec2& lhs)
|
||||
{
|
||||
return ImVec2(-lhs.x, -lhs.y);
|
||||
}
|
||||
# endif
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
inline float ImLength(float v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
inline float ImLength(const ImVec2& v)
|
||||
{
|
||||
return ImSqrt(ImLengthSqr(v));
|
||||
}
|
||||
|
||||
inline float ImLengthSqr(float v)
|
||||
{
|
||||
return v * v;
|
||||
}
|
||||
|
||||
inline ImVec2 ImNormalized(const ImVec2& v)
|
||||
{
|
||||
return v * ImInvLength(v, 0.0f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
inline bool ImRect_IsEmpty(const ImRect& rect)
|
||||
{
|
||||
return rect.Min.x >= rect.Max.x
|
||||
|| rect.Min.y >= rect.Max.y;
|
||||
}
|
||||
|
||||
inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImVec2& p, bool snap_to_edge)
|
||||
{
|
||||
if (!snap_to_edge && rect.Contains(p))
|
||||
return p;
|
||||
|
||||
return ImVec2(
|
||||
(p.x > rect.Max.x) ? rect.Max.x : (p.x < rect.Min.x ? rect.Min.x : p.x),
|
||||
(p.y > rect.Max.y) ? rect.Max.y : (p.y < rect.Min.y ? rect.Min.y : p.y)
|
||||
);
|
||||
}
|
||||
|
||||
inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImVec2& p, bool snap_to_edge, float radius)
|
||||
{
|
||||
auto point = ImRect_ClosestPoint(rect, p, snap_to_edge);
|
||||
|
||||
const auto offset = p - point;
|
||||
const auto distance_sq = offset.x * offset.x + offset.y * offset.y;
|
||||
if (distance_sq <= 0)
|
||||
return point;
|
||||
|
||||
const auto distance = ImSqrt(distance_sq);
|
||||
|
||||
return point + offset * (ImMin(distance, radius) * (1.0f / distance));
|
||||
}
|
||||
|
||||
inline ImVec2 ImRect_ClosestPoint(const ImRect& rect, const ImRect& other)
|
||||
{
|
||||
ImVec2 result;
|
||||
if (other.Min.x >= rect.Max.x)
|
||||
result.x = rect.Max.x;
|
||||
else if (other.Max.x <= rect.Min.x)
|
||||
result.x = rect.Min.x;
|
||||
else
|
||||
result.x = (ImMax(rect.Min.x, other.Min.x) + ImMin(rect.Max.x, other.Max.x)) / 2;
|
||||
|
||||
if (other.Min.y >= rect.Max.y)
|
||||
result.y = rect.Max.y;
|
||||
else if (other.Max.y <= rect.Min.y)
|
||||
result.y = rect.Min.y;
|
||||
else
|
||||
result.y = (ImMax(rect.Min.y, other.Min.y) + ImMin(rect.Max.y, other.Max.y)) / 2;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline ImLine ImRect_ClosestLine(const ImRect& rect_a, const ImRect& rect_b)
|
||||
{
|
||||
ImLine result;
|
||||
result.A = ImRect_ClosestPoint(rect_a, rect_b);
|
||||
result.B = ImRect_ClosestPoint(rect_b, rect_a);
|
||||
|
||||
auto distribute = [](float& a, float& b, float a0, float a1, float b0, float b1)
|
||||
{
|
||||
if (a0 >= b1 || a1 <= b0)
|
||||
return;
|
||||
|
||||
const auto aw = a1 - a0;
|
||||
const auto bw = b1 - b0;
|
||||
|
||||
if (aw > bw)
|
||||
{
|
||||
b = b0 + bw - bw * (a - a0) / aw;
|
||||
a = b;
|
||||
}
|
||||
else if (aw < bw)
|
||||
{
|
||||
a = a0 + aw - aw * (b - b0) / bw;
|
||||
b = a;
|
||||
}
|
||||
};
|
||||
|
||||
distribute(result.A.x, result.B.x, rect_a.Min.x, rect_a.Max.x, rect_b.Min.x, rect_b.Max.x);
|
||||
distribute(result.A.y, result.B.y, rect_a.Min.y, rect_a.Max.y, rect_b.Min.y, rect_b.Max.y);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline ImLine ImRect_ClosestLine(const ImRect& rect_a, const ImRect& rect_b, float radius_a, float radius_b)
|
||||
{
|
||||
auto line = ImRect_ClosestLine(rect_a, rect_b);
|
||||
if (radius_a < 0)
|
||||
radius_a = 0;
|
||||
if (radius_b < 0)
|
||||
radius_b = 0;
|
||||
|
||||
if (radius_a == 0 && radius_b == 0)
|
||||
return line;
|
||||
|
||||
const auto offset = line.B - line.A;
|
||||
const auto length_sq = offset.x * offset.x + offset.y * offset.y;
|
||||
const auto radius_a_sq = radius_a * radius_a;
|
||||
const auto radius_b_sq = radius_b * radius_b;
|
||||
|
||||
if (length_sq <= 0)
|
||||
return line;
|
||||
|
||||
const auto length = ImSqrt(length_sq);
|
||||
const auto direction = ImVec2(offset.x / length, offset.y / length);
|
||||
|
||||
const auto total_radius_sq = radius_a_sq + radius_b_sq;
|
||||
if (total_radius_sq > length_sq)
|
||||
{
|
||||
const auto scale = length / (radius_a + radius_b);
|
||||
radius_a *= scale;
|
||||
radius_b *= scale;
|
||||
}
|
||||
|
||||
line.A = line.A + (direction * radius_a);
|
||||
line.B = line.B - (direction * radius_b);
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
# endif // __IMGUI_EXTRA_MATH_INL__
|
3894
lib/imgui_internal.h
Normal file
3894
lib/imgui_internal.h
Normal file
File diff suppressed because it is too large
Load Diff
4379
lib/imgui_tables.cpp
Normal file
4379
lib/imgui_tables.cpp
Normal file
File diff suppressed because it is too large
Load Diff
9090
lib/imgui_widgets.cpp
Normal file
9090
lib/imgui_widgets.cpp
Normal file
File diff suppressed because it is too large
Load Diff
627
lib/imstb_rectpack.h
Normal file
627
lib/imstb_rectpack.h
Normal file
@ -0,0 +1,627 @@
|
||||
// [DEAR IMGUI]
|
||||
// This is a slightly modified version of stb_rect_pack.h 1.01.
|
||||
// Grep for [DEAR IMGUI] to find the changes.
|
||||
//
|
||||
// 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).
|
||||
//
|
||||
// Has only had a few tests run, may have issues.
|
||||
//
|
||||
// More docs to come.
|
||||
//
|
||||
// No memory allocations; uses qsort() and assert() from stdlib.
|
||||
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
|
||||
//
|
||||
// This library currently uses the Skyline Bottom-Left algorithm.
|
||||
//
|
||||
// Please note: better rectangle packers are welcome! Please
|
||||
// implement them to the same API, but with a different init
|
||||
// function.
|
||||
//
|
||||
// Credits
|
||||
//
|
||||
// Library
|
||||
// Sean Barrett
|
||||
// Minor features
|
||||
// Martins Mozeiko
|
||||
// github:IntellectualKitty
|
||||
//
|
||||
// Bugfixes / warning fixes
|
||||
// Jeremy Jaussaud
|
||||
// Fabian Giesen
|
||||
//
|
||||
// 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
|
||||
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
|
||||
// 0.09 (2016-08-27) fix compiler warnings
|
||||
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
|
||||
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
|
||||
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
|
||||
// 0.05: added STBRP_ASSERT to allow replacing assert
|
||||
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
|
||||
// 0.01: initial release
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file for license information.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// INCLUDE SECTION
|
||||
//
|
||||
|
||||
#ifndef STB_INCLUDE_STB_RECT_PACK_H
|
||||
#define STB_INCLUDE_STB_RECT_PACK_H
|
||||
|
||||
#define STB_RECT_PACK_VERSION 1
|
||||
|
||||
#ifdef STBRP_STATIC
|
||||
#define STBRP_DEF static
|
||||
#else
|
||||
#define STBRP_DEF extern
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct stbrp_context stbrp_context;
|
||||
typedef struct stbrp_node stbrp_node;
|
||||
typedef struct stbrp_rect stbrp_rect;
|
||||
|
||||
typedef int stbrp_coord;
|
||||
|
||||
#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
|
||||
// 'stbrp_rect' defined below, stored in the array 'rects', and there
|
||||
// are 'num_rects' many of them.
|
||||
//
|
||||
// Rectangles which are successfully packed have the 'was_packed' flag
|
||||
// set to a non-zero value and 'x' and 'y' store the minimum location
|
||||
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
|
||||
// if you imagine y increasing downwards). Rectangles which do not fit
|
||||
// have the 'was_packed' flag set to 0.
|
||||
//
|
||||
// You should not try to access the 'rects' array from another thread
|
||||
// while this function is running, as the function temporarily reorders
|
||||
// the array while it executes.
|
||||
//
|
||||
// To pack into another rectangle, you need to call stbrp_init_target
|
||||
// again. To continue packing into the same rectangle, you can call
|
||||
// this function again. Calling this multiple times with multiple rect
|
||||
// arrays will probably produce worse packing results than calling it
|
||||
// a single time with the full rectangle array, but the option is
|
||||
// available.
|
||||
//
|
||||
// The function returns 1 if all of the rectangles were successfully
|
||||
// packed and 0 otherwise.
|
||||
|
||||
struct stbrp_rect
|
||||
{
|
||||
// reserved for your use:
|
||||
int id;
|
||||
|
||||
// input:
|
||||
stbrp_coord w, h;
|
||||
|
||||
// output:
|
||||
stbrp_coord x, y;
|
||||
int was_packed; // non-zero if valid packing
|
||||
|
||||
}; // 16 bytes, nominally
|
||||
|
||||
|
||||
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
|
||||
// Initialize a rectangle packer to:
|
||||
// pack a rectangle that is 'width' by 'height' in dimensions
|
||||
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
|
||||
//
|
||||
// You must call this function every time you start packing into a new target.
|
||||
//
|
||||
// There is no "shutdown" function. The 'nodes' memory must stay valid for
|
||||
// the following stbrp_pack_rects() call (or calls), but can be freed after
|
||||
// the call (or calls) finish.
|
||||
//
|
||||
// Note: to guarantee best results, either:
|
||||
// 1. make sure 'num_nodes' >= 'width'
|
||||
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
|
||||
//
|
||||
// If you don't do either of the above things, widths will be quantized to multiples
|
||||
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
|
||||
//
|
||||
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
|
||||
// may run out of temporary storage and be unable to pack some rectangles.
|
||||
|
||||
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
|
||||
// Optionally call this function after init but before doing any packing to
|
||||
// change the handling of the out-of-temp-memory scenario, described above.
|
||||
// If you call init again, this will be reset to the default (false).
|
||||
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
|
||||
// Optionally select which packing heuristic the library should use. Different
|
||||
// heuristics will produce better/worse results for different data sets.
|
||||
// If you call init again, this will be reset to the default.
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP_HEURISTIC_Skyline_default=0,
|
||||
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
|
||||
STBRP_HEURISTIC_Skyline_BF_sortHeight
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// the details of the following structures don't matter to you, but they must
|
||||
// be visible so you can handle the memory allocations for them
|
||||
|
||||
struct stbrp_node
|
||||
{
|
||||
stbrp_coord x,y;
|
||||
stbrp_node *next;
|
||||
};
|
||||
|
||||
struct stbrp_context
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
int align;
|
||||
int init_mode;
|
||||
int heuristic;
|
||||
int num_nodes;
|
||||
stbrp_node *active_head;
|
||||
stbrp_node *free_head;
|
||||
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPLEMENTATION SECTION
|
||||
//
|
||||
|
||||
#ifdef STB_RECT_PACK_IMPLEMENTATION
|
||||
#ifndef STBRP_SORT
|
||||
#include <stdlib.h>
|
||||
#define STBRP_SORT qsort
|
||||
#endif
|
||||
|
||||
#ifndef STBRP_ASSERT
|
||||
#include <assert.h>
|
||||
#define STBRP_ASSERT assert
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define STBRP__NOTUSED(v) (void)(v)
|
||||
#define STBRP__CDECL __cdecl
|
||||
#else
|
||||
#define STBRP__NOTUSED(v) (void)sizeof(v)
|
||||
#define STBRP__CDECL
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP__INIT_skyline = 1
|
||||
};
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
|
||||
{
|
||||
switch (context->init_mode) {
|
||||
case STBRP__INIT_skyline:
|
||||
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
|
||||
context->heuristic = heuristic;
|
||||
break;
|
||||
default:
|
||||
STBRP_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
|
||||
{
|
||||
if (allow_out_of_mem)
|
||||
// if it's ok to run out of memory, then don't bother aligning them;
|
||||
// this gives better packing, but may fail due to OOM (even though
|
||||
// the rectangles easily fit). @TODO a smarter approach would be to only
|
||||
// quantize once we've hit OOM, then we could get rid of this parameter.
|
||||
context->align = 1;
|
||||
else {
|
||||
// if it's not ok to run out of memory, then quantize the widths
|
||||
// so that num_nodes is always enough nodes.
|
||||
//
|
||||
// I.e. num_nodes * align >= width
|
||||
// align >= width / num_nodes
|
||||
// align = ceil(width/num_nodes)
|
||||
|
||||
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
|
||||
}
|
||||
}
|
||||
|
||||
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < num_nodes-1; ++i)
|
||||
nodes[i].next = &nodes[i+1];
|
||||
nodes[i].next = NULL;
|
||||
context->init_mode = STBRP__INIT_skyline;
|
||||
context->heuristic = STBRP_HEURISTIC_Skyline_default;
|
||||
context->free_head = &nodes[0];
|
||||
context->active_head = &context->extra[0];
|
||||
context->width = width;
|
||||
context->height = height;
|
||||
context->num_nodes = num_nodes;
|
||||
stbrp_setup_allow_out_of_mem(context, 0);
|
||||
|
||||
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
|
||||
context->extra[0].x = 0;
|
||||
context->extra[0].y = 0;
|
||||
context->extra[0].next = &context->extra[1];
|
||||
context->extra[1].x = (stbrp_coord) width;
|
||||
context->extra[1].y = (1<<30);
|
||||
context->extra[1].next = NULL;
|
||||
}
|
||||
|
||||
// find minimum y position if it starts at x1
|
||||
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
|
||||
{
|
||||
stbrp_node *node = first;
|
||||
int x1 = x0 + width;
|
||||
int min_y, visited_width, waste_area;
|
||||
|
||||
STBRP__NOTUSED(c);
|
||||
|
||||
STBRP_ASSERT(first->x <= x0);
|
||||
|
||||
#if 0
|
||||
// skip in case we're past the node
|
||||
while (node->next->x <= x0)
|
||||
++node;
|
||||
#else
|
||||
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
|
||||
#endif
|
||||
|
||||
STBRP_ASSERT(node->x <= x0);
|
||||
|
||||
min_y = 0;
|
||||
waste_area = 0;
|
||||
visited_width = 0;
|
||||
while (node->x < x1) {
|
||||
if (node->y > min_y) {
|
||||
// raise min_y higher.
|
||||
// we've accounted for all waste up to min_y,
|
||||
// but we'll now add more waste for everything we've visted
|
||||
waste_area += visited_width * (node->y - min_y);
|
||||
min_y = node->y;
|
||||
// the first time through, visited_width might be reduced
|
||||
if (node->x < x0)
|
||||
visited_width += node->next->x - x0;
|
||||
else
|
||||
visited_width += node->next->x - node->x;
|
||||
} else {
|
||||
// add waste area
|
||||
int under_width = node->next->x - node->x;
|
||||
if (under_width + visited_width > width)
|
||||
under_width = width - visited_width;
|
||||
waste_area += under_width * (min_y - node->y);
|
||||
visited_width += under_width;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
*pwaste = waste_area;
|
||||
return min_y;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int x,y;
|
||||
stbrp_node **prev_link;
|
||||
} stbrp__findresult;
|
||||
|
||||
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
|
||||
{
|
||||
int best_waste = (1<<30), best_x, best_y = (1 << 30);
|
||||
stbrp__findresult fr;
|
||||
stbrp_node **prev, *node, *tail, **best = NULL;
|
||||
|
||||
// align to multiple of c->align
|
||||
width = (width + c->align - 1);
|
||||
width -= width % c->align;
|
||||
STBRP_ASSERT(width % c->align == 0);
|
||||
|
||||
// if it can't possibly fit, bail immediately
|
||||
if (width > c->width || height > c->height) {
|
||||
fr.prev_link = NULL;
|
||||
fr.x = fr.y = 0;
|
||||
return fr;
|
||||
}
|
||||
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
while (node->x + width <= c->width) {
|
||||
int y,waste;
|
||||
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
|
||||
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
|
||||
// bottom left
|
||||
if (y < best_y) {
|
||||
best_y = y;
|
||||
best = prev;
|
||||
}
|
||||
} else {
|
||||
// best-fit
|
||||
if (y + height <= c->height) {
|
||||
// can only use it if it first vertically
|
||||
if (y < best_y || (y == best_y && waste < best_waste)) {
|
||||
best_y = y;
|
||||
best_waste = waste;
|
||||
best = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
prev = &node->next;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
best_x = (best == NULL) ? 0 : (*best)->x;
|
||||
|
||||
// if doing best-fit (BF), we also have to try aligning right edge to each node position
|
||||
//
|
||||
// e.g, if fitting
|
||||
//
|
||||
// ____________________
|
||||
// |____________________|
|
||||
//
|
||||
// into
|
||||
//
|
||||
// | |
|
||||
// | ____________|
|
||||
// |____________|
|
||||
//
|
||||
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
|
||||
//
|
||||
// This makes BF take about 2x the time
|
||||
|
||||
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
|
||||
tail = c->active_head;
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
// find first node that's admissible
|
||||
while (tail->x < width)
|
||||
tail = tail->next;
|
||||
while (tail) {
|
||||
int xpos = tail->x - width;
|
||||
int y,waste;
|
||||
STBRP_ASSERT(xpos >= 0);
|
||||
// find the left position that matches this
|
||||
while (node->next->x <= xpos) {
|
||||
prev = &node->next;
|
||||
node = node->next;
|
||||
}
|
||||
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
|
||||
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
|
||||
if (y + height <= c->height) {
|
||||
if (y <= best_y) {
|
||||
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
|
||||
best_x = xpos;
|
||||
//STBRP_ASSERT(y <= best_y); [DEAR IMGUI]
|
||||
best_y = y;
|
||||
best_waste = waste;
|
||||
best = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
tail = tail->next;
|
||||
}
|
||||
}
|
||||
|
||||
fr.prev_link = best;
|
||||
fr.x = best_x;
|
||||
fr.y = best_y;
|
||||
return fr;
|
||||
}
|
||||
|
||||
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
|
||||
{
|
||||
// find best position according to heuristic
|
||||
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
|
||||
stbrp_node *node, *cur;
|
||||
|
||||
// bail if:
|
||||
// 1. it failed
|
||||
// 2. the best node doesn't fit (we don't always check this)
|
||||
// 3. we're out of memory
|
||||
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
|
||||
res.prev_link = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
// on success, create new node
|
||||
node = context->free_head;
|
||||
node->x = (stbrp_coord) res.x;
|
||||
node->y = (stbrp_coord) (res.y + height);
|
||||
|
||||
context->free_head = node->next;
|
||||
|
||||
// insert the new node into the right starting point, and
|
||||
// let 'cur' point to the remaining nodes needing to be
|
||||
// stiched back in
|
||||
|
||||
cur = *res.prev_link;
|
||||
if (cur->x < res.x) {
|
||||
// preserve the existing one, so start testing with the next one
|
||||
stbrp_node *next = cur->next;
|
||||
cur->next = node;
|
||||
cur = next;
|
||||
} else {
|
||||
*res.prev_link = node;
|
||||
}
|
||||
|
||||
// from here, traverse cur and free the nodes, until we get to one
|
||||
// that shouldn't be freed
|
||||
while (cur->next && cur->next->x <= res.x + width) {
|
||||
stbrp_node *next = cur->next;
|
||||
// move the current node to the free list
|
||||
cur->next = context->free_head;
|
||||
context->free_head = cur;
|
||||
cur = next;
|
||||
}
|
||||
|
||||
// stitch the list back in
|
||||
node->next = cur;
|
||||
|
||||
if (cur->x < res.x + width)
|
||||
cur->x = (stbrp_coord) (res.x + width);
|
||||
|
||||
#ifdef _DEBUG
|
||||
cur = context->active_head;
|
||||
while (cur->x < context->width) {
|
||||
STBRP_ASSERT(cur->x < cur->next->x);
|
||||
cur = cur->next;
|
||||
}
|
||||
STBRP_ASSERT(cur->next == NULL);
|
||||
|
||||
{
|
||||
int count=0;
|
||||
cur = context->active_head;
|
||||
while (cur) {
|
||||
cur = cur->next;
|
||||
++count;
|
||||
}
|
||||
cur = context->free_head;
|
||||
while (cur) {
|
||||
cur = cur->next;
|
||||
++count;
|
||||
}
|
||||
STBRP_ASSERT(count == context->num_nodes+2);
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
if (p->h > q->h)
|
||||
return -1;
|
||||
if (p->h < q->h)
|
||||
return 1;
|
||||
return (p->w > q->w) ? -1 : (p->w < q->w);
|
||||
}
|
||||
|
||||
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
|
||||
}
|
||||
|
||||
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
|
||||
{
|
||||
int i, all_rects_packed = 1;
|
||||
|
||||
// we use the 'was_packed' field internally to allow sorting/unsorting
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
rects[i].was_packed = i;
|
||||
}
|
||||
|
||||
// sort according to heuristic
|
||||
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
|
||||
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
if (rects[i].w == 0 || rects[i].h == 0) {
|
||||
rects[i].x = rects[i].y = 0; // empty rect needs no space
|
||||
} else {
|
||||
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
|
||||
if (fr.prev_link) {
|
||||
rects[i].x = (stbrp_coord) fr.x;
|
||||
rects[i].y = (stbrp_coord) fr.y;
|
||||
} else {
|
||||
rects[i].x = rects[i].y = STBRP__MAXVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unsort
|
||||
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
|
||||
|
||||
// set was_packed flags and all_rects_packed status
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
|
||||
if (!rects[i].was_packed)
|
||||
all_rects_packed = 0;
|
||||
}
|
||||
|
||||
// return the all_rects_packed status
|
||||
return all_rects_packed;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
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.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
1441
lib/imstb_textedit.h
Normal file
1441
lib/imstb_textedit.h
Normal file
File diff suppressed because it is too large
Load Diff
5085
lib/imstb_truetype.h
Normal file
5085
lib/imstb_truetype.h
Normal file
File diff suppressed because it is too large
Load Diff
534
lib/nodes/load_image.h
Normal file
534
lib/nodes/load_image.h
Normal file
@ -0,0 +1,534 @@
|
||||
|
||||
#include "../ImNodeFlow.h"
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
#include <ostream>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <SDL2/SDL.h>
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
#include <SDL2/SDL_opengles.h>
|
||||
#else
|
||||
#include <SDL2/SDL_opengl.h>
|
||||
#endif
|
||||
#else
|
||||
#include <SDL.h>
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
#include <SDL_opengles2.h>
|
||||
#else
|
||||
#include <SDL_opengl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "../image_model.h"
|
||||
#include "../imfilebrowser.h"
|
||||
#include "../stb_image.h"
|
||||
#include "../uuid.h"
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include "../emscripten_browser_file.h"
|
||||
#endif
|
||||
|
||||
struct Texture {
|
||||
ImTextureID texture;
|
||||
ImVec2 size;
|
||||
};
|
||||
|
||||
struct LoadCallback {
|
||||
std::string filename;
|
||||
std::string mime_type;
|
||||
std::string_view buffer;
|
||||
};
|
||||
|
||||
class Exposure : public ImFlow::BaseNode {
|
||||
public:
|
||||
ImageBundle returnBundle;
|
||||
Exposure() {
|
||||
setTitle("Exposure");
|
||||
setStyle(ImFlow::NodeStyle::green());
|
||||
addIN<ImageBundle>("Image", ImageBundle());
|
||||
addOUT<ImageBundle>("Image Out")->behaviour([this]() {
|
||||
return returnBundle;
|
||||
});
|
||||
}
|
||||
|
||||
~Exposure() { stbi_image_free(returnBundle.image); }
|
||||
|
||||
void draw() override {
|
||||
ImGui::SetNextItemWidth(100);
|
||||
ImGui::SliderInt("", &brightnessVal, -255, 255);
|
||||
ImageBundle val = getInVal<ImageBundle>("Image");
|
||||
|
||||
// If the input is valid, and out buffers are not
|
||||
if (val.loaded && !returnBundle.loaded) {
|
||||
int img_size = val.width * val.height * val.channels;
|
||||
uint8_t *duplicated_img = (uint8_t *)malloc(img_size);
|
||||
memcpy(duplicated_img, val.image, img_size);
|
||||
returnBundle.image = duplicated_img;
|
||||
returnBundle.height = val.height;
|
||||
returnBundle.width = val.width;
|
||||
returnBundle.channels = val.channels;
|
||||
returnBundle.loaded = true;
|
||||
returnBundle.fname = uuid::generate_uuid_v4();
|
||||
fname = val.fname;
|
||||
compute(val.image, returnBundle.image, img_size, returnBundle.channels);
|
||||
}
|
||||
|
||||
// If the input is invalid, and are buffers are valid
|
||||
if (!val.loaded && returnBundle.loaded) {
|
||||
stbi_image_free(returnBundle.image);
|
||||
returnBundle.loaded = false;
|
||||
}
|
||||
|
||||
// If the input has changed
|
||||
if (val.fname != fname) {
|
||||
int img_size = val.width * val.height * val.channels;
|
||||
int old_img_size =
|
||||
returnBundle.width * returnBundle.height * returnBundle.channels;
|
||||
if (img_size == old_img_size) {
|
||||
memcpy(returnBundle.image, val.image, img_size);
|
||||
returnBundle.fname = uuid::generate_uuid_v4();
|
||||
fname = val.fname;
|
||||
int img_size =
|
||||
returnBundle.width * returnBundle.height * returnBundle.channels;
|
||||
compute(val.image, returnBundle.image, img_size, returnBundle.channels);
|
||||
} else {
|
||||
stbi_image_free(returnBundle.image);
|
||||
uint8_t *duplicated_img = (uint8_t *)malloc(img_size);
|
||||
memcpy(duplicated_img, val.image, img_size);
|
||||
returnBundle.image = duplicated_img;
|
||||
returnBundle.height = val.height;
|
||||
returnBundle.width = val.width;
|
||||
returnBundle.channels = val.channels;
|
||||
returnBundle.fname = uuid::generate_uuid_v4();
|
||||
fname = val.fname;
|
||||
int img_size =
|
||||
returnBundle.width * returnBundle.height * returnBundle.channels;
|
||||
compute(val.image, returnBundle.image, img_size, returnBundle.channels);
|
||||
}
|
||||
}
|
||||
|
||||
if (returnBundle.loaded) {
|
||||
if (brightnessVal != prev_brightness) {
|
||||
int img_size =
|
||||
returnBundle.width * returnBundle.height * returnBundle.channels;
|
||||
compute(val.image, returnBundle.image, img_size, returnBundle.channels);
|
||||
prev_brightness = brightnessVal;
|
||||
returnBundle.fname = uuid::generate_uuid_v4();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static int formula(uint8_t color, int val) {
|
||||
float vf = static_cast<float>(val) / 255.0;
|
||||
vf = vf + 1.0;
|
||||
float cf = static_cast<float>(color) / 255.0;
|
||||
float ret_val = (cf * vf) * 255.0f;
|
||||
return static_cast<int>(ret_val);
|
||||
}
|
||||
|
||||
void compute(uint8_t *input, uint8_t *output, int size, int channels) {
|
||||
for (int i = 0; i < size; i += channels) {
|
||||
uint8_t r = std::clamp(formula(input[i], brightnessVal), 0, 255);
|
||||
uint8_t g = std::clamp(formula(input[i + 1], brightnessVal), 0, 255);
|
||||
uint8_t b = std::clamp(formula(input[i + 2], brightnessVal), 0, 255);
|
||||
output[i] = r;
|
||||
output[i + 1] = g;
|
||||
output[i + 2] = b;
|
||||
}
|
||||
}
|
||||
|
||||
int brightnessVal = 0;
|
||||
int prev_brightness = 0;
|
||||
std::string fname;
|
||||
};
|
||||
|
||||
class Contrast : public ImFlow::BaseNode {
|
||||
public:
|
||||
ImageBundle returnBundle;
|
||||
Contrast() {
|
||||
setTitle("Contrast");
|
||||
setStyle(ImFlow::NodeStyle::green());
|
||||
addIN<ImageBundle>("Image", ImageBundle());
|
||||
addOUT<ImageBundle>("Image Out")->behaviour([this]() {
|
||||
return returnBundle;
|
||||
});
|
||||
}
|
||||
|
||||
~Contrast() { stbi_image_free(returnBundle.image); }
|
||||
|
||||
void draw() override {
|
||||
ImGui::SetNextItemWidth(100);
|
||||
ImGui::SliderInt("", &brightnessVal, -255, 255);
|
||||
ImageBundle val = getInVal<ImageBundle>("Image");
|
||||
|
||||
// If the input is valid, and out buffers are not
|
||||
if (val.loaded && !returnBundle.loaded) {
|
||||
int img_size = val.width * val.height * val.channels;
|
||||
uint8_t *duplicated_img = (uint8_t *)malloc(img_size);
|
||||
memcpy(duplicated_img, val.image, img_size);
|
||||
returnBundle.image = duplicated_img;
|
||||
returnBundle.height = val.height;
|
||||
returnBundle.width = val.width;
|
||||
returnBundle.channels = val.channels;
|
||||
returnBundle.loaded = true;
|
||||
returnBundle.fname = uuid::generate_uuid_v4();
|
||||
fname = val.fname;
|
||||
compute(val.image, returnBundle.image, img_size, returnBundle.channels);
|
||||
}
|
||||
|
||||
// If the input is invalid, and are buffers are valid
|
||||
if (!val.loaded && returnBundle.loaded) {
|
||||
stbi_image_free(returnBundle.image);
|
||||
returnBundle.loaded = false;
|
||||
}
|
||||
|
||||
// If the input has changed
|
||||
if (val.fname != fname) {
|
||||
int img_size = val.width * val.height * val.channels;
|
||||
int old_img_size =
|
||||
returnBundle.width * returnBundle.height * returnBundle.channels;
|
||||
if (img_size == old_img_size) {
|
||||
memcpy(returnBundle.image, val.image, img_size);
|
||||
returnBundle.fname = uuid::generate_uuid_v4();
|
||||
fname = val.fname;
|
||||
int img_size =
|
||||
returnBundle.width * returnBundle.height * returnBundle.channels;
|
||||
compute(val.image, returnBundle.image, img_size, returnBundle.channels);
|
||||
} else {
|
||||
stbi_image_free(returnBundle.image);
|
||||
uint8_t *duplicated_img = (uint8_t *)malloc(img_size);
|
||||
memcpy(duplicated_img, val.image, img_size);
|
||||
returnBundle.image = duplicated_img;
|
||||
returnBundle.height = val.height;
|
||||
returnBundle.width = val.width;
|
||||
returnBundle.channels = val.channels;
|
||||
returnBundle.fname = uuid::generate_uuid_v4();
|
||||
fname = val.fname;
|
||||
int img_size =
|
||||
returnBundle.width * returnBundle.height * returnBundle.channels;
|
||||
compute(val.image, returnBundle.image, img_size, returnBundle.channels);
|
||||
}
|
||||
}
|
||||
|
||||
if (returnBundle.loaded) {
|
||||
if (brightnessVal != prev_brightness) {
|
||||
int img_size =
|
||||
returnBundle.width * returnBundle.height * returnBundle.channels;
|
||||
compute(val.image, returnBundle.image, img_size, returnBundle.channels);
|
||||
prev_brightness = brightnessVal;
|
||||
returnBundle.fname = uuid::generate_uuid_v4();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static int formula(uint8_t color, int val) {
|
||||
float vf = static_cast<float>(val) / 255.0;
|
||||
vf = vf + 1.0;
|
||||
float cf = static_cast<float>(color) / 255.0;
|
||||
float ret_val = (((cf - 0.5f) * vf) + 0.5f) * 255.0f;
|
||||
return static_cast<int>(ret_val);
|
||||
}
|
||||
|
||||
void compute(uint8_t *input, uint8_t *output, int size, int channels) {
|
||||
int nBval = brightnessVal + 256;
|
||||
for (int i = 0; i < size; i += channels) {
|
||||
uint8_t r = std::clamp(formula(input[i], brightnessVal), 0, 255);
|
||||
uint8_t g = std::clamp(formula(input[i + 1], brightnessVal), 0, 255);
|
||||
uint8_t b = std::clamp(formula(input[i + 2], brightnessVal), 0, 255);
|
||||
output[i] = r;
|
||||
output[i + 1] = g;
|
||||
output[i + 2] = b;
|
||||
}
|
||||
}
|
||||
|
||||
int brightnessVal = 0;
|
||||
int prev_brightness = 0;
|
||||
std::string fname;
|
||||
};
|
||||
|
||||
class SimpleBrightness : public ImFlow::BaseNode {
|
||||
public:
|
||||
ImageBundle returnBundle;
|
||||
SimpleBrightness() {
|
||||
setTitle("Simple Brightness");
|
||||
setStyle(ImFlow::NodeStyle::green());
|
||||
addIN<ImageBundle>("Image", ImageBundle());
|
||||
addOUT<ImageBundle>("Image Out")->behaviour([this]() {
|
||||
return returnBundle;
|
||||
});
|
||||
}
|
||||
|
||||
~SimpleBrightness() { stbi_image_free(returnBundle.image); }
|
||||
|
||||
void draw() override {
|
||||
ImGui::SetNextItemWidth(100);
|
||||
ImGui::SliderInt("", &brightnessVal, -255, 255);
|
||||
ImageBundle val = getInVal<ImageBundle>("Image");
|
||||
|
||||
// If the input is valid, and out buffers are not
|
||||
if (val.loaded && !returnBundle.loaded) {
|
||||
int img_size = val.width * val.height * val.channels;
|
||||
uint8_t *duplicated_img = (uint8_t *)malloc(img_size);
|
||||
memcpy(duplicated_img, val.image, img_size);
|
||||
returnBundle.image = duplicated_img;
|
||||
returnBundle.height = val.height;
|
||||
returnBundle.width = val.width;
|
||||
returnBundle.channels = val.channels;
|
||||
returnBundle.loaded = true;
|
||||
returnBundle.fname = uuid::generate_uuid_v4();
|
||||
fname = val.fname;
|
||||
compute(val.image, returnBundle.image, img_size, returnBundle.channels);
|
||||
}
|
||||
|
||||
// If the input is invalid, and are buffers are valid
|
||||
if (!val.loaded && returnBundle.loaded) {
|
||||
stbi_image_free(returnBundle.image);
|
||||
returnBundle.loaded = false;
|
||||
}
|
||||
|
||||
// If the input has changed
|
||||
if (val.fname != fname) {
|
||||
int img_size = val.width * val.height * val.channels;
|
||||
int old_img_size =
|
||||
returnBundle.width * returnBundle.height * returnBundle.channels;
|
||||
if (img_size == old_img_size) {
|
||||
memcpy(returnBundle.image, val.image, img_size);
|
||||
returnBundle.fname = uuid::generate_uuid_v4();
|
||||
fname = val.fname;
|
||||
int img_size =
|
||||
returnBundle.width * returnBundle.height * returnBundle.channels;
|
||||
compute(val.image, returnBundle.image, img_size, returnBundle.channels);
|
||||
} else {
|
||||
stbi_image_free(returnBundle.image);
|
||||
uint8_t *duplicated_img = (uint8_t *)malloc(img_size);
|
||||
memcpy(duplicated_img, val.image, img_size);
|
||||
returnBundle.image = duplicated_img;
|
||||
returnBundle.height = val.height;
|
||||
returnBundle.width = val.width;
|
||||
returnBundle.channels = val.channels;
|
||||
returnBundle.fname = uuid::generate_uuid_v4();
|
||||
fname = val.fname;
|
||||
int img_size =
|
||||
returnBundle.width * returnBundle.height * returnBundle.channels;
|
||||
compute(val.image, returnBundle.image, img_size, returnBundle.channels);
|
||||
}
|
||||
}
|
||||
|
||||
if (returnBundle.loaded) {
|
||||
if (brightnessVal != prev_brightness) {
|
||||
int img_size =
|
||||
returnBundle.width * returnBundle.height * returnBundle.channels;
|
||||
compute(val.image, returnBundle.image, img_size, returnBundle.channels);
|
||||
prev_brightness = brightnessVal;
|
||||
returnBundle.fname = uuid::generate_uuid_v4();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void compute(uint8_t *input, uint8_t *output, int size, int channels) {
|
||||
for (int i = 0; i < size; i += channels) {
|
||||
uint8_t r = std::clamp(input[i] + brightnessVal, 0, 255);
|
||||
uint8_t g = std::clamp(input[i + 1] + brightnessVal, 0, 255);
|
||||
uint8_t b = std::clamp(input[i + 2] + brightnessVal, 0, 255);
|
||||
output[i] = r;
|
||||
output[i + 1] = g;
|
||||
output[i + 2] = b;
|
||||
}
|
||||
}
|
||||
|
||||
int brightnessVal = 0;
|
||||
int prev_brightness = 0;
|
||||
std::string fname;
|
||||
};
|
||||
|
||||
class PreviewImage : public ImFlow::BaseNode {
|
||||
public:
|
||||
PreviewImage() {
|
||||
setTitle("Output");
|
||||
setStyle(ImFlow::NodeStyle::cyan());
|
||||
addIN<ImageBundle>("Image", ImageBundle());
|
||||
}
|
||||
|
||||
~PreviewImage() {
|
||||
if (loaded) {
|
||||
glDeleteTextures(1, &txHandle);
|
||||
}
|
||||
}
|
||||
|
||||
void draw() override {
|
||||
ImageBundle val = getInVal<ImageBundle>("Image");
|
||||
if (val.loaded && !loaded) {
|
||||
GLuint textureHandle;
|
||||
glGenTextures(1, &textureHandle);
|
||||
glBindTexture(GL_TEXTURE_2D, textureHandle);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
|
||||
GL_CLAMP_TO_EDGE); // This is required on WebGL for non
|
||||
// power-of-two textures
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
|
||||
GL_CLAMP_TO_EDGE); // Same
|
||||
#if defined(GL_UNPACK_ROW_LENGTH) && !defined(__EMSCRIPTEN__)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
#endif
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, val.width, val.height, 0, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, val.image);
|
||||
|
||||
txHandle = textureHandle;
|
||||
id = val.fname;
|
||||
loaded = true;
|
||||
prev_h = val.height;
|
||||
prev_w = val.width;
|
||||
}
|
||||
if (!val.loaded && loaded) {
|
||||
glDeleteTextures(1, &txHandle);
|
||||
loaded = false;
|
||||
}
|
||||
|
||||
if ((val.fname != id) && loaded) {
|
||||
if (prev_w != val.width || prev_h != val.height) {
|
||||
glDeleteTextures(1, &txHandle);
|
||||
GLuint textureHandle;
|
||||
glGenTextures(1, &textureHandle);
|
||||
glBindTexture(GL_TEXTURE_2D, textureHandle);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
|
||||
GL_CLAMP_TO_EDGE); // This is required on WebGL for non
|
||||
// power-of-two textures
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
|
||||
GL_CLAMP_TO_EDGE); // Same
|
||||
#if defined(GL_UNPACK_ROW_LENGTH) && !defined(__EMSCRIPTEN__)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
#endif
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, val.width, val.height, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, val.image);
|
||||
|
||||
txHandle = textureHandle;
|
||||
|
||||
} else {
|
||||
glBindTexture(GL_TEXTURE_2D, txHandle);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, val.width, val.height, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, val.image);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
prev_h = val.height;
|
||||
prev_w = val.width;
|
||||
id = val.fname;
|
||||
}
|
||||
|
||||
if (loaded) {
|
||||
if (val.height < val.width) {
|
||||
ImGui::Image((void *)(intptr_t)txHandle,
|
||||
ImVec2(256, val.calcResizedWidth(256)));
|
||||
} else {
|
||||
ImGui::Image((void *)(intptr_t)txHandle,
|
||||
ImVec2(val.calcResizedHeight(256), 256));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int prev_h = 0;
|
||||
int prev_w = 0;
|
||||
bool loaded = false;
|
||||
GLuint txHandle;
|
||||
std::string id;
|
||||
};
|
||||
|
||||
class LoadImage : public ImFlow::BaseNode {
|
||||
public:
|
||||
ImageBundle bundle;
|
||||
|
||||
LoadImage() {
|
||||
setTitle("Load Image");
|
||||
setStyle(ImFlow::NodeStyle::brown());
|
||||
addOUT<ImageBundle>("Image")->behaviour([this]() { return bundle; });
|
||||
}
|
||||
|
||||
~LoadImage() {
|
||||
if (bundle.loaded) {
|
||||
stbi_image_free(bundle.image);
|
||||
}
|
||||
}
|
||||
|
||||
void draw() override {
|
||||
LoadCallback lc = LoadCallback();
|
||||
#ifdef __EMSCRIPTEN__
|
||||
if (ImGui::Button("Select File")) {
|
||||
emscripten_browser_file::upload(".png,.jpg,.jpeg", handle_upload_file,
|
||||
this);
|
||||
}
|
||||
#else
|
||||
if (bundle.fname == "") {
|
||||
handle_upload_file_local(
|
||||
"/Users/tanishqdubey/Downloads/Odd-eyed_cat_by_ihasb33r.jpg", this);
|
||||
}
|
||||
#endif
|
||||
if (bundle.fname != "") {
|
||||
bundle.loaded = true;
|
||||
ImGui::Text("File Loaded");
|
||||
} else {
|
||||
ImGui::Text("No image loaded");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool showPreview = false;
|
||||
|
||||
static void handle_upload_file_local(const char *filename, void *callback) {
|
||||
auto lc{reinterpret_cast<LoadImage *>(callback)};
|
||||
const int channelCount = 4;
|
||||
int imageFileChannelCount;
|
||||
int width, height;
|
||||
|
||||
uint8_t *image = (uint8_t *)stbi_load(filename, &width, &height,
|
||||
&imageFileChannelCount, channelCount);
|
||||
|
||||
if (image == NULL) {
|
||||
fprintf(stderr, "%s\nFailed to open %s\n", stbi_failure_reason(),
|
||||
lc->bundle.fname.c_str());
|
||||
lc->bundle.fname = "";
|
||||
}
|
||||
|
||||
lc->bundle.fname = uuid::generate_uuid_v4();
|
||||
lc->bundle.width = width;
|
||||
lc->bundle.height = height;
|
||||
lc->bundle.channels = channelCount;
|
||||
lc->bundle.image = image;
|
||||
lc->bundle.loaded = true;
|
||||
}
|
||||
|
||||
static void handle_upload_file(std::string const &filename,
|
||||
std::string const &mime_type,
|
||||
std::string_view buffer, void *callback) {
|
||||
auto lc{reinterpret_cast<LoadImage *>(callback)};
|
||||
const int channelCount = 4;
|
||||
int imageFileChannelCount;
|
||||
int width, height;
|
||||
|
||||
auto d = buffer.data();
|
||||
stbi_uc *image = (stbi_uc *)stbi_load_from_memory(
|
||||
(const stbi_uc *)buffer.data(), buffer.size(), &width, &height,
|
||||
&imageFileChannelCount, channelCount);
|
||||
|
||||
if (image == NULL) {
|
||||
fprintf(stderr, "%s\nFailed to open %s - %s\n", stbi_failure_reason(),
|
||||
filename.c_str(), mime_type.c_str());
|
||||
lc->bundle.fname = "";
|
||||
}
|
||||
|
||||
lc->bundle.fname = uuid::generate_uuid_v4();
|
||||
lc->bundle.width = width;
|
||||
lc->bundle.height = height;
|
||||
lc->bundle.channels = channelCount;
|
||||
lc->bundle.image = image;
|
||||
lc->bundle.loaded = true;
|
||||
}
|
||||
};
|
7547
lib/stb_image.h
Normal file
7547
lib/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
35
lib/uuid.cpp
Normal file
35
lib/uuid.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
#include "uuid.h"
|
||||
|
||||
namespace uuid {
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen(rd());
|
||||
static std::uniform_int_distribution<> dis(0, 15);
|
||||
static std::uniform_int_distribution<> dis2(8, 11);
|
||||
|
||||
std::string generate_uuid_v4() {
|
||||
std::stringstream ss;
|
||||
int i;
|
||||
ss << std::hex;
|
||||
for (i = 0; i < 8; i++) {
|
||||
ss << dis(gen);
|
||||
}
|
||||
ss << "-";
|
||||
for (i = 0; i < 4; i++) {
|
||||
ss << dis(gen);
|
||||
}
|
||||
ss << "-4";
|
||||
for (i = 0; i < 3; i++) {
|
||||
ss << dis(gen);
|
||||
}
|
||||
ss << "-";
|
||||
ss << dis2(gen);
|
||||
for (i = 0; i < 3; i++) {
|
||||
ss << dis(gen);
|
||||
}
|
||||
ss << "-";
|
||||
for (i = 0; i < 12; i++) {
|
||||
ss << dis(gen);
|
||||
};
|
||||
return ss.str();
|
||||
}
|
||||
} // namespace uuid
|
12
lib/uuid.h
Normal file
12
lib/uuid.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef UUID_H
|
||||
#define UUID_H
|
||||
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace uuid {
|
||||
std::string generate_uuid_v4();
|
||||
}
|
||||
|
||||
#endif // UUID_H
|
272
main.cpp
Normal file
272
main.cpp
Normal file
@ -0,0 +1,272 @@
|
||||
// Dear ImGui: standalone example application for SDL2 + OpenGL
|
||||
// (SDL is a cross-platform general purpose library for handling windows,
|
||||
// inputs, OpenGL/Vulkan/Metal graphics context creation, etc.)
|
||||
|
||||
// Learn about Dear ImGui:
|
||||
// - FAQ https://dearimgui.com/faq
|
||||
// - Getting Started https://dearimgui.com/getting-started
|
||||
// - Documentation https://dearimgui.com/docs (same as your local docs/
|
||||
// folder).
|
||||
// - Introduction, links and more at the top of imgui.cpp
|
||||
|
||||
#include <cstddef>
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
|
||||
#include "lib/backends/imgui_impl_opengl3.h"
|
||||
#include "lib/backends/imgui_impl_sdl2.h"
|
||||
#include "lib/imgui.h"
|
||||
#include "lib/nodes/load_image.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "lib/stb_image.h"
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <SDL2/SDL.h>
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
#include <SDL2/SDL_opengles.h>
|
||||
#else
|
||||
#include <SDL2/SDL_opengl.h>
|
||||
#endif
|
||||
#else
|
||||
#include <SDL.h>
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
#include <SDL_opengles2.h>
|
||||
#else
|
||||
#include <SDL_opengl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// This example can also compile and run with Emscripten! See
|
||||
// 'Makefile.emscripten' for details.
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include "lib/emscripten/emscripten_mainloop_stub.h"
|
||||
#endif
|
||||
|
||||
#include "lib/ImNodeFlow.h"
|
||||
|
||||
static bool init = true;
|
||||
|
||||
// Main code
|
||||
int main(int, char **) {
|
||||
// Setup SDL
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) !=
|
||||
0) {
|
||||
printf("Error: %s\n", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Decide GL+GLSL versions
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
// GL ES 2.0 + GLSL 100
|
||||
const char *glsl_version = "#version 100";
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||
#elif defined(__APPLE__)
|
||||
// GL 3.2 Core + GLSL 150
|
||||
const char *glsl_version = "#version 150";
|
||||
SDL_GL_SetAttribute(
|
||||
SDL_GL_CONTEXT_FLAGS,
|
||||
SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); // Always required on Mac
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
|
||||
#else
|
||||
// GL 3.0 + GLSL 130
|
||||
const char *glsl_version = "#version 130";
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||
#endif
|
||||
|
||||
// From 2.0.18: Enable native IME.
|
||||
#ifdef SDL_HINT_IME_SHOW_UI
|
||||
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
|
||||
#endif
|
||||
|
||||
// Create window with graphics context
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
||||
SDL_WindowFlags window_flags =
|
||||
(SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE |
|
||||
SDL_WINDOW_ALLOW_HIGHDPI);
|
||||
SDL_Window *window =
|
||||
SDL_CreateWindow("PPD Node", SDL_WINDOWPOS_CENTERED,
|
||||
SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags);
|
||||
if (window == nullptr) {
|
||||
printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_GLContext gl_context = SDL_GL_CreateContext(window);
|
||||
SDL_GL_MakeCurrent(window, gl_context);
|
||||
SDL_GL_SetSwapInterval(1); // Enable vsync
|
||||
|
||||
// Setup Dear ImGui context
|
||||
IMGUI_CHECKVERSION();
|
||||
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
(void)io;
|
||||
io.ConfigFlags |=
|
||||
ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport /
|
||||
// Platform Windows
|
||||
// io.ConfigViewportsNoAutoMerge = true;
|
||||
// io.ConfigViewportsNoTaskBarIcon = true;
|
||||
|
||||
// Setup Dear ImGui style
|
||||
ImGui::StyleColorsDark();
|
||||
// ImGui::StyleColorsLight();
|
||||
|
||||
// When viewports are enabled we tweak WindowRounding/WindowBg so platform
|
||||
// windows can look identical to regular ones.
|
||||
ImGuiStyle &style = ImGui::GetStyle();
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
|
||||
style.WindowRounding = 0.0f;
|
||||
style.Colors[ImGuiCol_WindowBg].w = 1.0f;
|
||||
}
|
||||
|
||||
// Setup Platform/Renderer backends
|
||||
ImGui_ImplSDL2_InitForOpenGL(window, gl_context);
|
||||
ImGui_ImplOpenGL3_Init(glsl_version);
|
||||
|
||||
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
|
||||
ImFlow::ImNodeFlow editor = ImFlow::ImNodeFlow("Nodes");
|
||||
|
||||
// Main loop
|
||||
bool done = false;
|
||||
#ifdef __EMSCRIPTEN__
|
||||
// For an Emscripten build we are disabling file-system access, so let's not
|
||||
// attempt to do a fopen() of the imgui.ini file. You may manually call
|
||||
// LoadIniSettingsFromMemory() to load settings from your own storage.
|
||||
io.IniFilename = nullptr;
|
||||
EMSCRIPTEN_MAINLOOP_BEGIN
|
||||
#else
|
||||
while (!done)
|
||||
#endif
|
||||
{
|
||||
// Poll and handle events (inputs, window resize, etc.)
|
||||
// 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, or clear/overwrite your copy of the mouse data.
|
||||
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input
|
||||
// data to your main application, or clear/overwrite your copy of the
|
||||
// keyboard data. Generally you may always pass all inputs to dear imgui,
|
||||
// and hide them from your application based on those two flags.
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
ImGui_ImplSDL2_ProcessEvent(&event);
|
||||
if (event.type == SDL_QUIT)
|
||||
done = true;
|
||||
if (event.type == SDL_WINDOWEVENT &&
|
||||
event.window.event == SDL_WINDOWEVENT_CLOSE &&
|
||||
event.window.windowID == SDL_GetWindowID(window))
|
||||
done = true;
|
||||
}
|
||||
|
||||
// Start the Dear ImGui frame
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplSDL2_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
{
|
||||
#ifdef IMGUI_HAS_VIEWPORT
|
||||
ImGuiViewport *viewport = ImGui::GetMainViewport();
|
||||
ImGui::SetNextWindowPos(viewport->WorkPos);
|
||||
ImGui::SetNextWindowSize(viewport->WorkSize);
|
||||
ImGui::SetNextWindowViewport(viewport->ID);
|
||||
#else
|
||||
ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f));
|
||||
ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize);
|
||||
#endif
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||
ImGui::Begin("Main", NULL,
|
||||
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoResize);
|
||||
ImGuiID dockspace_id = ImGui::GetID("MyDockspace");
|
||||
ImGuiDockNodeFlags dockspace_flags =
|
||||
ImGuiDockNodeFlags_PassthruCentralNode;
|
||||
ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f));
|
||||
if (init) {
|
||||
init = false;
|
||||
ImGui::DockBuilderRemoveNode(dockspace_id);
|
||||
ImGui::DockBuilderAddNode(
|
||||
dockspace_id, dockspace_flags | ImGuiDockNodeFlags_DockSpace);
|
||||
ImGui::DockBuilderSetNodeSize(dockspace_id, viewport->Size);
|
||||
ImGui::DockBuilderDockWindow("Editor", dockspace_id);
|
||||
ImGui::DockBuilderFinish(dockspace_id);
|
||||
}
|
||||
if (ImGui::BeginMainMenuBar()) {
|
||||
if (ImGui::BeginMenu("Add")) {
|
||||
if (ImGui::MenuItem("Load image")) {
|
||||
editor.addNode<LoadImage>(ImVec2(10, 10));
|
||||
}
|
||||
if (ImGui::MenuItem("Preview")) {
|
||||
editor.addNode<PreviewImage>(ImVec2(10, 10));
|
||||
}
|
||||
if (ImGui::MenuItem("Simple Brightness")) {
|
||||
editor.addNode<SimpleBrightness>(ImVec2(10, 10));
|
||||
}
|
||||
if (ImGui::MenuItem("Contrast")) {
|
||||
editor.addNode<Contrast>(ImVec2(10, 10));
|
||||
}
|
||||
if (ImGui::MenuItem("Exposure")) {
|
||||
editor.addNode<Exposure>(ImVec2(10, 10));
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::EndMainMenuBar();
|
||||
}
|
||||
|
||||
ImGui::Begin("Editor", NULL,
|
||||
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoResize);
|
||||
editor.update();
|
||||
ImGui::End();
|
||||
ImGui::End();
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
|
||||
// Rendering
|
||||
ImGui::Render();
|
||||
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
|
||||
glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w,
|
||||
clear_color.z * clear_color.w, clear_color.w);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
// Update and Render additional Platform Windows
|
||||
// (Platform functions may change the current OpenGL context, so we
|
||||
// save/restore it to make it easier to paste this code elsewhere.
|
||||
// For this specific demo app we could also call SDL_GL_MakeCurrent(window,
|
||||
// gl_context) directly)
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
|
||||
SDL_Window *backup_current_window = SDL_GL_GetCurrentWindow();
|
||||
SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext();
|
||||
ImGui::UpdatePlatformWindows();
|
||||
ImGui::RenderPlatformWindowsDefault();
|
||||
SDL_GL_MakeCurrent(backup_current_window, backup_current_context);
|
||||
}
|
||||
|
||||
SDL_GL_SwapWindow(window);
|
||||
}
|
||||
#ifdef __EMSCRIPTEN__
|
||||
EMSCRIPTEN_MAINLOOP_END;
|
||||
#endif
|
||||
|
||||
// Cleanup
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplSDL2_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
|
||||
SDL_GL_DeleteContext(gl_context);
|
||||
SDL_DestroyWindow(window);
|
||||
SDL_Quit();
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user