diff --git a/.clang-format b/.clang-format
index a114609f392618fec5fd1d6907e7298cc71d0ee7..b385ff463b91e79239db99a3611d95524600f4e7 100644
--- a/.clang-format
+++ b/.clang-format
@@ -54,3 +54,6 @@ AccessModifierOffset: -4
 FixNamespaceComments: false
 AlignTrailingComments: true
 CommentPragmas: '!Api.*'
+
+# Includes
+IncludeBlocks: Preserve
diff --git a/.gitignore b/.gitignore
index b528bed598beecb515305fd7de375034af0b640c..789aaee3e0562f3035e542198ebad8883529d4c0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,532 +1,48 @@
+# Prerequisites
+*.d
 
-# Created by https://www.gitignore.io/api/++,qt,c,cmake,visualstudiocode,visualstudio,windows,linux,tortoisegit,sublimetext,osx,ninja,eclipse,kate,python
-
-#!! ERROR: ++ is undefined. Use list command to see defined gitignore types !!#
-
-### Qt ###
-# C++ objects and libs
-
+# Compiled Object files
 *.slo
 *.lo
 *.o
-*.a
-*.la
-*.lai
-*.so
-*.dll
-*.dylib
-
-# Qt-es
-
-/.qmake.cache
-/.qmake.stash
-*.pro.user
-*.pro.user.*
-*.qbs.user
-*.qbs.user.*
-*.moc
-moc_*.cpp
-qrc_*.cpp
-ui_*.h
-Makefile*
-*build-*
-
-# QtCreator
-
-*.autosave
-
-#QtCtreator Qml
-*.qmlproject.user
-*.qmlproject.user.*
-
-
-### C ###
-# Object files
-*.o
-*.ko
 *.obj
-*.elf
 
 # Precompiled Headers
 *.gch
 *.pch
 
-# Libraries
-*.lib
-*.a
-*.la
-*.lo
-
-# Shared objects (inc. Windows DLLs)
-*.dll
+# Compiled Dynamic libraries
 *.so
-*.so.*
 *.dylib
+*.dll
+
+# Fortran module files
+*.mod
+*.smod
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+*.lib
 
 # Executables
 *.exe
 *.out
 *.app
-*.i*86
-*.x86_64
-*.hex
-
-# Debug files
-*.dSYM/
 
+# qtcreator
+CMakeLists.txt.user
 
-### CMake ###
-CMakeCache.txt
-CMakeFiles
-CMakeScripts
-Makefile
-cmake_install.cmake
-install_manifest.txt
-
+# binary dir
+bin/
+build/
 
-### VisualStudioCode ###
+# VS Code
 .vscode
-
-
-
-### VisualStudio ###
-## Ignore Visual Studio temporary files, build results, and
-## files generated by popular Visual Studio add-ons.
-
-# User-specific files
-*.suo
-*.user
-*.userosscache
-*.sln.docstates
-
-# User-specific files (MonoDevelop/Xamarin Studio)
-*.userprefs
-
-# Build results
-[Dd]ebug/
-[Dd]ebugPublic/
-[Rr]elease/
-[Rr]eleases/
-x64/
-x86/
-bld/
-[Oo]bj/
-
-# Visual Studio 2015 cache/options directory
+build_vs/
 .vs/
-# Uncomment if you have tasks that create the project's static files in wwwroot
-#wwwroot/
-
-# MSTest test Results
-[Tt]est[Rr]esult*/
-[Bb]uild[Ll]og.*
-
-# NUNIT
-*.VisualState.xml
-TestResult.xml
-
-# Build Results of an ATL Project
-[Dd]ebugPS/
-[Rr]eleasePS/
-dlldata.c
-
-# DNX
-project.lock.json
-artifacts/
-
-*_i.c
-*_p.c
-*_i.h
-*.ilk
-*.meta
-*.pch
-*.pdb
-*.pgc
-*.pgd
-*.rsp
-*.sbr
-*.tlb
-*.tli
-*.tlh
-*.tmp
-*.tmp_proj
-*.log
-*.vspscc
-*.vssscc
-.builds
-*.pidb
-*.svclog
-*.scc
-
-# Chutzpah Test files
-_Chutzpah*
-
-# Visual C++ cache files
-ipch/
-*.aps
-*.ncb
-*.opendb
-*.opensdf
-*.sdf
-*.cachefile
-
-# Visual Studio profiler
-*.psess
-*.vsp
-*.vspx
-*.sap
-
-# TFS 2012 Local Workspace
-$tf/
-
-# Guidance Automation Toolkit
-*.gpState
-
-# ReSharper is a .NET coding add-in
-_ReSharper*/
-*.[Rr]e[Ss]harper
-*.DotSettings.user
-
-# JustCode is a .NET coding add-in
-.JustCode
-
-# TeamCity is a build add-in
-_TeamCity*
-
-# DotCover is a Code Coverage Tool
-*.dotCover
-
-# NCrunch
-_NCrunch_*
-.*crunch*.local.xml
-nCrunchTemp_*
-
-# MightyMoose
-*.mm.*
-AutoTest.Net/
-
-# Web workbench (sass)
-.sass-cache/
-
-# Installshield output folder
-[Ee]xpress/
-
-# DocProject is a documentation generator add-in
-DocProject/buildhelp/
-DocProject/Help/*.HxT
-DocProject/Help/*.HxC
-DocProject/Help/*.hhc
-DocProject/Help/*.hhk
-DocProject/Help/*.hhp
-DocProject/Help/Html2
-DocProject/Help/html
-
-# Click-Once directory
-publish/
-
-# Publish Web Output
-*.[Pp]ublish.xml
-*.azurePubxml
-# TODO: Comment the next line if you want to checkin your web deploy settings
-# but database connection strings (with potential passwords) will be unencrypted
-*.pubxml
-*.publishproj
-
-# NuGet Packages
-*.nupkg
-# The packages folder can be ignored because of Package Restore
-**/packages/*
-# except build/, which is used as an MSBuild target.
-!**/packages/build/
-# Uncomment if necessary however generally it will be regenerated when needed
-#!**/packages/repositories.config
-# NuGet v3's project.json files produces more ignoreable files
-*.nuget.props
-*.nuget.targets
-
-# Microsoft Azure Build Output
-csx/
-*.build.csdef
-
-# Microsoft Azure Emulator
-ecf/
-rcf/
-
-# Microsoft Azure ApplicationInsights config file
-ApplicationInsights.config
-
-# Windows Store app package directory
-AppPackages/
-BundleArtifacts/
-
-# Visual Studio cache files
-# files ending in .cache can be ignored
-*.[Cc]ache
-# but keep track of directories ending in .cache
-!*.[Cc]ache/
-
-# Others
-ClientBin/
-~$*
-*~
-*.dbmdl
-*.dbproj.schemaview
-*.pfx
-*.publishsettings
-node_modules/
-orleans.codegen.cs
-
-# RIA/Silverlight projects
-Generated_Code/
-
-# Backup & report files from converting an old project file
-# to a newer Visual Studio version. Backup files are not needed,
-# because we have git ;-)
-_UpgradeReport_Files/
-Backup*/
-UpgradeLog*.XML
-UpgradeLog*.htm
-
-# SQL Server files
-*.mdf
-*.ldf
-
-# Business Intelligence projects
-*.rdl.data
-*.bim.layout
-*.bim_*.settings
-
-# Microsoft Fakes
-FakesAssemblies/
-
-# GhostDoc plugin setting file
-*.GhostDoc.xml
-
-# Node.js Tools for Visual Studio
-.ntvs_analysis.dat
-
-# Visual Studio 6 build log
-*.plg
-
-# Visual Studio 6 workspace options file
-*.opt
-
-# Visual Studio LightSwitch build output
-**/*.HTMLClient/GeneratedArtifacts
-**/*.DesktopClient/GeneratedArtifacts
-**/*.DesktopClient/ModelManifest.xml
-**/*.Server/GeneratedArtifacts
-**/*.Server/ModelManifest.xml
-_Pvt_Extensions
-
-# Paket dependency manager
-.paket/paket.exe
-
-# FAKE - F# Make
-.fake/
-
-
-### Windows ###
-# Windows image file caches
-Thumbs.db
-ehthumbs.db
-
-# Folder config file
-Desktop.ini
-
-# Recycle Bin used on file shares
-$RECYCLE.BIN/
-
-# Windows Installer files
-*.cab
-*.msi
-*.msm
-*.msp
-
-# Windows shortcuts
-*.lnk
-
-
-### Linux ###
-*~
-
-# temporary files which can be created if a process still has a handle open of a deleted file
-.fuse_hidden*
-
-# KDE directory preferences
-.directory
-
-# Linux trash folder which might appear on any partition or disk
-.Trash-*
-
-
-### TortoiseGit ###
-# Project-level settings
-/.tgitconfig
-
-
-### SublimeText ###
-# cache files for sublime text
-*.tmlanguage.cache
-*.tmPreferences.cache
-*.stTheme.cache
-
-# workspace files are user-specific
-*.sublime-workspace
-
-# project files should be checked into the repository, unless a significant
-# proportion of contributors will probably not be using SublimeText
-# *.sublime-project
-
-# sftp configuration file
-sftp-config.json
-
-
-### OSX ###
-.DS_Store
-.AppleDouble
-.LSOverride
-
-# Icon must end with two \r
-Icon
-
-
-# Thumbnails
-._*
-
-# Files that might appear in the root of a volume
-.DocumentRevisions-V100
-.fseventsd
-.Spotlight-V100
-.TemporaryItems
-.Trashes
-.VolumeIcon.icns
-
-# Directories potentially created on remote AFP share
-.AppleDB
-.AppleDesktop
-Network Trash Folder
-Temporary Items
-.apdisk
-
-
-### Ninja ###
-.ninja_deps
-.ninja_log
-
-
-### Eclipse ###
-
-.metadata
-tmp/
-*.tmp
-*.bak
-*.swp
-*~.nib
-local.properties
-.settings/
-.loadpath
-
-# Eclipse Core
-.project
-
-# External tool builders
-.externalToolBuilders/
-
-# Locally stored "Eclipse launch configurations"
-*.launch
-
-# PyDev specific (Python IDE for Eclipse)
-*.pydevproject
-
-# CDT-specific (C/C++ Development Tooling)
-.cproject
-
-# JDT-specific (Eclipse Java Development Tools)
-.classpath
-
-# Java annotation processor (APT)
-.factorypath
-
-# PDT-specific (PHP Development Tools)
-.buildpath
-
-# sbteclipse plugin
-.target
-
-# TeXlipse plugin
-.texlipse
-
-# STS (Spring Tool Suite)
-.springBeans
-
-
-### Kate ###
-# Swap Files #
-.*.kate-swp
-.swp.*
-
-
-### Python ###
-# Byte-compiled / optimized / DLL files
-__pycache__/
-*.py[cod]
-*$py.class
-
-# C extensions
-*.so
-
-# Distribution / packaging
-.Python
-env/
-build/
-develop-eggs/
-dist/
-downloads/
-eggs/
-.eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
-*.egg-info/
-.installed.cfg
-*.egg
-
-# PyInstaller
-#  Usually these files are written by a python script from a template
-#  before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
-
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.coverage
-.coverage.*
-.cache
-nosetests.xml
-coverage.xml
-*,cover
-.hypothesis/
-
-# Translations
-*.mo
-*.pot
-
-# Django stuff:
-*.log
-
-# Sphinx documentation
-docs/_build/
-
-# PyBuilder
-target/
+*.code-workspace
 
-#Ipython Notebook
-.ipynb_checkpoints
+# misc workdir spam
+imgui.ini
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 852536cc5cbd20eaf3c1c3d91dea8851ae01ec7a..7432d025a192d100c7001b4f29c4dd29f04de88d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.0)
 project(PolyMesh)
 
 include(cmake/UnityBuild.cmake)
+include(cmake/SourceGroup.cmake)
 
 option(POLYMESH_ENABLE_ASSERTIONS "if true, enables assertions (even in RelWithDebug, not in Release)" ON)
 option(POLYMESH_ENABLE_UNITY_BUILD "If enabled, compiles this library as a single compilation unit" ON)
@@ -10,11 +11,12 @@ file(GLOB_RECURSE SOURCE_FILES "src/*.cc")
 file(GLOB_RECURSE HEADER_FILES "src/*.hh")
 
 if(${CMAKE_VERSION} VERSION_GREATER "3.8.0")
-    source_group("${CMAKE_CURRENT_SOURCE_DIR}/src" FILES ${SOURCE_FILES} ${HEADER_FILES})
+    arcana_source_group(SOURCE_FILES)
+    arcana_source_group(HEADER_FILES)
 endif()
 
 if (POLYMESH_ENABLE_UNITY_BUILD)
-    enable_unity_build(polymesh SOURCE_FILES 100 cc)
+    arcana_enable_unity_build(polymesh SOURCE_FILES 100 cc)
 endif()
 
 add_library(polymesh STATIC ${SOURCE_FILES} ${HEADER_FILES})
diff --git a/cmake/SourceGroup.cmake b/cmake/SourceGroup.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..33e3b3ff95340700bf6b1227cf941b10f02cadb6
--- /dev/null
+++ b/cmake/SourceGroup.cmake
@@ -0,0 +1,9 @@
+
+# properly groups sources for Qt Creator / Visual Studio
+macro(arcana_source_group ARG_SOURCES)
+    if (${CMAKE_GENERATOR} MATCHES "Visual Studio")
+        source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/src" FILES ${${ARG_SOURCES}})
+    else()
+        source_group("${CMAKE_CURRENT_SOURCE_DIR}/src" FILES ${${ARG_SOURCES}})
+    endif()
+endmacro()
diff --git a/cmake/UnityBuild.cmake b/cmake/UnityBuild.cmake
index 38fcfdcbb30682d688e3f107a12382a93591a367..1e8f2dfc9efe0f695a5f16ed36445570f70ee360 100644
--- a/cmake/UnityBuild.cmake
+++ b/cmake/UnityBuild.cmake
@@ -27,7 +27,7 @@
 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 #
 
-MACRO (COMMIT_UNITY_FILE UNITY_FILE FILE_CONTENT)
+MACRO (arcana_commit_unity_file UNITY_FILE FILE_CONTENT)
   SET(DIRTY FALSE)
   # Check if the build file exists
   SET(OLD_FILE_CONTENT "")
@@ -44,7 +44,7 @@ MACRO (COMMIT_UNITY_FILE UNITY_FILE FILE_CONTENT)
     ENDIF ()
   ENDIF ()
   IF (DIRTY MATCHES TRUE)
-    MESSAGE(STATUS "Write Unity Build file: " ${${UNITY_FILE}})
+    MESSAGE(STATUS "[arcana_commit_unity_file] writing unity build file: " ${${UNITY_FILE}})
     FILE(WRITE ${${UNITY_FILE}} "${${FILE_CONTENT}}")
   ENDIF ()
   # Create a dummy copy of the unity file to trigger CMake reconfigure if it is deleted.
@@ -55,7 +55,7 @@ MACRO (COMMIT_UNITY_FILE UNITY_FILE FILE_CONTENT)
   CONFIGURE_FILE(${${UNITY_FILE}} ${UNITY_FILE_PATH}/CMakeFiles/${UNITY_FILE_NAME}.dummy)
 ENDMACRO ()
 
-MACRO (ENABLE_UNITY_BUILD TARGET_NAME SOURCE_VARIABLE_NAME UNIT_SIZE EXTENSION)
+MACRO (arcana_enable_unity_build TARGET_NAME SOURCE_VARIABLE_NAME UNIT_SIZE EXTENSION)
   # Limit is zero based conversion of unit_size
   MATH(EXPR LIMIT ${UNIT_SIZE}-1)
   SET(FILES ${SOURCE_VARIABLE_NAME})
@@ -75,7 +75,7 @@ MACRO (ENABLE_UNITY_BUILD TARGET_NAME SOURCE_VARIABLE_NAME UNIT_SIZE EXTENSION)
       SET(_DEPS "")
       # Write the actual Unity Build file
       IF (NOT ${BUILD_FILE} STREQUAL "" AND NOT ${BUILD_FILE_CONTENT} STREQUAL "")
-        COMMIT_UNITY_FILE(BUILD_FILE BUILD_FILE_CONTENT)
+        arcana_commit_unity_file(BUILD_FILE BUILD_FILE_CONTENT)
       ENDIF ()
       SET(UNITY_BUILD_FILES ${UNITY_BUILD_FILES} ${BUILD_FILE})
       # Set the variables for the current Unity Build file
@@ -121,17 +121,17 @@ MACRO (ENABLE_UNITY_BUILD TARGET_NAME SOURCE_VARIABLE_NAME UNIT_SIZE EXTENSION)
   ENDFOREACH ()
   # Write out the last Unity Build file
   IF (NOT ${BUILD_FILE} STREQUAL "" AND NOT ${BUILD_FILE_CONTENT} STREQUAL "")
-    COMMIT_UNITY_FILE(BUILD_FILE BUILD_FILE_CONTENT)
+    arcana_commit_unity_file(BUILD_FILE BUILD_FILE_CONTENT)
   ENDIF ()
   SET(UNITY_BUILD_FILES ${UNITY_BUILD_FILES} ${BUILD_FILE})
   SET(${SOURCE_VARIABLE_NAME} ${${SOURCE_VARIABLE_NAME}} ${UNITY_BUILD_FILES})
 ENDMACRO ()
 
-MACRO (UNITY_GENERATE_MOC TARGET_NAME SOURCES HEADERS)
+MACRO (arcana_unity_generate_moc TARGET_NAME SOURCES HEADERS)
   SET(NEW_SOURCES "")
   FOREACH (HEADER_FILE ${${HEADERS}})
     IF (NOT EXISTS ${HEADER_FILE})
-      MESSAGE(FATAL_ERROR "Header file does not exist (mocing): ${HEADER_FILE}")
+      MESSAGE(FATAL_ERROR "[arcana_unity_generate_moc] header file does not exist (mocing): ${HEADER_FILE}")
     ENDIF ()
     FILE(READ ${HEADER_FILE} FILE_CONTENT)
     STRING(FIND "${FILE_CONTENT}" "Q_OBJECT" QOBJECT_POS)