diff --git a/3rdparty/ozz-animation/.idea/.gitignore b/3rdparty/ozz-animation/.idea/.gitignore
deleted file mode 100644
index 13566b8..0000000
--- a/3rdparty/ozz-animation/.idea/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Editor-based HTTP Client requests
-/httpRequests/
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml
diff --git a/3rdparty/ozz-animation/.idea/.name b/3rdparty/ozz-animation/.idea/.name
deleted file mode 100644
index 35c3d80..0000000
--- a/3rdparty/ozz-animation/.idea/.name
+++ /dev/null
@@ -1 +0,0 @@
-ozz
\ No newline at end of file
diff --git a/3rdparty/ozz-animation/.idea/misc.xml b/3rdparty/ozz-animation/.idea/misc.xml
deleted file mode 100644
index 79b3c94..0000000
--- a/3rdparty/ozz-animation/.idea/misc.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/3rdparty/ozz-animation/.idea/modules.xml b/3rdparty/ozz-animation/.idea/modules.xml
deleted file mode 100644
index 1c6fd35..0000000
--- a/3rdparty/ozz-animation/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/3rdparty/ozz-animation/.idea/ozz-animation.iml b/3rdparty/ozz-animation/.idea/ozz-animation.iml
deleted file mode 100644
index f08604b..0000000
--- a/3rdparty/ozz-animation/.idea/ozz-animation.iml
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
\ No newline at end of file
diff --git a/3rdparty/ozz-animation/.idea/vcs.xml b/3rdparty/ozz-animation/.idea/vcs.xml
deleted file mode 100644
index 94a25f7..0000000
--- a/3rdparty/ozz-animation/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/3rdparty/ozz-animation/.travis.yml b/3rdparty/ozz-animation/.travis.yml
deleted file mode 100644
index 81f8ceb..0000000
--- a/3rdparty/ozz-animation/.travis.yml
+++ /dev/null
@@ -1,387 +0,0 @@
-language: cpp
-
-dist: xenial
-
-jobs:
- include:
-
- # Emscripten cross compiling
- #- os: linux
- # compiler: gcc
- # env:
- # - env_build_emscripten=1
-
- # mac os
- # Default mac os clang build
- - os: osx
- osx_image: xcode10
- compiler: clang
- - os: osx
- compiler: clang
- - os: osx
- compiler: clang
- env:
- - env_cmake_configuration=Release
-
- # Xcode mac os clang build
- - os: osx
- compiler: clang
- env :
- - env_cmake_generator=Xcode
- - os: osx
- compiler: clang
- env :
- - env_cmake_generator=Xcode
- - env_cmake_configuration=Release
-
- # Linux ARM
- - os: linux
- compiler: clang
- env:
- - env_build_fbx=0
- - env_cmake_configuration=Debug
- arch:
- - arm64
- - os: linux
- compiler: clang
- env:
- - env_build_fbx=0
- - env_cmake_configuration=Release
- arch:
- - arm64
-
- # Linux
- # Default linux clang debug
- - os: linux
- compiler: clang
- env:
- - env_cmake_configuration=Debug
- # Default linux release clang
- - os: linux
- compiler: clang
- env:
- - env_cmake_configuration=Release
-
- # Specific configurations
- - os: linux
- compiler: clang
- env:
- - env_build_fbx=0
- - os: linux
- compiler: clang
- env:
- - env_build_gltf=0
- - os: linux
- compiler: clang
- env:
- - env_build_howtos=0
- - os: linux
- compiler: clang
- env:
- - env_build_samples=0
- - os: linux
- compiler: clang
- env:
- - env_build_tools=0
- - os: linux
- compiler: clang
- env:
- - env_build_postfix=0
- - os: linux
- compiler: clang
- env:
- - env_build_simd_ref=1
- - os: linux
- compiler: clang
- env:
- - env_build_tests=0
- - os: linux
- compiler: clang
- env:
- - env_build_fbx=0
- - env_build_gltf=0
- - env_build_samples=0
- - os: linux
- compiler: clang
- env:
- - env_build_fbx=0
- - env_build_gltf=0
- - env_build_tests=0
- - os: linux
- compiler: clang
- env:
- - env_build_data=0
- - env_build_fbx=0
- - env_build_gltf=0
- - env_build_samples=0
- - env_build_tests=0
- - os: linux
- compiler: clang
- env:
- - env_build_data=0
- - os: linux
- compiler: clang
- env:
- - env_src_root="../test/sub/"
-
- # Default linux gcc debug
- - os: linux
- compiler: gcc
- env:
- - env_cmake_configuration=Debug
- # Default linux gcc release
- - os: linux
- compiler: gcc
- env:
- - env_cmake_configuration=Release
-
- # Newer gcc
- - os: linux
- compiler: gcc-4.9
- env:
- - env_cmake_cxx_compiler=g++-4.9
- - env_cmake_c_compiler=gcc-4.9
- addons:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- packages:
- - g++-4.9
- - os: linux
- compiler: gcc-5
- env:
- - env_cmake_cxx_compiler=g++-5
- - env_cmake_c_compiler=gcc-5
- addons:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- packages:
- - g++-5
- - os: linux
- compiler: gcc-6
- env:
- - env_cmake_cxx_compiler=g++-6
- - env_cmake_c_compiler=gcc-6
- addons:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- packages:
- - g++-6
- - os: linux
- compiler: gcc-7
- env:
- - env_cmake_cxx_compiler=g++-7
- - env_cmake_c_compiler=gcc-7
- addons:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- packages:
- - g++-7
- - os: linux
- compiler: gcc-8
- env:
- - env_cmake_cxx_compiler=g++-8
- - env_cmake_c_compiler=gcc-8
- addons:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- packages:
- - g++-8
-
- # Newer clang
- - os: linux
- compiler: clang-3.9
- env:
- - env_cmake_cxx_compiler=clang++-3.9
- - env_cmake_c_compiler=clang-3.9
- addons:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- - llvm-toolchain-xenial-3.9
- packages:
- - clang-3.9
- - os: linux
- compiler: clang-4.0
- env:
- - env_cmake_cxx_compiler=clang++-4.0
- - env_cmake_c_compiler=clang-4.0
- addons:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- - llvm-toolchain-xenial-4.0
- packages:
- - clang-4.0
- - os: linux
- compiler: clang-5.0
- env:
- - env_cmake_cxx_compiler=clang++-5.0
- - env_cmake_c_compiler=clang-5.0
- addons:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- - llvm-toolchain-xenial-5.0
- packages:
- - clang-5.0
- - os: linux
- compiler: clang-6.0
- env:
- - env_cmake_cxx_compiler=clang++-6.0
- - env_cmake_c_compiler=clang-6.0
- addons:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- - llvm-toolchain-xenial-6.0
- packages:
- - clang-6.0
- - os: linux
- compiler: clang-7
- env:
- - env_cmake_cxx_compiler=clang++-7
- - env_cmake_c_compiler=clang-7
- addons:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- - llvm-toolchain-xenial-7
- packages:
- - clang-7
- - os: linux
- compiler: clang-8
- env:
- - env_cmake_cxx_compiler=clang++-8
- - env_cmake_c_compiler=clang-8
- addons:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- - llvm-toolchain-xenial-8
- packages:
- - clang-8
-
- # older fbx sdk
- - os: linux
- compiler: gcc
- env:
- - fbx_download=http://download.autodesk.com/us/fbx/2017/2017.1/fbx20171_fbxsdk_linux.tar.gz
- - os: osx
- compiler: clang
- env:
- - fbx_download=http://download.autodesk.com/us/fbx/2017/2017.1/fbx20171_fbxsdk_clang_mac.pkg.tgz
-
-before_install:
-- echo before_install----------------------------------------------------------
-
-install:
-- echo install-----------------------------------------------------------------
-# Download and install mesa dev
-- if [[ $TRAVIS_OS_NAME == "linux" ]]; then
- sudo apt-get install libgl1-mesa-dev libglu1-mesa-dev;
- fi
-# Download and install fbx sdk
-# "|| true" because 2019 sdk would return code 130 when reading the readme
-# chmod because fbx2019 will install with 700
-- if [[ $TRAVIS_OS_NAME == "linux" ]]; then
- if [ -z "$fbx_download" ]; then
- FBX_DOWNLOAD=${fbx_download:-"http://www.autodesk.com/content/dam/autodesk/www/adn/fbx/20192/fbx20192_fbxsdk_linux.tar.gz"};
- else
- FBX_DOWNLOAD="$fbx_download";
- fi;
- mkdir fbx;
- cd fbx;
- sudo wget $FBX_DOWNLOAD -O fbx.tar.gz;
- sudo tar -xf "fbx.tar.gz";
- (yes yes | sudo ./*_fbxsdk_linux /usr/local) || true;
- sudo chmod -R 755 /usr/local/lib;
- sudo chmod -R 755 /usr/local/include;
- cd ..;
- fi
-- if [[ $TRAVIS_OS_NAME == "osx" ]]; then
- if [ -z "$fbx_download" ]; then
- FBX_DOWNLOAD=${fbx_download:-"http://www.autodesk.com/content/dam/autodesk/www/adn/fbx/20192/fbx20192_fbxsdk_clang_mac.pkg.tgz"};
- else
- FBX_DOWNLOAD="$fbx_download";
- fi;
- mkdir fbx;
- cd fbx;
- sudo wget $FBX_DOWNLOAD -O fbx.tgz;
- sudo tar -xf "fbx.tgz";
- sudo installer -pkg *_fbxsdk_clang_macos.pkg -target /;
- cd ..;
- fi
-# Download and install emscripten sdk
-- if [[ $env_build_emscripten ]]; then
- sudo apt-get install software-properties-common -y;
- sudo add-apt-repository ppa:george-edison55/cmake-3.x -y;
- sudo apt-get update;
- sudo apt-get install --only-upgrade cmake -y;
- git clone https://github.com/juj/emsdk.git;
- cd emsdk;
- sudo ./emsdk update-tags;
- sudo ./emsdk install sdk-nightly-latest-64bit;
- sudo ./emsdk activate --embedded sdk-nightly-latest-64bit;
- source ./emsdk_env.sh;
- cd ..;
- fi
-
-before_script:
-- echo before_script-----------------------------------------------------------
-
-# Setup default environment variables
-- if [[ -z $env_src_root ]]; then export env_src_root=".."; fi
-- if [[ -z $env_build_fbx ]]; then export env_build_fbx=1; fi
-- if [[ -z $env_build_gltf ]]; then export env_build_gltf=1; fi
-- if [[ -z $env_build_data ]]; then export env_build_data=1; fi
-- if [[ -z $env_build_howtos ]]; then export env_build_howtos=1; fi
-- if [[ -z $env_build_tools ]]; then export env_build_tools=1; fi
-- if [[ -z $env_build_postfix ]]; then export env_build_postfix=1; fi
-- if [[ -z $env_build_samples ]]; then export env_build_samples=1; fi
-- if [[ -z $env_build_simd_ref ]]; then export env_build_simd_ref=0; fi
-- if [[ -z $env_build_tests ]]; then export env_build_tests=1; fi
-- if [[ -z $env_cmake_configuration ]]; then export env_cmake_configuration=Debug; fi
-- if [[ -z $env_cmake_cxx_compiler ]]; then export env_cmake_cxx_compiler=$CXX; fi
-- if [[ -z $env_cmake_c_compiler ]]; then export env_cmake_c_compiler=$CC; fi
-- if [[ -z $env_cmake_generator ]]; then export env_cmake_generator="Unix Makefiles"; fi
-- if [[ $env_cmake_generator == "Unix Makefiles" ]]; then export env_cmake_generator_specific="-j2"; fi
-- if [[ $env_cmake_generator == "Unix Makefiles" ]]; then export env_ctest_generator_specific="-j16"; fi
-- if [[ $EMSCRIPTEN ]]; then env_cmake_toolchain="-DCMAKE_TOOLCHAIN_FILE=$EMSCRIPTEN/cmake/Modules/Platform/Emscripten.cmake"; fi
-
-# Display cmake version
-- cmake --version
-
-script:
-- echo script------------------------------------------------------------------
-# Configure build
-- mkdir build
-- cd build
-- echo $env_cmake_toolchain
-- cmake -G "$env_cmake_generator" $env_cmake_toolchain -DCMAKE_CXX_COMPILER=$env_cmake_cxx_compiler -DCMAKE_C_COMPILER=$env_cmake_c_compiler -DCMAKE_BUILD_TYPE=$env_cmake_configuration -Dozz_build_fbx=$env_build_fbx -Dozz_build_data=$env_build_data -Dozz_build_howtos=$env_build_howtos -Dozz_build_samples=$env_build_samples -Dozz_build_postfix=$env_build_postfix -Dozz_build_tools=$env_build_tools -Dozz_build_simd_ref=$env_build_simd_ref -Dozz_build_tests=$env_build_tests $env_src_root
-# Build
-- cmake --build ./ --config $env_cmake_configuration --use-stderr -- $env_cmake_generator_specific
-# Test
-- ctest --build-config $env_cmake_configuration --output-on-failure -- $env_ctest_generator_specific
-
-after_success:
-- echo after_success-----------------------------------------------------------
-
-after_failure:
-- echo after_failure-----------------------------------------------------------
-
-before_deploy:
-#- echo before_deploy-----------------------------------------------------------
-
-deploy:
-#- echo deploy------------------------------------------------------------------
-
-after_deploy:
-#- echo after_deploy------------------------------------------------------------
-
-after_script:
-#- echo after_script------------------------------------------------------------
diff --git a/3rdparty/ozz-animation/AUTHORS.md b/3rdparty/ozz-animation/AUTHORS.md
index cc59ee5..f294ccf 100644
--- a/3rdparty/ozz-animation/AUTHORS.md
+++ b/3rdparty/ozz-animation/AUTHORS.md
@@ -14,3 +14,4 @@ The following authors have all licensed their contributions to ozz-animation und
- Kota Iguchi
- Mikołaj Siedlarek
- Paul Gruenbacher
+- Christophe Meyer
diff --git a/3rdparty/ozz-animation/CHANGES.md b/3rdparty/ozz-animation/CHANGES.md
index fcf2243..0e3fff3 100644
--- a/3rdparty/ozz-animation/CHANGES.md
+++ b/3rdparty/ozz-animation/CHANGES.md
@@ -1,3 +1,17 @@
+Release version 0.14.1
+----------------------
+
+* Samples
+ - Allows reusing sample framework outside of sample directory.
+ - #154 Exposes swap interval
+
+* Library
+ - #153 Fixes deprecated implicit copy warning.
+ - #141 Removes non-ASCII characters in source codes.
+
+* Build pipeline
+ - Exposes ozz cmake configuration variables to PARENT_SCOPE, so it can be used/changed by an external project.
+
Release version 0.14.0
----------------------
diff --git a/3rdparty/ozz-animation/CMakeLists.txt b/3rdparty/ozz-animation/CMakeLists.txt
index 292cad1..07d5bbd 100644
--- a/3rdparty/ozz-animation/CMakeLists.txt
+++ b/3rdparty/ozz-animation/CMakeLists.txt
@@ -3,10 +3,13 @@ cmake_minimum_required (VERSION 3.3)
# Defines the project's name
project(ozz)
+# Check if project is top level or a sub project
+get_directory_property(is_sub_project PARENT_DIRECTORY)
+
# Current version
set(OZZ_VERSION_MAJOR 0)
set(OZZ_VERSION_MINOR 14)
-set(OZZ_VERSION_PATCH 0)
+set(OZZ_VERSION_PATCH 1)
set(OZZ_VERSION ${OZZ_VERSION_MAJOR}.${OZZ_VERSION_MINOR}.${OZZ_VERSION_PATCH})
# Add project build options
@@ -27,6 +30,9 @@ if(WIN32 AND BUILD_SHARED_LIBS AND NOT ozz_build_msvc_rt_dll)
message("Forcing ozz_build_msvc_rt_dll to ON as ozz is being built as dll (BUILD_SHARED_LIBS is ON).")
set(ozz_build_msvc_rt_dll ON)
endif()
+if(is_sub_project)
+ set(ozz_build_msvc_rt_dll ${ozz_build_msvc_rt_dll} PARENT_SCOPE)
+endif()
# Include ozz cmake parameters and scripts
include(CheckCXXCompilerFlag)
@@ -63,12 +69,18 @@ else()
# Disables fbx if tools are disabled
set(ozz_build_fbx OFF)
endif()
+if(is_sub_project)
+ set(ozz_build_fbx ${ozz_build_fbx} PARENT_SCOPE)
+endif()
# gltf
if(ozz_build_tools AND ozz_build_gltf)
else()
set(ozz_build_gltf OFF)
endif()
+if(is_sub_project)
+ set(ozz_build_gltf ${ozz_build_gltf} PARENT_SCOPE)
+endif()
# Enables unit tests.
if(ozz_build_tests)
@@ -115,7 +127,6 @@ if(ozz_build_tests AND NOT EMSCRIPTEN)
add_subdirectory(test)
endif()
-
install(FILES
${PROJECT_SOURCE_DIR}/CHANGES.md
${PROJECT_SOURCE_DIR}/LICENSE.md
diff --git a/3rdparty/ozz-animation/appveyor.yml b/3rdparty/ozz-animation/appveyor.yml
deleted file mode 100644
index 76efffa..0000000
--- a/3rdparty/ozz-animation/appveyor.yml
+++ /dev/null
@@ -1,88 +0,0 @@
-version: '{build}'
-image: Visual Studio 2019
-environment:
- matrix:
- # Comilers matrix
- - env_cmake_generator: "Visual Studio 14 2015"
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
- env_cmake_configuration: Debug
- env_fbxsdk_path: "http://www.autodesk.com/content/dam/autodesk/www/adn/fbx/20195/fbx20195_fbxsdk_vs2015_win.exe"
- - env_cmake_generator: "Visual Studio 14 2015 Win64"
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
- env_cmake_configuration: Debug
- env_fbxsdk_path: "http://www.autodesk.com/content/dam/autodesk/www/adn/fbx/20195/fbx20195_fbxsdk_vs2015_win.exe"
- - env_cmake_generator: "Visual Studio 15 2017"
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
- env_cmake_configuration: Debug
- env_fbxsdk_path: "http://www.autodesk.com/content/dam/autodesk/www/adn/fbx/20195/fbx20195_fbxsdk_vs2017_win.exe"
- - env_cmake_generator: "Visual Studio 15 2017 Win64"
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
- env_cmake_configuration: Debug
- env_fbxsdk_path: "http://www.autodesk.com/content/dam/autodesk/www/adn/fbx/20195/fbx20195_fbxsdk_vs2017_win.exe"
- - env_cmake_generator: "Visual Studio 15 2017"
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
- env_cmake_configuration: Release
- env_fbxsdk_path: "http://www.autodesk.com/content/dam/autodesk/www/adn/fbx/20195/fbx20195_fbxsdk_vs2017_win.exe"
- - env_cmake_generator: "Visual Studio 15 2017 Win64"
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
- env_cmake_configuration: Release
- env_fbxsdk_path: "http://www.autodesk.com/content/dam/autodesk/www/adn/fbx/20195/fbx20195_fbxsdk_vs2017_win.exe"
- - env_cmake_generator: "Visual Studio 16 2019"
- env_cmake_configuration: Debug
- env_fbxsdk_path: "http://www.autodesk.com/content/dam/autodesk/www/adn/fbx/20195/fbx20195_fbxsdk_vs2017_win.exe"
- - env_cmake_generator: "Visual Studio 16 2019"
- env_cmake_configuration: Release
- env_fbxsdk_path: "http://www.autodesk.com/content/dam/autodesk/www/adn/fbx/20195/fbx20195_fbxsdk_vs2017_win.exe"
- - env_cmake_generator: "Visual Studio 16 2019"
- env_cmake_configuration: Release
- env_fbxsdk_path: "http://www.autodesk.com/content/dam/autodesk/www/adn/fbx/20195/fbx20195_fbxsdk_vs2017_win.exe"
- env_build_msvc_rt_dll: "1"
- - env_cmake_generator: "Visual Studio 16 2019"
- env_cmake_configuration: Release
- env_fbxsdk_path: "http://www.autodesk.com/content/dam/autodesk/www/adn/fbx/20195/fbx20195_fbxsdk_vs2017_win.exe"
- env_build_msvc_rt_dll: "0"
-
- # No fbx sdk
- - env_cmake_generator: "Visual Studio 16 2019"
- env_cmake_configuration: Release
-
- # Use ozz as a sub project (should set msvc rt dll for ozz as this is the default in cmake)
- - env_cmake_generator: "Visual Studio 16 2019"
- env_cmake_configuration: Release
- env_src_root: "../test/sub/"
- env_fbxsdk_path: "http://www.autodesk.com/content/dam/autodesk/www/adn/fbx/20195/fbx20195_fbxsdk_vs2017_win.exe"
- - env_cmake_generator: "Visual Studio 16 2019"
- env_cmake_configuration: Debug
- env_src_root: "../test/sub/"
- env_fbxsdk_path: "http://www.autodesk.com/content/dam/autodesk/www/adn/fbx/20195/fbx20195_fbxsdk_vs2017_win.exe"
-
-install:
-# Setup Fbx sdk
-- ps: >-
- if ($Env:env_fbxsdk_path) {
- md fbx
- cd fbx
- Start-FileDownload $Env:env_fbxsdk_path "fbxsdk.exe"
- Start-Process -FilePath "fbxsdk.exe" /S -Wait
- cd ..
- }
-# Fixes up env_src_root if it isn't defined
-- ps: >-
- if (!$Env:env_src_root) {
- $Env:env_src_root=".."
- }
-# Fixes up env_build_msvc_rt_dll if it isn't defined
-- ps: >-
- if (!$Env:env_build_msvc_rt_dll) {
- $Env:env_build_msvc_rt_dll="1"
- }
-
-build_script:
-- cmake --version
-- mkdir build
-- cd build
-- cmake -G "%env_cmake_generator%" -Dozz_build_tests=1 -Dozz_build_data=1 -Dozz_build_msvc_rt_dll=%env_build_msvc_rt_dll% -DCMAKE_BUILD_TYPE=%env_cmake_configuration% %env_src_root%
-- cmake --build ./ --config %env_cmake_configuration%
-
-test_script:
-- ctest --build-config %env_cmake_configuration%
diff --git a/3rdparty/ozz-animation/extern/gtest/fused-src/gtest/gtest.h b/3rdparty/ozz-animation/extern/gtest/fused-src/gtest/gtest.h
index 3e3e986..e5da69e 100644
--- a/3rdparty/ozz-animation/extern/gtest/fused-src/gtest/gtest.h
+++ b/3rdparty/ozz-animation/extern/gtest/fused-src/gtest/gtest.h
@@ -7917,7 +7917,7 @@ namespace edit_distance {
// Returns the optimal edits to go from 'left' to 'right'.
// All edits cost the same, with replace having lower priority than
// add/remove.
-// Simple implementation of the Wagner–Fischer algorithm.
+// Simple implementation of the Wagner-Fischer algorithm.
// See http://en.wikipedia.org/wiki/Wagner-Fischer_algorithm
enum EditType { kMatch, kAdd, kRemove, kReplace };
GTEST_API_ std::vector CalculateOptimalEdits(
diff --git a/3rdparty/ozz-animation/include/ozz/base/span.h b/3rdparty/ozz-animation/include/ozz/base/span.h
index 24a545b..e5722ed 100644
--- a/3rdparty/ozz-animation/include/ozz/base/span.h
+++ b/3rdparty/ozz-animation/include/ozz/base/span.h
@@ -61,6 +61,9 @@ struct span {
// elements.
span(_Ty* _begin, size_t _size) : data_(_begin), size_(_size) {}
+ // Copy constructor.
+ span(const span& _other) = default;
+
// Copy operator.
void operator=(const span& _other) {
data_ = _other.data_;
diff --git a/3rdparty/ozz-animation/samples/demo.zip b/3rdparty/ozz-animation/samples/demo.zip
deleted file mode 100644
index c5a37bd..0000000
Binary files a/3rdparty/ozz-animation/samples/demo.zip and /dev/null differ
diff --git a/3rdparty/ozz-animation/samples/framework/CMakeLists.txt b/3rdparty/ozz-animation/samples/framework/CMakeLists.txt
index 4b8e2c0..cf0f361 100644
--- a/3rdparty/ozz-animation/samples/framework/CMakeLists.txt
+++ b/3rdparty/ozz-animation/samples/framework/CMakeLists.txt
@@ -36,6 +36,10 @@ target_link_libraries(sample_framework
ozz_geometry
ozz_animation_offline
ozz_options)
+
+target_include_directories(sample_framework PUBLIC
+ $
+ $/samples>)
if(TARGET BUILD_DATA_SAMPLE)
add_dependencies(sample_framework BUILD_DATA_SAMPLE)
diff --git a/3rdparty/ozz-animation/samples/framework/application.cc b/3rdparty/ozz-animation/samples/framework/application.cc
index b7778cb..ede6c40 100644
--- a/3rdparty/ozz-animation/samples/framework/application.cc
+++ b/3rdparty/ozz-animation/samples/framework/application.cc
@@ -98,6 +98,8 @@ Application::Application()
time_(0.f),
last_idle_time_(0.),
show_help_(false),
+ vertical_sync_(true),
+ swap_interval_(1),
show_grid_(true),
show_axes_(true),
capture_video_(false),
@@ -209,7 +211,7 @@ int Application::Run(int _argc, const char** _argv, const char* _version,
#endif // EMSCRIPTEN
// Setup the window and installs callbacks.
- glfwSwapInterval(1); // Enables vertical sync by default.
+ glfwSwapInterval(vertical_sync_ ? swap_interval_ : 0);
glfwSetWindowSizeCallback(&ResizeCbk);
glfwSetWindowCloseCallback(&CloseCbk);
@@ -611,10 +613,14 @@ bool Application::FrameworkGui() {
GL(Disable(GL_MULTISAMPLE));
}
}
- // Vertical sync
- static bool vertical_sync_ = true; // On by default.
- if (im_gui->DoCheckBox("Vertical sync", &vertical_sync_, true)) {
- glfwSwapInterval(vertical_sync_ ? 1 : 0);
+ // Vertical sync & swap interval
+ bool changed = im_gui->DoCheckBox("Vertical sync", &vertical_sync_);
+ char szLabel[64];
+ std::sprintf(szLabel, "Swap interval: %d", swap_interval_);
+ changed |=
+ im_gui->DoSlider(szLabel, 1, 4, &swap_interval_, 1.f, vertical_sync_);
+ if (changed) {
+ glfwSwapInterval(vertical_sync_ ? swap_interval_ : 0);
}
im_gui->DoCheckBox("Show grid", &show_grid_, true);
diff --git a/3rdparty/ozz-animation/samples/framework/application.h b/3rdparty/ozz-animation/samples/framework/application.h
index fb004cd..c91ecfe 100644
--- a/3rdparty/ozz-animation/samples/framework/application.h
+++ b/3rdparty/ozz-animation/samples/framework/application.h
@@ -216,6 +216,9 @@ class Application {
// Set to true to display help.
bool show_help_;
+ bool vertical_sync_; // On by default.
+ int swap_interval_;
+
// Grid display settings.
bool show_grid_;
bool show_axes_;
diff --git a/3rdparty/ozz-animation/samples/framework/utils.cc b/3rdparty/ozz-animation/samples/framework/utils.cc
index af2c787..85fca39 100644
--- a/3rdparty/ozz-animation/samples/framework/utils.cc
+++ b/3rdparty/ozz-animation/samples/framework/utils.cc
@@ -32,6 +32,7 @@
#include "framework/imgui.h"
#include "framework/mesh.h"
+#include "ozz/animation/offline/raw_animation.h"
#include "ozz/animation/offline/raw_skeleton.h"
#include "ozz/animation/runtime/animation.h"
#include "ozz/animation/runtime/local_to_model_job.h"
@@ -326,6 +327,30 @@ bool LoadAnimation(const char* _filename,
return true;
}
+bool LoadRawAnimation(const char* _filename,
+ ozz::animation::offline::RawAnimation* _animation) {
+ assert(_filename && _animation);
+ ozz::log::Out() << "Loading raw animation archive: " << _filename << "."
+ << std::endl;
+ ozz::io::File file(_filename, "rb");
+ if (!file.opened()) {
+ ozz::log::Err() << "Failed to open raw animation file " << _filename << "."
+ << std::endl;
+ return false;
+ }
+ ozz::io::IArchive archive(&file);
+ if (!archive.TestTag()) {
+ ozz::log::Err() << "Failed to load raw animation instance from file "
+ << _filename << "." << std::endl;
+ return false;
+ }
+
+ // Once the tag is validated, reading cannot fail.
+ archive >> *_animation;
+
+ return true;
+}
+
namespace {
template
bool LoadTrackImpl(const char* _filename, _Track* _track) {
@@ -411,7 +436,7 @@ bool LoadMeshes(const char* _filename,
}
namespace {
-// Moller–Trumbore intersection algorithm
+// Moller-Trumbore intersection algorithm
// https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
bool RayIntersectsTriangle(const ozz::math::Float3& _ray_origin,
const ozz::math::Float3& _ray_direction,
diff --git a/3rdparty/ozz-animation/samples/framework/utils.h b/3rdparty/ozz-animation/samples/framework/utils.h
index a665139..85a6c9a 100644
--- a/3rdparty/ozz-animation/samples/framework/utils.h
+++ b/3rdparty/ozz-animation/samples/framework/utils.h
@@ -167,6 +167,14 @@ bool LoadSkeleton(const char* _filename, ozz::animation::Skeleton* _skeleton);
bool LoadAnimation(const char* _filename,
ozz::animation::Animation* _animation);
+// Loads a raw animation from an ozz archive file named _filename.
+// This function will fail and return false if the file cannot be opened or if
+// it is not a valid ozz animation archive. A valid animation archive can be
+// produced with ozz tools (fbx2ozz) or using ozz animation serialization API.
+// _filename and _animation must be non-nullptr.
+bool LoadRawAnimation(const char* _filename,
+ ozz::animation::offline::RawAnimation* _animation);
+
// Loads a float track from an ozz archive file named _filename.
// This function will fail and return false if the file cannot be opened or if
// it is not a valid ozz float track archive. A valid float track archive can be
diff --git a/3rdparty/ozz-animation/src/animation/offline/decimate.h b/3rdparty/ozz-animation/src/animation/offline/decimate.h
index 3994382..9f450bf 100644
--- a/3rdparty/ozz-animation/src/animation/offline/decimate.h
+++ b/3rdparty/ozz-animation/src/animation/offline/decimate.h
@@ -41,7 +41,7 @@ namespace ozz {
namespace animation {
namespace offline {
-// Decimation algorithm based on Ramer–Douglas–Peucker.
+// Decimation algorithm based on Ramer-Douglas-Peucker.
// https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm
// _Track must have std::vector interface.
// Adapter must have the following interface:
diff --git a/3rdparty/ozz-animation/src/animation/runtime/ik_two_bone_job.cc b/3rdparty/ozz-animation/src/animation/runtime/ik_two_bone_job.cc
index f429c72..f7d999f 100644
--- a/3rdparty/ozz-animation/src/animation/runtime/ik_two_bone_job.cc
+++ b/3rdparty/ozz-animation/src/animation/runtime/ik_two_bone_job.cc
@@ -184,7 +184,7 @@ bool SoftenTarget(const IKTwoBoneJob& _job, const IKConstantSetup& _setup,
// The maximum distance we can reach is the soften bone chain length: da
// (stored in !x). The minimum distance we can reach is the absolute value of
- // the difference of the 2 bone lengths, |d1−d2| (stored in z). x is 0 and z
+ // the difference of the 2 bone lengths, |d1-d2| (stored in z). x is 0 and z
// is 1, yw are untested.
return (comp_mask & 0x5) == 0x4;
}
diff --git a/3rdparty/ozz-animation/test/base/containers/intrusive_list_tests.cc b/3rdparty/ozz-animation/test/base/containers/intrusive_list_tests.cc
index 6c47090..164c236 100644
--- a/3rdparty/ozz-animation/test/base/containers/intrusive_list_tests.cc
+++ b/3rdparty/ozz-animation/test/base/containers/intrusive_list_tests.cc
@@ -645,10 +645,9 @@ class is_to_be_removed {
public:
explicit is_to_be_removed(int _which) : which_(_which) {}
bool operator()(typename _List::const_reference) { return which_-- == 0; }
+ void operator=(const is_to_be_removed&) = delete;
private:
- void operator=(const is_to_be_removed&);
-
int which_;
};
diff --git a/3rdparty/sokol/CHANGELOG.md b/3rdparty/sokol/CHANGELOG.md
index f40ad30..bfe7cce 100644
--- a/3rdparty/sokol/CHANGELOG.md
+++ b/3rdparty/sokol/CHANGELOG.md
@@ -1,5 +1,691 @@
## Updates
+- **20-Feb-2023**: sokol_gfx.h has a new set of functions to get a 'best-effort'
+ desc struct with the creation parameters of a specific resource object:
+
+ ```c
+ sg_buffer_desc sg_query_buffer_desc(sg_buffer buf);
+ sg_image_desc sg_query_image_desc(sg_image img);
+ sg_shader_desc sg_query_shader_desc(sg_shader shd);
+ sg_pipeline_desc sg_query_pipeline_desc(sg_pipeline pip);
+ sg_pass_desc sg_query_pass_desc(sg_pass pass);
+ ```
+
+ The returned structs will *not* be an exact copy of the desc struct that
+ was used for creation the resource object, instead:
+
+ - references to external data (like buffer and image content or
+ shader sources) will be zeroed
+ - any attributes that have not been kept around internally after
+ creation will be zeroed (the ```sg_shader_desc``` struct is most
+ affected by this, the other structs are fairly complete).
+
+ Calling the functions with an invalid or dangling resource handle
+ will return a completely zeroed struct (thus it may make sense
+ to first check the resource state via ```sg_query_*_state()```)
+
+ Nevertheless, those functions may be useful to get a partially filled out
+ 'creation blueprint' for creating similar resources without the need
+ to keep and pass around the original desc structs.
+
+ >MINOR BREAKING CHANGE: the struct members ```sg_image_info.width``` and
+ ```sg_image_info.height``` have been removed, this information is now
+ returned by ```sg_query_image_desc()```.
+
+ PR: https://github.com/floooh/sokol/pull/796, fixes: https://github.com/floooh/sokol/issues/568
+
+- **17-Feb-2023**: sokol_app.h on macOS now has a proper fix for the problem
+ that macOS doesn't send key-up events while the Cmd key is held down.
+ Previously this was handled through a workaround of immediately sending a
+ key-up event after its key-down event if the Cmd key is currently held down
+ to prevent a 'stuck key'. The proper fix is now to install an "event monitor"
+ callback (many thanks to GLFW for finding and implementing the solution).
+ Unfortunately there's no such solution for the Emscripten code path, which
+ also don't send a key-up event while Cmd is pressed on macOS (the workaround
+ there to send a key-up event right on key-down while Cmd is held down to
+ prevent a stuck key is still in place) For more details, see:
+ https://github.com/floooh/sokol/issues/794
+
+- **15-Feb-2023**: A fix in the sokol_gfx.h GL backend: due to a bug in the
+ state cache, the GL backend could only bind a total of
+ SG_MAX_SHADERSTAGE_IMAGES (= 12) when it actually should be twice that amount
+ (12 per shader stage). Note however that the total amount of texture bindings
+ is still internally limited by the GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
+ runtime variable (~~currently this is not exposed in sg_limits though~~). Many
+ thanks to @allcreater for PR https://github.com/floooh/sokol/pull/787.
+ PS: sg_limits now exposes GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS as
+ ```sg_limits.gl_max_combined_texture_image_units```, and the
+ value can also be inspected via the debug UI in sokol_gfx_imgui.h.
+
+- **13-Feb-2023**: The way logging works has been completely revamped in
+ the sokol headers. UWP support has been removed from sokol_audio.h
+ and sokol_app.h (this also means that the sokol headers no longer contain
+ any C++ code).
+
+ **REQUIRED ACTION**: Since the sokol headers are now completely silent
+ without a logging callback (explanation below), it is highly recommended
+ to use the standard logging callback provided by the new header ```sokol_log.h```.
+ For instance for sokol_gfx.h it looks like this:
+
+ ```c
+ #include "sokol_log.h"
+ //...
+ sg_setup(&(sg_desc){
+ //...
+ .logger.func = slog_func,
+ });
+ ```
+
+ All sokol samples have been updated to use sokol_log.h for logging.
+
+ The former logging callback is now a combined
+ logging- and error-reporting callback, and more information is available
+ to the logging function:
+ - a 'tag string' which identifies the sokol headers, this string
+ is identical with the API prefix (e.g. "sg" for sokol_gfx.h,
+ "sapp" for sokol_app.h etc...)
+ - a numeric log level: 0=panic, 1=error, 2=warning, 3=info
+ - a numeric 'log item id' (think of it as error code, but since
+ not only errors are reported I called it a log item id)
+ - a human readable error message
+ - a source file line number where the log item was reported
+ - the file path of the sokol header
+
+ Log level ```panic``` is special in that it terminates execution inside
+ the log function. When a sokol header issues a panic log message, it means
+ that the problem is so big that execution can not continue. By default,
+ the sokol headers and the standard log function in sokol_log.h call
+ ```abort()``` when a panic log message is issued.
+
+ In debug mode (NDEBUG not defined, or SOKOL_DEBUG defined), a log message
+ (in this case from sokol_spine.h) will look like this:
+
+ ```
+ [sspine][error][id:12] /Users/floh/projects/sokol/util/sokol_spine.h:3472:0:
+ SKELETON_DESC_NO_ATLAS: no atlas object provided in sspine_skeleton_desc.atlas
+ ```
+ The information can be 'parsed' like this:
+ - ```[sspine]```: it's a message from sokol_spine.h
+ - ```[error]```: it's an error
+ - ```[id:12]```: the numeric log item id (associated with ```SKELETON_DESC_NO_ATLAS``` below)
+ - source file path and line number in a compiler-specific format - in some IDEs and terminals
+ this is a clickable link
+ - the line below is the human readable log item id and message
+
+ In release mode (NDEBUG is defined and SOKOL_DEBUG is not defined), log messages
+ are drastically reduced (the reason is to not bloat the executable with all the extra string data):
+
+ ```
+ [sspine][error][id:12][line:3472]
+ ```
+ ...this reduced information still gives all the necessary information to identify the location and type of error.
+
+ A custom logging function must adhere to a few rules:
+
+ - must be re-entrant because it might be called from different threads
+ - must treat **all** provided string pointers as optional (can be null)
+ - don't store the string pointers, copy the string data instead
+ - must not return for log level panic
+
+ A new header ```sokol_log.h``` has been added to provide a standard logging callback implementation
+ which provides logging output on all platforms to stderr and/or platform specific logging
+ facilities. ```sokol_log.h``` only uses fputs() and platform specific logging function instead
+ of fprintf() to preverse some executable size.
+
+ **QUESTION**: Why are the sokol headers now silent, unless a logging callback is installed?
+ This is mainly because a standard logging function which does something meaningful on all
+ platforms (including Windows and Android) isn't trivial. E.g. printing to stderr is not
+ enough. It's better to move that stuff into a centralized place in a separate header,
+ but since the core sokol headers must not (statically) depend on other sokol headers
+ the only solution that made sense was to provide a standard logging function which must
+ be 'registered' as a callback.
+
+- **26-Jan-2023**: Work on SRGB support in sokol_gfx.h has started, but
+ this requires more effort to be really usable. For now, only a new
+ pixel format has been added: SG_PIXELFORMAT_SRGB8A8 (see https://github.com/floooh/sokol/pull/758,
+ many thanks to @allcreater). The sokol-gfx GL backend has a temporary
+ workaround to align behaviour with D3D11 and Metal: automatic SRGB conversion
+ is enabled for offscreen render passes, but disabled for the default
+ framebuffer. A proper fix will require separate work on sokol_app.h to
+ support an SRGB default framebuffer and communicate to sokol-gfx
+ whether the default framebuffer is SRGB enabled or not.
+
+- **24-Jan-2023**: sokol_gfx.h Metal: A minor inconsistency has been fixed in
+ the validation layer and an assert for the function ```sg_apply_uniforms()```
+ which checks the size of the incoming data against the uniform block size.
+ The validation layer and Metal backend did a ```<=``` test while the D3D11
+ and GL backends checked for an exact size match. Both the validation layer
+ and the Metal backend now also check for an exact match. Thanks to @nmr8acme
+ for noticing the issue and providing a PR! (https://github.com/floooh/sokol/pull/776)
+
+- **23-Jan-2023**: A couple more sokol_audio.h updates:
+ - an AAudio backend has been added for Android, and made the default. This
+ means you now need to link with ```aaudio``` instead of ```OpenSLES``` when
+ using sokol_audio.h on Android. The OpenSLES backend code still exists (for
+ now), but must be explicitly selected by compiling the sokol_audio.h
+ implementation with the define ```SAUDIO_ANDROID_SLES``` (e.g. there is
+ no runtime fallback from AAudio to OpenSLES). AAudio is fully supported
+ since Android 8.1. Many thanks to @oviano for the initial AAudio PR
+ (https://github.com/floooh/sokol/pull/484)
+ - in the WebAudio backend, WebAudio is now properly activated on the first
+ input action again on Chrome for Android (at some point activating WebAudio
+ via a ```touchstart``` event stopped working and had to be moved to the
+ ```touchend``` event, see https://github.com/floooh/sokol/issues/701)
+ - audio backend initialization on iOS and macOS is now a bit more fault-tolerant,
+ errors during initialization now properly set sokol_audio.h to 'silent mode'
+ instead of asserting (or in release mode ignoring the error)
+ - ...and some minor general code cleanup things in sokol_audio.h: backend-specific
+ functions now generally have a matching prefix (like ```_saudio_alsa_...()```)
+ for better searchability
+
+- **16-Jan-2023**:
+ - sokol_audio.h android: https://github.com/floooh/sokol/pull/747 has been merged
+ which adds a couple more error checks at OpenSLES startup.
+ - sokol_gfx.h: support for half-float vertex formats has been added via
+ PR https://github.com/floooh/sokol/pull/745
+ - sokol_imgui.h: fixes for Dear ImGui 1.89 deprecations (via PR https://github.com/floooh/sokol/pull/761)
+
+- **15-Jan-2023**: two bugfixes in sokol_app.h and sokol_gfx.h:
+ - sokol_app.h x11: Mouse button events now always return valid mouse
+ coordinates, also when no mouse movement happened yet
+ (fixes https://github.com/floooh/sokol/issues/770)
+ - sokol_gfx.h gl: The GL context is now configured with
+ GL_UNPACK_ALIGNMENT = 1, this should bring texture creation and updating
+ behaviour in line with the other backends for tightly packed texture
+ data that doesn't have a row-pitch with a multiple of 4
+ (fixes https://github.com/floooh/sokol/issues/767)
+
+- **14-Jan-2023**: sokol_app.h x11: a drag'n'drop related bugfix, the
+ XdndFinished reply event was sent with the wrong window handle which
+ confused some apps where the drag operation originated
+ (see https://github.com/floooh/sokol/pull/765#issuecomment-1382750611)
+
+- **16-Dec-2022**: In the sokol_gfx.h Metal backend: A fix for a Metal
+ validation layer error which I just discovered yesterday (seems to be new in
+ macOS 13). When the validation layer is active, and the application window
+ becomes fully obscured, the validation layer throws an error after a short
+ time (for details see: https://github.com/floooh/sokol/issues/762).
+ The reason appears to be that sokol_gfx.h creates a command buffer with
+ 'unretained references' (e.g. the command buffer doesn't manage the
+ lifetime of resources used by the commands stored in the buffer). This
+ seems to clash with MTKView's and/or CAMetalLayer's expectations. I fixed
+ this now by creating a second command buffer with 'retained references',
+ which only holds the ```presentDrawable``` command. That way, regular
+ draw commands don't have the refcounting overhead (because they're stored
+ in an unretained-references cmdbuffer), while the drawable surface is
+ still properly lifetime managed (because it's used in a separate command
+ buffer with retained references).
+
+- **15-Dec-2022**: A small but important update in sokol_imgui.h which fixes
+ touch input handling on mobile devices. Many thanks to github user @Xadiant
+ for the bug investigation and [PR](https://github.com/floooh/sokol/pull/760).
+
+- **25-Nov-2022**: Some code cleanup around resource creation and destruction in sokol_gfx.h:
+ - It's now safe to call the destroy, uninit and dealloc functions in any
+ resource state, in general, the functions will do the right thing without
+ assertions getting in the way (there are however new log warnings in some
+ cases though, such as attempting to call an ```sg_dealloc_*()``` function on
+ a resource object that's not in ALLOC state)
+ - A related **minor breaking change**: the ```sg_uninit_*()``` functions now return
+ void instead of bool, this is because ```sg_dealloc_*()``` no longer asserts
+ when called in the wrong resource state
+ - Related internal code cleanup in the backend-agnostic resource creation
+ and cleanup code, better or more consistent function names, etc...
+ - The validation layer can now be disabled in debug mode with a runtime
+ flag during setup: ```sg_desc.disable_validation```. This is mainly useful
+ for test code.
+ - Creating a pass object with invalid image objects now no longer asserts,
+ but instead results in a pass object in FAILED state. In debug mode,
+ the validation layer will still stop at this problem though (it's mostly
+ an 'undefined API behaviour' fix in release mode).
+ - Calling ```sg_shutdown()``` with existing resources in ALLOC state will
+ no longer print a log message about an 'active context mismatch'.
+ - A new header documentation blurb about the two-step resource creation
+ and destruction functions (search for RESOURCE CREATION AND DESTRUCTION IN DETAIL)
+
+- **16-Nov-2022**: Render layer support has been added to sokol_debugtext.h,
+ same general changes as in sokol_gl.h with two new functions:
+ sdtx_layer(layer_id) to select the layer to record text into, and
+ sdtx_draw_layer(layer_id) to draw the recorded text in that layer inside a
+ sokol-gfx render pass. The new sample [debugtext-layers-sapp](https://floooh.github.io/sokol-html5/debugtext-layers-sapp) demonstrates the feature together with
+ sokol-gl.
+
+
+- **11-Nov-2022**: sokol_gl.h has 2 new public API functions which enable
+ layered rendering: sgl_layer(), sgl_draw_layer() (technically it's three
+ functions: there's also sgl_context_draw_layer(), but that's just a variant of
+ sgl_draw_layer()). This allows to 'interleave' sokol-gl rendering
+ with other render operations. The [spine-layers-sapp](https://floooh.github.io/sokol-html5/spine-layers-sapp.html)
+ sample has been updated to use multiple sokol-gl layers.
+
+- **09-Nov-2022**: sokol_gfx.h now allows to add 'commit listeners', these
+ are callback functions which are called from inside sg_commit(). This is
+ mainly useful for libraries which build on top of sokol-gfx to be notified
+ about the start/end point of a frame, which in turn may simplify the public
+ API, or the internal implementation, because the library no longer needs to
+ 'guess' when a new frame starts.
+
+ For more details, search for 'COMMIT LISTENERS' in the sokol_gfx.h header.
+
+ This also results in a minor breaking change in sokol_spine.h: The function
+ ```sspine_new_frame()``` has been removed and replaced with an internal commit
+ listener.
+
+ Likewise, sokol_gl.h now uses a commit listener in the implementation, but
+ without changing the public API (the feature will be important for an upcoming
+ sokol-gl feature to support rendering layers, and for this a 'new-frame-function'
+ would have been needed).
+
+- **05-Nov-2022** A breaking change in sokol_fetch.h, and a minor change in
+ sokol_app.h which should only break for very few users:
+ - An ```sfetch_range_t``` ptr/size pair struct has been added to sokol_fetch.h,
+ and discrete ptr/size pairs have been replaced with sfetch_range_t
+ items. This affects the structs ```sfetch_request_t``` and ```sfetch_response_t```,
+ and the function ```sfetch_bind_buffer()```.
+ - The required changes in ```sfetch_response_t``` might be a bit non-obviois: To
+ access the fetched data, previous ```.buffer_ptr``` and ```.fetched_size```
+ was used. The fetched data is now accessible through an ```sfetch_range_t data```
+ item (```data.ptr``` and ```data.size```). The old ```.fetched_offset``` item
+ has been renamed to ```.data_offset``` to better conform with the new naming.
+ - The last two occurrences of discrete ptr/size pairs in sokol_app.h now have also
+ been replaced with ```sapp_range_t``` items, this only affects the structs
+ ```sapp_html5_fetch_request``` and ```sapp_html5_fetch_response```.
+
+- **03-Nov-2022** The language bindings generation has been updated for Zig 0.10.0,
+ and clang-14 (there was a minor change in the JSON ast-dump format).
+ Many thanks to github user @kcbanner for the Zig PR!
+
+- **02-Nov-2022** A new header sokol_spine.h (in the util dir), this is a
+ renderer and 'handle wrapper' around the spine-c runtime (Spine is a popular 2D
+ character anim system: http://esotericsoftware.com/). This turned out a much bigger
+ rabbit-hole than I initially expected, but the effort is justified by being a
+ experimentation testbed for a couple of things I want to add to other sokol
+ headers (for instance cleaned up handle pool code, a new logging- and error-reporting
+ system, render layers which will be useful for sokol_gl.h and sokol_debugtext.h).
+
+- **22-Oct-2022** All sokol headers now allow to override logging with a
+ callback function (installed in the setup call) instead of defining a SOKOL_LOG
+ macro. Overriding SOKOL_LOG still works as default fallback, but this is no
+ longer documented, consider this deprecated. Many thanks to github user
+ @Manuzor for the PR (see https://github.com/floooh/sokol/pull/721 for details)
+
+- **21-Oct-2022** RGB9E5 pixel format support in sokol_gfx.h and a GLES2 related
+ bugfix in the sokol_app.h Android backend:
+ - sokol_gfx.h now supports RGB9E5 textures (3*9 bit RGB + 5 bit shared exponent),
+ this works in all backends except GLES2 and WebGL1 (use ```sg_query_pixelformat()```
+ to check for runtime support). Many thanks to github user @allcreater for the PR!
+ - a bugfix in the sokol_app.h Android backend: when forcing a GLES2 context via
+ sapp_desc.gl_force_gles2, the Android backend correctly created a GLES2 context,
+ but then didn't communicate this through the function ```sapp_gles2()``` (which
+ still returned false in this case). This caused the sokol_gfx.h GL backend to
+ use the GLES3 code path instead GLES2 (which surprisingly seemed to have worked
+ fine, at least for the sokol samples which force GLES2).
+
+- **19-Oct-2022** Some fixes in the embedded Javascript code blocks (via EM_JS)
+ in sokol_app.h, sokol_args.h, sokol_audio.h and sokol_fetch.h:
+ - the JS code has been 'modernized' (e.g. const and let instead of var,
+ ```() => { ... }``` instead of ```function () { ... }``` for callbacks)
+ - false positives in the Closure static analysis have been suppressed
+ via inline hints
+
+- **16-Oct-2022** The Odin bindings generator and the generated bindings have
+ been simplified (the Odin binding now don't have separate wrapper functions).
+ Requires the latest Odin release. Also note: On M1 Macs I'm currently seeing
+ what looks like an ABI problem (in functions which pass color values to the C
+ side as uint8_t, the colors come out wrong). This also happened with the
+ previous binding version, so it looks like a regression in Odin. Might be
+ related to this recent bugfix (which I haven't tested yet):
+ https://github.com/odin-lang/Odin/issues/2121 Many thanks to @thePHTest for the
+ PR! (https://github.com/floooh/sokol/pull/719)
+
+- **15-Oct-2022**
+ - fixes for Emscripten 3.1.24: the sokol headers now use the new
+ **EM_JS_DEPS()** macro to declare 'indirect dependencies on JS library functions'.
+ This is a (much more robust) follow-up fix to the Emscripten related fixes from 10-Sep-2022.
+ The new Emscripten SDK also displays a couple of Javascript "static analyzer" warnings
+ by the Closure compiler (used in release mode to optimize and minify the generated
+ JS code). I fixed a couple of those warnings, but some warnings persist (all of them
+ false positives). Not sure yet if these can be fixed or need to be suppressed, but
+ that's for another time.
+ - the webkitAudioContext() fallback in sokol_audio.h's Emscripten backend
+ has been removed (only AudioContext is supported now), the fallback also
+ triggered a Closure warning, so it probably never worked as intended anyway.
+ - I also had to undo an older workaround in sokol_app.h on iOS (https://github.com/floooh/sokol/issues/645)
+ because this is now triggering a Metal validation layer error (https://github.com/floooh/sokol/issues/726).
+ The original case is no longer reproducible, so undoing the old workaround seems to
+ be a quick fix. Eventually I want to get rid of MTKView though, and go down to
+ CAMetalLayer.
+
+- **08-Oct-2022** sokol_app.h Android backend: the ```sapp_touchpoint``` struct
+ now has a new item ```sapp_android_tooltype android_tooltype;```. This exposes the
+ result of the Android NDK function ```AMotionEvent_getToolType()```.
+ Many thanks to @Wertzui123 for the initial PR (https://github.com/floooh/sokol/pull/717).
+
+- **25-Sep-2022**: sokol_app.h on Linux now optionally supports EGL instead of
+ GLX for the window system glue code and can create a GLES2 or GLES3 context
+ instead of a 'desktop GL' context.
+ To get EGL+GLES2/GLES3, just define SOKOL_GLES2 or SOKOL_GLES3 to compile the
+ implementation. To get EGL+GL, define SOKOL_GLCORE33 *and* SOKOL_FORCE_EGL.
+ By default, defining just SOKOL_GLCORE33 uses GLX for the window system glue
+ (just as before). Many thanks to GH user @billzez for the PR!
+
+- **10-Sep-2022**: sokol_app.h and sokol_args.h has been fixed for Emscripten 3.21, those headers
+ used the Emscripten Javascript helper function ```ccall()``` which is now part of the
+ 'legacy runtime' and causes linker errors. Instead of ```ccall()``` sokol_app.h and sokol_args.h
+ now drop down to a lower level set of Emscripten JS helper functions (which hopefully won't
+ go away anytime soon).
+
+- **05-Aug-2022**: New officially supported and automatically updated language bindings for Odin:
+ https://github.com/floooh/sokol-odin (also see [gen_odin.py](https://github.com/floooh/sokol/blob/master/bindgen/gen_odin.py))
+
+- **10-Jul-2022**: New features in sokol_app.h and sokol_imgui.h:
+ - In sokol_app.h it's now possible to set a mouse cursor type from a number of predefined
+ types via the new function ```sapp_set_mouse_cursor(sapp_mouse_cursor cursor)```. The
+ available cursor types are compatible with GLFW and Dear ImGui. Supported platforms
+ are: macOS, linux, win32, uwp and web.
+ - ```sapp_show_mouse(bool shown)``` now also works on the web platform.
+ - In sokol_app.h, the poorly defined 'user cursor' feature has been removed (```sapp_desc.user_cursor```
+ and ```SAPP_EVENTTYPE_UPDATE_CURSOR```). This was a hack to allow changing the mouse cursor and
+ only worked on Win32 and macOS (with different behaviour). Since setting the cursor type
+ is now 'properly supported, this hack was removed.
+ - sokol_imgui.h will now set the cursor type via ```sapp_set_mouse_cursor()```. This can be
+ disabled with the new ```simgui_desc_t``` item ```disable_set_mouse_cursor```.
+ - sokol_imgui.h now automatically enables resizing windows from edges (not just the bottom-right corner),
+ this behaviour can be disabled with the new ```simgui_desc_t``` item ```disable_windows_resize_from_edges```.
+ - sokol_imgui.h can now optionally write to the alpha channel (useful if you want to render the UI
+ into a separate render target, which is later composed onto the default framebuffer). The feature
+ is enabled with the new ```simgui_desc_t``` item ```write_alpha_channel```.
+
+ Many thanks to **@tomc1998** for the initial [Linux/X11 mouse cursor type PR](https://github.com/floooh/sokol/pull/678) and
+ **@luigi-rosso** for the [sokol_imgui.h alpha channel PR](https://github.com/floooh/sokol/pull/687)!
+
+- **03-Jul-2022**: A new sokol_gfx.h function ```bool sg_query_buffer_will_overflow(sg_buffer buf, size_t size)```
+which allows to check if a call to ```sg_append_buffer()``` would overflow the buffer. This
+is an alternative to the ```sg_query_buffer_overflow()``` function which only reports
+the overflow after the fact. Many thanks to @RandyGaul for the PR!
+
+- **29-Jun-2022**: In sokol_app.h with the D3D11 backend, if SOKOL_DEBUG is
+defined, and the D3D11 device creation fails, there's now a fallback code
+path which tries to create the device again without the D3D11_CREATE_DEVICE_DEBUG
+flag. Turns out the D3D11 debug support may suddenly stop working (just happened
+to me, indicated by the Win10 "Graphics Tool" feature being silently uninstalled
+and failing to install when asked to do so). This fix at least allows sokol_app.h
+applications compiled in debug mode to run, even if the D3D11 debug layer doesn't
+work.
+
+- **29-May-2022**: The code generation scripts for the
+[sokol-nim](https://github.com/floooh/sokol-nim) language bindings have been
+revised and updated, many thanks to Gustav Olsson for the PR! (I'm planning to
+spend a few more days integrating the bindings generation with Github Actions,
+so that it's easier to publish new bindings after updates to the sokol headers).
+
+- **26-May-2022**: The GL backend in sokol_app.h now allows to override the GL
+ context version via two new items in the ```sapp_desc``` struct:
+ ```sapp_desc.gl_major_version``` and ```sapp_desc.gl_minor_version```. The
+ default GL context version remains at 3.2. Overriding the GL version might make
+ sense if you're not using sokol_app.h together with sokol_gfx.h, or otherwise
+ want to call GL functions directly. Note that this only works for the
+ 'desktop GL' backends (Windows, Linux and macOS), but not for the GLES backends
+ (Android, iOS, web). Furthermore, on macOS only the GL versions 3.2 and 4.1
+ are available (plus the special config major=1 minor=0 creates an
+ NSOpenGLProfileVersionLegacy context). In general: use at your risk :) Many
+ thanks to Github user @pplux for the PR!
+
+- **15-May-2022**: The way internal memory allocation can be overridden with
+ your own functions has been changed from global macros to callbacks
+ provided in the API setup call. For instance in sokol_gfx.h:
+
+ ```c
+ void* my_malloc(size_t size, void* userdata) {
+ (void)userdata; // unused
+ return malloc(size);
+ }
+
+ void my_free(void* ptr, void* userdata) {
+ (void)userdata; // unused
+ free(ptr);
+ }
+
+ //...
+ sg_setup(&(sg_desc){
+ //...
+ .allocator = {
+ .alloc = my_malloc,
+ .free = my_free,
+ .user_data = ...,
+ }
+ });
+ ```
+
+ sokol_gfx.h will now call ```my_malloc()``` and ```my_free()``` whenever it needs
+ to allocate or free memory (note however that allocations inside OS
+ functions or 3rd party libraries are not affected).
+
+ If no override functions are provided, the standard library functions ```malloc()``` and ```free()```
+ will be used, just as before.
+
+ This change breaks source compatibility in the following headers:
+
+ - **sokol_fontstash.h**: the function signature of ```sfons_create()``` has changed,
+ this now takes a pointer to a new ```sfons_desc_t``` struct instead of
+ individual parameters.
+ - **sokol_gfx_imgui.h** (NOT sokol_imgui.h!): likewise, the function signature of
+ ```sg_imgui_init()``` has changed, this now takes an additional parameter
+ which is a pointer to a new ```sg_imgui_desc_t``` struct.
+
+ All affected headers also have a preprocessor check for the outdated
+ macros ```SOKOL_MALLOC```, ```SOKOL_CALLOC``` and ```SOKOL_FREE``` and throw
+ a compilation error if those macros are detected.
+
+ (if configuration through macros is still desired this could be added back in
+ the future, but I figured that the new way is more flexible in most situations).
+
+ The header sokol_memtrack.h and the sample [restart-sapp](https://floooh.github.io/sokol-html5/restart-sapp.html) have been updated accordingly.
+
+ Also search for ```MEMORY ALLOCATION OVERRIDE``` in the header documentation block
+ for more details.
+
+- **14-May-2022**: added a helper function ```simgui_map_keycode()``` to
+ sokol_imgui.h to map sokol_app.h keycodes (```sapp_keycode```,
+ ```SAPP_KEYCODE_*```) to Dear ImGui keycodes (```ImGuiKey```, ```ImGuiKey_*```).
+ If you're using Dear ImGui function to check for key input, you'll need to
+ update the code like this:
+
+ - Old:
+ ```cpp
+ ImGui::IsKeyPressed(SAPP_KEYCODE_A);
+ ```
+ - New:
+ ```cpp
+ ImGui::IsKeyPressed(simgui_map_keycode(SAPP_KEYCODE_A));
+ ```
+
+ This was basically 'fallout' from rewriting the input system in sokol_imgui.h
+ to the new evented IO system in Dear ImGui.
+
+- **08-Feb-2022**: sokol_imgui.h has been updated for Dear ImGui 1.87:
+ - sokol_imgui.h's input code has been rewritten to use the new evented IO
+ system and extended virtual key codes in Dear ImGui
+ - on non-Emscripten platforms, mouse buttons are no longer "cancelled" when
+ the mouse leaves the window (since the native desktop platforms
+ automatically capture the mouse when mouse buttons are pressed, but mouse
+ capture is not supported in the sokol_app.h Emscripten backend)
+
+- **28-Jan-2022**: some window size behaviour changes in sokol_app.h.
+ - Asking for a default-sized window (via sapp_desc.width/height = 0) now
+ behaves a bit differently on desktop platforms. Previously this set the
+ window size to 640x480, now a default window covers more screen area:
+ - on Windows CW_USEDEFAULT will be used for the size
+ - on macOS and Linux, the window size will be 4/5 of the
+ display size
+ - no behaviour changes on other platforms
+ - On Windows and Linux, the window is now centered (in a later update,
+ more control over the initial window position, and new functions for
+ positioning and sizing might be provided)
+ - On Windows, when toggling between windowed and fullscreen, the
+ window position and size will now be restored (on other platforms
+ this already happened automatically through the window system)
+ - On all desktop platforms if an application starts in fullscreen and
+ then is toggled back to windowed, the window will now be of the
+ expected size (provided in sapp_desc.width/height)
+
+- **20-Jan-2022**:
+ - sokol_audio.h: A compatibility fix in the sokol_audio.h WASAPI backend (Windows): On
+ some configs the IAudioClient::Initialize() call could fail because
+ of a mismatch between the requested number of channels and speaker config.
+ See [#614](https://github.com/floooh/sokol/issues/614) for details.
+ - sokol_app.h D3D11/DXGI: Fix an (uncritical) COM interface leak warning for IDXGIAdapter and
+ IDXGIFactory at shutdown, introduced with the recent disabling of Alt-Enter.
+
+- **18-Jan-2022**:
+ - sokol_app.h now has per-monitor DPI support on Windows and macOS: when
+ the application window is moved to a monitor with different DPI, the values
+ returned by sapp_dpi_scale(), sapp_width() and sapp_height() will update
+ accordingly (only if the application requested high-dpi rendering with
+ ```sapp_desc.high_dpi=true```, otherwise the dpi scale value remains
+ fixed at 1.0f). The application will receive an SAPP_EVENTTYPE_RESIZED event
+ if the default framebuffer size has changed because of a DPI change.
+ On Windows this feature requires Win10 version 1703 or later (aka the
+ 'Creators Update'), older Windows version simply behave as before.
+ Many thank to @tjachmann for the initial PR with the Windows implementation!
+ - sokol_app.h: DPI scale computation on macOS is now more robust using the
+ NSScreen.backingScaleFactor value
+ - sokol_app.h: the new frame timing code in sokol_app.h now detects if the display
+ refresh rate changes and adjusts itself accordingly (for instance if the
+ window is moved between displays with different refresh rate)
+ - sokol_app.h D3D11/DXGI: during window movement and resize, the frame is now
+ presented with DXGI_PRESENT_DO_NOT_WAIT, this fixes some window system
+ stuttering issues on Win10 configs with recent NVIDIA drivers.
+ - sokol_app.h D3D11/DXGI: the application will no longer appear to freeze for
+ 0.5 seconds when the title bar is grabbed with the mouse for movement, but
+ then not moving the mouse.
+ - sokol_app.h D3D11/DXGI: DXGI's automatic windowed/fullscreen switching via
+ Alt-Enter has been disabled, because this switched to 'real' fullscreen mode,
+ while sokol_app.h's fullscreen mode uses a borderless window. Use the
+ programmatic fullscreen/window switching via ```sapp_toggle_fullscreen()```
+ instead.
+ - **BREAKING CHANGE** in sokol_imgui.h: because the applications' DPI scale
+ can now change at any time, the DPI scale value is now communicated to
+ sokol_imgui.h in the ```simgui_new_frame()``` function. This has been
+ changed to accept a pointer to a new ```simgui_frame_desc_t``` struct.
+ With C99, change the simgui_new_frame() call as follows (if also using
+ sokol_app.h):
+ ```c
+ simgui_new_frame(&(simgui_frame_desc_t){
+ .width = sapp_width(),
+ .height = sapp_height(),
+ .delta_time = sapp_frame_duration(),
+ .dpi_scale = sapp_dpi_scale()
+ });
+ ```
+ On C++ this works:
+ ```c++
+ simgui_new_frame({ sapp_width(), sapp_height(), sapp_frame_duration(), sapp_dpi_scale() });
+ ```
+ ...or in C++20:
+ ```c++
+ simgui_new_frame({
+ .width = sapp_width(),
+ .height = sapp_height(),
+ .delta_time = sapp_frame_duration(),
+ .dpi_scale = sapp_dpi_scale()
+ });
+ ```
+ - **KNOWN ISSUE**: the recent change in sokol-audio's WASAPI backend to directly consume
+ float samples doesn't appear to work on some configs (see [#614](https://github.com/floooh/sokol/issues/614)),
+ investigation is underway
+
+- **15-Jan-2022**:
+ - A bugfix in the GL backend for uniform arrays using the 'native' uniform block layout.
+ The bug was a regression in the recent 'uniform data handling' update. See
+ [PR #611](https://github.com/floooh/sokol/pull/611) for details, and this [new sample/test](https://github.com/floooh/sokol-samples/blob/master/glfw/uniformarrays-glfw.c).
+ Many thanks to @nmr8acme for the PR!
+
+- **08-Jan-2022**: some enhancements and cleanup to uniform data handling in sokol_gfx.h
+ and the sokol-shdc shader compiler:
+ - *IMPORTANT*: when updating sokol_gfx.h (and you're using the sokol-shdc shader compiler),
+ don't forget to update the sokol-shdc binaries too!
+ - The GLSL uniform types int, ivec2, ivec3 and
+ ivec4 can now be used in shader code, those are exposed to the GL
+ backends with the new ```sg_uniform_type``` items
+ ```SG_UNIFORM_TYPE_INT[2,3,4]```.
+ - A new enum ```sg_uniform_layout```, currently with the values SG_UNIFORMLAYOUT_NATIVE
+ and SG_UNIFORMLAYOUT_STD140. The enum is used in ```sg_shader_uniform_block_desc```
+ as a 'packing rule hint', so that the GL backend can properly locate the offset
+ of uniform block members. The default (SG_UNIFORMLAYOUT_NATIVE) keeps the same
+ behaviour, so existing code shouldn't need to be changed. With the packing
+ rule SG_UNIFORMLAYOUT_STD140 the uniform block interior is expected to be
+ layed out according to the OpenGL std140 packing rule.
+ - Note that the SG_UNIFORMLAYOUT_STD140 only allows a subset of the actual std140
+ packing rule: arrays are only allowed for the types vec4, int4 and mat4.
+ This is because the uniform data must still be compatible with
+ ```glUniform()``` calls in the GL backends (which have different
+ 'interior alignment' for arrays).
+ - The sokol-shdc compiler supports the new uniform types and will annotate the
+ code-generated sg_shader_desc structs with SG_UNIFORMLAYOUT_STD140,
+ and there are new errors to make sure that uniform blocks are compatible
+ with all sokol_gfx.h backends.
+ - Likewise, sokol_gfx.h has tighter validation for the ```sg_shader_uniform_block```
+ desc struct, but only when the GL backend is used (in general, the interior
+ layout of uniform blocks is only relevant for GL backends, on all other backends
+ sokol_gfx.h just passes the uniform data as an opaque block to the shader)
+ For more details see:
+ - [new sections in the sokol_gfx.h documentation](https://github.com/floooh/sokol/blob/ba64add0b67cac16fc86fb6b64d1da5f67e80c0f/sokol_gfx.h#L343-L450)
+ - [documentation of ```sg_uniform_layout```](https://github.com/floooh/sokol/blob/ba64add0b67cac16fc86fb6b64d1da5f67e80c0f/sokol_gfx.h#L1322-L1355)
+ - [enhanced sokol-shdc documentation](https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md#glsl-uniform-blocks-and-c-structs)
+ - [a new sample 'uniformtypes-sapp'](https://floooh.github.io/sokol-html5/uniformtypes-sapp.html)
+
+ PS: and an unrelated change: the frame latency on Win32+D3D11 has been slightly improved
+ via IDXGIDevice1::SetMaximumFrameLatency()
+
+- **27-Dec-2021**: sokol_app.h frame timing improvements:
+ - A new function ```double sapp_frame_duration(void)``` which returns the frame
+ duration in seconds, averaged over the last 256 frames to smooth out
+ jittering spikes. If available, this uses platform/backend specific
+ functions of the swapchain API:
+ - On Windows: DXGI's GetFrameStatistics().SyncQPCTime.
+ - On Emscripten: the timestamp provided by the RAF callback, this will
+ still be clamped and jittered on some browsers, but averaged over
+ a number of frames yields a pretty accurate approximation
+ of the actual frame duration.
+ - On Metal, ```MTLDrawable addPresentedHandler + presentedTime```
+ doesn't appear to function correctly on macOS Monterey and/or M1 Macs, so
+ instead mach_absolute_time() is called at the start of the MTKView
+ frame callback.
+ - In all other situations, the same timing method is used as
+ in sokol_time.h.
+ - On macOS and iOS, sokol_app.h now queries the maximum display refresh rate
+ of the main display and uses this as base to compute the preferred frame
+ rate (by multiplying with ```sapp_desc.swap_interval```), previously the
+ preferred frame rate was hardwired to ```60 * swap_interval```. This means
+ that native macOS and iOS applications may now run at 120Hz instead of
+ 60Hz depending on the device (I realize that this isn't ideal, there
+ will probably be a different way to hint the preferred interval at
+ which the frame callback is called, which would also support disabling
+ vsync and probably also adaptive vsync).
+
+- **19-Dec-2021**: some sokol_audio.h changes:
+ - on Windows, sokol_audio.h no longer converts audio samples
+ from float to int16_t, but instead configures WASAPI to directly accept
+ float samples. Many thanks to github user iOrange for the PR!
+ - sokol_audio.h has a new public function ```saudio_suspended()``` which
+ returns true if the audio device/context is currently in suspended mode.
+ On all backends except WebAudio this always returns false. This allows
+ to show a visual hint to the user that audio is muted until the first
+ input event is received.
+
+- **18-Dec-2021**: the sokol_gfx.h ```sg_draw()``` function now uses the currently applied
+ pipeline object to decide if the GL or D3D11 backend's instanced drawing function
+ should be called instead of the ```num_instances``` argument. This fixes a
+ bug on some WebGL configs when instanced rendering is configured
+ but ```sg_draw()``` is called with an instance count of 1.
+
+- **18-Nov-2021**: sokol_gl.h has a new function to control the point size for
+ point list rendering: ```void sgl_point_size(float size)```. Note that on D3D11
+ the point size is currently ignored (since D3D11 doesn't support a point size at
+ all, the feature will need to be emulated in sokol_gl.h when the D3D11 backend is active).
+ Also note that points cannot currently be textured, only colored.
+
- **08-Oct-2021**: texture compression support in sokol_gfx.h has been revisited:
- tighter validation checks on texture creation:
- content data validation now also happens in ```sg_make_image()``` (previously only in ```sg_update_image()```)
@@ -67,7 +753,7 @@
ago (around iOS 12.x) MTKView started to ignore the contentScaleFactor
property, which lead to sokol_app.h always setting up a HighDPI
framebuffer even when sapp_desc.high_dpi wasn't set. The fix is to set
- the MTKView's drawableSize explicitely now.
+ the MTKView's drawableSize explicitly now.
- The iOS GL backend didn't support MSAA multisampling so far, this has
been fixed now, but only one MSAA mode (4x) is available, which will be
selected when sapp_desc.sample_count is greater than 1.
@@ -121,7 +807,7 @@ uses the **AVAudioSession** class to activate and deactivate audio output as nee
This fixes sokol_audio.h for iPhones (so far, sokol_audio.h accidentally only worked
for iPads). Please see [this issue](https://github.com/floooh/sokol/issues/431) for details.
A somewhat unfortunate side effect of this fix is that sokol_audio.h must now be compiled
-as Objective-C when targetting iOS, also note that a new framework must be linked: ```AVFoundation```.
+as Objective-C when targeting iOS, also note that a new framework must be linked: ```AVFoundation```.
Many thanks to @oviano for providing the PR!
- **14-Feb-2021**: The Dear ImGui rendering backend in [sokol_imgui.h](https://github.com/floooh/sokol/blob/master/util/sokol_imgui.h) has been rewritten to only do a single
diff --git a/3rdparty/sokol/bindgen/.gitignore b/3rdparty/sokol/bindgen/.gitignore
index 9dcbf6f..4528e59 100644
--- a/3rdparty/sokol/bindgen/.gitignore
+++ b/3rdparty/sokol/bindgen/.gitignore
@@ -4,3 +4,5 @@
__pycache__/
sokol-nim/
sokol-zig/
+sokol-odin/
+sokol-rust/
diff --git a/3rdparty/sokol/bindgen/gen_all.py b/3rdparty/sokol/bindgen/gen_all.py
index dc409d2..51d7e55 100644
--- a/3rdparty/sokol/bindgen/gen_all.py
+++ b/3rdparty/sokol/bindgen/gen_all.py
@@ -1,8 +1,10 @@
-import os, gen_nim, gen_zig
+import os, gen_nim, gen_zig, gen_odin, gen_rust
tasks = [
+ [ '../sokol_log.h', 'slog_', [] ],
[ '../sokol_gfx.h', 'sg_', [] ],
[ '../sokol_app.h', 'sapp_', [] ],
+ [ '../sokol_glue.h', 'sapp_sg', ['sg_'] ],
[ '../sokol_time.h', 'stm_', [] ],
[ '../sokol_audio.h', 'saudio_', [] ],
[ '../util/sokol_gl.h', 'sgl_', ['sg_'] ],
@@ -10,18 +12,26 @@ tasks = [
[ '../util/sokol_shape.h', 'sshape_', ['sg_'] ],
]
+# Odin
+gen_odin.prepare()
+for task in tasks:
+ [c_header_path, main_prefix, dep_prefixes] = task
+ gen_odin.gen(c_header_path, main_prefix, dep_prefixes)
+
# Nim
gen_nim.prepare()
for task in tasks:
- c_header_path = task[0]
- main_prefix = task[1]
- dep_prefixes = task[2]
+ [c_header_path, main_prefix, dep_prefixes] = task
gen_nim.gen(c_header_path, main_prefix, dep_prefixes)
# Zig
gen_zig.prepare()
for task in tasks:
- c_header_path = task[0]
- main_prefix = task[1]
- dep_prefixes = task[2]
+ [c_header_path, main_prefix, dep_prefixes] = task
gen_zig.gen(c_header_path, main_prefix, dep_prefixes)
+
+# Rust
+gen_rust.prepare()
+for task in tasks:
+ [c_header_path, main_prefix, dep_prefixes] = task
+ gen_rust.gen(c_header_path, main_prefix, dep_prefixes)
diff --git a/3rdparty/sokol/bindgen/gen_ir.py b/3rdparty/sokol/bindgen/gen_ir.py
index c1e2ab5..0089ae2 100644
--- a/3rdparty/sokol/bindgen/gen_ir.py
+++ b/3rdparty/sokol/bindgen/gen_ir.py
@@ -59,11 +59,11 @@ def parse_enum(decl):
if 'inner' in item_decl:
const_expr = item_decl['inner'][0]
if const_expr['kind'] != 'ConstantExpr':
- sys.exit(f"ERROR: Enum values must be a ConstantExpr ({decl['name']})")
- if const_expr['valueCategory'] != 'rvalue':
- sys.exit(f"ERROR: Enum value ConstantExpr must be 'rvalue' ({decl['name']})")
+ sys.exit(f"ERROR: Enum values must be a ConstantExpr ({item_decl['name']}), is '{const_expr['kind']}'")
+ if const_expr['valueCategory'] != 'rvalue' and const_expr['valueCategory'] != 'prvalue':
+ sys.exit(f"ERROR: Enum value ConstantExpr must be 'rvalue' or 'prvalue' ({item_decl['name']}), is '{const_expr['valueCategory']}'")
if not ((len(const_expr['inner']) == 1) and (const_expr['inner'][0]['kind'] == 'IntegerLiteral')):
- sys.exit(f"ERROR: Enum value ConstantExpr must have exactly one IntegerLiteral ({decl['name']})")
+ sys.exit(f"ERROR: Enum value ConstantExpr must have exactly one IntegerLiteral ({item_decl['name']})")
item['value'] = const_expr['inner'][0]['value']
if needs_value and 'value' not in item:
sys.exit(f"ERROR: anonymous enum items require an explicit value")
@@ -79,7 +79,7 @@ def parse_func(decl):
if 'inner' in decl:
for param in decl['inner']:
if param['kind'] != 'ParmVarDecl':
- print(f"warning: ignoring func {decl['name']} (unsupported parameter type)")
+ print(f" >> warning: ignoring func {decl['name']} (unsupported parameter type)")
return None
outp_param = {}
outp_param['name'] = param['name']
@@ -119,4 +119,6 @@ def gen(header_path, source_path, module, main_prefix, dep_prefixes):
outp_decl['is_dep'] = is_dep
outp_decl['dep_prefix'] = dep_prefix(decl, dep_prefixes)
outp['decls'].append(outp_decl)
+ with open(f'{module}.json', 'w') as f:
+ f.write(json.dumps(outp, indent=2));
return outp
diff --git a/3rdparty/sokol/bindgen/gen_nim.py b/3rdparty/sokol/bindgen/gen_nim.py
index fb6ba45..06a3b91 100644
--- a/3rdparty/sokol/bindgen/gen_nim.py
+++ b/3rdparty/sokol/bindgen/gen_nim.py
@@ -1,16 +1,19 @@
#-------------------------------------------------------------------------------
-# Read output of gen_json.py and generate Zig language bindings.
+# Generate Nim bindings
#
# Nim coding style:
-# - types and constants are PascalCase
-# - functions, parameters, and fields are camelCase
+# - type identifiers are PascalCase, everything else is camelCase
+# - reference: https://nim-lang.org/docs/nep1.html
#-------------------------------------------------------------------------------
import gen_ir
-import json, re, os, shutil
+import gen_util as util
+import os, shutil, sys
module_names = {
+ 'slog_': 'log',
'sg_': 'gfx',
'sapp_': 'app',
+ 'sapp_sg': 'glue',
'stm_': 'time',
'saudio_': 'audio',
'sgl_': 'gl',
@@ -19,8 +22,10 @@ module_names = {
}
c_source_paths = {
+ 'slog_': 'sokol-nim/src/sokol/c/sokol_log.c',
'sg_': 'sokol-nim/src/sokol/c/sokol_gfx.c',
'sapp_': 'sokol-nim/src/sokol/c/sokol_app.c',
+ 'sapp_sg': 'sokol-nim/src/sokol/c/sokol_glue.c',
'stm_': 'sokol-nim/src/sokol/c/sokol_time.c',
'saudio_': 'sokol-nim/src/sokol/c/sokol_audio.c',
'sgl_': 'sokol-nim/src/sokol/c/sokol_gl.c',
@@ -28,20 +33,57 @@ c_source_paths = {
'sshape_': 'sokol-nim/src/sokol/c/sokol_shape.c',
}
-func_name_ignores = [
+c_callbacks = [
+ 'slog_func',
+]
+
+ignores = [
'sdtx_printf',
'sdtx_vprintf',
]
-func_name_overrides = {
- 'sgl_error': 'sgl_get_error', # 'error' is reserved in Zig
- 'sgl_deg': 'sgl_as_degrees',
- 'sgl_rad': 'sgl_as_radians',
-}
-
-struct_field_type_overrides = {
+overrides = {
+ 'sgl_error': 'sgl_get_error',
+ 'sgl_deg': 'sgl_as_degrees',
+ 'sgl_rad': 'sgl_as_radians',
'sg_context_desc.color_format': 'int',
'sg_context_desc.depth_format': 'int',
+ 'SGL_NO_ERROR': 'SGL_ERROR_NO_ERROR',
+ 'SG_BUFFERTYPE_VERTEXBUFFER': 'SG_BUFFERTYPE_VERTEX_BUFFER',
+ 'SG_BUFFERTYPE_INDEXBUFFER': 'SG_BUFFERTYPE_INDEX_BUFFER',
+ 'SG_ACTION_DONTCARE': 'SG_ACTION_DONT_CARE',
+ 'ptr': 'addr', # range ptr
+ 'func': 'fn',
+ 'slog_func': 'fn',
+}
+
+enumPrefixOverrides = {
+ # sokol_gfx.h
+ 'PIXELFORMAT': 'pixelFormat',
+ 'RESOURCESTATE': 'resourceState',
+ 'BUFFERTYPE': 'bufferType',
+ 'INDEXTYPE': 'indexType',
+ 'IMAGETYPE': 'imageType',
+ 'SAMPLERTYPE': 'samplerType',
+ 'CUBEFACE': 'cubeFace',
+ 'SHADERSTAGE': 'shaderStage',
+ 'PRIMITIVETYPE': 'primitiveType',
+ 'BORDERCOLOR': 'borderColor',
+ 'VERTEXFORMAT': 'vertexFormat',
+ 'VERTEXSTEP': 'vertexStep',
+ 'UNIFORMTYPE': 'uniformType',
+ 'UNIFORMLAYOUT': 'uniformLayout',
+ 'CULLMODE': 'cullMode',
+ 'FACEWINDING': 'faceWinding',
+ 'COMPAREFUNC': 'compareFunc',
+ 'STENCILOP': 'stencilOp',
+ 'BLENDFACTOR': 'blendFactor',
+ 'BLENDOP': 'blendOp',
+ 'COLORMASK': 'colorMask',
+ # sokol_app.h
+ 'EVENTTYPE': 'eventType',
+ 'KEYCODE': 'keyCode',
+ 'MOUSEBUTTON': 'mouseButton',
}
prim_types = {
@@ -60,7 +102,7 @@ prim_types = {
'double': 'float64',
'uintptr_t': 'uint',
'intptr_t': 'int',
- 'size_t': 'int',
+ 'size_t': 'int', # not a bug, Nim's sizeof() returns int
}
prim_defaults = {
@@ -74,31 +116,62 @@ prim_defaults = {
'uint32_t': '0',
'int64_t': '0',
'uint64_t': '0',
- 'float': '0.0',
+ 'float': '0.0f',
'double': '0.0',
'uintptr_t': '0',
'intptr_t': '0',
'size_t': '0'
}
+common_prim_types = """
+array
+untyped typed void
+bool byte char
+int int8 int16 int32 int64
+uint uint8 uint16 uint32 uint64
+float float32 float64
+string
+cchar cint csize_t
+cfloat cdouble
+cstring
+pointer
+""".split()
+
+keywords = """
+addr and as asm
+bind block break
+case cast concept const continue converter
+defer discard distinct div do
+elif else end enum except export
+finally for from func
+if import in include interface is isnot iterator
+let
+macro method mixin mod
+nil not notin
+object of or out
+proc ptr
+raise ref return
+shl shr static
+template try tuple type
+using
+var
+when while
+xor
+yield
+""".split() + common_prim_types
+
struct_types = []
enum_types = []
-enum_items = {}
out_lines = ''
def reset_globals():
global struct_types
global enum_types
- global enum_items
global out_lines
struct_types = []
enum_types = []
- enum_items = {}
out_lines = ''
-re_1d_array = re.compile("^(?:const )?\w*\s\*?\[\d*\]$")
-re_2d_array = re.compile("^(?:const )?\w*\s\*?\[\d*\]\[\d*\]$")
-
def l(s):
global out_lines
out_lines += s + '\n'
@@ -107,90 +180,66 @@ def as_nim_prim_type(s):
return prim_types[s]
# prefix_bla_blub(_t) => (dep.)BlaBlub
-def as_nim_struct_type(s, prefix):
+def as_nim_type_name(s, prefix):
parts = s.lower().split('_')
- outp = '' if s.startswith(prefix) else f'{parts[0]}.'
+ dep = parts[0] + '_'
+ outp = ''
+ if not s.startswith(prefix) and dep in module_names:
+ outp = module_names[dep] + '.'
for part in parts[1:]:
+ # ignore '_t' type postfix
if (part != 't'):
outp += part.capitalize()
return outp
-# prefix_bla_blub(_t) => (dep.)BlaBlub
-def as_nim_enum_type(s, prefix):
- parts = s.lower().split('_')
- outp = '' if s.startswith(prefix) else f'{parts[0]}.'
- for part in parts[1:]:
- if (part != 't'):
- outp += part.capitalize()
- return outp
-
-# prefix_bla_blub(_t) => (dep.)BlaBlub
-def as_nim_const_type(s, prefix):
- parts = s.lower().split('_')
- outp = '' if s.startswith(prefix) else f'{parts[0]}.'
- for part in parts[1:]:
- if (part != 't'):
- outp += part.capitalize()
- return outp
-
-def check_struct_field_type_override(struct_name, field_name, orig_type):
- s = f"{struct_name}.{field_name}"
- if s in struct_field_type_overrides:
- return struct_field_type_overrides[s]
+def check_override(name, default=None):
+ if name in overrides:
+ return overrides[name]
+ elif default is None:
+ return name
else:
- return orig_type
+ return default
-def check_func_name_ignore(func_name):
- return func_name in func_name_ignores
+def check_ignore(name):
+ return name in ignores
-def check_func_name_override(func_name):
- if func_name in func_name_overrides:
- return func_name_overrides[func_name]
+def is_power_of_two(val):
+ return val == 0 or val & (val - 1) == 0
+
+def wrap_keywords(s):
+ if s in keywords:
+ return f'`{s}`'
else:
- return func_name
-
-def trim_prefix(s, prefix):
- outp = s;
- if outp.lower().startswith(prefix.lower()):
- outp = outp[len(prefix):]
- return outp
-
-# PREFIX_BLA_BLUB to bla_blub
-def as_snake_case(s, prefix = ""):
- return trim_prefix(s, prefix).lower()
+ return s
# prefix_bla_blub => blaBlub
-def as_camel_case(s, prefix = ""):
- parts = trim_prefix(s, prefix).lower().split('_')
+def as_camel_case(s, prefix, wrap=True):
+ outp = s.lower()
+ if outp.startswith(prefix):
+ outp = outp[len(prefix):]
+ parts = outp.lstrip('_').split('_')
outp = parts[0]
for part in parts[1:]:
outp += part.capitalize()
+ if wrap:
+ outp = wrap_keywords(outp)
return outp
-# prefix_bla_blub => BlaBlub
-def as_pascal_case(s, prefix):
- parts = trim_prefix(s, prefix).lower().split('_')
- outp = ""
- for part in parts:
+# PREFIX_ENUM_BLA_BLO => blaBlo
+def as_enum_item_name(s, wrap=True):
+ outp = s.lstrip('_')
+ parts = outp.split('_')[1:]
+ if parts[0] in enumPrefixOverrides:
+ parts[0] = enumPrefixOverrides[parts[0]]
+ else:
+ parts[0] = parts[0].lower()
+ outp = parts[0]
+ for part in parts[1:]:
outp += part.capitalize()
+ if wrap:
+ outp = wrap_keywords(outp)
return outp
-# PREFIX_ENUM_BLA => Bla, _PREFIX_ENUM_BLA => Bla
-def as_enum_item_name(s):
- outp = s
- if outp.startswith('_'):
- outp = outp[1:]
- parts = outp.lower().split('_')[2:]
- outp = ""
- for part in parts:
- outp += part.capitalize()
- if outp[0].isdigit():
- outp = 'N' + outp
- return outp
-
-def enum_default_item(enum_name):
- return enum_items[enum_name][0]
-
def is_prim_type(s):
return s in prim_types
@@ -200,15 +249,6 @@ def is_struct_type(s):
def is_enum_type(s):
return s in enum_types
-def is_string_ptr(s):
- return s == "const char *"
-
-def is_const_void_ptr(s):
- return s == "const void *"
-
-def is_void_ptr(s):
- return s == "void *"
-
def is_const_prim_ptr(s):
for prim_type in prim_types:
if s == f"const {prim_type} *":
@@ -227,266 +267,208 @@ def is_const_struct_ptr(s):
return True
return False
-def is_func_ptr(s):
- return '(*)' in s
-
-def is_1d_array_type(s):
- return re_1d_array.match(s)
-
-def is_2d_array_type(s):
- return re_2d_array.match(s)
-
def type_default_value(s):
return prim_defaults[s]
-def extract_array_type(s):
- return s[:s.index('[')].strip()
-
-def extract_array_nums(s):
- return s[s.index('['):].replace('[', ' ').replace(']', ' ').split()
-
-def extract_ptr_type(s):
- tokens = s.split()
- if tokens[0] == 'const':
- return tokens[1]
- else:
- return tokens[0]
-
-def as_extern_c_arg_type(arg_type, prefix):
- if arg_type == "void":
- return "void"
- elif is_prim_type(arg_type):
- return as_nim_prim_type(arg_type)
- elif is_struct_type(arg_type):
- return as_nim_struct_type(arg_type, prefix)
- elif is_enum_type(arg_type):
- return as_nim_enum_type(arg_type, prefix)
- elif is_void_ptr(arg_type):
- return "pointer"
- elif is_const_void_ptr(arg_type):
- return "pointer"
- elif is_string_ptr(arg_type):
- return "cstring"
- elif is_const_struct_ptr(arg_type):
- return f"ptr {as_nim_struct_type(extract_ptr_type(arg_type), prefix)}"
- elif is_prim_ptr(arg_type):
- return f"[*c] {as_nim_prim_type(extract_ptr_type(arg_type))}"
- elif is_const_prim_ptr(arg_type):
- return f"ptr {as_nim_prim_type(extract_ptr_type(arg_type))}"
- else:
- return '??? (as_extern_c_arg_type)'
-
-def as_nim_arg_type(arg_prefix, arg_type, prefix):
- # NOTE: if arg_prefix is None, the result is used as return value
- pre = "" if arg_prefix is None else arg_prefix
- if arg_type == "void":
- if arg_prefix is None:
- return "void"
- else:
- return ""
- elif is_prim_type(arg_type):
- return pre + as_nim_prim_type(arg_type)
- elif is_struct_type(arg_type):
- return pre + as_nim_struct_type(arg_type, prefix)
- elif is_enum_type(arg_type):
- return pre + as_nim_enum_type(arg_type, prefix)
- elif is_void_ptr(arg_type):
- return pre + "pointer"
- elif is_const_void_ptr(arg_type):
- return pre + "pointer"
- elif is_string_ptr(arg_type):
- return pre + "cstring"
- elif is_const_struct_ptr(arg_type):
- return pre + f"ptr {as_nim_struct_type(extract_ptr_type(arg_type), prefix)}"
- elif is_prim_ptr(arg_type):
- return pre + f"ptr {as_nim_prim_type(extract_ptr_type(arg_type))}"
- elif is_const_prim_ptr(arg_type):
- return pre + f"ptr {as_nim_prim_type(extract_ptr_type(arg_type))}"
- else:
- return arg_prefix + "??? (as_nim_arg_type)"
-
-# get C-style arguments of a function pointer as string
-def funcptr_args_c(field_type, prefix):
+def funcptr_args(field_type, prefix):
tokens = field_type[field_type.index('(*)')+4:-1].split(',')
s = ""
n = 0
for token in tokens:
n += 1
- arg_type = token.strip()
+ arg_ctype = token.strip()
if s != "":
s += ", "
- c_arg = f"a{n}:" + as_extern_c_arg_type(arg_type, prefix)
- if (c_arg == "void"):
- return ""
- else:
- s += c_arg
+ arg_nimtype = as_nim_type(arg_ctype, prefix)
+ if arg_nimtype == "":
+ return "" # fun(void)
+ s += f"a{n}:{arg_nimtype}"
if s == "a1:void":
s = ""
return s
-# get C-style result of a function pointer as string
-def funcptr_res_c(field_type):
- res_type = field_type[:field_type.index('(*)')].strip()
- if res_type == 'void':
- return ''
- elif is_const_void_ptr(res_type):
- return ':pointer'
- else:
- return '???'
+def funcptr_result(field_type, prefix):
+ ctype = field_type[:field_type.index('(*)')].strip()
+ return as_nim_type(ctype, prefix)
-def funcdecl_args_c(decl, prefix):
- s = ""
- for param_decl in decl['params']:
- if s != "":
- s += ", "
- arg_type = param_decl['type']
- s += as_extern_c_arg_type(arg_type, prefix)
- return s
-
-def funcdecl_args_nim(decl, prefix):
- s = ""
- for param_decl in decl['params']:
- if s != "":
- s += ", "
- arg_name = param_decl['name']
- arg_type = param_decl['type']
- s += f"{as_nim_arg_type(f'{arg_name}:', arg_type, prefix)}"
- return s
-
-def funcdecl_res_c(decl, prefix):
- decl_type = decl['type']
- res_type = decl_type[:decl_type.index('(')].strip()
- return as_extern_c_arg_type(res_type, prefix)
-
-def funcdecl_res_nim(decl, prefix):
- decl_type = decl['type']
- res_type = decl_type[:decl_type.index('(')].strip()
- nim_res_type = as_nim_arg_type(None, res_type, prefix)
- if nim_res_type == "":
- nim_res_type = "void"
- return nim_res_type
-
-def gen_struct(decl, prefix, use_raw_name=False):
- struct_name = decl['name']
- nim_type = struct_name if use_raw_name else as_nim_struct_type(struct_name, prefix)
- l(f"type {nim_type}* = object")
- isPublic = True
- for field in decl['fields']:
- field_name = field['name']
- if field_name == "__pad":
- # FIXME: these should be guarded by SOKOL_ZIG_BINDINGS, but aren't?
- continue
- isPublic = not field_name.startswith("_")
- field_name = as_camel_case(field_name, "_")
- if field_name == "ptr":
- field_name = "source"
- if field_name == "ref":
- field_name = "`ref`"
- if field_name == "type":
- field_name = "`type`"
- if isPublic:
- field_name += "*"
- field_type = field['type']
- field_type = check_struct_field_type_override(struct_name, field_name, field_type)
- if is_prim_type(field_type):
- l(f" {field_name}:{as_nim_prim_type(field_type)}")
- elif is_struct_type(field_type):
- l(f" {field_name}:{as_nim_struct_type(field_type, prefix)}")
- elif is_enum_type(field_type):
- l(f" {field_name}:{as_nim_enum_type(field_type, prefix)}")
- elif is_string_ptr(field_type):
- l(f" {field_name}:cstring")
- elif is_const_void_ptr(field_type):
- l(f" {field_name}:pointer")
- elif is_void_ptr(field_type):
- l(f" {field_name}:pointer")
- elif is_const_prim_ptr(field_type):
- l(f" {field_name}:ptr {as_nim_prim_type(extract_ptr_type(field_type))}")
- elif is_func_ptr(field_type):
- l(f" {field_name}:proc({funcptr_args_c(field_type, prefix)}){funcptr_res_c(field_type)} {{.cdecl.}}")
- elif is_1d_array_type(field_type):
- array_type = extract_array_type(field_type)
- array_nums = extract_array_nums(field_type)
- if is_prim_type(array_type) or is_struct_type(array_type):
- if is_prim_type(array_type):
- nim_type = as_nim_prim_type(array_type)
- elif is_struct_type(array_type):
- nim_type = as_nim_struct_type(array_type, prefix)
- elif is_enum_type(array_type):
- nim_type = as_nim_enum_type(array_type, prefix)
- else:
- nim_type = '??? (array type)'
- t0 = f"array[{array_nums[0]}, {nim_type}]"
- t0_slice = f"[]const {nim_type}"
- t1 = f"[_]{nim_type}"
- l(f" {field_name}:{t0}")
- elif is_const_void_ptr(array_type):
- l(f" {field_name}:array[{array_nums[0]}, pointer]")
- else:
- l(f"// FIXME: ??? array {field_name}:{field_type} => {array_type} [{array_nums[0]}]")
- elif is_2d_array_type(field_type):
- array_type = extract_array_type(field_type)
- array_nums = extract_array_nums(field_type)
- if is_prim_type(array_type):
- nim_type = as_nim_prim_type(array_type)
- def_val = type_default_value(array_type)
- elif is_struct_type(array_type):
- nim_type = as_nim_struct_type(array_type, prefix)
- def_val = ".{ }"
- else:
- nim_type = "???"
- def_val = "???"
- t0 = f"array[{array_nums[0]}, array[{array_nums[1]}, {nim_type}]]"
- l(f" {field_name}:{t0}")
+def as_nim_type(ctype, prefix, struct_ptr_as_value=False):
+ if ctype == "void":
+ return ""
+ elif is_prim_type(ctype):
+ return as_nim_prim_type(ctype)
+ elif is_struct_type(ctype):
+ return as_nim_type_name(ctype, prefix)
+ elif is_enum_type(ctype):
+ return as_nim_type_name(ctype, prefix)
+ elif util.is_string_ptr(ctype):
+ return "cstring"
+ elif util.is_void_ptr(ctype) or util.is_const_void_ptr(ctype):
+ return "pointer"
+ elif is_const_struct_ptr(ctype):
+ nim_type = as_nim_type(util.extract_ptr_type(ctype), prefix)
+ if struct_ptr_as_value:
+ return f"{nim_type}"
else:
- l(f"// FIXME: {field_name}:{field_type};")
+ return f"ptr {nim_type}"
+ elif is_prim_ptr(ctype) or is_const_prim_ptr(ctype):
+ return f"ptr {as_nim_type(util.extract_ptr_type(ctype), prefix)}"
+ elif util.is_func_ptr(ctype):
+ args = funcptr_args(ctype, prefix)
+ res = funcptr_result(ctype, prefix)
+ if res != "":
+ res = ":" + res
+ return f"proc({args}){res} {{.cdecl.}}"
+ elif util.is_1d_array_type(ctype):
+ array_ctype = util.extract_array_type(ctype)
+ array_sizes = util.extract_array_sizes(ctype)
+ return f'array[{array_sizes[0]}, {as_nim_type(array_ctype, prefix)}]'
+ elif util.is_2d_array_type(ctype):
+ array_ctype = util.extract_array_type(ctype)
+ array_sizes = util.extract_array_sizes(ctype)
+ return f'array[{array_sizes[0]}, array[{array_sizes[1]}, {as_nim_type(array_ctype, prefix)}]]'
+ else:
+ sys.exit(f"ERROR as_nim_type: {ctype}")
+
+def as_nim_struct_name(struct_decl, prefix):
+ struct_name = check_override(struct_decl['name'])
+ nim_type = f'{as_nim_type_name(struct_name, prefix)}'
+ return nim_type
+
+def as_nim_field_name(field_decl, prefix, check_private=True):
+ field_name = as_camel_case(check_override(field_decl['name']), prefix)
+ if check_private:
+ is_private = field_decl['name'].startswith('_')
+ if not is_private:
+ field_name += "*"
+ return field_name
+
+def as_nim_field_type(struct_decl, field_decl, prefix):
+ return as_nim_type(check_override(f"{struct_decl['name']}.{field_decl['name']}", default=field_decl['type']), prefix)
+
+def gen_struct(decl, prefix):
+ l(f"type {as_nim_struct_name(decl, prefix)}* = object")
+ for field in decl['fields']:
+ l(f" {as_nim_field_name(field, prefix)}:{as_nim_field_type(decl, field, prefix)}")
l("")
def gen_consts(decl, prefix):
l("const")
for item in decl['items']:
- l(f" {trim_prefix(item['name'], prefix)}* = {item['value']}")
+ item_name = check_override(item['name'])
+ l(f" {as_camel_case(item_name, prefix)}* = {item['value']}")
l("")
def gen_enum(decl, prefix):
item_names_by_value = {}
value = -1
- hasForceU32 = False
- hasExplicitValues = False
+ has_explicit_values = False
for item in decl['items']:
- itemName = item['name']
- if itemName.endswith("_FORCE_U32"):
- hasForceU32 = True
- elif itemName.endswith("_NUM"):
+ item_name = check_override(item['name'])
+ if item_name.endswith("_NUM") or item_name.endswith("_FORCE_U32"):
continue
else:
if 'value' in item:
- hasExplicitValues = True
+ has_explicit_values = True
value = int(item['value'])
else:
value += 1
- item_names_by_value[value] = as_enum_item_name(item['name']);
- if hasForceU32:
- l(f"type {as_nim_enum_type(decl['name'], prefix)}* {{.pure, size:4.}} = enum")
- else:
- l(f"type {as_nim_enum_type(decl['name'], prefix)}* {{.pure.}} = enum")
- if hasExplicitValues:
+ item_names_by_value[value] = as_enum_item_name(item_name)
+ enum_name_nim = as_nim_type_name(decl['name'], prefix)
+ l('type')
+ l(f" {enum_name_nim}* {{.size:sizeof(int32).}} = enum")
+ if has_explicit_values:
# Nim requires explicit enum values to be declared in ascending order
for value in sorted(item_names_by_value):
name = item_names_by_value[value]
- l(f" {name} = {value},")
+ l(f" {name} = {value},")
else:
for name in item_names_by_value.values():
- l(f" {name},")
+ l(f" {name},")
l("")
+# returns C prototype compatible function args (with pointers)
+def funcdecl_args_c(decl, prefix):
+ s = ""
+ func_name = decl['name']
+ for param_decl in decl['params']:
+ if s != "":
+ s += ", "
+ arg_name = param_decl['name']
+ arg_type = check_override(f'{func_name}.{arg_name}', default=param_decl['type'])
+ s += f"{as_camel_case(arg_name, prefix)}:{as_nim_type(arg_type, prefix)}"
+ return s
+
+# returns Nim function args (pass structs by value)
+def funcdecl_args_nim(decl, prefix):
+ s = ""
+ func_name = decl['name']
+ for param_decl in decl['params']:
+ if s != "":
+ s += ", "
+ arg_name = param_decl['name']
+ arg_type = check_override(f'{func_name}.{arg_name}', default=param_decl['type'])
+ s += f"{as_camel_case(arg_name, prefix)}:{as_nim_type(arg_type, prefix, struct_ptr_as_value=True)}"
+ return s
+
+def funcdecl_result(decl, prefix):
+ func_name = decl['name']
+ decl_type = decl['type']
+ result_type = check_override(f'{func_name}.RESULT', default=decl_type[:decl_type.index('(')].strip())
+ nim_res_type = as_nim_type(result_type, prefix)
+ if nim_res_type == "":
+ nim_res_type = "void"
+ return nim_res_type
+
def gen_func_nim(decl, prefix):
c_func_name = decl['name']
- nim_func_name = as_camel_case(decl['name'], prefix)
- nim_res_type = funcdecl_res_nim(decl, prefix)
- l(f"proc {nim_func_name}*({funcdecl_args_nim(decl, prefix)}):{funcdecl_res_nim(decl, prefix)} {{.cdecl, importc:\"{decl['name']}\".}}")
+ nim_func_name = as_camel_case(check_override(c_func_name), prefix, wrap=False)
+ nim_res_type = funcdecl_result(decl, prefix)
+ if c_func_name in c_callbacks:
+ l(f"proc {nim_func_name}*({funcdecl_args_c(decl, prefix)}):{nim_res_type} {{.cdecl, importc:\"{c_func_name}\".}}")
+ else:
+ l(f"proc c_{nim_func_name}({funcdecl_args_c(decl, prefix)}):{nim_res_type} {{.cdecl, importc:\"{c_func_name}\".}}")
+ l(f"proc {wrap_keywords(nim_func_name)}*({funcdecl_args_nim(decl, prefix)}):{nim_res_type} =")
+ s = f" c_{nim_func_name}("
+ for i, param_decl in enumerate(decl['params']):
+ if i > 0:
+ s += ", "
+ arg_name = param_decl['name']
+ arg_type = param_decl['type']
+ if is_const_struct_ptr(arg_type):
+ s += f"unsafeAddr({arg_name})"
+ else:
+ s += arg_name
+ s += ")"
+ l(s)
l("")
+def gen_array_converters(decl, prefix):
+ for field in decl['fields']:
+ if util.is_array_type(field['type']):
+ array_type = util.extract_array_type(field['type'])
+ array_sizes = util.extract_array_sizes(field['type'])
+ struct_name = as_nim_struct_name(decl, prefix)
+ field_name = as_nim_field_name(field, prefix, check_private=False)
+ array_base_type = as_nim_type(array_type, prefix)
+ if util.is_1d_array_type(field['type']):
+ n = array_sizes[0]
+ l(f'converter to{struct_name}{field_name}*[N:static[int]](items: array[N, {array_base_type}]): array[{n}, {array_base_type}] =')
+ l(f' static: assert(N < {n})')
+ l(f' for index,item in items.pairs: result[index]=item')
+ l('')
+ elif util.is_2d_array_type(field['type']):
+ x = array_sizes[1]
+ y = array_sizes[0]
+ l(f'converter to{struct_name}{field_name}*[Y:static[int], X:static[int]](items: array[Y, array[X, {array_base_type}]]): array[{y}, array[{x}, {array_base_type}]] =')
+ l(f' static: assert(X < {x})')
+ l(f' static: assert(Y < {y})')
+ l(f' for indexY,itemY in items.pairs:')
+ l(f' for indexX, itemX in itemY.pairs:')
+ l(f' result[indexY][indexX] = itemX')
+ l('')
+ else:
+ sys.exit('Unsupported converter array dimension (> 2)!')
+
def pre_parse(inp):
global struct_types
global enum_types
@@ -497,15 +479,92 @@ def pre_parse(inp):
elif kind == 'enum':
enum_name = decl['name']
enum_types.append(enum_name)
- enum_items[enum_name] = []
- for item in decl['items']:
- enum_items[enum_name].append(as_enum_item_name(item['name']))
def gen_imports(inp, dep_prefixes):
for dep_prefix in dep_prefixes:
dep_module_name = module_names[dep_prefix]
l(f'import {dep_module_name}')
+ l('')
+
+def gen_extra(inp):
+ if inp['prefix'] in ['sg_']:
+ # FIXME: remove when sokol-shdc has been integrated!
+ l('when defined gl:')
+ l(' const gl* = true')
+ l(' const d3d11* = false')
+ l(' const metal* = false')
+ l('elif defined windows:')
+ l(' const gl* = false')
+ l(' const d3d11* = true')
+ l(' const metal* = false')
+ l('elif defined macosx:')
+ l(' const gl* = false')
+ l(' const d3d11* = false')
+ l(' const metal* = true')
+ l('elif defined linux:')
+ l(' const gl* = true')
+ l(' const d3d11* = false')
+ l(' const metal* = false')
+ l('else:')
+ l(' error("unsupported platform")')
l('')
+ if inp['prefix'] in ['sg_', 'sapp_']:
+ l('when defined windows:')
+ l(' when not defined vcc:')
+ l(' {.passl:"-lkernel32 -luser32 -lshell32 -lgdi32".}')
+ l(' when defined gl:')
+ l(' {.passc:"-DSOKOL_GLCORE33".}')
+ l(' else:')
+ l(' {.passc:"-DSOKOL_D3D11".}')
+ l(' when not defined vcc:')
+ l(' {.passl:"-ld3d11 -ldxgi".}')
+ l('elif defined macosx:')
+ l(' {.passc:"-x objective-c".}')
+ l(' {.passl:"-framework Cocoa -framework QuartzCore".}')
+ l(' when defined gl:')
+ l(' {.passc:"-DSOKOL_GLCORE33".}')
+ l(' {.passl:"-framework OpenGL".}')
+ l(' else:')
+ l(' {.passc:"-DSOKOL_METAL".}')
+ l(' {.passl:"-framework Metal -framework MetalKit".}')
+ l('elif defined linux:')
+ l(' {.passc:"-DSOKOL_GLCORE33".}')
+ l(' {.passl:"-lX11 -lXi -lXcursor -lGL -lm -ldl -lpthread".}')
+ l('else:')
+ l(' error("unsupported platform")')
+ l('')
+ if inp['prefix'] in ['saudio_']:
+ l('when defined windows:')
+ l(' when not defined vcc:')
+ l(' {.passl:"-lkernel32 -lole32".}')
+ l('elif defined macosx:')
+ l(' {.passl:"-framework AudioToolbox".}')
+ l('elif defined linux:')
+ l(' {.passl:"-lasound -lm -lpthread".}')
+ l('else:')
+ l(' error("unsupported platform")')
+ l('')
+ if inp['prefix'] in ['sg_']:
+ l('## Convert a 4-element tuple of numbers to a gfx.Color')
+ l('converter toColor*[R:SomeNumber,G:SomeNumber,B:SomeNumber,A:SomeNumber](rgba: tuple [r:R,g:G,b:B,a:A]):Color =')
+ l(' Color(r:rgba.r.float32, g:rgba.g.float32, b:rgba.b.float32, a:rgba.a.float32)')
+ l('')
+ l('## Convert a 3-element tuple of numbers to a gfx.Color')
+ l('converter toColor*[R:SomeNumber,G:SomeNumber,B:SomeNumber](rgba: tuple [r:R,g:G,b:B]):Color =')
+ l(' Color(r:rgba.r.float32, g:rgba.g.float32, b:rgba.b.float32, a:1.float32)')
+ l('')
+ # NOTE: this simplistic to_Range() converter has various issues, some of them dangerous:
+ # - doesn't work as expected for slice types
+ # - it's very easy to create a range that points to invalid memory
+ # (so far observed for stack-allocated structs <= 16 bytes)
+ #if inp['prefix'] in ['sg_', 'sdtx_', 'sshape_']:
+ # l('# helper function to convert "anything" into a Range')
+ # l('converter to_Range*[T](source: T): Range =')
+ # l(' Range(addr: source.unsafeAddr, size: source.sizeof.uint)')
+ # l('')
+ c_source_path = '/'.join(c_source_paths[inp['prefix']].split('/')[3:])
+ l('{.passc:"-DSOKOL_NIM_IMPL".}')
+ l(f'{{.compile:"{c_source_path}".}}')
def gen_module(inp, dep_prefixes):
l('## machine generated, do not edit')
@@ -518,22 +577,27 @@ def gen_module(inp, dep_prefixes):
kind = decl['kind']
if kind == 'consts':
gen_consts(decl, prefix)
- elif kind == 'enum':
- gen_enum(decl, prefix)
- elif kind == 'struct':
- gen_struct(decl, prefix)
- elif kind == 'func':
- if not check_func_name_ignore(decl['name']):
+ elif not check_ignore(decl['name']):
+ if kind == 'struct':
+ gen_struct(decl, prefix)
+ gen_array_converters(decl, prefix)
+ elif kind == 'enum':
+ gen_enum(decl, prefix)
+ elif kind == 'func':
gen_func_nim(decl, prefix)
+ gen_extra(inp)
def prepare():
- print('Generating nim bindings:')
+ print('=== Generating Nim bindings:')
if not os.path.isdir('sokol-nim/src/sokol'):
os.makedirs('sokol-nim/src/sokol')
if not os.path.isdir('sokol-nim/src/sokol/c'):
os.makedirs('sokol-nim/src/sokol/c')
def gen(c_header_path, c_prefix, dep_c_prefixes):
+ if not c_prefix in module_names:
+ print(f' >> warning: skipping generation for {c_prefix} prefix...')
+ return
global out_lines
module_name = module_names[c_prefix]
c_source_path = c_source_paths[c_prefix]
@@ -543,20 +607,5 @@ def gen(c_header_path, c_prefix, dep_c_prefixes):
ir = gen_ir.gen(c_header_path, c_source_path, module_name, c_prefix, dep_c_prefixes)
gen_module(ir, dep_c_prefixes)
output_path = f"sokol-nim/src/sokol/{ir['module']}.nim"
-
- ## some changes for readability
- out_lines = out_lines.replace("PixelformatInfo", "PixelFormatInfo")
- out_lines = out_lines.replace(" Dontcare,", " DontCare,")
- out_lines = out_lines.replace(" Vertexbuffer,", " VertexBuffer,")
- out_lines = out_lines.replace(" Indexbuffer,", " IndexBuffer,")
- out_lines = out_lines.replace(" N2d,", " Plane,")
- out_lines = out_lines.replace(" N3d,", " Volume,")
- out_lines = out_lines.replace(" Vs,", " Vertex,")
- out_lines = out_lines.replace(" Fs,", " Fragment,")
-
- ## include extensions in generated code
- l("# Nim-specific API extensions")
- l(f"include nim/{ir['module']}")
-
with open(output_path, 'w', newline='\n') as f_outp:
f_outp.write(out_lines)
diff --git a/3rdparty/sokol/bindgen/gen_zig.py b/3rdparty/sokol/bindgen/gen_zig.py
index 00d1f6b..a8768ca 100644
--- a/3rdparty/sokol/bindgen/gen_zig.py
+++ b/3rdparty/sokol/bindgen/gen_zig.py
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Read output of gen_json.py and generate Zig language bindings.
+# Generate Zig bindings.
#
# Zig coding style:
# - types are PascalCase
@@ -7,9 +7,12 @@
# - otherwise snake_case
#-------------------------------------------------------------------------------
import gen_ir
-import json, re, os, shutil
+import os, shutil, sys
+
+import gen_util as util
module_names = {
+ 'slog_': 'log',
'sg_': 'gfx',
'sapp_': 'app',
'stm_': 'time',
@@ -20,6 +23,7 @@ module_names = {
}
c_source_paths = {
+ 'slog_': 'sokol-zig/src/sokol/c/sokol_log.c',
'sg_': 'sokol-zig/src/sokol/c/sokol_gfx.c',
'sapp_': 'sokol-zig/src/sokol/c/sokol_app.c',
'stm_': 'sokol-zig/src/sokol/c/sokol_time.c',
@@ -29,21 +33,23 @@ c_source_paths = {
'sshape_': 'sokol-zig/src/sokol/c/sokol_shape.c',
}
-name_ignores = [
+ignores = [
'sdtx_printf',
'sdtx_vprintf',
'sg_install_trace_hooks',
'sg_trace_hooks',
]
-name_overrides = {
- 'sgl_error': 'sgl_get_error', # 'error' is reserved in Zig
- 'sgl_deg': 'sgl_as_degrees',
- 'sgl_rad': 'sgl_as_radians'
-}
+# functions that need to be exposed as 'raw' C callbacks without a Zig wrapper function
+c_callbacks = [
+ 'slog_func'
+]
# NOTE: syntax for function results: "func_name.RESULT"
-type_overrides = {
+overrides = {
+ 'sgl_error': 'sgl_get_error', # 'error' is reserved in Zig
+ 'sgl_deg': 'sgl_as_degrees',
+ 'sgl_rad': 'sgl_as_radians',
'sg_context_desc.color_format': 'int',
'sg_context_desc.depth_format': 'int',
'sg_apply_uniforms.ub_index': 'uint32_t',
@@ -53,6 +59,7 @@ type_overrides = {
'sshape_element_range_t.base_element': 'uint32_t',
'sshape_element_range_t.num_elements': 'uint32_t',
'sdtx_font.font_index': 'uint32_t',
+ 'SGL_NO_ERROR': 'SGL_ERROR_NO_ERROR',
}
prim_types = {
@@ -92,6 +99,7 @@ prim_defaults = {
'size_t': '0'
}
+
struct_types = []
enum_types = []
enum_items = {}
@@ -107,9 +115,6 @@ def reset_globals():
enum_items = {}
out_lines = ''
-re_1d_array = re.compile("^(?:const )?\w*\s\*?\[\d*\]$")
-re_2d_array = re.compile("^(?:const )?\w*\s\*?\[\d*\]\[\d*\]$")
-
def l(s):
global out_lines
out_lines += s + '\n'
@@ -122,6 +127,7 @@ def as_zig_struct_type(s, prefix):
parts = s.lower().split('_')
outp = '' if s.startswith(prefix) else f'{parts[0]}.'
for part in parts[1:]:
+ # ignore '_t' type postfix
if (part != 't'):
outp += part.capitalize()
return outp
@@ -135,42 +141,20 @@ def as_zig_enum_type(s, prefix):
outp += part.capitalize()
return outp
-def check_type_override(func_or_struct_name, field_or_arg_name, orig_type):
- s = f"{func_or_struct_name}.{field_or_arg_name}"
- if s in type_overrides:
- return type_overrides[s]
- else:
- return orig_type
-
-def check_name_override(name):
- if name in name_overrides:
- return name_overrides[name]
- else:
+def check_override(name, default=None):
+ if name in overrides:
+ return overrides[name]
+ elif default is None:
return name
+ else:
+ return default
-def check_name_ignore(name):
- return name in name_ignores
-
-# PREFIX_BLA_BLUB to bla_blub
-def as_snake_case(s, prefix):
- outp = s.lower()
- if outp.startswith(prefix):
- outp = outp[len(prefix):]
- return outp
-
-# prefix_bla_blub => blaBlub
-def as_camel_case(s):
- parts = s.lower().split('_')[1:]
- outp = parts[0]
- for part in parts[1:]:
- outp += part.capitalize()
- return outp
+def check_ignore(name):
+ return name in ignores
# PREFIX_ENUM_BLA => Bla, _PREFIX_ENUM_BLA => Bla
def as_enum_item_name(s):
- outp = s
- if outp.startswith('_'):
- outp = outp[1:]
+ outp = s.lstrip('_')
parts = outp.split('_')[2:]
outp = '_'.join(parts)
if outp[0].isdigit():
@@ -189,15 +173,6 @@ def is_struct_type(s):
def is_enum_type(s):
return s in enum_types
-def is_string_ptr(s):
- return s == "const char *"
-
-def is_const_void_ptr(s):
- return s == "const void *"
-
-def is_void_ptr(s):
- return s == "void *"
-
def is_const_prim_ptr(s):
for prim_type in prim_types:
if s == f"const {prim_type} *":
@@ -216,32 +191,10 @@ def is_const_struct_ptr(s):
return True
return False
-def is_func_ptr(s):
- return '(*)' in s
-
-def is_1d_array_type(s):
- return re_1d_array.match(s)
-
-def is_2d_array_type(s):
- return re_2d_array.match(s)
-
def type_default_value(s):
return prim_defaults[s]
-def extract_array_type(s):
- return s[:s.index('[')].strip()
-
-def extract_array_nums(s):
- return s[s.index('['):].replace('[', ' ').replace(']', ' ').split()
-
-def extract_ptr_type(s):
- tokens = s.split()
- if tokens[0] == 'const':
- return tokens[1]
- else:
- return tokens[0]
-
-def as_extern_c_arg_type(arg_type, prefix):
+def as_c_arg_type(arg_type, prefix):
if arg_type == "void":
return "void"
elif is_prim_type(arg_type):
@@ -250,20 +203,20 @@ def as_extern_c_arg_type(arg_type, prefix):
return as_zig_struct_type(arg_type, prefix)
elif is_enum_type(arg_type):
return as_zig_enum_type(arg_type, prefix)
- elif is_void_ptr(arg_type):
- return "?*c_void"
- elif is_const_void_ptr(arg_type):
- return "?*const c_void"
- elif is_string_ptr(arg_type):
+ elif util.is_void_ptr(arg_type):
+ return "?*anyopaque"
+ elif util.is_const_void_ptr(arg_type):
+ return "?*const anyopaque"
+ elif util.is_string_ptr(arg_type):
return "[*c]const u8"
elif is_const_struct_ptr(arg_type):
- return f"[*c]const {as_zig_struct_type(extract_ptr_type(arg_type), prefix)}"
+ return f"[*c]const {as_zig_struct_type(util.extract_ptr_type(arg_type), prefix)}"
elif is_prim_ptr(arg_type):
- return f"[*c] {as_zig_prim_type(extract_ptr_type(arg_type))}"
+ return f"[*c] {as_zig_prim_type(util.extract_ptr_type(arg_type))}"
elif is_const_prim_ptr(arg_type):
- return f"[*c]const {as_zig_prim_type(extract_ptr_type(arg_type))}"
+ return f"[*c]const {as_zig_prim_type(util.extract_ptr_type(arg_type))}"
else:
- return '??? (as_extern_c_arg_type)'
+ sys.exit(f"Error as_c_arg_type(): {arg_type}")
def as_zig_arg_type(arg_prefix, arg_type, prefix):
# NOTE: if arg_prefix is None, the result is used as return value
@@ -279,21 +232,24 @@ def as_zig_arg_type(arg_prefix, arg_type, prefix):
return pre + as_zig_struct_type(arg_type, prefix)
elif is_enum_type(arg_type):
return pre + as_zig_enum_type(arg_type, prefix)
- elif is_void_ptr(arg_type):
- return pre + "?*c_void"
- elif is_const_void_ptr(arg_type):
- return pre + "?*const c_void"
- elif is_string_ptr(arg_type):
+ elif util.is_void_ptr(arg_type):
+ return pre + "?*anyopaque"
+ elif util.is_const_void_ptr(arg_type):
+ return pre + "?*const anyopaque"
+ elif util.is_string_ptr(arg_type):
return pre + "[:0]const u8"
elif is_const_struct_ptr(arg_type):
# not a bug, pass const structs by value
- return pre + f"{as_zig_struct_type(extract_ptr_type(arg_type), prefix)}"
+ return pre + f"{as_zig_struct_type(util.extract_ptr_type(arg_type), prefix)}"
elif is_prim_ptr(arg_type):
- return pre + f"* {as_zig_prim_type(extract_ptr_type(arg_type))}"
+ return pre + f"* {as_zig_prim_type(util.extract_ptr_type(arg_type))}"
elif is_const_prim_ptr(arg_type):
- return pre + f"*const {as_zig_prim_type(extract_ptr_type(arg_type))}"
+ return pre + f"*const {as_zig_prim_type(util.extract_ptr_type(arg_type))}"
else:
- return arg_prefix + "??? (as_zig_arg_type)"
+ sys.exit(f"ERROR as_zig_arg_type(): {arg_type}")
+
+def is_zig_string(zig_type):
+ return zig_type == "[:0]const u8"
# get C-style arguments of a function pointer as string
def funcptr_args_c(field_type, prefix):
@@ -303,22 +259,24 @@ def funcptr_args_c(field_type, prefix):
arg_type = token.strip()
if s != "":
s += ", "
- c_arg = as_extern_c_arg_type(arg_type, prefix)
- if (c_arg == "void"):
+ c_arg = as_c_arg_type(arg_type, prefix)
+ if c_arg == "void":
return ""
else:
s += c_arg
return s
# get C-style result of a function pointer as string
-def funcptr_res_c(field_type):
+def funcptr_result_c(field_type):
res_type = field_type[:field_type.index('(*)')].strip()
if res_type == 'void':
return 'void'
- elif is_const_void_ptr(res_type):
- return '?*const c_void'
+ elif util.is_const_void_ptr(res_type):
+ return '?*const anyopaque'
+ elif util.is_void_ptr(res_type):
+ return '?*anyopaque'
else:
- return '???'
+ sys.exit(f"ERROR funcptr_result_c(): {field_type}")
def funcdecl_args_c(decl, prefix):
s = ""
@@ -327,8 +285,8 @@ def funcdecl_args_c(decl, prefix):
if s != "":
s += ", "
param_name = param_decl['name']
- param_type = check_type_override(func_name, param_name, param_decl['type'])
- s += as_extern_c_arg_type(param_type, prefix)
+ param_type = check_override(f'{func_name}.{param_name}', default=param_decl['type'])
+ s += as_c_arg_type(param_type, prefix)
return s
def funcdecl_args_zig(decl, prefix):
@@ -338,55 +296,49 @@ def funcdecl_args_zig(decl, prefix):
if s != "":
s += ", "
param_name = param_decl['name']
- param_type = check_type_override(func_name, param_name, param_decl['type'])
+ param_type = check_override(f'{func_name}.{param_name}', default=param_decl['type'])
s += f"{as_zig_arg_type(f'{param_name}: ', param_type, prefix)}"
return s
def funcdecl_result_c(decl, prefix):
func_name = decl['name']
decl_type = decl['type']
- result_type = check_type_override(func_name, 'RESULT', decl_type[:decl_type.index('(')].strip())
- return as_extern_c_arg_type(result_type, prefix)
+ result_type = check_override(f'{func_name}.RESULT', default=decl_type[:decl_type.index('(')].strip())
+ return as_c_arg_type(result_type, prefix)
def funcdecl_result_zig(decl, prefix):
func_name = decl['name']
decl_type = decl['type']
- result_type = check_type_override(func_name, 'RESULT', decl_type[:decl_type.index('(')].strip())
+ result_type = check_override(f'{func_name}.RESULT', default=decl_type[:decl_type.index('(')].strip())
zig_res_type = as_zig_arg_type(None, result_type, prefix)
- if zig_res_type == "":
- zig_res_type = "void"
return zig_res_type
-def gen_struct(decl, prefix, callconvc_funcptrs = True, use_raw_name=False, use_extern=True):
- struct_name = decl['name']
- zig_type = struct_name if use_raw_name else as_zig_struct_type(struct_name, prefix)
- l(f"pub const {zig_type} = {'extern ' if use_extern else ''}struct {{")
+def gen_struct(decl, prefix):
+ struct_name = check_override(decl['name'])
+ zig_type = as_zig_struct_type(struct_name, prefix)
+ l(f"pub const {zig_type} = extern struct {{")
for field in decl['fields']:
- field_name = field['name']
- field_type = field['type']
- field_type = check_type_override(struct_name, field_name, field_type)
+ field_name = check_override(field['name'])
+ field_type = check_override(f'{struct_name}.{field_name}', default=field['type'])
if is_prim_type(field_type):
l(f" {field_name}: {as_zig_prim_type(field_type)} = {type_default_value(field_type)},")
elif is_struct_type(field_type):
l(f" {field_name}: {as_zig_struct_type(field_type, prefix)} = .{{ }},")
elif is_enum_type(field_type):
l(f" {field_name}: {as_zig_enum_type(field_type, prefix)} = .{enum_default_item(field_type)},")
- elif is_string_ptr(field_type):
+ elif util.is_string_ptr(field_type):
l(f" {field_name}: [*c]const u8 = null,")
- elif is_const_void_ptr(field_type):
- l(f" {field_name}: ?*const c_void = null,")
- elif is_void_ptr(field_type):
- l(f" {field_name}: ?*c_void = null,")
+ elif util.is_const_void_ptr(field_type):
+ l(f" {field_name}: ?*const anyopaque = null,")
+ elif util.is_void_ptr(field_type):
+ l(f" {field_name}: ?*anyopaque = null,")
elif is_const_prim_ptr(field_type):
- l(f" {field_name}: ?[*]const {as_zig_prim_type(extract_ptr_type(field_type))} = null,")
- elif is_func_ptr(field_type):
- if callconvc_funcptrs:
- l(f" {field_name}: ?fn({funcptr_args_c(field_type, prefix)}) callconv(.C) {funcptr_res_c(field_type)} = null,")
- else:
- l(f" {field_name}: ?fn({funcptr_args_c(field_type, prefix)}) {funcptr_res_c(field_type)} = null,")
- elif is_1d_array_type(field_type):
- array_type = extract_array_type(field_type)
- array_nums = extract_array_nums(field_type)
+ l(f" {field_name}: ?[*]const {as_zig_prim_type(util.extract_ptr_type(field_type))} = null,")
+ elif util.is_func_ptr(field_type):
+ l(f" {field_name}: ?*const fn({funcptr_args_c(field_type, prefix)}) callconv(.C) {funcptr_result_c(field_type)} = null,")
+ elif util.is_1d_array_type(field_type):
+ array_type = util.extract_array_type(field_type)
+ array_sizes = util.extract_array_sizes(field_type)
if is_prim_type(array_type) or is_struct_type(array_type):
if is_prim_type(array_type):
zig_type = as_zig_prim_type(array_type)
@@ -398,19 +350,17 @@ def gen_struct(decl, prefix, callconvc_funcptrs = True, use_raw_name=False, use_
zig_type = as_zig_enum_type(array_type, prefix)
def_val = '.{}'
else:
- zig_type = '??? (array type)'
- def_val = '???'
- t0 = f"[{array_nums[0]}]{zig_type}"
- t0_slice = f"[]const {zig_type}"
+ sys.exit(f"ERROR gen_struct is_1d_array_type: {array_type}")
+ t0 = f"[{array_sizes[0]}]{zig_type}"
t1 = f"[_]{zig_type}"
- l(f" {field_name}: {t0} = {t1}{{{def_val}}} ** {array_nums[0]},")
- elif is_const_void_ptr(array_type):
- l(f" {field_name}: [{array_nums[0]}]?*const c_void = [_]?*const c_void {{ null }} ** {array_nums[0]},")
+ l(f" {field_name}: {t0} = {t1}{{{def_val}}} ** {array_sizes[0]},")
+ elif util.is_const_void_ptr(array_type):
+ l(f" {field_name}: [{array_sizes[0]}]?*const anyopaque = [_]?*const anyopaque {{ null }} ** {array_sizes[0]},")
else:
- l(f"// FIXME: ??? array {field_name}: {field_type} => {array_type} [{array_nums[0]}]")
- elif is_2d_array_type(field_type):
- array_type = extract_array_type(field_type)
- array_nums = extract_array_nums(field_type)
+ sys.exit(f"ERROR gen_struct: array {field_name}: {field_type} => {array_type} [{array_sizes[0]}]")
+ elif util.is_2d_array_type(field_type):
+ array_type = util.extract_array_type(field_type)
+ array_sizes = util.extract_array_sizes(field_type)
if is_prim_type(array_type):
zig_type = as_zig_prim_type(array_type)
def_val = type_default_value(array_type)
@@ -418,22 +368,23 @@ def gen_struct(decl, prefix, callconvc_funcptrs = True, use_raw_name=False, use_
zig_type = as_zig_struct_type(array_type, prefix)
def_val = ".{ }"
else:
- zig_type = "???"
- def_val = "???"
- t0 = f"[{array_nums[0]}][{array_nums[1]}]{zig_type}"
- l(f" {field_name}: {t0} = [_][{array_nums[1]}]{zig_type}{{[_]{zig_type}{{ {def_val} }}**{array_nums[1]}}}**{array_nums[0]},")
+ sys.exit(f"ERROR gen_struct is_2d_array_type: {array_type}")
+ t0 = f"[{array_sizes[0]}][{array_sizes[1]}]{zig_type}"
+ l(f" {field_name}: {t0} = [_][{array_sizes[1]}]{zig_type}{{[_]{zig_type}{{ {def_val} }}**{array_sizes[1]}}}**{array_sizes[0]},")
else:
- l(f"// FIXME: {field_name}: {field_type};")
+ sys.exit(f"ERROR gen_struct: {field_name}: {field_type};")
l("};")
def gen_consts(decl, prefix):
for item in decl['items']:
- l(f"pub const {as_snake_case(item['name'], prefix)} = {item['value']};")
+ item_name = check_override(item['name'])
+ l(f"pub const {util.as_lower_snake_case(item_name, prefix)} = {item['value']};")
def gen_enum(decl, prefix):
- l(f"pub const {as_zig_enum_type(decl['name'], prefix)} = enum(i32) {{")
+ enum_name = check_override(decl['name'])
+ l(f"pub const {as_zig_enum_type(enum_name, prefix)} = enum(i32) {{")
for item in decl['items']:
- item_name = as_enum_item_name(item['name'])
+ item_name = as_enum_item_name(check_override(item['name']))
if item_name != "FORCE_U32":
if 'value' in item:
l(f" {item_name} = {item['value']},")
@@ -446,27 +397,36 @@ def gen_func_c(decl, prefix):
def gen_func_zig(decl, prefix):
c_func_name = decl['name']
- zig_func_name = as_camel_case(check_name_override(decl['name']))
- zig_res_type = funcdecl_result_zig(decl, prefix)
- l(f"pub fn {zig_func_name}({funcdecl_args_zig(decl, prefix)}) {zig_res_type} {{")
- if zig_res_type != 'void':
- s = f" return {c_func_name}("
+ zig_func_name = util.as_lower_camel_case(check_override(decl['name']), prefix)
+ if c_func_name in c_callbacks:
+ # a simple forwarded C callback function
+ l(f"pub const {zig_func_name} = {c_func_name};")
else:
- s = f" {c_func_name}("
- for i, param_decl in enumerate(decl['params']):
- if i > 0:
- s += ", "
- arg_name = param_decl['name']
- arg_type = param_decl['type']
- if is_const_struct_ptr(arg_type):
- s += f"&{arg_name}"
- elif is_string_ptr(arg_type):
- s += f"@ptrCast([*c]const u8,{arg_name})"
+ zig_res_type = funcdecl_result_zig(decl, prefix)
+ l(f"pub fn {zig_func_name}({funcdecl_args_zig(decl, prefix)}) {zig_res_type} {{")
+ if is_zig_string(zig_res_type):
+ # special case: convert C string to Zig string slice
+ s = f" return cStrToZig({c_func_name}("
+ elif zig_res_type != 'void':
+ s = f" return {c_func_name}("
else:
- s += arg_name
- s += ");"
- l(s)
- l("}")
+ s = f" {c_func_name}("
+ for i, param_decl in enumerate(decl['params']):
+ if i > 0:
+ s += ", "
+ arg_name = param_decl['name']
+ arg_type = param_decl['type']
+ if is_const_struct_ptr(arg_type):
+ s += f"&{arg_name}"
+ elif util.is_string_ptr(arg_type):
+ s += f"@ptrCast([*c]const u8,{arg_name})"
+ else:
+ s += arg_name
+ if is_zig_string(zig_res_type):
+ s += ")"
+ s += ");"
+ l(s)
+ l("}")
def pre_parse(inp):
global struct_types
@@ -483,12 +443,17 @@ def pre_parse(inp):
enum_items[enum_name].append(as_enum_item_name(item['name']))
def gen_imports(inp, dep_prefixes):
+ l('const builtin = @import("builtin");')
for dep_prefix in dep_prefixes:
dep_module_name = module_names[dep_prefix]
l(f'const {dep_prefix[:-1]} = @import("{dep_module_name}.zig");')
- l('')
+ l('')
def gen_helpers(inp):
+ l('// helper function to convert a C string to a Zig string slice')
+ l('fn cStrToZig(c_str: [*c]const u8) [:0]const u8 {')
+ l(' return @import("std").mem.span(c_str);')
+ l('}')
if inp['prefix'] in ['sg_', 'sdtx_', 'sshape_']:
l('// helper function to convert "anything" to a Range struct')
l('pub fn asRange(val: anytype) Range {')
@@ -502,7 +467,7 @@ def gen_helpers(inp):
l(' }')
l(' },')
l(' .Struct, .Array => {')
- l(' return .{ .ptr = &val, .size = @sizeOf(@TypeOf(val)) };')
+ l(' @compileError("Structs and arrays must be passed as pointers to asRange");')
l(' },')
l(' else => {')
l(' @compileError("Cannot convert to range!");')
@@ -547,7 +512,7 @@ def gen_module(inp, dep_prefixes):
kind = decl['kind']
if kind == 'consts':
gen_consts(decl, prefix)
- elif not check_name_ignore(decl['name']):
+ elif not check_ignore(decl['name']):
if kind == 'struct':
gen_struct(decl, prefix)
elif kind == 'enum':
@@ -557,13 +522,16 @@ def gen_module(inp, dep_prefixes):
gen_func_zig(decl, prefix)
def prepare():
- print('Generating zig bindings:')
+ print('=== Generating Zig bindings:')
if not os.path.isdir('sokol-zig/src/sokol'):
os.makedirs('sokol-zig/src/sokol')
if not os.path.isdir('sokol-zig/src/sokol/c'):
os.makedirs('sokol-zig/src/sokol/c')
def gen(c_header_path, c_prefix, dep_c_prefixes):
+ if not c_prefix in module_names:
+ print(f' >> warning: skipping generation for {c_prefix} prefix...')
+ return
module_name = module_names[c_prefix]
c_source_path = c_source_paths[c_prefix]
print(f' {c_header_path} => {module_name}')
diff --git a/src/main.cc b/src/main.cc
index 3a069e4..a3f753e 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -9,6 +9,7 @@
#define SOKOL_IMPL
#define SOKOL_GLCORE33
#include "sokol_gfx.h"
+#include "sokol_log.h"
#include "sokol_time.h"
#define SOKOL_GL_IMPL
#include "util/sokol_gl.h"
@@ -28,6 +29,7 @@ const int MaxVertices = (1 << 16);
const int MaxIndices = MaxVertices * 3;
uint64_t last_time = 0;
+const int cMSAASampleCount = 8;
sg_pass_action pass_action;
sg_pipeline pip;
@@ -42,7 +44,6 @@ static void draw_imgui(ImDrawData*);
#define HANDMADE_MATH_IMPLEMENTATION
#define HANDMADE_MATH_NO_SSE
#include "HandmadeMath.h"
-#include "camera.h"
// ozz-animation headers
#include // fmodf
@@ -77,7 +78,7 @@ static struct {
struct {
double frame;
double anim_update_time;
- float absolute;
+ double absolute;
uint64_t laptime;
float factor;
float anim_ratio;
@@ -107,6 +108,7 @@ struct Viewport {
sg_pass_action pass_action = {};
sg_pass pass = {};
sg_pipeline pip = {};
+ sgl_pipeline glpip = {};
sg_bindings bind = {};
sg_image color_image = {};
sg_image depth_image = {};
@@ -138,7 +140,7 @@ struct Viewport {
.width = this->size[0],
.height = this->size[1],
.pixel_format = SG_PIXELFORMAT_RGBA8,
- .sample_count = 4,
+ .sample_count = cMSAASampleCount,
.min_filter = SG_FILTER_LINEAR,
.mag_filter = SG_FILTER_LINEAR,
.wrap_u = SG_WRAP_REPEAT,
@@ -155,6 +157,14 @@ struct Viewport {
offscreen_pass_desc.label = "offscreen-pass";
this->pass = sg_make_pass(&offscreen_pass_desc);
+
+ sg_pipeline_desc gl_pipeline_desc = {
+ .depth = {
+ .compare = SG_COMPAREFUNC_LESS_EQUAL,
+ .write_enabled = true
+ },
+ .cull_mode = SG_CULLMODE_BACK
+ };
}
};
@@ -350,11 +360,8 @@ ApplicationConfig gApplicationConfig;
static uint8_t skel_data_buffer[4 * 1024];
static uint8_t anim_data_buffer[32 * 1024];
-static void draw_grid(void);
-static void draw_ui(void);
-// static void skeleton_data_loaded(const sfetch_response_t* response);
-// static void animation_data_loaded(const sfetch_response_t* response);
-static void frame(void);
+static void draw_grid();
+static void frame();
void handle_mouse(GLFWwindow* w, GuiInputState* io_input_state) {
if (!glfwGetWindowAttrib(w, GLFW_FOCUSED)) {
@@ -414,6 +421,19 @@ void save_application_config(const char* filename) {
output_file.close();
}
+void sokol_logger(
+ const char* tag,
+ uint32_t log_level,
+ uint32_t log_item_id,
+ const char*
+ message_or_null, // a message string, may be nullptr in release mode
+ uint32_t line_nr, // line number in sokol_gl.h
+ const char*
+ filename_or_null, // source filename, may be nullptr in release mode
+ void* user_data) {
+ fprintf(stderr, "%s\n", message_or_null);
+}
+
int main() {
// window and GL context via GLFW and flextGL
glfwInit();
@@ -423,7 +443,8 @@ int main() {
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE);
glfwWindowHint(GLFW_SAMPLES, 16);
- GLFWwindow* w = glfwCreateWindow(Width, Height, "ATP Editor", 0, 0);
+ GLFWwindow* w =
+ glfwCreateWindow(Width, Height, "ATP Editor", nullptr, nullptr);
glfwMakeContextCurrent(w);
glfwSwapInterval(1);
@@ -476,16 +497,19 @@ int main() {
// setup sokol_gfx and sokol_time
stm_setup();
- sg_desc desc = {};
+ sg_desc desc = {.logger = {.func = slog_func}};
sg_setup(&desc);
assert(sg_isvalid());
// setup sokol-gl
sgl_desc_t sgldesc = {
- .sample_count = 4
- };
+ .sample_count = cMSAASampleCount,
+ .logger = sokol_logger};
sgl_setup(&sgldesc);
+ // sgl_context_desc_t sgl_context_desc = {};
+ // sgl_context ctx = sgl_make_context(&sgl_context_desc);
+
SkinnedMeshResource skinned_mesh_resource;
skinned_mesh_resource.loadFromFile("../media/SampleSkinnedMesh.json");
@@ -602,6 +626,7 @@ int main() {
pip_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA;
pip_desc.colors[0].blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA;
pip_desc.colors[0].write_mask = SG_COLORMASK_RGB;
+ pip_desc.label = "imgui-rendering";
pip = sg_make_pipeline(&pip_desc);
// initial clear color
@@ -625,7 +650,7 @@ int main() {
if (state.ozz.animation != nullptr) {
state.time.absolute =
- fmodf(state.time.absolute, state.ozz.animation->duration());
+ fmod(state.time.absolute, state.ozz.animation->duration());
}
// Update window state
@@ -643,7 +668,6 @@ int main() {
glfwGetFramebufferSize(w, &cur_width, &cur_height);
// this is standard ImGui demo code
- ImGuiIO& io = ImGui::GetIO();
io.DisplaySize = ImVec2(float(cur_width), float(cur_height));
io.DeltaTime = (float)stm_sec(stm_laptime(&last_time));
ImGui::NewFrame();
@@ -664,7 +688,7 @@ int main() {
&state.camera,
offscreen_viewport.size[0],
offscreen_viewport.size[1],
- state.time.frame,
+ static_cast(state.time.frame),
0,
0,
nullptr);
@@ -703,7 +727,7 @@ int main() {
&state.camera,
cur_width,
cur_height,
- state.time.frame,
+ static_cast(state.time.frame),
gGuiInputState.mousedX,
gGuiInputState.mousedY,
camera_accel);
@@ -769,22 +793,22 @@ int main() {
if (gApplicationConfig.viewport_widget.visible) {
ImGui::SetNextWindowPos(
ImVec2(
- gApplicationConfig.viewport_widget.position[0],
- gApplicationConfig.viewport_widget.position[1]),
+ static_cast(
+ gApplicationConfig.viewport_widget.position[0]),
+ static_cast(
+ gApplicationConfig.viewport_widget.position[1])),
ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(
ImVec2(
- gApplicationConfig.viewport_widget.size[0],
- gApplicationConfig.viewport_widget.size[1]),
+ static_cast(gApplicationConfig.viewport_widget.size[0]),
+ static_cast(gApplicationConfig.viewport_widget.size[1])),
ImGuiCond_FirstUseEver);
ImGui::Begin("Viewport", &gApplicationConfig.viewport_widget.visible);
ImVec2 viewport_widget_size = ImGui::GetWindowSize();
- gApplicationConfig.viewport_widget.size[0] =
- viewport_widget_size.x;
- gApplicationConfig.viewport_widget.size[1] =
- viewport_widget_size.y;
+ gApplicationConfig.viewport_widget.size[0] = viewport_widget_size.x;
+ gApplicationConfig.viewport_widget.size[1] = viewport_widget_size.y;
ImGui::Text(
"Viewport size: %d, %d",
@@ -795,15 +819,15 @@ int main() {
int* current_size = offscreen_viewport.size;
- if (current_size[0] != content_size[0] || current_size[1] != content_size[1]) {
+ if (current_size[0] != content_size[0]
+ || current_size[1] != content_size[1]
+ || offscreen_viewport.pass.id == 0) {
offscreen_viewport.Resize(content_size[0], content_size[1]);
}
ImGui::Image(
(ImTextureID)(uintptr_t)offscreen_viewport.color_image.id,
- ImVec2(
- offscreen_viewport.size[0],
- offscreen_viewport.size[1]),
+ ImVec2(offscreen_viewport.size[0], offscreen_viewport.size[1]),
ImVec2(0.0f, 1.0f),
ImVec2(1.0f, 0.0f));
@@ -927,13 +951,16 @@ int main() {
if (state.ozz.animation != nullptr) {
ImGui::SameLine();
- ImGui::SliderFloat(
- "Time",
- &state.time.absolute,
- 0,
- state.ozz.animation->duration(),
- "%.3f",
- 0);
+ float time_absolute_float = static_cast(state.time.absolute);
+ if (ImGui::SliderFloat(
+ "Time",
+ &time_absolute_float,
+ 0,
+ state.ozz.animation->duration(),
+ "%.3f",
+ 0)) {
+ state.time.absolute = time_absolute_float;
+ }
}
ImGui::End();
@@ -1012,8 +1039,9 @@ int main() {
ImGui::ShowDemoWindow();
}
- // Rendering of the offscreen scene
+ sgl_defaults();
sg_begin_pass(offscreen_viewport.pass, &offscreen_viewport.pass_action);
+ sgl_load_pipeline(offscreen_viewport.glpip);
sgl_draw();
sg_end_pass();
@@ -1023,6 +1051,9 @@ int main() {
draw_imgui(ImGui::GetDrawData());
sg_end_pass();
+
+
+
sg_commit();
glfwSwapBuffers(w);
glfwPollEvents();