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