Updated ozz-animation to version 0.14.1.
parent
eb70c06c57
commit
72bcf8a21b
|
@ -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
|
|
|
@ -1 +0,0 @@
|
||||||
ozz
|
|
|
@ -1,4 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
|
||||||
</project>
|
|
|
@ -1,8 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/ozz-animation.iml" filepath="$PROJECT_DIR$/.idea/ozz-animation.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
|
@ -1,2 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module classpath="CMake" type="CPP_MODULE" version="4" />
|
|
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
|
@ -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------------------------------------------------------------
|
|
|
@ -14,3 +14,4 @@ The following authors have all licensed their contributions to ozz-animation und
|
||||||
- Kota Iguchi <developer@infosia.co.jp>
|
- Kota Iguchi <developer@infosia.co.jp>
|
||||||
- Mikołaj Siedlarek <mikolaj@siedlarek.net>
|
- Mikołaj Siedlarek <mikolaj@siedlarek.net>
|
||||||
- Paul Gruenbacher <pgruenbacher@gmail.com>
|
- Paul Gruenbacher <pgruenbacher@gmail.com>
|
||||||
|
- Christophe Meyer <christophe.meyer.pro@gmail.com>
|
||||||
|
|
|
@ -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
|
Release version 0.14.0
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,13 @@ cmake_minimum_required (VERSION 3.3)
|
||||||
# Defines the project's name
|
# Defines the project's name
|
||||||
project(ozz)
|
project(ozz)
|
||||||
|
|
||||||
|
# Check if project is top level or a sub project
|
||||||
|
get_directory_property(is_sub_project PARENT_DIRECTORY)
|
||||||
|
|
||||||
# Current version
|
# Current version
|
||||||
set(OZZ_VERSION_MAJOR 0)
|
set(OZZ_VERSION_MAJOR 0)
|
||||||
set(OZZ_VERSION_MINOR 14)
|
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})
|
set(OZZ_VERSION ${OZZ_VERSION_MAJOR}.${OZZ_VERSION_MINOR}.${OZZ_VERSION_PATCH})
|
||||||
|
|
||||||
# Add project build options
|
# 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).")
|
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)
|
set(ozz_build_msvc_rt_dll ON)
|
||||||
endif()
|
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 ozz cmake parameters and scripts
|
||||||
include(CheckCXXCompilerFlag)
|
include(CheckCXXCompilerFlag)
|
||||||
|
@ -63,12 +69,18 @@ else()
|
||||||
# Disables fbx if tools are disabled
|
# Disables fbx if tools are disabled
|
||||||
set(ozz_build_fbx OFF)
|
set(ozz_build_fbx OFF)
|
||||||
endif()
|
endif()
|
||||||
|
if(is_sub_project)
|
||||||
|
set(ozz_build_fbx ${ozz_build_fbx} PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
|
||||||
# gltf
|
# gltf
|
||||||
if(ozz_build_tools AND ozz_build_gltf)
|
if(ozz_build_tools AND ozz_build_gltf)
|
||||||
else()
|
else()
|
||||||
set(ozz_build_gltf OFF)
|
set(ozz_build_gltf OFF)
|
||||||
endif()
|
endif()
|
||||||
|
if(is_sub_project)
|
||||||
|
set(ozz_build_gltf ${ozz_build_gltf} PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Enables unit tests.
|
# Enables unit tests.
|
||||||
if(ozz_build_tests)
|
if(ozz_build_tests)
|
||||||
|
@ -115,7 +127,6 @@ if(ozz_build_tests AND NOT EMSCRIPTEN)
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
install(FILES
|
install(FILES
|
||||||
${PROJECT_SOURCE_DIR}/CHANGES.md
|
${PROJECT_SOURCE_DIR}/CHANGES.md
|
||||||
${PROJECT_SOURCE_DIR}/LICENSE.md
|
${PROJECT_SOURCE_DIR}/LICENSE.md
|
||||||
|
|
|
@ -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%
|
|
|
@ -7917,7 +7917,7 @@ namespace edit_distance {
|
||||||
// Returns the optimal edits to go from 'left' to 'right'.
|
// Returns the optimal edits to go from 'left' to 'right'.
|
||||||
// All edits cost the same, with replace having lower priority than
|
// All edits cost the same, with replace having lower priority than
|
||||||
// add/remove.
|
// 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
|
// See http://en.wikipedia.org/wiki/Wagner-Fischer_algorithm
|
||||||
enum EditType { kMatch, kAdd, kRemove, kReplace };
|
enum EditType { kMatch, kAdd, kRemove, kReplace };
|
||||||
GTEST_API_ std::vector<EditType> CalculateOptimalEdits(
|
GTEST_API_ std::vector<EditType> CalculateOptimalEdits(
|
||||||
|
|
|
@ -61,6 +61,9 @@ struct span {
|
||||||
// elements.
|
// elements.
|
||||||
span(_Ty* _begin, size_t _size) : data_(_begin), size_(_size) {}
|
span(_Ty* _begin, size_t _size) : data_(_begin), size_(_size) {}
|
||||||
|
|
||||||
|
// Copy constructor.
|
||||||
|
span(const span& _other) = default;
|
||||||
|
|
||||||
// Copy operator.
|
// Copy operator.
|
||||||
void operator=(const span& _other) {
|
void operator=(const span& _other) {
|
||||||
data_ = _other.data_;
|
data_ = _other.data_;
|
||||||
|
|
Binary file not shown.
|
@ -36,6 +36,10 @@ target_link_libraries(sample_framework
|
||||||
ozz_geometry
|
ozz_geometry
|
||||||
ozz_animation_offline
|
ozz_animation_offline
|
||||||
ozz_options)
|
ozz_options)
|
||||||
|
|
||||||
|
target_include_directories(sample_framework PUBLIC
|
||||||
|
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/samples>
|
||||||
|
$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/samples>)
|
||||||
|
|
||||||
if(TARGET BUILD_DATA_SAMPLE)
|
if(TARGET BUILD_DATA_SAMPLE)
|
||||||
add_dependencies(sample_framework BUILD_DATA_SAMPLE)
|
add_dependencies(sample_framework BUILD_DATA_SAMPLE)
|
||||||
|
|
|
@ -98,6 +98,8 @@ Application::Application()
|
||||||
time_(0.f),
|
time_(0.f),
|
||||||
last_idle_time_(0.),
|
last_idle_time_(0.),
|
||||||
show_help_(false),
|
show_help_(false),
|
||||||
|
vertical_sync_(true),
|
||||||
|
swap_interval_(1),
|
||||||
show_grid_(true),
|
show_grid_(true),
|
||||||
show_axes_(true),
|
show_axes_(true),
|
||||||
capture_video_(false),
|
capture_video_(false),
|
||||||
|
@ -209,7 +211,7 @@ int Application::Run(int _argc, const char** _argv, const char* _version,
|
||||||
#endif // EMSCRIPTEN
|
#endif // EMSCRIPTEN
|
||||||
|
|
||||||
// Setup the window and installs callbacks.
|
// Setup the window and installs callbacks.
|
||||||
glfwSwapInterval(1); // Enables vertical sync by default.
|
glfwSwapInterval(vertical_sync_ ? swap_interval_ : 0);
|
||||||
glfwSetWindowSizeCallback(&ResizeCbk);
|
glfwSetWindowSizeCallback(&ResizeCbk);
|
||||||
glfwSetWindowCloseCallback(&CloseCbk);
|
glfwSetWindowCloseCallback(&CloseCbk);
|
||||||
|
|
||||||
|
@ -611,10 +613,14 @@ bool Application::FrameworkGui() {
|
||||||
GL(Disable(GL_MULTISAMPLE));
|
GL(Disable(GL_MULTISAMPLE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Vertical sync
|
// Vertical sync & swap interval
|
||||||
static bool vertical_sync_ = true; // On by default.
|
bool changed = im_gui->DoCheckBox("Vertical sync", &vertical_sync_);
|
||||||
if (im_gui->DoCheckBox("Vertical sync", &vertical_sync_, true)) {
|
char szLabel[64];
|
||||||
glfwSwapInterval(vertical_sync_ ? 1 : 0);
|
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);
|
im_gui->DoCheckBox("Show grid", &show_grid_, true);
|
||||||
|
|
|
@ -216,6 +216,9 @@ class Application {
|
||||||
// Set to true to display help.
|
// Set to true to display help.
|
||||||
bool show_help_;
|
bool show_help_;
|
||||||
|
|
||||||
|
bool vertical_sync_; // On by default.
|
||||||
|
int swap_interval_;
|
||||||
|
|
||||||
// Grid display settings.
|
// Grid display settings.
|
||||||
bool show_grid_;
|
bool show_grid_;
|
||||||
bool show_axes_;
|
bool show_axes_;
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
#include "framework/imgui.h"
|
#include "framework/imgui.h"
|
||||||
#include "framework/mesh.h"
|
#include "framework/mesh.h"
|
||||||
|
#include "ozz/animation/offline/raw_animation.h"
|
||||||
#include "ozz/animation/offline/raw_skeleton.h"
|
#include "ozz/animation/offline/raw_skeleton.h"
|
||||||
#include "ozz/animation/runtime/animation.h"
|
#include "ozz/animation/runtime/animation.h"
|
||||||
#include "ozz/animation/runtime/local_to_model_job.h"
|
#include "ozz/animation/runtime/local_to_model_job.h"
|
||||||
|
@ -326,6 +327,30 @@ bool LoadAnimation(const char* _filename,
|
||||||
return true;
|
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::animation::offline::RawAnimation>()) {
|
||||||
|
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 {
|
namespace {
|
||||||
template <typename _Track>
|
template <typename _Track>
|
||||||
bool LoadTrackImpl(const char* _filename, _Track* _track) {
|
bool LoadTrackImpl(const char* _filename, _Track* _track) {
|
||||||
|
@ -411,7 +436,7 @@ bool LoadMeshes(const char* _filename,
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// Moller–Trumbore intersection algorithm
|
// Moller-Trumbore intersection algorithm
|
||||||
// https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
|
// https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
|
||||||
bool RayIntersectsTriangle(const ozz::math::Float3& _ray_origin,
|
bool RayIntersectsTriangle(const ozz::math::Float3& _ray_origin,
|
||||||
const ozz::math::Float3& _ray_direction,
|
const ozz::math::Float3& _ray_direction,
|
||||||
|
|
|
@ -167,6 +167,14 @@ bool LoadSkeleton(const char* _filename, ozz::animation::Skeleton* _skeleton);
|
||||||
bool LoadAnimation(const char* _filename,
|
bool LoadAnimation(const char* _filename,
|
||||||
ozz::animation::Animation* _animation);
|
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.
|
// 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
|
// 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
|
// it is not a valid ozz float track archive. A valid float track archive can be
|
||||||
|
|
|
@ -41,7 +41,7 @@ namespace ozz {
|
||||||
namespace animation {
|
namespace animation {
|
||||||
namespace offline {
|
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
|
// https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm
|
||||||
// _Track must have std::vector interface.
|
// _Track must have std::vector interface.
|
||||||
// Adapter must have the following interface:
|
// Adapter must have the following interface:
|
||||||
|
|
|
@ -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
|
// 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
|
// (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.
|
// is 1, yw are untested.
|
||||||
return (comp_mask & 0x5) == 0x4;
|
return (comp_mask & 0x5) == 0x4;
|
||||||
}
|
}
|
||||||
|
|
|
@ -645,10 +645,9 @@ class is_to_be_removed {
|
||||||
public:
|
public:
|
||||||
explicit is_to_be_removed(int _which) : which_(_which) {}
|
explicit is_to_be_removed(int _which) : which_(_which) {}
|
||||||
bool operator()(typename _List::const_reference) { return which_-- == 0; }
|
bool operator()(typename _List::const_reference) { return which_-- == 0; }
|
||||||
|
void operator=(const is_to_be_removed&) = delete;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void operator=(const is_to_be_removed&);
|
|
||||||
|
|
||||||
int which_;
|
int which_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,691 @@
|
||||||
## Updates
|
## 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:
|
- **08-Oct-2021**: texture compression support in sokol_gfx.h has been revisited:
|
||||||
- tighter validation checks on texture creation:
|
- tighter validation checks on texture creation:
|
||||||
- content data validation now also happens in ```sg_make_image()``` (previously only in ```sg_update_image()```)
|
- 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
|
ago (around iOS 12.x) MTKView started to ignore the contentScaleFactor
|
||||||
property, which lead to sokol_app.h always setting up a HighDPI
|
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
|
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
|
- 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
|
been fixed now, but only one MSAA mode (4x) is available, which will be
|
||||||
selected when sapp_desc.sample_count is greater than 1.
|
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
|
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.
|
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
|
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!
|
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
|
- **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
|
||||||
|
|
|
@ -4,3 +4,5 @@
|
||||||
__pycache__/
|
__pycache__/
|
||||||
sokol-nim/
|
sokol-nim/
|
||||||
sokol-zig/
|
sokol-zig/
|
||||||
|
sokol-odin/
|
||||||
|
sokol-rust/
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import os, gen_nim, gen_zig
|
import os, gen_nim, gen_zig, gen_odin, gen_rust
|
||||||
|
|
||||||
tasks = [
|
tasks = [
|
||||||
|
[ '../sokol_log.h', 'slog_', [] ],
|
||||||
[ '../sokol_gfx.h', 'sg_', [] ],
|
[ '../sokol_gfx.h', 'sg_', [] ],
|
||||||
[ '../sokol_app.h', 'sapp_', [] ],
|
[ '../sokol_app.h', 'sapp_', [] ],
|
||||||
|
[ '../sokol_glue.h', 'sapp_sg', ['sg_'] ],
|
||||||
[ '../sokol_time.h', 'stm_', [] ],
|
[ '../sokol_time.h', 'stm_', [] ],
|
||||||
[ '../sokol_audio.h', 'saudio_', [] ],
|
[ '../sokol_audio.h', 'saudio_', [] ],
|
||||||
[ '../util/sokol_gl.h', 'sgl_', ['sg_'] ],
|
[ '../util/sokol_gl.h', 'sgl_', ['sg_'] ],
|
||||||
|
@ -10,18 +12,26 @@ tasks = [
|
||||||
[ '../util/sokol_shape.h', 'sshape_', ['sg_'] ],
|
[ '../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
|
# Nim
|
||||||
gen_nim.prepare()
|
gen_nim.prepare()
|
||||||
for task in tasks:
|
for task in tasks:
|
||||||
c_header_path = task[0]
|
[c_header_path, main_prefix, dep_prefixes] = task
|
||||||
main_prefix = task[1]
|
|
||||||
dep_prefixes = task[2]
|
|
||||||
gen_nim.gen(c_header_path, main_prefix, dep_prefixes)
|
gen_nim.gen(c_header_path, main_prefix, dep_prefixes)
|
||||||
|
|
||||||
# Zig
|
# Zig
|
||||||
gen_zig.prepare()
|
gen_zig.prepare()
|
||||||
for task in tasks:
|
for task in tasks:
|
||||||
c_header_path = task[0]
|
[c_header_path, main_prefix, dep_prefixes] = task
|
||||||
main_prefix = task[1]
|
|
||||||
dep_prefixes = task[2]
|
|
||||||
gen_zig.gen(c_header_path, main_prefix, dep_prefixes)
|
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)
|
||||||
|
|
|
@ -59,11 +59,11 @@ def parse_enum(decl):
|
||||||
if 'inner' in item_decl:
|
if 'inner' in item_decl:
|
||||||
const_expr = item_decl['inner'][0]
|
const_expr = item_decl['inner'][0]
|
||||||
if const_expr['kind'] != 'ConstantExpr':
|
if const_expr['kind'] != 'ConstantExpr':
|
||||||
sys.exit(f"ERROR: Enum values must be a ConstantExpr ({decl['name']})")
|
sys.exit(f"ERROR: Enum values must be a ConstantExpr ({item_decl['name']}), is '{const_expr['kind']}'")
|
||||||
if const_expr['valueCategory'] != 'rvalue':
|
if const_expr['valueCategory'] != 'rvalue' and const_expr['valueCategory'] != 'prvalue':
|
||||||
sys.exit(f"ERROR: Enum value ConstantExpr must be 'rvalue' ({decl['name']})")
|
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')):
|
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']
|
item['value'] = const_expr['inner'][0]['value']
|
||||||
if needs_value and 'value' not in item:
|
if needs_value and 'value' not in item:
|
||||||
sys.exit(f"ERROR: anonymous enum items require an explicit value")
|
sys.exit(f"ERROR: anonymous enum items require an explicit value")
|
||||||
|
@ -79,7 +79,7 @@ def parse_func(decl):
|
||||||
if 'inner' in decl:
|
if 'inner' in decl:
|
||||||
for param in decl['inner']:
|
for param in decl['inner']:
|
||||||
if param['kind'] != 'ParmVarDecl':
|
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
|
return None
|
||||||
outp_param = {}
|
outp_param = {}
|
||||||
outp_param['name'] = param['name']
|
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['is_dep'] = is_dep
|
||||||
outp_decl['dep_prefix'] = dep_prefix(decl, dep_prefixes)
|
outp_decl['dep_prefix'] = dep_prefix(decl, dep_prefixes)
|
||||||
outp['decls'].append(outp_decl)
|
outp['decls'].append(outp_decl)
|
||||||
|
with open(f'{module}.json', 'w') as f:
|
||||||
|
f.write(json.dumps(outp, indent=2));
|
||||||
return outp
|
return outp
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
# Read output of gen_json.py and generate Zig language bindings.
|
# Generate Nim bindings
|
||||||
#
|
#
|
||||||
# Nim coding style:
|
# Nim coding style:
|
||||||
# - types and constants are PascalCase
|
# - type identifiers are PascalCase, everything else is camelCase
|
||||||
# - functions, parameters, and fields are camelCase
|
# - reference: https://nim-lang.org/docs/nep1.html
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
import gen_ir
|
import gen_ir
|
||||||
import json, re, os, shutil
|
import gen_util as util
|
||||||
|
import os, shutil, sys
|
||||||
|
|
||||||
module_names = {
|
module_names = {
|
||||||
|
'slog_': 'log',
|
||||||
'sg_': 'gfx',
|
'sg_': 'gfx',
|
||||||
'sapp_': 'app',
|
'sapp_': 'app',
|
||||||
|
'sapp_sg': 'glue',
|
||||||
'stm_': 'time',
|
'stm_': 'time',
|
||||||
'saudio_': 'audio',
|
'saudio_': 'audio',
|
||||||
'sgl_': 'gl',
|
'sgl_': 'gl',
|
||||||
|
@ -19,8 +22,10 @@ module_names = {
|
||||||
}
|
}
|
||||||
|
|
||||||
c_source_paths = {
|
c_source_paths = {
|
||||||
|
'slog_': 'sokol-nim/src/sokol/c/sokol_log.c',
|
||||||
'sg_': 'sokol-nim/src/sokol/c/sokol_gfx.c',
|
'sg_': 'sokol-nim/src/sokol/c/sokol_gfx.c',
|
||||||
'sapp_': 'sokol-nim/src/sokol/c/sokol_app.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',
|
'stm_': 'sokol-nim/src/sokol/c/sokol_time.c',
|
||||||
'saudio_': 'sokol-nim/src/sokol/c/sokol_audio.c',
|
'saudio_': 'sokol-nim/src/sokol/c/sokol_audio.c',
|
||||||
'sgl_': 'sokol-nim/src/sokol/c/sokol_gl.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',
|
'sshape_': 'sokol-nim/src/sokol/c/sokol_shape.c',
|
||||||
}
|
}
|
||||||
|
|
||||||
func_name_ignores = [
|
c_callbacks = [
|
||||||
|
'slog_func',
|
||||||
|
]
|
||||||
|
|
||||||
|
ignores = [
|
||||||
'sdtx_printf',
|
'sdtx_printf',
|
||||||
'sdtx_vprintf',
|
'sdtx_vprintf',
|
||||||
]
|
]
|
||||||
|
|
||||||
func_name_overrides = {
|
overrides = {
|
||||||
'sgl_error': 'sgl_get_error', # 'error' is reserved in Zig
|
'sgl_error': 'sgl_get_error',
|
||||||
'sgl_deg': 'sgl_as_degrees',
|
'sgl_deg': 'sgl_as_degrees',
|
||||||
'sgl_rad': 'sgl_as_radians',
|
'sgl_rad': 'sgl_as_radians',
|
||||||
}
|
|
||||||
|
|
||||||
struct_field_type_overrides = {
|
|
||||||
'sg_context_desc.color_format': 'int',
|
'sg_context_desc.color_format': 'int',
|
||||||
'sg_context_desc.depth_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 = {
|
prim_types = {
|
||||||
|
@ -60,7 +102,7 @@ prim_types = {
|
||||||
'double': 'float64',
|
'double': 'float64',
|
||||||
'uintptr_t': 'uint',
|
'uintptr_t': 'uint',
|
||||||
'intptr_t': 'int',
|
'intptr_t': 'int',
|
||||||
'size_t': 'int',
|
'size_t': 'int', # not a bug, Nim's sizeof() returns int
|
||||||
}
|
}
|
||||||
|
|
||||||
prim_defaults = {
|
prim_defaults = {
|
||||||
|
@ -74,31 +116,62 @@ prim_defaults = {
|
||||||
'uint32_t': '0',
|
'uint32_t': '0',
|
||||||
'int64_t': '0',
|
'int64_t': '0',
|
||||||
'uint64_t': '0',
|
'uint64_t': '0',
|
||||||
'float': '0.0',
|
'float': '0.0f',
|
||||||
'double': '0.0',
|
'double': '0.0',
|
||||||
'uintptr_t': '0',
|
'uintptr_t': '0',
|
||||||
'intptr_t': '0',
|
'intptr_t': '0',
|
||||||
'size_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 = []
|
struct_types = []
|
||||||
enum_types = []
|
enum_types = []
|
||||||
enum_items = {}
|
|
||||||
out_lines = ''
|
out_lines = ''
|
||||||
|
|
||||||
def reset_globals():
|
def reset_globals():
|
||||||
global struct_types
|
global struct_types
|
||||||
global enum_types
|
global enum_types
|
||||||
global enum_items
|
|
||||||
global out_lines
|
global out_lines
|
||||||
struct_types = []
|
struct_types = []
|
||||||
enum_types = []
|
enum_types = []
|
||||||
enum_items = {}
|
|
||||||
out_lines = ''
|
out_lines = ''
|
||||||
|
|
||||||
re_1d_array = re.compile("^(?:const )?\w*\s\*?\[\d*\]$")
|
|
||||||
re_2d_array = re.compile("^(?:const )?\w*\s\*?\[\d*\]\[\d*\]$")
|
|
||||||
|
|
||||||
def l(s):
|
def l(s):
|
||||||
global out_lines
|
global out_lines
|
||||||
out_lines += s + '\n'
|
out_lines += s + '\n'
|
||||||
|
@ -107,90 +180,66 @@ def as_nim_prim_type(s):
|
||||||
return prim_types[s]
|
return prim_types[s]
|
||||||
|
|
||||||
# prefix_bla_blub(_t) => (dep.)BlaBlub
|
# prefix_bla_blub(_t) => (dep.)BlaBlub
|
||||||
def as_nim_struct_type(s, prefix):
|
def as_nim_type_name(s, prefix):
|
||||||
parts = s.lower().split('_')
|
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:]:
|
for part in parts[1:]:
|
||||||
|
# ignore '_t' type postfix
|
||||||
if (part != 't'):
|
if (part != 't'):
|
||||||
outp += part.capitalize()
|
outp += part.capitalize()
|
||||||
return outp
|
return outp
|
||||||
|
|
||||||
# prefix_bla_blub(_t) => (dep.)BlaBlub
|
def check_override(name, default=None):
|
||||||
def as_nim_enum_type(s, prefix):
|
if name in overrides:
|
||||||
parts = s.lower().split('_')
|
return overrides[name]
|
||||||
outp = '' if s.startswith(prefix) else f'{parts[0]}.'
|
elif default is None:
|
||||||
for part in parts[1:]:
|
return name
|
||||||
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]
|
|
||||||
else:
|
else:
|
||||||
return orig_type
|
return default
|
||||||
|
|
||||||
def check_func_name_ignore(func_name):
|
def check_ignore(name):
|
||||||
return func_name in func_name_ignores
|
return name in ignores
|
||||||
|
|
||||||
def check_func_name_override(func_name):
|
def is_power_of_two(val):
|
||||||
if func_name in func_name_overrides:
|
return val == 0 or val & (val - 1) == 0
|
||||||
return func_name_overrides[func_name]
|
|
||||||
|
def wrap_keywords(s):
|
||||||
|
if s in keywords:
|
||||||
|
return f'`{s}`'
|
||||||
else:
|
else:
|
||||||
return func_name
|
return s
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
# prefix_bla_blub => blaBlub
|
# prefix_bla_blub => blaBlub
|
||||||
def as_camel_case(s, prefix = ""):
|
def as_camel_case(s, prefix, wrap=True):
|
||||||
parts = trim_prefix(s, prefix).lower().split('_')
|
outp = s.lower()
|
||||||
|
if outp.startswith(prefix):
|
||||||
|
outp = outp[len(prefix):]
|
||||||
|
parts = outp.lstrip('_').split('_')
|
||||||
outp = parts[0]
|
outp = parts[0]
|
||||||
for part in parts[1:]:
|
for part in parts[1:]:
|
||||||
outp += part.capitalize()
|
outp += part.capitalize()
|
||||||
|
if wrap:
|
||||||
|
outp = wrap_keywords(outp)
|
||||||
return outp
|
return outp
|
||||||
|
|
||||||
# prefix_bla_blub => BlaBlub
|
# PREFIX_ENUM_BLA_BLO => blaBlo
|
||||||
def as_pascal_case(s, prefix):
|
def as_enum_item_name(s, wrap=True):
|
||||||
parts = trim_prefix(s, prefix).lower().split('_')
|
outp = s.lstrip('_')
|
||||||
outp = ""
|
parts = outp.split('_')[1:]
|
||||||
for part in parts:
|
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()
|
outp += part.capitalize()
|
||||||
|
if wrap:
|
||||||
|
outp = wrap_keywords(outp)
|
||||||
return 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):
|
def is_prim_type(s):
|
||||||
return s in prim_types
|
return s in prim_types
|
||||||
|
|
||||||
|
@ -200,15 +249,6 @@ def is_struct_type(s):
|
||||||
def is_enum_type(s):
|
def is_enum_type(s):
|
||||||
return s in enum_types
|
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):
|
def is_const_prim_ptr(s):
|
||||||
for prim_type in prim_types:
|
for prim_type in prim_types:
|
||||||
if s == f"const {prim_type} *":
|
if s == f"const {prim_type} *":
|
||||||
|
@ -227,266 +267,208 @@ def is_const_struct_ptr(s):
|
||||||
return True
|
return True
|
||||||
return False
|
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):
|
def type_default_value(s):
|
||||||
return prim_defaults[s]
|
return prim_defaults[s]
|
||||||
|
|
||||||
def extract_array_type(s):
|
def funcptr_args(field_type, prefix):
|
||||||
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):
|
|
||||||
tokens = field_type[field_type.index('(*)')+4:-1].split(',')
|
tokens = field_type[field_type.index('(*)')+4:-1].split(',')
|
||||||
s = ""
|
s = ""
|
||||||
n = 0
|
n = 0
|
||||||
for token in tokens:
|
for token in tokens:
|
||||||
n += 1
|
n += 1
|
||||||
arg_type = token.strip()
|
arg_ctype = token.strip()
|
||||||
if s != "":
|
if s != "":
|
||||||
s += ", "
|
s += ", "
|
||||||
c_arg = f"a{n}:" + as_extern_c_arg_type(arg_type, prefix)
|
arg_nimtype = as_nim_type(arg_ctype, prefix)
|
||||||
if (c_arg == "void"):
|
if arg_nimtype == "":
|
||||||
return ""
|
return "" # fun(void)
|
||||||
else:
|
s += f"a{n}:{arg_nimtype}"
|
||||||
s += c_arg
|
|
||||||
if s == "a1:void":
|
if s == "a1:void":
|
||||||
s = ""
|
s = ""
|
||||||
return s
|
return s
|
||||||
|
|
||||||
# get C-style result of a function pointer as string
|
def funcptr_result(field_type, prefix):
|
||||||
def funcptr_res_c(field_type):
|
ctype = field_type[:field_type.index('(*)')].strip()
|
||||||
res_type = field_type[:field_type.index('(*)')].strip()
|
return as_nim_type(ctype, prefix)
|
||||||
if res_type == 'void':
|
|
||||||
return ''
|
|
||||||
elif is_const_void_ptr(res_type):
|
|
||||||
return ':pointer'
|
|
||||||
else:
|
|
||||||
return '???'
|
|
||||||
|
|
||||||
def funcdecl_args_c(decl, prefix):
|
def as_nim_type(ctype, prefix, struct_ptr_as_value=False):
|
||||||
s = ""
|
if ctype == "void":
|
||||||
for param_decl in decl['params']:
|
return ""
|
||||||
if s != "":
|
elif is_prim_type(ctype):
|
||||||
s += ", "
|
return as_nim_prim_type(ctype)
|
||||||
arg_type = param_decl['type']
|
elif is_struct_type(ctype):
|
||||||
s += as_extern_c_arg_type(arg_type, prefix)
|
return as_nim_type_name(ctype, prefix)
|
||||||
return s
|
elif is_enum_type(ctype):
|
||||||
|
return as_nim_type_name(ctype, prefix)
|
||||||
def funcdecl_args_nim(decl, prefix):
|
elif util.is_string_ptr(ctype):
|
||||||
s = ""
|
return "cstring"
|
||||||
for param_decl in decl['params']:
|
elif util.is_void_ptr(ctype) or util.is_const_void_ptr(ctype):
|
||||||
if s != "":
|
return "pointer"
|
||||||
s += ", "
|
elif is_const_struct_ptr(ctype):
|
||||||
arg_name = param_decl['name']
|
nim_type = as_nim_type(util.extract_ptr_type(ctype), prefix)
|
||||||
arg_type = param_decl['type']
|
if struct_ptr_as_value:
|
||||||
s += f"{as_nim_arg_type(f'{arg_name}:', arg_type, prefix)}"
|
return f"{nim_type}"
|
||||||
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}")
|
|
||||||
else:
|
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("")
|
l("")
|
||||||
|
|
||||||
def gen_consts(decl, prefix):
|
def gen_consts(decl, prefix):
|
||||||
l("const")
|
l("const")
|
||||||
for item in decl['items']:
|
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("")
|
l("")
|
||||||
|
|
||||||
def gen_enum(decl, prefix):
|
def gen_enum(decl, prefix):
|
||||||
item_names_by_value = {}
|
item_names_by_value = {}
|
||||||
value = -1
|
value = -1
|
||||||
hasForceU32 = False
|
has_explicit_values = False
|
||||||
hasExplicitValues = False
|
|
||||||
for item in decl['items']:
|
for item in decl['items']:
|
||||||
itemName = item['name']
|
item_name = check_override(item['name'])
|
||||||
if itemName.endswith("_FORCE_U32"):
|
if item_name.endswith("_NUM") or item_name.endswith("_FORCE_U32"):
|
||||||
hasForceU32 = True
|
|
||||||
elif itemName.endswith("_NUM"):
|
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
if 'value' in item:
|
if 'value' in item:
|
||||||
hasExplicitValues = True
|
has_explicit_values = True
|
||||||
value = int(item['value'])
|
value = int(item['value'])
|
||||||
else:
|
else:
|
||||||
value += 1
|
value += 1
|
||||||
item_names_by_value[value] = as_enum_item_name(item['name']);
|
item_names_by_value[value] = as_enum_item_name(item_name)
|
||||||
if hasForceU32:
|
enum_name_nim = as_nim_type_name(decl['name'], prefix)
|
||||||
l(f"type {as_nim_enum_type(decl['name'], prefix)}* {{.pure, size:4.}} = enum")
|
l('type')
|
||||||
else:
|
l(f" {enum_name_nim}* {{.size:sizeof(int32).}} = enum")
|
||||||
l(f"type {as_nim_enum_type(decl['name'], prefix)}* {{.pure.}} = enum")
|
if has_explicit_values:
|
||||||
if hasExplicitValues:
|
|
||||||
# Nim requires explicit enum values to be declared in ascending order
|
# Nim requires explicit enum values to be declared in ascending order
|
||||||
for value in sorted(item_names_by_value):
|
for value in sorted(item_names_by_value):
|
||||||
name = item_names_by_value[value]
|
name = item_names_by_value[value]
|
||||||
l(f" {name} = {value},")
|
l(f" {name} = {value},")
|
||||||
else:
|
else:
|
||||||
for name in item_names_by_value.values():
|
for name in item_names_by_value.values():
|
||||||
l(f" {name},")
|
l(f" {name},")
|
||||||
l("")
|
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):
|
def gen_func_nim(decl, prefix):
|
||||||
c_func_name = decl['name']
|
c_func_name = decl['name']
|
||||||
nim_func_name = as_camel_case(decl['name'], prefix)
|
nim_func_name = as_camel_case(check_override(c_func_name), prefix, wrap=False)
|
||||||
nim_res_type = funcdecl_res_nim(decl, prefix)
|
nim_res_type = funcdecl_result(decl, prefix)
|
||||||
l(f"proc {nim_func_name}*({funcdecl_args_nim(decl, prefix)}):{funcdecl_res_nim(decl, prefix)} {{.cdecl, importc:\"{decl['name']}\".}}")
|
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("")
|
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):
|
def pre_parse(inp):
|
||||||
global struct_types
|
global struct_types
|
||||||
global enum_types
|
global enum_types
|
||||||
|
@ -497,15 +479,92 @@ def pre_parse(inp):
|
||||||
elif kind == 'enum':
|
elif kind == 'enum':
|
||||||
enum_name = decl['name']
|
enum_name = decl['name']
|
||||||
enum_types.append(enum_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):
|
def gen_imports(inp, dep_prefixes):
|
||||||
for dep_prefix in dep_prefixes:
|
for dep_prefix in dep_prefixes:
|
||||||
dep_module_name = module_names[dep_prefix]
|
dep_module_name = module_names[dep_prefix]
|
||||||
l(f'import {dep_module_name}')
|
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('')
|
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):
|
def gen_module(inp, dep_prefixes):
|
||||||
l('## machine generated, do not edit')
|
l('## machine generated, do not edit')
|
||||||
|
@ -518,22 +577,27 @@ def gen_module(inp, dep_prefixes):
|
||||||
kind = decl['kind']
|
kind = decl['kind']
|
||||||
if kind == 'consts':
|
if kind == 'consts':
|
||||||
gen_consts(decl, prefix)
|
gen_consts(decl, prefix)
|
||||||
elif kind == 'enum':
|
elif not check_ignore(decl['name']):
|
||||||
gen_enum(decl, prefix)
|
if kind == 'struct':
|
||||||
elif kind == 'struct':
|
gen_struct(decl, prefix)
|
||||||
gen_struct(decl, prefix)
|
gen_array_converters(decl, prefix)
|
||||||
elif kind == 'func':
|
elif kind == 'enum':
|
||||||
if not check_func_name_ignore(decl['name']):
|
gen_enum(decl, prefix)
|
||||||
|
elif kind == 'func':
|
||||||
gen_func_nim(decl, prefix)
|
gen_func_nim(decl, prefix)
|
||||||
|
gen_extra(inp)
|
||||||
|
|
||||||
def prepare():
|
def prepare():
|
||||||
print('Generating nim bindings:')
|
print('=== Generating Nim bindings:')
|
||||||
if not os.path.isdir('sokol-nim/src/sokol'):
|
if not os.path.isdir('sokol-nim/src/sokol'):
|
||||||
os.makedirs('sokol-nim/src/sokol')
|
os.makedirs('sokol-nim/src/sokol')
|
||||||
if not os.path.isdir('sokol-nim/src/sokol/c'):
|
if not os.path.isdir('sokol-nim/src/sokol/c'):
|
||||||
os.makedirs('sokol-nim/src/sokol/c')
|
os.makedirs('sokol-nim/src/sokol/c')
|
||||||
|
|
||||||
def gen(c_header_path, c_prefix, dep_c_prefixes):
|
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
|
global out_lines
|
||||||
module_name = module_names[c_prefix]
|
module_name = module_names[c_prefix]
|
||||||
c_source_path = c_source_paths[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)
|
ir = gen_ir.gen(c_header_path, c_source_path, module_name, c_prefix, dep_c_prefixes)
|
||||||
gen_module(ir, dep_c_prefixes)
|
gen_module(ir, dep_c_prefixes)
|
||||||
output_path = f"sokol-nim/src/sokol/{ir['module']}.nim"
|
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:
|
with open(output_path, 'w', newline='\n') as f_outp:
|
||||||
f_outp.write(out_lines)
|
f_outp.write(out_lines)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
# Read output of gen_json.py and generate Zig language bindings.
|
# Generate Zig bindings.
|
||||||
#
|
#
|
||||||
# Zig coding style:
|
# Zig coding style:
|
||||||
# - types are PascalCase
|
# - types are PascalCase
|
||||||
|
@ -7,9 +7,12 @@
|
||||||
# - otherwise snake_case
|
# - otherwise snake_case
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
import gen_ir
|
import gen_ir
|
||||||
import json, re, os, shutil
|
import os, shutil, sys
|
||||||
|
|
||||||
|
import gen_util as util
|
||||||
|
|
||||||
module_names = {
|
module_names = {
|
||||||
|
'slog_': 'log',
|
||||||
'sg_': 'gfx',
|
'sg_': 'gfx',
|
||||||
'sapp_': 'app',
|
'sapp_': 'app',
|
||||||
'stm_': 'time',
|
'stm_': 'time',
|
||||||
|
@ -20,6 +23,7 @@ module_names = {
|
||||||
}
|
}
|
||||||
|
|
||||||
c_source_paths = {
|
c_source_paths = {
|
||||||
|
'slog_': 'sokol-zig/src/sokol/c/sokol_log.c',
|
||||||
'sg_': 'sokol-zig/src/sokol/c/sokol_gfx.c',
|
'sg_': 'sokol-zig/src/sokol/c/sokol_gfx.c',
|
||||||
'sapp_': 'sokol-zig/src/sokol/c/sokol_app.c',
|
'sapp_': 'sokol-zig/src/sokol/c/sokol_app.c',
|
||||||
'stm_': 'sokol-zig/src/sokol/c/sokol_time.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',
|
'sshape_': 'sokol-zig/src/sokol/c/sokol_shape.c',
|
||||||
}
|
}
|
||||||
|
|
||||||
name_ignores = [
|
ignores = [
|
||||||
'sdtx_printf',
|
'sdtx_printf',
|
||||||
'sdtx_vprintf',
|
'sdtx_vprintf',
|
||||||
'sg_install_trace_hooks',
|
'sg_install_trace_hooks',
|
||||||
'sg_trace_hooks',
|
'sg_trace_hooks',
|
||||||
]
|
]
|
||||||
|
|
||||||
name_overrides = {
|
# functions that need to be exposed as 'raw' C callbacks without a Zig wrapper function
|
||||||
'sgl_error': 'sgl_get_error', # 'error' is reserved in Zig
|
c_callbacks = [
|
||||||
'sgl_deg': 'sgl_as_degrees',
|
'slog_func'
|
||||||
'sgl_rad': 'sgl_as_radians'
|
]
|
||||||
}
|
|
||||||
|
|
||||||
# NOTE: syntax for function results: "func_name.RESULT"
|
# 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.color_format': 'int',
|
||||||
'sg_context_desc.depth_format': 'int',
|
'sg_context_desc.depth_format': 'int',
|
||||||
'sg_apply_uniforms.ub_index': 'uint32_t',
|
'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.base_element': 'uint32_t',
|
||||||
'sshape_element_range_t.num_elements': 'uint32_t',
|
'sshape_element_range_t.num_elements': 'uint32_t',
|
||||||
'sdtx_font.font_index': 'uint32_t',
|
'sdtx_font.font_index': 'uint32_t',
|
||||||
|
'SGL_NO_ERROR': 'SGL_ERROR_NO_ERROR',
|
||||||
}
|
}
|
||||||
|
|
||||||
prim_types = {
|
prim_types = {
|
||||||
|
@ -92,6 +99,7 @@ prim_defaults = {
|
||||||
'size_t': '0'
|
'size_t': '0'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct_types = []
|
struct_types = []
|
||||||
enum_types = []
|
enum_types = []
|
||||||
enum_items = {}
|
enum_items = {}
|
||||||
|
@ -107,9 +115,6 @@ def reset_globals():
|
||||||
enum_items = {}
|
enum_items = {}
|
||||||
out_lines = ''
|
out_lines = ''
|
||||||
|
|
||||||
re_1d_array = re.compile("^(?:const )?\w*\s\*?\[\d*\]$")
|
|
||||||
re_2d_array = re.compile("^(?:const )?\w*\s\*?\[\d*\]\[\d*\]$")
|
|
||||||
|
|
||||||
def l(s):
|
def l(s):
|
||||||
global out_lines
|
global out_lines
|
||||||
out_lines += s + '\n'
|
out_lines += s + '\n'
|
||||||
|
@ -122,6 +127,7 @@ def as_zig_struct_type(s, prefix):
|
||||||
parts = s.lower().split('_')
|
parts = s.lower().split('_')
|
||||||
outp = '' if s.startswith(prefix) else f'{parts[0]}.'
|
outp = '' if s.startswith(prefix) else f'{parts[0]}.'
|
||||||
for part in parts[1:]:
|
for part in parts[1:]:
|
||||||
|
# ignore '_t' type postfix
|
||||||
if (part != 't'):
|
if (part != 't'):
|
||||||
outp += part.capitalize()
|
outp += part.capitalize()
|
||||||
return outp
|
return outp
|
||||||
|
@ -135,42 +141,20 @@ def as_zig_enum_type(s, prefix):
|
||||||
outp += part.capitalize()
|
outp += part.capitalize()
|
||||||
return outp
|
return outp
|
||||||
|
|
||||||
def check_type_override(func_or_struct_name, field_or_arg_name, orig_type):
|
def check_override(name, default=None):
|
||||||
s = f"{func_or_struct_name}.{field_or_arg_name}"
|
if name in overrides:
|
||||||
if s in type_overrides:
|
return overrides[name]
|
||||||
return type_overrides[s]
|
elif default is None:
|
||||||
else:
|
|
||||||
return orig_type
|
|
||||||
|
|
||||||
def check_name_override(name):
|
|
||||||
if name in name_overrides:
|
|
||||||
return name_overrides[name]
|
|
||||||
else:
|
|
||||||
return name
|
return name
|
||||||
|
else:
|
||||||
|
return default
|
||||||
|
|
||||||
def check_name_ignore(name):
|
def check_ignore(name):
|
||||||
return name in name_ignores
|
return name in 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
|
|
||||||
|
|
||||||
# PREFIX_ENUM_BLA => Bla, _PREFIX_ENUM_BLA => Bla
|
# PREFIX_ENUM_BLA => Bla, _PREFIX_ENUM_BLA => Bla
|
||||||
def as_enum_item_name(s):
|
def as_enum_item_name(s):
|
||||||
outp = s
|
outp = s.lstrip('_')
|
||||||
if outp.startswith('_'):
|
|
||||||
outp = outp[1:]
|
|
||||||
parts = outp.split('_')[2:]
|
parts = outp.split('_')[2:]
|
||||||
outp = '_'.join(parts)
|
outp = '_'.join(parts)
|
||||||
if outp[0].isdigit():
|
if outp[0].isdigit():
|
||||||
|
@ -189,15 +173,6 @@ def is_struct_type(s):
|
||||||
def is_enum_type(s):
|
def is_enum_type(s):
|
||||||
return s in enum_types
|
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):
|
def is_const_prim_ptr(s):
|
||||||
for prim_type in prim_types:
|
for prim_type in prim_types:
|
||||||
if s == f"const {prim_type} *":
|
if s == f"const {prim_type} *":
|
||||||
|
@ -216,32 +191,10 @@ def is_const_struct_ptr(s):
|
||||||
return True
|
return True
|
||||||
return False
|
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):
|
def type_default_value(s):
|
||||||
return prim_defaults[s]
|
return prim_defaults[s]
|
||||||
|
|
||||||
def extract_array_type(s):
|
def as_c_arg_type(arg_type, prefix):
|
||||||
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":
|
if arg_type == "void":
|
||||||
return "void"
|
return "void"
|
||||||
elif is_prim_type(arg_type):
|
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)
|
return as_zig_struct_type(arg_type, prefix)
|
||||||
elif is_enum_type(arg_type):
|
elif is_enum_type(arg_type):
|
||||||
return as_zig_enum_type(arg_type, prefix)
|
return as_zig_enum_type(arg_type, prefix)
|
||||||
elif is_void_ptr(arg_type):
|
elif util.is_void_ptr(arg_type):
|
||||||
return "?*c_void"
|
return "?*anyopaque"
|
||||||
elif is_const_void_ptr(arg_type):
|
elif util.is_const_void_ptr(arg_type):
|
||||||
return "?*const c_void"
|
return "?*const anyopaque"
|
||||||
elif is_string_ptr(arg_type):
|
elif util.is_string_ptr(arg_type):
|
||||||
return "[*c]const u8"
|
return "[*c]const u8"
|
||||||
elif is_const_struct_ptr(arg_type):
|
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):
|
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):
|
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:
|
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):
|
def as_zig_arg_type(arg_prefix, arg_type, prefix):
|
||||||
# NOTE: if arg_prefix is None, the result is used as return value
|
# 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)
|
return pre + as_zig_struct_type(arg_type, prefix)
|
||||||
elif is_enum_type(arg_type):
|
elif is_enum_type(arg_type):
|
||||||
return pre + as_zig_enum_type(arg_type, prefix)
|
return pre + as_zig_enum_type(arg_type, prefix)
|
||||||
elif is_void_ptr(arg_type):
|
elif util.is_void_ptr(arg_type):
|
||||||
return pre + "?*c_void"
|
return pre + "?*anyopaque"
|
||||||
elif is_const_void_ptr(arg_type):
|
elif util.is_const_void_ptr(arg_type):
|
||||||
return pre + "?*const c_void"
|
return pre + "?*const anyopaque"
|
||||||
elif is_string_ptr(arg_type):
|
elif util.is_string_ptr(arg_type):
|
||||||
return pre + "[:0]const u8"
|
return pre + "[:0]const u8"
|
||||||
elif is_const_struct_ptr(arg_type):
|
elif is_const_struct_ptr(arg_type):
|
||||||
# not a bug, pass const structs by value
|
# 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):
|
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):
|
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:
|
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
|
# get C-style arguments of a function pointer as string
|
||||||
def funcptr_args_c(field_type, prefix):
|
def funcptr_args_c(field_type, prefix):
|
||||||
|
@ -303,22 +259,24 @@ def funcptr_args_c(field_type, prefix):
|
||||||
arg_type = token.strip()
|
arg_type = token.strip()
|
||||||
if s != "":
|
if s != "":
|
||||||
s += ", "
|
s += ", "
|
||||||
c_arg = as_extern_c_arg_type(arg_type, prefix)
|
c_arg = as_c_arg_type(arg_type, prefix)
|
||||||
if (c_arg == "void"):
|
if c_arg == "void":
|
||||||
return ""
|
return ""
|
||||||
else:
|
else:
|
||||||
s += c_arg
|
s += c_arg
|
||||||
return s
|
return s
|
||||||
|
|
||||||
# get C-style result of a function pointer as string
|
# 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()
|
res_type = field_type[:field_type.index('(*)')].strip()
|
||||||
if res_type == 'void':
|
if res_type == 'void':
|
||||||
return 'void'
|
return 'void'
|
||||||
elif is_const_void_ptr(res_type):
|
elif util.is_const_void_ptr(res_type):
|
||||||
return '?*const c_void'
|
return '?*const anyopaque'
|
||||||
|
elif util.is_void_ptr(res_type):
|
||||||
|
return '?*anyopaque'
|
||||||
else:
|
else:
|
||||||
return '???'
|
sys.exit(f"ERROR funcptr_result_c(): {field_type}")
|
||||||
|
|
||||||
def funcdecl_args_c(decl, prefix):
|
def funcdecl_args_c(decl, prefix):
|
||||||
s = ""
|
s = ""
|
||||||
|
@ -327,8 +285,8 @@ def funcdecl_args_c(decl, prefix):
|
||||||
if s != "":
|
if s != "":
|
||||||
s += ", "
|
s += ", "
|
||||||
param_name = param_decl['name']
|
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 += as_extern_c_arg_type(param_type, prefix)
|
s += as_c_arg_type(param_type, prefix)
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def funcdecl_args_zig(decl, prefix):
|
def funcdecl_args_zig(decl, prefix):
|
||||||
|
@ -338,55 +296,49 @@ def funcdecl_args_zig(decl, prefix):
|
||||||
if s != "":
|
if s != "":
|
||||||
s += ", "
|
s += ", "
|
||||||
param_name = param_decl['name']
|
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)}"
|
s += f"{as_zig_arg_type(f'{param_name}: ', param_type, prefix)}"
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def funcdecl_result_c(decl, prefix):
|
def funcdecl_result_c(decl, prefix):
|
||||||
func_name = decl['name']
|
func_name = decl['name']
|
||||||
decl_type = decl['type']
|
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())
|
||||||
return as_extern_c_arg_type(result_type, prefix)
|
return as_c_arg_type(result_type, prefix)
|
||||||
|
|
||||||
def funcdecl_result_zig(decl, prefix):
|
def funcdecl_result_zig(decl, prefix):
|
||||||
func_name = decl['name']
|
func_name = decl['name']
|
||||||
decl_type = decl['type']
|
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)
|
zig_res_type = as_zig_arg_type(None, result_type, prefix)
|
||||||
if zig_res_type == "":
|
|
||||||
zig_res_type = "void"
|
|
||||||
return zig_res_type
|
return zig_res_type
|
||||||
|
|
||||||
def gen_struct(decl, prefix, callconvc_funcptrs = True, use_raw_name=False, use_extern=True):
|
def gen_struct(decl, prefix):
|
||||||
struct_name = decl['name']
|
struct_name = check_override(decl['name'])
|
||||||
zig_type = struct_name if use_raw_name else as_zig_struct_type(struct_name, prefix)
|
zig_type = as_zig_struct_type(struct_name, prefix)
|
||||||
l(f"pub const {zig_type} = {'extern ' if use_extern else ''}struct {{")
|
l(f"pub const {zig_type} = extern struct {{")
|
||||||
for field in decl['fields']:
|
for field in decl['fields']:
|
||||||
field_name = field['name']
|
field_name = check_override(field['name'])
|
||||||
field_type = field['type']
|
field_type = check_override(f'{struct_name}.{field_name}', default=field['type'])
|
||||||
field_type = check_type_override(struct_name, field_name, field_type)
|
|
||||||
if is_prim_type(field_type):
|
if is_prim_type(field_type):
|
||||||
l(f" {field_name}: {as_zig_prim_type(field_type)} = {type_default_value(field_type)},")
|
l(f" {field_name}: {as_zig_prim_type(field_type)} = {type_default_value(field_type)},")
|
||||||
elif is_struct_type(field_type):
|
elif is_struct_type(field_type):
|
||||||
l(f" {field_name}: {as_zig_struct_type(field_type, prefix)} = .{{ }},")
|
l(f" {field_name}: {as_zig_struct_type(field_type, prefix)} = .{{ }},")
|
||||||
elif is_enum_type(field_type):
|
elif is_enum_type(field_type):
|
||||||
l(f" {field_name}: {as_zig_enum_type(field_type, prefix)} = .{enum_default_item(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,")
|
l(f" {field_name}: [*c]const u8 = null,")
|
||||||
elif is_const_void_ptr(field_type):
|
elif util.is_const_void_ptr(field_type):
|
||||||
l(f" {field_name}: ?*const c_void = null,")
|
l(f" {field_name}: ?*const anyopaque = null,")
|
||||||
elif is_void_ptr(field_type):
|
elif util.is_void_ptr(field_type):
|
||||||
l(f" {field_name}: ?*c_void = null,")
|
l(f" {field_name}: ?*anyopaque = null,")
|
||||||
elif is_const_prim_ptr(field_type):
|
elif is_const_prim_ptr(field_type):
|
||||||
l(f" {field_name}: ?[*]const {as_zig_prim_type(extract_ptr_type(field_type))} = null,")
|
l(f" {field_name}: ?[*]const {as_zig_prim_type(util.extract_ptr_type(field_type))} = null,")
|
||||||
elif is_func_ptr(field_type):
|
elif util.is_func_ptr(field_type):
|
||||||
if callconvc_funcptrs:
|
l(f" {field_name}: ?*const fn({funcptr_args_c(field_type, prefix)}) callconv(.C) {funcptr_result_c(field_type)} = null,")
|
||||||
l(f" {field_name}: ?fn({funcptr_args_c(field_type, prefix)}) callconv(.C) {funcptr_res_c(field_type)} = null,")
|
elif util.is_1d_array_type(field_type):
|
||||||
else:
|
array_type = util.extract_array_type(field_type)
|
||||||
l(f" {field_name}: ?fn({funcptr_args_c(field_type, prefix)}) {funcptr_res_c(field_type)} = null,")
|
array_sizes = util.extract_array_sizes(field_type)
|
||||||
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) or is_struct_type(array_type):
|
||||||
if is_prim_type(array_type):
|
if is_prim_type(array_type):
|
||||||
zig_type = as_zig_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)
|
zig_type = as_zig_enum_type(array_type, prefix)
|
||||||
def_val = '.{}'
|
def_val = '.{}'
|
||||||
else:
|
else:
|
||||||
zig_type = '??? (array type)'
|
sys.exit(f"ERROR gen_struct is_1d_array_type: {array_type}")
|
||||||
def_val = '???'
|
t0 = f"[{array_sizes[0]}]{zig_type}"
|
||||||
t0 = f"[{array_nums[0]}]{zig_type}"
|
|
||||||
t0_slice = f"[]const {zig_type}"
|
|
||||||
t1 = f"[_]{zig_type}"
|
t1 = f"[_]{zig_type}"
|
||||||
l(f" {field_name}: {t0} = {t1}{{{def_val}}} ** {array_nums[0]},")
|
l(f" {field_name}: {t0} = {t1}{{{def_val}}} ** {array_sizes[0]},")
|
||||||
elif is_const_void_ptr(array_type):
|
elif util.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}: [{array_sizes[0]}]?*const anyopaque = [_]?*const anyopaque {{ null }} ** {array_sizes[0]},")
|
||||||
else:
|
else:
|
||||||
l(f"// FIXME: ??? array {field_name}: {field_type} => {array_type} [{array_nums[0]}]")
|
sys.exit(f"ERROR gen_struct: array {field_name}: {field_type} => {array_type} [{array_sizes[0]}]")
|
||||||
elif is_2d_array_type(field_type):
|
elif util.is_2d_array_type(field_type):
|
||||||
array_type = extract_array_type(field_type)
|
array_type = util.extract_array_type(field_type)
|
||||||
array_nums = extract_array_nums(field_type)
|
array_sizes = util.extract_array_sizes(field_type)
|
||||||
if is_prim_type(array_type):
|
if is_prim_type(array_type):
|
||||||
zig_type = as_zig_prim_type(array_type)
|
zig_type = as_zig_prim_type(array_type)
|
||||||
def_val = type_default_value(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)
|
zig_type = as_zig_struct_type(array_type, prefix)
|
||||||
def_val = ".{ }"
|
def_val = ".{ }"
|
||||||
else:
|
else:
|
||||||
zig_type = "???"
|
sys.exit(f"ERROR gen_struct is_2d_array_type: {array_type}")
|
||||||
def_val = "???"
|
t0 = f"[{array_sizes[0]}][{array_sizes[1]}]{zig_type}"
|
||||||
t0 = f"[{array_nums[0]}][{array_nums[1]}]{zig_type}"
|
l(f" {field_name}: {t0} = [_][{array_sizes[1]}]{zig_type}{{[_]{zig_type}{{ {def_val} }}**{array_sizes[1]}}}**{array_sizes[0]},")
|
||||||
l(f" {field_name}: {t0} = [_][{array_nums[1]}]{zig_type}{{[_]{zig_type}{{ {def_val} }}**{array_nums[1]}}}**{array_nums[0]},")
|
|
||||||
else:
|
else:
|
||||||
l(f"// FIXME: {field_name}: {field_type};")
|
sys.exit(f"ERROR gen_struct: {field_name}: {field_type};")
|
||||||
l("};")
|
l("};")
|
||||||
|
|
||||||
def gen_consts(decl, prefix):
|
def gen_consts(decl, prefix):
|
||||||
for item in decl['items']:
|
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):
|
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']:
|
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 item_name != "FORCE_U32":
|
||||||
if 'value' in item:
|
if 'value' in item:
|
||||||
l(f" {item_name} = {item['value']},")
|
l(f" {item_name} = {item['value']},")
|
||||||
|
@ -446,27 +397,36 @@ def gen_func_c(decl, prefix):
|
||||||
|
|
||||||
def gen_func_zig(decl, prefix):
|
def gen_func_zig(decl, prefix):
|
||||||
c_func_name = decl['name']
|
c_func_name = decl['name']
|
||||||
zig_func_name = as_camel_case(check_name_override(decl['name']))
|
zig_func_name = util.as_lower_camel_case(check_override(decl['name']), prefix)
|
||||||
zig_res_type = funcdecl_result_zig(decl, prefix)
|
if c_func_name in c_callbacks:
|
||||||
l(f"pub fn {zig_func_name}({funcdecl_args_zig(decl, prefix)}) {zig_res_type} {{")
|
# a simple forwarded C callback function
|
||||||
if zig_res_type != 'void':
|
l(f"pub const {zig_func_name} = {c_func_name};")
|
||||||
s = f" return {c_func_name}("
|
|
||||||
else:
|
else:
|
||||||
s = f" {c_func_name}("
|
zig_res_type = funcdecl_result_zig(decl, prefix)
|
||||||
for i, param_decl in enumerate(decl['params']):
|
l(f"pub fn {zig_func_name}({funcdecl_args_zig(decl, prefix)}) {zig_res_type} {{")
|
||||||
if i > 0:
|
if is_zig_string(zig_res_type):
|
||||||
s += ", "
|
# special case: convert C string to Zig string slice
|
||||||
arg_name = param_decl['name']
|
s = f" return cStrToZig({c_func_name}("
|
||||||
arg_type = param_decl['type']
|
elif zig_res_type != 'void':
|
||||||
if is_const_struct_ptr(arg_type):
|
s = f" return {c_func_name}("
|
||||||
s += f"&{arg_name}"
|
|
||||||
elif is_string_ptr(arg_type):
|
|
||||||
s += f"@ptrCast([*c]const u8,{arg_name})"
|
|
||||||
else:
|
else:
|
||||||
s += arg_name
|
s = f" {c_func_name}("
|
||||||
s += ");"
|
for i, param_decl in enumerate(decl['params']):
|
||||||
l(s)
|
if i > 0:
|
||||||
l("}")
|
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):
|
def pre_parse(inp):
|
||||||
global struct_types
|
global struct_types
|
||||||
|
@ -483,12 +443,17 @@ def pre_parse(inp):
|
||||||
enum_items[enum_name].append(as_enum_item_name(item['name']))
|
enum_items[enum_name].append(as_enum_item_name(item['name']))
|
||||||
|
|
||||||
def gen_imports(inp, dep_prefixes):
|
def gen_imports(inp, dep_prefixes):
|
||||||
|
l('const builtin = @import("builtin");')
|
||||||
for dep_prefix in dep_prefixes:
|
for dep_prefix in dep_prefixes:
|
||||||
dep_module_name = module_names[dep_prefix]
|
dep_module_name = module_names[dep_prefix]
|
||||||
l(f'const {dep_prefix[:-1]} = @import("{dep_module_name}.zig");')
|
l(f'const {dep_prefix[:-1]} = @import("{dep_module_name}.zig");')
|
||||||
l('')
|
l('')
|
||||||
|
|
||||||
def gen_helpers(inp):
|
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_']:
|
if inp['prefix'] in ['sg_', 'sdtx_', 'sshape_']:
|
||||||
l('// helper function to convert "anything" to a Range struct')
|
l('// helper function to convert "anything" to a Range struct')
|
||||||
l('pub fn asRange(val: anytype) Range {')
|
l('pub fn asRange(val: anytype) Range {')
|
||||||
|
@ -502,7 +467,7 @@ def gen_helpers(inp):
|
||||||
l(' }')
|
l(' }')
|
||||||
l(' },')
|
l(' },')
|
||||||
l(' .Struct, .Array => {')
|
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(' },')
|
||||||
l(' else => {')
|
l(' else => {')
|
||||||
l(' @compileError("Cannot convert to range!");')
|
l(' @compileError("Cannot convert to range!");')
|
||||||
|
@ -547,7 +512,7 @@ def gen_module(inp, dep_prefixes):
|
||||||
kind = decl['kind']
|
kind = decl['kind']
|
||||||
if kind == 'consts':
|
if kind == 'consts':
|
||||||
gen_consts(decl, prefix)
|
gen_consts(decl, prefix)
|
||||||
elif not check_name_ignore(decl['name']):
|
elif not check_ignore(decl['name']):
|
||||||
if kind == 'struct':
|
if kind == 'struct':
|
||||||
gen_struct(decl, prefix)
|
gen_struct(decl, prefix)
|
||||||
elif kind == 'enum':
|
elif kind == 'enum':
|
||||||
|
@ -557,13 +522,16 @@ def gen_module(inp, dep_prefixes):
|
||||||
gen_func_zig(decl, prefix)
|
gen_func_zig(decl, prefix)
|
||||||
|
|
||||||
def prepare():
|
def prepare():
|
||||||
print('Generating zig bindings:')
|
print('=== Generating Zig bindings:')
|
||||||
if not os.path.isdir('sokol-zig/src/sokol'):
|
if not os.path.isdir('sokol-zig/src/sokol'):
|
||||||
os.makedirs('sokol-zig/src/sokol')
|
os.makedirs('sokol-zig/src/sokol')
|
||||||
if not os.path.isdir('sokol-zig/src/sokol/c'):
|
if not os.path.isdir('sokol-zig/src/sokol/c'):
|
||||||
os.makedirs('sokol-zig/src/sokol/c')
|
os.makedirs('sokol-zig/src/sokol/c')
|
||||||
|
|
||||||
def gen(c_header_path, c_prefix, dep_c_prefixes):
|
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]
|
module_name = module_names[c_prefix]
|
||||||
c_source_path = c_source_paths[c_prefix]
|
c_source_path = c_source_paths[c_prefix]
|
||||||
print(f' {c_header_path} => {module_name}')
|
print(f' {c_header_path} => {module_name}')
|
||||||
|
|
103
src/main.cc
103
src/main.cc
|
@ -9,6 +9,7 @@
|
||||||
#define SOKOL_IMPL
|
#define SOKOL_IMPL
|
||||||
#define SOKOL_GLCORE33
|
#define SOKOL_GLCORE33
|
||||||
#include "sokol_gfx.h"
|
#include "sokol_gfx.h"
|
||||||
|
#include "sokol_log.h"
|
||||||
#include "sokol_time.h"
|
#include "sokol_time.h"
|
||||||
#define SOKOL_GL_IMPL
|
#define SOKOL_GL_IMPL
|
||||||
#include "util/sokol_gl.h"
|
#include "util/sokol_gl.h"
|
||||||
|
@ -28,6 +29,7 @@ const int MaxVertices = (1 << 16);
|
||||||
const int MaxIndices = MaxVertices * 3;
|
const int MaxIndices = MaxVertices * 3;
|
||||||
|
|
||||||
uint64_t last_time = 0;
|
uint64_t last_time = 0;
|
||||||
|
const int cMSAASampleCount = 8;
|
||||||
|
|
||||||
sg_pass_action pass_action;
|
sg_pass_action pass_action;
|
||||||
sg_pipeline pip;
|
sg_pipeline pip;
|
||||||
|
@ -42,7 +44,6 @@ static void draw_imgui(ImDrawData*);
|
||||||
#define HANDMADE_MATH_IMPLEMENTATION
|
#define HANDMADE_MATH_IMPLEMENTATION
|
||||||
#define HANDMADE_MATH_NO_SSE
|
#define HANDMADE_MATH_NO_SSE
|
||||||
#include "HandmadeMath.h"
|
#include "HandmadeMath.h"
|
||||||
#include "camera.h"
|
|
||||||
|
|
||||||
// ozz-animation headers
|
// ozz-animation headers
|
||||||
#include <cmath> // fmodf
|
#include <cmath> // fmodf
|
||||||
|
@ -77,7 +78,7 @@ static struct {
|
||||||
struct {
|
struct {
|
||||||
double frame;
|
double frame;
|
||||||
double anim_update_time;
|
double anim_update_time;
|
||||||
float absolute;
|
double absolute;
|
||||||
uint64_t laptime;
|
uint64_t laptime;
|
||||||
float factor;
|
float factor;
|
||||||
float anim_ratio;
|
float anim_ratio;
|
||||||
|
@ -107,6 +108,7 @@ struct Viewport {
|
||||||
sg_pass_action pass_action = {};
|
sg_pass_action pass_action = {};
|
||||||
sg_pass pass = {};
|
sg_pass pass = {};
|
||||||
sg_pipeline pip = {};
|
sg_pipeline pip = {};
|
||||||
|
sgl_pipeline glpip = {};
|
||||||
sg_bindings bind = {};
|
sg_bindings bind = {};
|
||||||
sg_image color_image = {};
|
sg_image color_image = {};
|
||||||
sg_image depth_image = {};
|
sg_image depth_image = {};
|
||||||
|
@ -138,7 +140,7 @@ struct Viewport {
|
||||||
.width = this->size[0],
|
.width = this->size[0],
|
||||||
.height = this->size[1],
|
.height = this->size[1],
|
||||||
.pixel_format = SG_PIXELFORMAT_RGBA8,
|
.pixel_format = SG_PIXELFORMAT_RGBA8,
|
||||||
.sample_count = 4,
|
.sample_count = cMSAASampleCount,
|
||||||
.min_filter = SG_FILTER_LINEAR,
|
.min_filter = SG_FILTER_LINEAR,
|
||||||
.mag_filter = SG_FILTER_LINEAR,
|
.mag_filter = SG_FILTER_LINEAR,
|
||||||
.wrap_u = SG_WRAP_REPEAT,
|
.wrap_u = SG_WRAP_REPEAT,
|
||||||
|
@ -155,6 +157,14 @@ struct Viewport {
|
||||||
offscreen_pass_desc.label = "offscreen-pass";
|
offscreen_pass_desc.label = "offscreen-pass";
|
||||||
|
|
||||||
this->pass = sg_make_pass(&offscreen_pass_desc);
|
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 skel_data_buffer[4 * 1024];
|
||||||
static uint8_t anim_data_buffer[32 * 1024];
|
static uint8_t anim_data_buffer[32 * 1024];
|
||||||
|
|
||||||
static void draw_grid(void);
|
static void draw_grid();
|
||||||
static void draw_ui(void);
|
static void frame();
|
||||||
// static void skeleton_data_loaded(const sfetch_response_t* response);
|
|
||||||
// static void animation_data_loaded(const sfetch_response_t* response);
|
|
||||||
static void frame(void);
|
|
||||||
|
|
||||||
void handle_mouse(GLFWwindow* w, GuiInputState* io_input_state) {
|
void handle_mouse(GLFWwindow* w, GuiInputState* io_input_state) {
|
||||||
if (!glfwGetWindowAttrib(w, GLFW_FOCUSED)) {
|
if (!glfwGetWindowAttrib(w, GLFW_FOCUSED)) {
|
||||||
|
@ -414,6 +421,19 @@ void save_application_config(const char* filename) {
|
||||||
output_file.close();
|
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() {
|
int main() {
|
||||||
// window and GL context via GLFW and flextGL
|
// window and GL context via GLFW and flextGL
|
||||||
glfwInit();
|
glfwInit();
|
||||||
|
@ -423,7 +443,8 @@ int main() {
|
||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||||
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE);
|
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE);
|
||||||
glfwWindowHint(GLFW_SAMPLES, 16);
|
glfwWindowHint(GLFW_SAMPLES, 16);
|
||||||
GLFWwindow* w = glfwCreateWindow(Width, Height, "ATP Editor", 0, 0);
|
GLFWwindow* w =
|
||||||
|
glfwCreateWindow(Width, Height, "ATP Editor", nullptr, nullptr);
|
||||||
glfwMakeContextCurrent(w);
|
glfwMakeContextCurrent(w);
|
||||||
glfwSwapInterval(1);
|
glfwSwapInterval(1);
|
||||||
|
|
||||||
|
@ -476,16 +497,19 @@ int main() {
|
||||||
|
|
||||||
// setup sokol_gfx and sokol_time
|
// setup sokol_gfx and sokol_time
|
||||||
stm_setup();
|
stm_setup();
|
||||||
sg_desc desc = {};
|
sg_desc desc = {.logger = {.func = slog_func}};
|
||||||
sg_setup(&desc);
|
sg_setup(&desc);
|
||||||
assert(sg_isvalid());
|
assert(sg_isvalid());
|
||||||
|
|
||||||
// setup sokol-gl
|
// setup sokol-gl
|
||||||
sgl_desc_t sgldesc = {
|
sgl_desc_t sgldesc = {
|
||||||
.sample_count = 4
|
.sample_count = cMSAASampleCount,
|
||||||
};
|
.logger = sokol_logger};
|
||||||
sgl_setup(&sgldesc);
|
sgl_setup(&sgldesc);
|
||||||
|
|
||||||
|
// sgl_context_desc_t sgl_context_desc = {};
|
||||||
|
// sgl_context ctx = sgl_make_context(&sgl_context_desc);
|
||||||
|
|
||||||
SkinnedMeshResource skinned_mesh_resource;
|
SkinnedMeshResource skinned_mesh_resource;
|
||||||
skinned_mesh_resource.loadFromFile("../media/SampleSkinnedMesh.json");
|
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.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].blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA;
|
||||||
pip_desc.colors[0].write_mask = SG_COLORMASK_RGB;
|
pip_desc.colors[0].write_mask = SG_COLORMASK_RGB;
|
||||||
|
pip_desc.label = "imgui-rendering";
|
||||||
pip = sg_make_pipeline(&pip_desc);
|
pip = sg_make_pipeline(&pip_desc);
|
||||||
|
|
||||||
// initial clear color
|
// initial clear color
|
||||||
|
@ -625,7 +650,7 @@ int main() {
|
||||||
|
|
||||||
if (state.ozz.animation != nullptr) {
|
if (state.ozz.animation != nullptr) {
|
||||||
state.time.absolute =
|
state.time.absolute =
|
||||||
fmodf(state.time.absolute, state.ozz.animation->duration());
|
fmod(state.time.absolute, state.ozz.animation->duration());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update window state
|
// Update window state
|
||||||
|
@ -643,7 +668,6 @@ int main() {
|
||||||
glfwGetFramebufferSize(w, &cur_width, &cur_height);
|
glfwGetFramebufferSize(w, &cur_width, &cur_height);
|
||||||
|
|
||||||
// this is standard ImGui demo code
|
// this is standard ImGui demo code
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
io.DisplaySize = ImVec2(float(cur_width), float(cur_height));
|
io.DisplaySize = ImVec2(float(cur_width), float(cur_height));
|
||||||
io.DeltaTime = (float)stm_sec(stm_laptime(&last_time));
|
io.DeltaTime = (float)stm_sec(stm_laptime(&last_time));
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
@ -664,7 +688,7 @@ int main() {
|
||||||
&state.camera,
|
&state.camera,
|
||||||
offscreen_viewport.size[0],
|
offscreen_viewport.size[0],
|
||||||
offscreen_viewport.size[1],
|
offscreen_viewport.size[1],
|
||||||
state.time.frame,
|
static_cast<float>(state.time.frame),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
nullptr);
|
nullptr);
|
||||||
|
@ -703,7 +727,7 @@ int main() {
|
||||||
&state.camera,
|
&state.camera,
|
||||||
cur_width,
|
cur_width,
|
||||||
cur_height,
|
cur_height,
|
||||||
state.time.frame,
|
static_cast<float>(state.time.frame),
|
||||||
gGuiInputState.mousedX,
|
gGuiInputState.mousedX,
|
||||||
gGuiInputState.mousedY,
|
gGuiInputState.mousedY,
|
||||||
camera_accel);
|
camera_accel);
|
||||||
|
@ -769,22 +793,22 @@ int main() {
|
||||||
if (gApplicationConfig.viewport_widget.visible) {
|
if (gApplicationConfig.viewport_widget.visible) {
|
||||||
ImGui::SetNextWindowPos(
|
ImGui::SetNextWindowPos(
|
||||||
ImVec2(
|
ImVec2(
|
||||||
gApplicationConfig.viewport_widget.position[0],
|
static_cast<float>(
|
||||||
gApplicationConfig.viewport_widget.position[1]),
|
gApplicationConfig.viewport_widget.position[0]),
|
||||||
|
static_cast<float>(
|
||||||
|
gApplicationConfig.viewport_widget.position[1])),
|
||||||
ImGuiCond_FirstUseEver);
|
ImGuiCond_FirstUseEver);
|
||||||
ImGui::SetNextWindowSize(
|
ImGui::SetNextWindowSize(
|
||||||
ImVec2(
|
ImVec2(
|
||||||
gApplicationConfig.viewport_widget.size[0],
|
static_cast<float>(gApplicationConfig.viewport_widget.size[0]),
|
||||||
gApplicationConfig.viewport_widget.size[1]),
|
static_cast<float>(gApplicationConfig.viewport_widget.size[1])),
|
||||||
ImGuiCond_FirstUseEver);
|
ImGuiCond_FirstUseEver);
|
||||||
|
|
||||||
ImGui::Begin("Viewport", &gApplicationConfig.viewport_widget.visible);
|
ImGui::Begin("Viewport", &gApplicationConfig.viewport_widget.visible);
|
||||||
|
|
||||||
ImVec2 viewport_widget_size = ImGui::GetWindowSize();
|
ImVec2 viewport_widget_size = ImGui::GetWindowSize();
|
||||||
gApplicationConfig.viewport_widget.size[0] =
|
gApplicationConfig.viewport_widget.size[0] = viewport_widget_size.x;
|
||||||
viewport_widget_size.x;
|
gApplicationConfig.viewport_widget.size[1] = viewport_widget_size.y;
|
||||||
gApplicationConfig.viewport_widget.size[1] =
|
|
||||||
viewport_widget_size.y;
|
|
||||||
|
|
||||||
ImGui::Text(
|
ImGui::Text(
|
||||||
"Viewport size: %d, %d",
|
"Viewport size: %d, %d",
|
||||||
|
@ -795,15 +819,15 @@ int main() {
|
||||||
|
|
||||||
int* current_size = offscreen_viewport.size;
|
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]);
|
offscreen_viewport.Resize(content_size[0], content_size[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Image(
|
ImGui::Image(
|
||||||
(ImTextureID)(uintptr_t)offscreen_viewport.color_image.id,
|
(ImTextureID)(uintptr_t)offscreen_viewport.color_image.id,
|
||||||
ImVec2(
|
ImVec2(offscreen_viewport.size[0], offscreen_viewport.size[1]),
|
||||||
offscreen_viewport.size[0],
|
|
||||||
offscreen_viewport.size[1]),
|
|
||||||
ImVec2(0.0f, 1.0f),
|
ImVec2(0.0f, 1.0f),
|
||||||
ImVec2(1.0f, 0.0f));
|
ImVec2(1.0f, 0.0f));
|
||||||
|
|
||||||
|
@ -927,13 +951,16 @@ int main() {
|
||||||
if (state.ozz.animation != nullptr) {
|
if (state.ozz.animation != nullptr) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
ImGui::SliderFloat(
|
float time_absolute_float = static_cast<float>(state.time.absolute);
|
||||||
"Time",
|
if (ImGui::SliderFloat(
|
||||||
&state.time.absolute,
|
"Time",
|
||||||
0,
|
&time_absolute_float,
|
||||||
state.ozz.animation->duration(),
|
0,
|
||||||
"%.3f",
|
state.ozz.animation->duration(),
|
||||||
0);
|
"%.3f",
|
||||||
|
0)) {
|
||||||
|
state.time.absolute = time_absolute_float;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
@ -1012,8 +1039,9 @@ int main() {
|
||||||
ImGui::ShowDemoWindow();
|
ImGui::ShowDemoWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rendering of the offscreen scene
|
sgl_defaults();
|
||||||
sg_begin_pass(offscreen_viewport.pass, &offscreen_viewport.pass_action);
|
sg_begin_pass(offscreen_viewport.pass, &offscreen_viewport.pass_action);
|
||||||
|
sgl_load_pipeline(offscreen_viewport.glpip);
|
||||||
sgl_draw();
|
sgl_draw();
|
||||||
sg_end_pass();
|
sg_end_pass();
|
||||||
|
|
||||||
|
@ -1023,6 +1051,9 @@ int main() {
|
||||||
draw_imgui(ImGui::GetDrawData());
|
draw_imgui(ImGui::GetDrawData());
|
||||||
sg_end_pass();
|
sg_end_pass();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sg_commit();
|
sg_commit();
|
||||||
glfwSwapBuffers(w);
|
glfwSwapBuffers(w);
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
|
|
Loading…
Reference in New Issue