Updated ozz-animation to version 0.14.1 @35b2efd4

AnimGraphEditor
Martin Felis 2023-03-26 11:44:29 +02:00
parent bf3189ff49
commit 15871f349c
194 changed files with 3495 additions and 1957 deletions

View File

@ -10,3 +10,7 @@ The following authors have all licensed their contributions to ozz-animation und
- Andreas Streichardt <andreas.streichardt@gmail.com> - Andreas Streichardt <andreas.streichardt@gmail.com>
- Chen Junjie <kitchen.gz.020@gmail.com> - Chen Junjie <kitchen.gz.020@gmail.com>
- James W. Walker <jw@jwwalker.com> - James W. Walker <jw@jwwalker.com>
- James W. Fleming <jaemz@alum.mit.edu>
- Kota Iguchi <developer@infosia.co.jp>
- Mikołaj Siedlarek <mikolaj@siedlarek.net>
- Paul Gruenbacher <pgruenbacher@gmail.com>

View File

@ -1,3 +1,24 @@
Release version 0.14.0
----------------------
* Samples
- [sample_fbx2mesh] Supports vertices part of a skinned mesh but with a weight of 0.
- [sample_fbx2mesh] Assigns non-influenced vertices to root joint.
* Library
- [offline] #124 Fixes incorrect root joint detection bug in glTF importer.
- [offline] #129 #130 Copy animation name to output in ozz::animation::offline::AdditiveAnimationBuilder.
- [animation] #103 Allows move constructor and assignment for ozz::animation::Skeleton, ozz::animation::Animation and ozz::animation::Track.
- [animation] Renames SamplingCache to SamplingJob::Context.
- [animation] #110 Renames skeleton bind pose to rest pose, to avoid confusion with skinning bind pose.
- [base] Fixes Float4x4::FromEuler which was swapping pitch and roll.
* Build pipeline
- Moves CI to github actions.
- #59 Adds support for shared libraries on Windows (dll), Linux and MacOS platforms.
- #111 Removes _GLIBCXX_DEBUG from default build settings as it can create incompatibilities when using prebuilt packages.
- #122 #137 Adds support for gcc 11 compiler.
Release version 0.13.0 Release version 0.13.0
---------------------- ----------------------
@ -52,7 +73,7 @@ Release version 0.11.0
* Library * Library
- [animation] Adds two-bone and aim inverse kinematic solvers. They can be used at runtime to procedurally affect joint local-space transforms. - [animation] Adds two-bone and aim inverse kinematic solvers. They can be used at runtime to procedurally affect joint local-space transforms.
- [animation] Allows resizing SamplingCache, meaning the can be allocated without knowing the number of joints the cache needs to support. - [animation] Allows resizing SamplingJob::Context, meaning the can be allocated without knowing the number of joints the cache needs to support.
- [animation] Allow ozz::animation::LocalToModelJob to partially update a hierarchy, aka all children of a joint. This is useful when changes to a local-space pose has been limited to part of the joint hierarchy, like when applying IK or modifying model-space matrices independently from local-space transform. - [animation] Allow ozz::animation::LocalToModelJob to partially update a hierarchy, aka all children of a joint. This is useful when changes to a local-space pose has been limited to part of the joint hierarchy, like when applying IK or modifying model-space matrices independently from local-space transform.
- [animation] Changes ozz::animation::Skeleton joints from breadth-first to depth-first. This change breaks compatibility of previous ozz::animation::offline::RawAnimation, ozz::animation::Animation and ozz::animation::Skeleton archives. - [animation] Changes ozz::animation::Skeleton joints from breadth-first to depth-first. This change breaks compatibility of previous ozz::animation::offline::RawAnimation, ozz::animation::Animation and ozz::animation::Skeleton archives.
- [animation] Renames track_triggering_job_stl.h to track_triggering_job_trait.h. - [animation] Renames track_triggering_job_stl.h to track_triggering_job_trait.h.

View File

@ -5,11 +5,12 @@ project(ozz)
# Current version # Current version
set(OZZ_VERSION_MAJOR 0) set(OZZ_VERSION_MAJOR 0)
set(OZZ_VERSION_MINOR 13) set(OZZ_VERSION_MINOR 14)
set(OZZ_VERSION_PATCH 0) set(OZZ_VERSION_PATCH 0)
set(OZZ_VERSION ${OZZ_VERSION_MAJOR}.${OZZ_VERSION_MINOR}.${OZZ_VERSION_PATCH}) set(OZZ_VERSION ${OZZ_VERSION_MAJOR}.${OZZ_VERSION_MINOR}.${OZZ_VERSION_PATCH})
# Add project build options # Add project build options
option(BUILD_SHARED_LIBS "Build ozz as shared libraries" OFF)
option(ozz_build_tools "Build tools" ON) option(ozz_build_tools "Build tools" ON)
option(ozz_build_fbx "Build Fbx pipeline (Requires Fbx SDK)" ON) option(ozz_build_fbx "Build Fbx pipeline (Requires Fbx SDK)" ON)
option(ozz_build_gltf "Build glTF importer (Requires c++11)" ON) option(ozz_build_gltf "Build glTF importer (Requires c++11)" ON)
@ -18,8 +19,14 @@ option(ozz_build_samples "Build samples" ON)
option(ozz_build_howtos "Build howtos" ON) option(ozz_build_howtos "Build howtos" ON)
option(ozz_build_tests "Build unit tests" ON) option(ozz_build_tests "Build unit tests" ON)
option(ozz_build_simd_ref "Force SIMD math reference implementation" OFF) option(ozz_build_simd_ref "Force SIMD math reference implementation" OFF)
option(ozz_build_msvc_rt_dll "Select msvc DLL runtime library" ON)
option(ozz_build_postfix "Use per config postfix name" ON) option(ozz_build_postfix "Use per config postfix name" ON)
option(ozz_build_msvc_rt_dll "Select msvc DLL runtime library" OFF)
# Checks DLL flags
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()
# Include ozz cmake parameters and scripts # Include ozz cmake parameters and scripts
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)
@ -27,6 +34,7 @@ include(${PROJECT_SOURCE_DIR}/build-utils/cmake/compiler_settings.cmake)
include(${PROJECT_SOURCE_DIR}/build-utils/cmake/package_settings.cmake) include(${PROJECT_SOURCE_DIR}/build-utils/cmake/package_settings.cmake)
include(${PROJECT_SOURCE_DIR}/build-utils/cmake/fuse_target.cmake) include(${PROJECT_SOURCE_DIR}/build-utils/cmake/fuse_target.cmake)
include(${PROJECT_SOURCE_DIR}/build-utils/cmake/clang_format.cmake) include(${PROJECT_SOURCE_DIR}/build-utils/cmake/clang_format.cmake)
include(${PROJECT_SOURCE_DIR}/build-utils/cmake/shared_library.cmake)
# Add project execution options # Add project execution options
option(ozz_run_tests_headless "Run samples without rendering (used for unit tests)" ON) option(ozz_run_tests_headless "Run samples without rendering (used for unit tests)" ON)
@ -39,6 +47,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/build-utils/cm
if(ozz_build_tools AND ozz_build_fbx) if(ozz_build_tools AND ozz_build_fbx)
# Select a msvc runtime compatible with ozz_build_msvc_rt_dll # Select a msvc runtime compatible with ozz_build_msvc_rt_dll
set(FBX_SHARED ${BUILD_SHARED_LIBS})
set(FBX_MSVC_RT_DLL ${ozz_build_msvc_rt_dll}) set(FBX_MSVC_RT_DLL ${ozz_build_msvc_rt_dll})
# Search for FBX sdk package # Search for FBX sdk package
@ -49,6 +58,7 @@ if(ozz_build_tools AND ozz_build_fbx)
message("Fbx SDK not found, FBX tools libraries and samples will be skipped.") message("Fbx SDK not found, FBX tools libraries and samples will be skipped.")
set(ozz_build_fbx OFF) set(ozz_build_fbx OFF)
endif() endif()
else() else()
# Disables fbx if tools are disabled # Disables fbx if tools are disabled
set(ozz_build_fbx OFF) set(ozz_build_fbx OFF)
@ -75,6 +85,7 @@ file(MAKE_DIRECTORY ${ozz_temp_directory})
# Outputs selected options (can be modified by the command line) # Outputs selected options (can be modified by the command line)
message("-- ---------------------------------------------------------") message("-- ---------------------------------------------------------")
message("-- Selected options:") message("-- Selected options:")
message("-- - BUILD_SHARED_LIBS: " ${BUILD_SHARED_LIBS})
message("-- - ozz_build_tools: " ${ozz_build_tools}) message("-- - ozz_build_tools: " ${ozz_build_tools})
message("-- - ozz_build_fbx: " ${ozz_build_fbx}) message("-- - ozz_build_fbx: " ${ozz_build_fbx})
message("-- - ozz_build_gltf: " ${ozz_build_gltf}) message("-- - ozz_build_gltf: " ${ozz_build_gltf})

View File

@ -25,10 +25,10 @@ Samples, tools and tests depend on external libraries (glfw, tinygltf, Fbx SDK,
Build status Build status
------------ ------------
| | Linux | Mac OS | Windows | | | Linux | macOS | Windows |
| ------- | ------ | ------ | ------- | | ------- | ------ | ------ | ------- |
| master | [![Travis-CI](https://travis-ci.org/guillaumeblanc/ozz-animation.svg?branch=master)](http://travis-ci.org/guillaumeblanc/ozz-animation) | [![Travis-CI](https://travis-ci.org/guillaumeblanc/ozz-animation.svg?branch=master)](http://travis-ci.org/guillaumeblanc/ozz-animation) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/github/guillaumeblanc/ozz-animation?branch=master&svg=true)](http://ci.appveyor.com/project/guillaumeblanc/ozz-animation) | | master | [![Linux](https://github.com/guillaumeblanc/ozz-animation/actions/workflows/linux.yml/badge.svg?branch=master)](https://github.com/guillaumeblanc/ozz-animation/actions/workflows/linux.yml) | [![macOS](https://github.com/guillaumeblanc/ozz-animation/actions/workflows/macos.yml/badge.svg?branch=master)](https://github.com/guillaumeblanc/ozz-animation/actions/workflows/macos.yml) | [![Windows](https://github.com/guillaumeblanc/ozz-animation/actions/workflows/windows.yml/badge.svg?branch=master)](https://github.com/guillaumeblanc/ozz-animation/actions/workflows/windows.yml) |
| develop | [![Travis-CI](https://travis-ci.org/guillaumeblanc/ozz-animation.svg?branch=develop)](http://travis-ci.org/guillaumeblanc/ozz-animation) | [![Travis-CI](https://travis-ci.org/guillaumeblanc/ozz-animation.svg?branch=develop)](http://travis-ci.org/guillaumeblanc/ozz-animation) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/github/guillaumeblanc/ozz-animation?branch=develop&svg=true)](http://ci.appveyor.com/project/guillaumeblanc/ozz-animation) | | develop | [![Linux](https://github.com/guillaumeblanc/ozz-animation/actions/workflows/linux.yml/badge.svg?branch=develop)](https://github.com/guillaumeblanc/ozz-animation/actions/workflows/linux.yml) | [![macOS](https://github.com/guillaumeblanc/ozz-animation/actions/workflows/macos.yml/badge.svg?branch=develop)](https://github.com/guillaumeblanc/ozz-animation/actions/workflows/macos.yml) | [![Windows](https://github.com/guillaumeblanc/ozz-animation/actions/workflows/windows.yml/badge.svg?branch=develop)](https://github.com/guillaumeblanc/ozz-animation/actions/workflows/windows.yml) |
The dashboard for all branches is available [here](http://guillaumeblanc.github.io/ozz-animation/documentation/dashboard/). The dashboard for all branches is available [here](http://guillaumeblanc.github.io/ozz-animation/documentation/dashboard/).

View File

@ -30,33 +30,34 @@ set(cxx_all_flags
# Cross compiler compilation flags # Cross compiler compilation flags
# Requires C++11 # Requires C++11
set(CMAKE_CXX_STANDARD 11) if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11)
endif()
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_EXTENSIONS OFF)
# Simd math force ref # Simd math force ref
if(ozz_build_simd_ref) if(ozz_build_simd_ref)
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS OZZ_BUILD_SIMD_REF) add_compile_definitions(OZZ_BUILD_SIMD_REF)
endif() endif()
# Disables crt secure warnings
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
#-------------------------------------- #--------------------------------------
# Modify default MSVC compilation flags # Modify default MSVC compilation flags
if(MSVC) if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
#--------------------------- #---------------------------
# For the common build flags # For the common build flags
# Disables crt secure warnings
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS _CRT_SECURE_NO_WARNINGS)
# Adds support for multiple processes builds # Adds support for multiple processes builds
set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "/MP") add_compile_options(/MP)
# Set the warning level to W4 # Set the warning level to W4
set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "/W4") add_compile_options(/W4)
# Set warning as error # Set warning as error
set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "/WX") add_compile_options(/WX)
# Select whether to use the DLL version or the static library version of the Visual C++ runtime library. # Select whether to use the DLL version or the static library version of the Visual C++ runtime library.
foreach(flag ${cxx_all_flags}) foreach(flag ${cxx_all_flags})
@ -68,40 +69,35 @@ if(MSVC)
endforeach() endforeach()
#-------------------------------------- #--------------------------------------
# else consider the compiler as GCC compatible # else consider the compiler as GCC compatible (inc clang)
# Modify default GCC compilation flags
else() else()
# Set the warning level to Wall # Set the warning level to Wall
set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "-Wall") add_compile_options(-Wall)
# Enable extra level of warning # Enable extra level of warning
#set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "-Wextra") #add_compile_options(-Wextra)
# Set warning as error # Set warning as error
set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "-Werror") add_compile_options(-Werror)
# Disables warning: ignored-attributes reports issue when using _m128 as template argument # ignored-attributes reports issue when using _m128 as template argument
check_cxx_compiler_flag("-Wignored-attributes" W_IGNORED_ATTRIBUTES) check_cxx_compiler_flag("-Wignored-attributes" W_IGNORED_ATTRIBUTES)
if(W_IGNORED_ATTRIBUTES) if(W_IGNORED_ATTRIBUTES)
set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "-Wno-ignored-attributes") add_compile_options(-Wno-ignored-attributes)
endif() endif()
# Enables warning: sign comparison warnings # Disables c98 retrocompatibility warnings
check_cxx_compiler_flag("-Wsign-compare" W_SIGN_COMPARE) check_cxx_compiler_flag("-Wc++98-compat-pedantic" W_98_COMPAT_PEDANTIC)
if(W_SIGN_COMPARE) if(W_98_COMPAT_PEDANTIC)
set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "-Wsign-compare") add_compile_options(-Wno-c++98-compat-pedantic)
endif() endif()
# Check some more options availability for the targeted compiler
# Check some options availibity for the targetted compiler
check_cxx_compiler_flag("-Wnull-dereference" W_NULL_DEREFERENCE) check_cxx_compiler_flag("-Wnull-dereference" W_NULL_DEREFERENCE)
check_cxx_compiler_flag("-Wpragma-pack" W_PRAGMA_PACK) check_cxx_compiler_flag("-Wpragma-pack" W_PRAGMA_PACK)
# Enables debug glibcxx if NDebug isn't defined, not supported by APPLE
if(NOT APPLE)
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "$<$<CONFIG:Debug>:_GLIBCXX_DEBUG>")
endif()
#---------------------- #----------------------
# Sets emscripten output # Sets emscripten output
if(EMSCRIPTEN) if(EMSCRIPTEN)

View File

@ -9,11 +9,18 @@ function(fuse_target _target_name)
# Get all target sources. # Get all target sources.
get_property(target_source_files TARGET ${_target_name} PROPERTY SOURCES) get_property(target_source_files TARGET ${_target_name} PROPERTY SOURCES)
foreach(src_file ${target_source_files})
if(IS_ABSOLUTE ${src_file})
file(RELATIVE_PATH src_file ${CMAKE_CURRENT_LIST_DIR} ${src_file})
endif()
list(APPEND relative_target_source_files ${src_file})
endforeach()
add_custom_command( add_custom_command(
OUTPUT ${output_file} OUTPUT ${output_file}
DEPENDS ${target_source_files} DEPENDS ${target_source_files}
${PROJECT_SOURCE_DIR}/build-utils/cmake/fuse_target_script.cmake ${PROJECT_SOURCE_DIR}/build-utils/cmake/fuse_target_script.cmake
COMMAND ${CMAKE_COMMAND} -Dozz_fuse_output_file="${output_file}" -Dozz_target_source_files="${target_source_files}" -Dozz_fuse_target_dir="${CMAKE_CURRENT_LIST_DIR}" -Dozz_fuse_src_dir="${PROJECT_SOURCE_DIR}" -P "${PROJECT_SOURCE_DIR}/build-utils/cmake/fuse_target_script.cmake") COMMAND ${CMAKE_COMMAND} -Dozz_fuse_output_file="${output_file}" -Dozz_target_source_files="${relative_target_source_files}" -Dozz_fuse_target_dir="${CMAKE_CURRENT_LIST_DIR}" -Dozz_fuse_src_dir="${PROJECT_SOURCE_DIR}" -P "${PROJECT_SOURCE_DIR}/build-utils/cmake/fuse_target_script.cmake")
add_custom_target(BUILD_FUSE_${_target_name} ALL DEPENDS ${output_file}) add_custom_target(BUILD_FUSE_${_target_name} ALL DEPENDS ${output_file})
set_target_properties(BUILD_FUSE_${_target_name} PROPERTIES FOLDER "ozz/fuse") set_target_properties(BUILD_FUSE_${_target_name} PROPERTIES FOLDER "ozz/fuse")

View File

@ -2,18 +2,25 @@
#---------------------------------------------------------- #----------------------------------------------------------
# Start with new content # Start with new content
string(CONCAT output_content "" "// This file is autogenerated. Do not modify it.\n\n") string(CONCAT output_content "" "// This file is autogenerated. Any modification might be lost.\n\n")
# Patches arguments so that cmake interprate it as a list. # Patches arguments so that cmake take them as a list.
string (REPLACE " " ";" ozz_target_source_files "${ozz_target_source_files}") separate_arguments(ozz_target_source_files)
string(REPLACE "\\ " " " ozz_fuse_target_dir "${ozz_fuse_target_dir}")
string(REPLACE "\\ " " " ozz_fuse_src_dir "${ozz_fuse_src_dir}")
string(REPLACE "\\ " " " ozz_fuse_output_file "${ozz_fuse_output_file}")
# Concat all sources to the output. # Concat all sources to the output.
foreach(src_file ${ozz_target_source_files}) foreach(src_file ${ozz_target_source_files})
get_filename_component(src_file_ext ${src_file} EXT)
get_filename_component(absolute_src_file ${src_file} ABSOLUTE BASE_DIR ${ozz_fuse_target_dir})
get_filename_component(src_file_ext ${absolute_src_file} EXT)
# Handle source files. # Handle source files.
if(src_file_ext STREQUAL ".cc") if(src_file_ext STREQUAL ".cc")
file(READ "${ozz_fuse_target_dir}/${src_file}" src_file_content)
file(READ "${absolute_src_file}" src_file_content)
string(CONCAT output_content "${output_content}" "// Including ${src_file} file.\n\n") string(CONCAT output_content "${output_content}" "// Including ${src_file} file.\n\n")
string(CONCAT output_content "${output_content}" "${src_file_content}\n") string(CONCAT output_content "${output_content}" "${src_file_content}\n")
@ -28,10 +35,12 @@ foreach(internal_include_line ${internal_include_lines})
STRING(REGEX REPLACE "#include \"([^\"]+)\"" "\\1" internal_include_file "${internal_include_line}" ) STRING(REGEX REPLACE "#include \"([^\"]+)\"" "\\1" internal_include_file "${internal_include_line}" )
file(READ "${ozz_fuse_src_dir}/src/${internal_include_file}" internal_src_file_content) get_filename_component(internal_src_file src/${internal_include_file} ABSOLUTE BASE_DIR ${ozz_fuse_src_dir})
file(READ "${internal_src_file}" internal_src_file_content)
string(REPLACE "${internal_include_line}" "\n// Includes internal include file ${internal_include_file}\n\n${internal_src_file_content}" output_content "${output_content}") string(REPLACE "${internal_include_line}" "\n// Includes internal include file ${internal_include_file}\n\n${internal_src_file_content}" output_content "${output_content}")
endforeach() endforeach()
# Output new file
file(WRITE "${ozz_fuse_output_file}" "${output_content}") file(WRITE "${ozz_fuse_output_file}" "${output_content}")

View File

@ -9,9 +9,15 @@
# FBX_INCLUDE_DIRS - The Fbx SDK include directories # FBX_INCLUDE_DIRS - The Fbx SDK include directories
# FBX_LIBRARIES - The libraries needed to use Fbx SDK # FBX_LIBRARIES - The libraries needed to use Fbx SDK
# FBX_LIBRARIES_DEBUG - The libraries needed to use debug Fbx SDK # FBX_LIBRARIES_DEBUG - The libraries needed to use debug Fbx SDK
# FBX_SHARED_LIBRARIES - The shared library file (dll, so) to use Fbx
# FBX_SHARED_LIBRARIES_DEBUG - The shared library file (dll, so) to use debug
# Fbx SDK
#
# A cmake target named fbx::sdk is also created. Adding this target to your
# project via target_link_libraries will setup everything automatically.
# #
# It accepts the following variables as input: # It accepts the following variables as input:
# # FBX_SHARED - Optional. Select whether to use the shared version fbx sdk.
# FBX_MSVC_RT_DLL - Optional. Select whether to use the DLL version or the # FBX_MSVC_RT_DLL - Optional. Select whether to use the DLL version or the
# static library version of the Visual C++ runtime library. # static library version of the Visual C++ runtime library.
# Default is ON (aka, DLL version: /MD). # Default is ON (aka, DLL version: /MD).
@ -52,7 +58,7 @@
############################################################################### ###############################################################################
# Generic library search function definition # Generic library search function definition
############################################################################### ###############################################################################
function(FindFbxLibrariesGeneric _FBX_ROOT_DIR _OUT_FBX_LIBRARIES _OUT_FBX_LIBRARIES_DEBUG) function(FindFbxLibrariesGeneric _FBX_ROOT_DIR _OUT_FBX_LIBRARIES _OUT_FBX_LIBRARIES_DEBUG _OUT_FBX_SHARED_LIBRARIES _OUT_FBX_SHARED_LIBRARIES_DEBUG)
# Directory structure depends on the platform: # Directory structure depends on the platform:
# - Windows: \lib\<compiler_version>\<processor_type>\<build_mode> # - Windows: \lib\<compiler_version>\<processor_type>\<build_mode>
# - Mac OSX: \lib\<compiler_version>\ub\<processor_type>\<build_mode> # - Mac OSX: \lib\<compiler_version>\ub\<processor_type>\<build_mode>
@ -61,7 +67,9 @@ function(FindFbxLibrariesGeneric _FBX_ROOT_DIR _OUT_FBX_LIBRARIES _OUT_FBX_LIBRA
# Figures out matching compiler/os directory. # Figures out matching compiler/os directory.
if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10) if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.20)
set(FBX_CP_PATH "vs2019")
elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10)
set(FBX_CP_PATH "vs2017") set(FBX_CP_PATH "vs2017")
elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19) elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19)
set(FBX_CP_PATH "vs2015") set(FBX_CP_PATH "vs2015")
@ -90,8 +98,13 @@ function(FindFbxLibrariesGeneric _FBX_ROOT_DIR _OUT_FBX_LIBRARIES _OUT_FBX_LIBRA
endif() endif()
endif() endif()
# Set libraries names to search, sorted by preference. # Select whether to use the DLL version or the static library version of fbx sdk.
set(FBX_SEARCH_LIB_NAMES fbxsdk-static.a libfbxsdk.a fbxsdk.a) if (FBX_SHARED)
# Dynamic libraries
set(FBX_SEARCH_LIB_NAMES ${FBX_SEARCH_LIB_NAMES} libfbxsdk.lib libfbxsdk.dylib libfbxsdk.so)
else()
# static library names
set(FBX_SEARCH_LIB_NAMES ${FBX_SEARCH_LIB_NAMES} libfbxsdk.a libfbxsdk-static.a)
# Select whether to use the DLL version or the static library version of the Visual C++ runtime library. # Select whether to use the DLL version or the static library version of the Visual C++ runtime library.
# Default is "md", aka use the multithread DLL version of the run-time library. # Default is "md", aka use the multithread DLL version of the run-time library.
@ -100,9 +113,10 @@ function(FindFbxLibrariesGeneric _FBX_ROOT_DIR _OUT_FBX_LIBRARIES _OUT_FBX_LIBRA
else() else()
set(FBX_SEARCH_LIB_NAMES ${FBX_SEARCH_LIB_NAMES} libfbxsdk-mt.lib) set(FBX_SEARCH_LIB_NAMES ${FBX_SEARCH_LIB_NAMES} libfbxsdk-mt.lib)
endif() endif()
endif()
# Set search path. # Set search path.
set(FBX_SEARCH_LIB_PATH "${_FBX_ROOT_DIR}/lib/${FBX_CP_PATH}/${FBX_PROCESSOR_PATH}") set(FBX_SEARCH_LIB_PATH "${_FBX_ROOT_DIR}lib/${FBX_CP_PATH}/${FBX_PROCESSOR_PATH}")
find_library(FBX_LIB find_library(FBX_LIB
${FBX_SEARCH_LIB_NAMES} ${FBX_SEARCH_LIB_NAMES}
@ -114,21 +128,42 @@ function(FindFbxLibrariesGeneric _FBX_ROOT_DIR _OUT_FBX_LIBRARIES _OUT_FBX_LIBRA
${FBX_SEARCH_LIB_NAMES} ${FBX_SEARCH_LIB_NAMES}
HINTS "${FBX_SEARCH_LIB_PATH}/debug/") HINTS "${FBX_SEARCH_LIB_PATH}/debug/")
if(UNIX) # Looks for shared libraries
if(APPLE) # APPLE requires to link with Carbon framework if (FBX_SHARED)
find_library(CARBON_FRAMEWORK Carbon) set(FBX_SEARCH_SHARED_LIB_NAMES libfbxsdk.dll libfbxsdk.so libfbxsdk.dylib)
list(APPEND FBX_LIB ${CARBON_FRAMEWORK})
list(APPEND FBX_LIB_DEBUG ${CARBON_FRAMEWORK}) find_file(FBX_SHARED_LIB
${FBX_SEARCH_SHARED_LIB_NAMES}
HINTS "${FBX_SEARCH_LIB_PATH}/release/")
find_file(FBX_SHARED_LIB_DEBUG
${FBX_SEARCH_SHARED_LIB_NAMES}
HINTS "${FBX_SEARCH_LIB_PATH}/debug/")
set(${_OUT_FBX_SHARED_LIBRARIES} ${FBX_SHARED_LIB} PARENT_SCOPE)
set(${_OUT_FBX_SHARED_LIBRARIES_DEBUG} ${FBX_SHARED_LIB_DEBUG} PARENT_SCOPE)
endif()
# Create a target for a convenient use of the sdk with cmake
if(FBX_SHARED)
add_library(fbx::sdk SHARED IMPORTED GLOBAL)
set_property(TARGET fbx::sdk PROPERTY IMPORTED_LOCATION ${FBX_SHARED_LIB})
set_property(TARGET fbx::sdk PROPERTY IMPORTED_LOCATION_DEBUG ${FBX_SHARED_LIB_DEBUG})
set_property(TARGET fbx::sdk PROPERTY IMPORTED_IMPLIB ${FBX_LIB})
set_property(TARGET fbx::sdk PROPERTY IMPORTED_IMPLIB_DEBUG ${FBX_LIB_DEBUG})
target_compile_definitions(fbx::sdk INTERFACE FBXSDK_SHARED)
else() else()
find_package(Threads) add_library(fbx::sdk STATIC IMPORTED GLOBAL)
list(APPEND FBX_LIB ${CMAKE_THREAD_LIBS_INIT} dl) set_property(TARGET fbx::sdk PROPERTY IMPORTED_LOCATION ${FBX_LIB})
list(APPEND FBX_LIB_DEBUG ${CMAKE_THREAD_LIBS_INIT} dl) set_property(TARGET fbx::sdk PROPERTY IMPORTED_LOCATION_DEBUG ${FBX_LIB_DEBUG})
endif()
endif() endif()
target_include_directories(fbx::sdk INTERFACE "${_FBX_ROOT_DIR}include/")
target_compile_options(fbx::sdk
INTERFACE $<$<BOOL:${W_NULL_DEREFERENCE}>:-Wno-null-dereference>
INTERFACE $<$<BOOL:${W_PRAGMA_PACK}>:-Wno-pragma-pack>)
FindFbxVersion(${FBX_ROOT_DIR} PATH_VERSION) FindFbxVersion(${FBX_ROOT_DIR} PATH_VERSION)
# 2019 SDK needs to link against bundled libxml and zlib # 2019+ non-DLL SDK needs to link against bundled libxml and zlib
if(PATH_VERSION GREATER_EQUAL "2019.1") if(PATH_VERSION GREATER_EQUAL "2019.1")
if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
set(ADDITIONAL_LIB_SEARCH_PATH_RELEASE "${FBX_SEARCH_LIB_PATH}/release/") set(ADDITIONAL_LIB_SEARCH_PATH_RELEASE "${FBX_SEARCH_LIB_PATH}/release/")
@ -150,48 +185,71 @@ function(FindFbxLibrariesGeneric _FBX_ROOT_DIR _OUT_FBX_LIBRARIES _OUT_FBX_LIBRA
find_library(XML_LIB find_library(XML_LIB
${XML_SEARCH_LIB_NAMES} ${XML_SEARCH_LIB_NAMES}
HINTS ${ADDITIONAL_LIB_SEARCH_PATH_RELEASE}) HINTS ${ADDITIONAL_LIB_SEARCH_PATH_RELEASE})
find_library(Z_LIB
${Z_SEARCH_LIB_NAMES}
HINTS ${ADDITIONAL_LIB_SEARCH_PATH_RELEASE})
# Searches debug version also
find_library(XML_LIB_DEBUG find_library(XML_LIB_DEBUG
${XML_SEARCH_LIB_NAMES} ${XML_SEARCH_LIB_NAMES}
HINTS ${ADDITIONAL_LIB_SEARCH_PATH_DEBUG}) HINTS ${ADDITIONAL_LIB_SEARCH_PATH_DEBUG})
if(XML_LIB AND XML_LIB_DEBUG)
target_link_libraries(fbx::sdk INTERFACE optimized ${XML_LIB})
target_link_libraries(fbx::sdk INTERFACE debug ${XML_LIB_DEBUG})
else()
message(WARNING "FBX found but required libxml2 was not found!")
endif()
find_library(Z_LIB
${Z_SEARCH_LIB_NAMES}
HINTS ${ADDITIONAL_LIB_SEARCH_PATH_RELEASE})
find_library(Z_LIB_DEBUG find_library(Z_LIB_DEBUG
${Z_SEARCH_LIB_NAMES} ${Z_SEARCH_LIB_NAMES}
HINTS ${ADDITIONAL_LIB_SEARCH_PATH_DEBUG}) HINTS ${ADDITIONAL_LIB_SEARCH_PATH_DEBUG})
# for whatever reason on apple it will need iconv as well?! if(Z_LIB AND Z_LIB_DEBUG)
if(APPLE) target_link_libraries(fbx::sdk INTERFACE optimized ${Z_LIB})
find_library(ICONV_LIB target_link_libraries(fbx::sdk INTERFACE debug ${Z_LIB_DEBUG})
iconv) else()
# no special debug search here as mac only anyway
if(NOT ICONV_LIB)
message(WARNING "FBX found but required iconv was not found!")
endif()
list(APPEND FBX_LIB ${ICONV_LIB})
list(APPEND FBX_LIB_DEBUG ${ICONV_LIB})
endif()
if(NOT XML_LIB)
message(WARNING "FBX found but required libxml2 was not found!")
endif()
if(NOT Z_LIB)
message(WARNING "FBX found but required zlib was not found!") message(WARNING "FBX found but required zlib was not found!")
endif() endif()
list(APPEND FBX_LIB ${XML_LIB} ${Z_LIB}) list(APPEND FBX_LIB ${XML_LIB} ${Z_LIB})
list(APPEND FBX_LIB_DEBUG ${XML_LIB_DEBUG} ${Z_LIB_DEBUG}) list(APPEND FBX_LIB_DEBUG ${XML_LIB_DEBUG} ${Z_LIB_DEBUG})
endif() endif()
# Other dependencies.
if(APPLE)
find_library(ICONV_LIB iconv)
if(ICONV_LIB)
target_link_libraries(fbx::sdk INTERFACE ${ICONV_LIB})
list(APPEND FBX_LIB ${ICONV_LIB})
list(APPEND FBX_LIB_DEBUG ${ICONV_LIB})
else()
message(WARNING "FBX found but required iconv was not found!")
endif()
find_library(CARBON_FRAMEWORK Carbon)
if(CARBON_FRAMEWORK)
target_link_libraries(fbx::sdk INTERFACE ${CARBON_FRAMEWORK})
list(APPEND FBX_LIB ${CARBON_FRAMEWORK})
list(APPEND FBX_LIB_DEBUG ${CARBON_FRAMEWORK})
else()
message(WARNING "FBX found but required Carbon was not found!")
endif()
endif()
if(UNIX)
find_package(Threads)
target_link_libraries(fbx::sdk INTERFACE ${CMAKE_THREAD_LIBS_INIT} dl)
list(APPEND FBX_LIB ${CMAKE_THREAD_LIBS_INIT} dl)
list(APPEND FBX_LIB_DEBUG ${CMAKE_THREAD_LIBS_INIT} dl)
endif()
set(${_OUT_FBX_LIBRARIES} ${FBX_LIB} PARENT_SCOPE) set(${_OUT_FBX_LIBRARIES} ${FBX_LIB} PARENT_SCOPE)
set(${_OUT_FBX_LIBRARIES_DEBUG} ${FBX_LIB_DEBUG} PARENT_SCOPE) set(${_OUT_FBX_LIBRARIES_DEBUG} ${FBX_LIB_DEBUG} PARENT_SCOPE)
else() else()
message ("A Fbx SDK was found, but doesn't match your compiler settings.") message("A Fbx installation was found, but couldn't be matched with current compiler settings.")
endif() endif()
# Deduce fbx sdk version
endfunction() endfunction()
############################################################################### ###############################################################################
@ -257,7 +315,7 @@ if(FBX_INCLUDE_DIR)
set(FBX_INCLUDE_DIRS "${FBX_INCLUDE_DIR}/include") set(FBX_INCLUDE_DIRS "${FBX_INCLUDE_DIR}/include")
# Searches libraries according to the current compiler # Searches libraries according to the current compiler
FindFbxLibrariesGeneric(${FBX_ROOT_DIR} FBX_LIBRARIES FBX_LIBRARIES_DEBUG) FindFbxLibrariesGeneric(${FBX_ROOT_DIR} FBX_LIBRARIES FBX_LIBRARIES_DEBUG FBX_SHARED_LIBRARIES FBX_SHARED_LIBRARIES_DEBUG)
endif() endif()
# Handles find_package arguments and set FBX_FOUND to TRUE if all listed variables and version are valid. # Handles find_package arguments and set FBX_FOUND to TRUE if all listed variables and version are valid.

View File

@ -0,0 +1,48 @@
# Finds target dependencies on shared libraries so they can
# be copied next to the exe.
#----------------------------------------------------------
# Finds all target dependencies
function(get_link_libraries OUTPUT_LIST _TARGET)
get_target_property(LIBS ${_TARGET} LINK_LIBRARIES)
list(APPEND VISITED_TARGETS ${TARGET})
set(LIB_FILES "")
foreach(LIB ${LIBS})
if (TARGET ${LIB})
list(FIND VISITED_TARGETS ${LIB} VISITED)
if (${VISITED} EQUAL -1)
get_link_libraries(LINK_LIBS ${LIB})
list(APPEND LIB_FILES ${LIB} ${LINK_LIBS})
endif()
endif()
endforeach()
set(VISITED_TARGETS ${VISITED_TARGETS} PARENT_SCOPE)
set(${OUTPUT_LIST} ${LIB_FILES} PARENT_SCOPE)
endfunction()
# Copy dependent shared libraries next to executable target
function(target_copy_shared_libraries _TARGET)
get_link_libraries(LINKED_TARGETS ${_TARGET})
foreach(LINKED_TARGET ${LINKED_TARGETS})
get_target_property(TARGET_TYPE ${LINKED_TARGET} TYPE)
if(TARGET_TYPE STREQUAL "SHARED_LIBRARY")
list(APPEND DLL_TARGETS "$<TARGET_FILE:${LINKED_TARGET}>")
endif()
endforeach()
if(DLL_TARGETS)
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${_TARGET}_dll_copy"
DEPENDS ${DLL_TARGETS}
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DLL_TARGETS} "./"
COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_CURRENT_BINARY_DIR}/${_TARGET}_dll_copy"
VERBATIM)
# This allows to create a dependency with the command above, so command is executed again when target is built AND a DLL changed
target_sources(${_TARGET} PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/${_TARGET}_dll_copy")
endif()
endfunction()

View File

@ -1,4 +1,4 @@
add_library(gtest add_library(gtest STATIC
fused-src/gtest/gtest_main.cc fused-src/gtest/gtest_main.cc
fused-src/gtest/gtest-all.cc fused-src/gtest/gtest-all.cc
fused-src/gtest/gtest.h) fused-src/gtest/gtest.h)
@ -12,4 +12,3 @@ target_link_libraries(gtest
target_include_directories(gtest PUBLIC target_include_directories(gtest PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/extern/gtest/fused-src>) $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/extern/gtest/fused-src>)

View File

@ -7832,14 +7832,14 @@ static int ExecDeathTestChildMain(void* child_arg) {
// correct answer. // correct answer.
void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_; void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_;
void StackLowerThanAddress(const void* ptr, bool* result) { void StackLowerThanAddress(const void* ptr, bool* result) {
int dummy; int dummy = 0;
*result = (&dummy < ptr); *result = (&dummy < ptr);
} }
// Make sure AddressSanitizer does not tamper with the stack here. // Make sure AddressSanitizer does not tamper with the stack here.
GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
bool StackGrowsDown() { bool StackGrowsDown() {
int dummy; int dummy = 0;
bool result; bool result;
StackLowerThanAddress(&dummy, &result); StackLowerThanAddress(&dummy, &result);
return result; return result;

View File

@ -6,8 +6,18 @@ add_library(json
set_target_properties(json set_target_properties(json
PROPERTIES FOLDER "extern") PROPERTIES FOLDER "extern")
target_compile_definitions(json
PUBLIC $<$<BOOL:${BUILD_SHARED_LIBS}>:JSON_DLL>
PRIVATE $<$<BOOL:${BUILD_SHARED_LIBS}>:JSON_DLL_BUILD>)
set_target_properties(json set_target_properties(json
PROPERTIES COMPILE_OPTIONS $<$<CXX_COMPILER_ID:MSVC>:/wd4702>) PROPERTIES COMPILE_OPTIONS $<$<CXX_COMPILER_ID:MSVC>:/wd4702>)
set_target_properties(json
PROPERTIES COMPILE_OPTIONS $<$<CXX_COMPILER_ID:MSVC>:/wd4275>)
target_compile_options(json
PUBLIC $<$<CXX_COMPILER_ID:MSVC>:/wd4702>
PUBLIC $<$<CXX_COMPILER_ID:MSVC>:/wd4275>)
target_include_directories(json PUBLIC target_include_directories(json PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/extern/jsoncpp/dist>) $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/extern/jsoncpp/dist>)

View File

@ -416,7 +416,7 @@ public:
virtual ~Exception() throw(); virtual ~Exception() throw();
virtual char const* what() const throw(); virtual char const* what() const throw();
protected: protected:
void operator = (const Exception&); void operator = (const Exception&) = delete;
std::string const msg_; std::string const msg_;
}; };

View File

@ -4,6 +4,7 @@ add_executable(load_from_file
load_from_file.cc) load_from_file.cc)
target_link_libraries(load_from_file target_link_libraries(load_from_file
ozz_animation) ozz_animation)
target_copy_shared_libraries(load_from_file)
set_target_properties(load_from_file set_target_properties(load_from_file
PROPERTIES FOLDER "howtos") PROPERTIES FOLDER "howtos")
add_test(NAME load_from_file COMMAND load_from_file "${ozz_media_directory}/bin/pab_skeleton.ozz") add_test(NAME load_from_file COMMAND load_from_file "${ozz_media_directory}/bin/pab_skeleton.ozz")
@ -18,6 +19,7 @@ add_executable(custom_skeleton_importer
custom_skeleton_importer.cc) custom_skeleton_importer.cc)
target_link_libraries(custom_skeleton_importer target_link_libraries(custom_skeleton_importer
ozz_animation_offline) ozz_animation_offline)
target_copy_shared_libraries(custom_skeleton_importer)
set_target_properties(custom_skeleton_importer set_target_properties(custom_skeleton_importer
PROPERTIES FOLDER "howtos") PROPERTIES FOLDER "howtos")
add_test(NAME custom_skeleton_importer COMMAND custom_skeleton_importer) add_test(NAME custom_skeleton_importer COMMAND custom_skeleton_importer)
@ -28,6 +30,7 @@ add_executable(custom_animation_importer
custom_animation_importer.cc) custom_animation_importer.cc)
target_link_libraries(custom_animation_importer target_link_libraries(custom_animation_importer
ozz_animation_offline) ozz_animation_offline)
target_copy_shared_libraries(custom_animation_importer)
set_target_properties(custom_animation_importer set_target_properties(custom_animation_importer
PROPERTIES FOLDER "howtos") PROPERTIES FOLDER "howtos")
add_test(NAME custom_animation_importer COMMAND custom_animation_importer) add_test(NAME custom_animation_importer COMMAND custom_animation_importer)

View File

@ -25,13 +25,12 @@
// // // //
//----------------------------------------------------------------------------// //----------------------------------------------------------------------------//
#include <cstdlib>
#include "ozz/animation/offline/raw_skeleton.h" #include "ozz/animation/offline/raw_skeleton.h"
#include "ozz/animation/offline/skeleton_builder.h" #include "ozz/animation/offline/skeleton_builder.h"
#include "ozz/animation/runtime/skeleton.h" #include "ozz/animation/runtime/skeleton.h"
#include <cstdlib>
// Code for ozz-animation HowTo: "How to write a custon skeleton importer?" // Code for ozz-animation HowTo: "How to write a custon skeleton importer?"
int main(int argc, char const* argv[]) { int main(int argc, char const* argv[]) {
@ -52,7 +51,7 @@ int main(int argc, char const* argv[]) {
// Setup root joints name. // Setup root joints name.
root.name = "root"; root.name = "root";
// Setup root joints bind-pose/rest transformation, in joint local-space. // Setup root joints rest pose transformation, in joint local-space.
// This is the default skeleton posture (most of the time a T-pose). It's // This is the default skeleton posture (most of the time a T-pose). It's
// used as a fallback when there's no animation for a joint. // used as a fallback when there's no animation for a joint.
root.transform.translation = ozz::math::Float3(0.f, 1.f, 0.f); root.transform.translation = ozz::math::Float3(0.f, 1.f, 0.f);

View File

@ -28,6 +28,7 @@
#ifndef OZZ_OZZ_ANIMATION_OFFLINE_ADDITIVE_ANIMATION_BUILDER_H_ #ifndef OZZ_OZZ_ANIMATION_OFFLINE_ADDITIVE_ANIMATION_BUILDER_H_
#define OZZ_OZZ_ANIMATION_OFFLINE_ADDITIVE_ANIMATION_BUILDER_H_ #define OZZ_OZZ_ANIMATION_OFFLINE_ADDITIVE_ANIMATION_BUILDER_H_
#include "ozz/animation/offline/export.h"
#include "ozz/base/platform.h" #include "ozz/base/platform.h"
#include "ozz/base/span.h" #include "ozz/base/span.h"
@ -46,7 +47,7 @@ struct RawAnimation;
// Defines the class responsible for building a delta animation from an offline // Defines the class responsible for building a delta animation from an offline
// raw animation. This is used to create animations compatible with additive // raw animation. This is used to create animations compatible with additive
// blending. // blending.
class AdditiveAnimationBuilder { class OZZ_ANIMOFFLINE_DLL AdditiveAnimationBuilder {
public: public:
// Initializes the builder. // Initializes the builder.
AdditiveAnimationBuilder(); AdditiveAnimationBuilder();

View File

@ -28,6 +28,7 @@
#ifndef OZZ_OZZ_ANIMATION_OFFLINE_ANIMATION_BUILDER_H_ #ifndef OZZ_OZZ_ANIMATION_OFFLINE_ANIMATION_BUILDER_H_
#define OZZ_OZZ_ANIMATION_OFFLINE_ANIMATION_BUILDER_H_ #define OZZ_OZZ_ANIMATION_OFFLINE_ANIMATION_BUILDER_H_
#include "ozz/animation/offline/export.h"
#include "ozz/base/memory/unique_ptr.h" #include "ozz/base/memory/unique_ptr.h"
namespace ozz { namespace ozz {
@ -44,7 +45,7 @@ struct RawAnimation;
// Defines the class responsible of building runtime animation instances from // Defines the class responsible of building runtime animation instances from
// offline raw animations. // offline raw animations.
// No optimization at all is performed on the raw animation. // No optimization at all is performed on the raw animation.
class AnimationBuilder { class OZZ_ANIMOFFLINE_DLL AnimationBuilder {
public: public:
// Creates an Animation based on _raw_animation and *this builder parameters. // Creates an Animation based on _raw_animation and *this builder parameters.
// Returns a valid Animation on success. // Returns a valid Animation on success.

View File

@ -28,6 +28,7 @@
#ifndef OZZ_OZZ_ANIMATION_OFFLINE_ANIMATION_OPTIMIZER_H_ #ifndef OZZ_OZZ_ANIMATION_OFFLINE_ANIMATION_OPTIMIZER_H_
#define OZZ_OZZ_ANIMATION_OFFLINE_ANIMATION_OPTIMIZER_H_ #define OZZ_OZZ_ANIMATION_OFFLINE_ANIMATION_OPTIMIZER_H_
#include "ozz/animation/offline/export.h"
#include "ozz/base/containers/map.h" #include "ozz/base/containers/map.h"
namespace ozz { namespace ozz {
@ -54,7 +55,7 @@ struct RawAnimation;
// that leads to the hand if user wants it to be precise. Default optimization // that leads to the hand if user wants it to be precise. Default optimization
// tolerances are set in order to favor quality over runtime performances and // tolerances are set in order to favor quality over runtime performances and
// memory footprint. // memory footprint.
class AnimationOptimizer { class OZZ_ANIMOFFLINE_DLL AnimationOptimizer {
public: public:
// Initializes the optimizer with default tolerances (favoring quality). // Initializes the optimizer with default tolerances (favoring quality).
AnimationOptimizer(); AnimationOptimizer();
@ -89,7 +90,7 @@ class AnimationOptimizer {
float distance; float distance;
}; };
// Golbal optimization settings. These settings apply to all joints of the // Global optimization settings. These settings apply to all joints of the
// hierarchy, unless overriden by joint specific settings. // hierarchy, unless overriden by joint specific settings.
Setting setting; Setting setting;

View File

@ -0,0 +1,44 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_ANIMATION_OFFLINE_EXPORT_H_
#define OZZ_OZZ_ANIMATION_OFFLINE_EXPORT_H_
#if defined(_MSC_VER) && defined(OZZ_USE_DYNAMIC_LINKING)
#ifdef OZZ_BUILD_ANIMOFFLINE_LIB
// Import/Export for dynamic linking while building ozz
#define OZZ_ANIMOFFLINE_DLL __declspec(dllexport)
#else
#define OZZ_ANIMOFFLINE_DLL __declspec(dllimport)
#endif
#else // defined(_MSC_VER) && defined(OZZ_USE_DYNAMIC_LINKING)
// Static or non msvc linking
#define OZZ_ANIMOFFLINE_DLL
#endif // defined(_MSC_VER) && defined(OZZ_USE_DYNAMIC_LINKING)
#endif // OZZ_OZZ_ANIMATION_OFFLINE_EXPORT_H_

View File

@ -0,0 +1,44 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_ANIMATION_OFFLINE_FBX_EXPORT_H_
#define OZZ_OZZ_ANIMATION_OFFLINE_FBX_EXPORT_H_
#if defined(_MSC_VER) && defined(OZZ_USE_DYNAMIC_LINKING)
#ifdef OZZ_BUILD_ANIMATIONFBX_LIB
// Import/Export for dynamic linking while building ozz
#define OZZ_ANIMFBX_DLL __declspec(dllexport)
#else
#define OZZ_ANIMFBX_DLL __declspec(dllimport)
#endif
#else // defined(_MSC_VER) && defined(OZZ_USE_DYNAMIC_LINKING)
// Static or non msvc linking
#define OZZ_ANIMFBX_DLL
#endif // defined(_MSC_VER) && defined(OZZ_USE_DYNAMIC_LINKING)
#endif // OZZ_OZZ_ANIMATION_OFFLINE_FBX_EXPORT_H_

View File

@ -30,6 +30,7 @@
#include <fbxsdk.h> #include <fbxsdk.h>
#include "ozz/animation/offline/fbx/export.h"
#include "ozz/base/maths/simd_math.h" #include "ozz/base/maths/simd_math.h"
#include "ozz/base/maths/transform.h" #include "ozz/base/maths/transform.h"
@ -42,7 +43,7 @@ namespace offline {
namespace fbx { namespace fbx {
// Manages FbxManager instance. // Manages FbxManager instance.
class FbxManagerInstance { class OZZ_ANIMFBX_DLL FbxManagerInstance {
public: public:
// Instantiates FbxManager. // Instantiates FbxManager.
FbxManagerInstance(); FbxManagerInstance();
@ -58,7 +59,7 @@ class FbxManagerInstance {
}; };
// Default io settings used to import a scene. // Default io settings used to import a scene.
class FbxDefaultIOSettings { class OZZ_ANIMFBX_DLL FbxDefaultIOSettings {
public: public:
// Instantiates default settings. // Instantiates default settings.
explicit FbxDefaultIOSettings(const FbxManagerInstance& _manager); explicit FbxDefaultIOSettings(const FbxManagerInstance& _manager);
@ -77,13 +78,13 @@ class FbxDefaultIOSettings {
}; };
// Io settings used to import an animation from a scene. // Io settings used to import an animation from a scene.
class FbxAnimationIOSettings : public FbxDefaultIOSettings { class OZZ_ANIMFBX_DLL FbxAnimationIOSettings : public FbxDefaultIOSettings {
public: public:
FbxAnimationIOSettings(const FbxManagerInstance& _manager); FbxAnimationIOSettings(const FbxManagerInstance& _manager);
}; };
// Io settings used to import a skeleton from a scene. // Io settings used to import a skeleton from a scene.
class FbxSkeletonIOSettings : public FbxDefaultIOSettings { class OZZ_ANIMFBX_DLL FbxSkeletonIOSettings : public FbxDefaultIOSettings {
public: public:
FbxSkeletonIOSettings(const FbxManagerInstance& _manager); FbxSkeletonIOSettings(const FbxManagerInstance& _manager);
}; };
@ -94,7 +95,7 @@ class FbxSkeletonIOSettings : public FbxDefaultIOSettings {
// While Fbx sdk FbxAxisSystem::ConvertScene and FbxSystem::ConvertScene only // While Fbx sdk FbxAxisSystem::ConvertScene and FbxSystem::ConvertScene only
// affect scene root, this class functions can be used to bake nodes, vertices, // affect scene root, this class functions can be used to bake nodes, vertices,
// animations transformations... // animations transformations...
class FbxSystemConverter { class OZZ_ANIMFBX_DLL FbxSystemConverter {
public: public:
// Initialize converter with fbx scene systems. // Initialize converter with fbx scene systems.
FbxSystemConverter(const FbxAxisSystem& _from_axis, FbxSystemConverter(const FbxAxisSystem& _from_axis,
@ -133,7 +134,7 @@ class FbxSystemConverter {
}; };
// Loads a scene from a Fbx file. // Loads a scene from a Fbx file.
class FbxSceneLoader { class OZZ_ANIMFBX_DLL FbxSceneLoader {
public: public:
// Loads the scene that can then be obtained with scene() function. // Loads the scene that can then be obtained with scene() function.
FbxSceneLoader(const char* _filename, const char* _password, FbxSceneLoader(const char* _filename, const char* _password,

View File

@ -28,6 +28,8 @@
#ifndef OZZ_OZZ_ANIMATION_OFFLINE_FBX_FBX_ANIMATION_H_ #ifndef OZZ_OZZ_ANIMATION_OFFLINE_FBX_FBX_ANIMATION_H_
#define OZZ_OZZ_ANIMATION_OFFLINE_FBX_FBX_ANIMATION_H_ #define OZZ_OZZ_ANIMATION_OFFLINE_FBX_FBX_ANIMATION_H_
#include "ozz/animation/offline/fbx/export.h"
#include "ozz/animation/offline/fbx/fbx.h" #include "ozz/animation/offline/fbx/fbx.h"
#include "ozz/animation/offline/tools/import2ozz.h" #include "ozz/animation/offline/tools/import2ozz.h"
@ -51,34 +53,40 @@ struct RawquaternionTrack;
namespace fbx { namespace fbx {
OzzImporter::AnimationNames GetAnimationNames(FbxSceneLoader& _scene_loader); OZZ_ANIMFBX_DLL OzzImporter::AnimationNames GetAnimationNames(
FbxSceneLoader& _scene_loader);
bool ExtractAnimation(const char* _animation_name, OZZ_ANIMFBX_DLL bool ExtractAnimation(const char* _animation_name,
FbxSceneLoader& _scene_loader, const Skeleton& _skeleton, FbxSceneLoader& _scene_loader, const Skeleton& _skeleton,
float _sampling_rate, RawAnimation* _animation); float _sampling_rate, RawAnimation* _animation);
OzzImporter::NodeProperties GetNodeProperties(FbxSceneLoader& _scene_loader, OZZ_ANIMFBX_DLL OzzImporter::NodeProperties GetNodeProperties(
FbxSceneLoader& _scene_loader,
const char* _node_name); const char* _node_name);
bool ExtractTrack(const char* _animation_name, const char* _node_name, OZZ_ANIMFBX_DLL bool ExtractTrack(const char* _animation_name,
const char* _node_name,
const char* _track_name, const char* _track_name,
OzzImporter::NodeProperty::Type _type, OzzImporter::NodeProperty::Type _type,
FbxSceneLoader& _scene_loader, float _sampling_rate, FbxSceneLoader& _scene_loader, float _sampling_rate,
RawFloatTrack* _track); RawFloatTrack* _track);
bool ExtractTrack(const char* _animation_name, const char* _node_name, OZZ_ANIMFBX_DLL bool ExtractTrack(const char* _animation_name,
const char* _node_name,
const char* _track_name, const char* _track_name,
OzzImporter::NodeProperty::Type _type, OzzImporter::NodeProperty::Type _type,
FbxSceneLoader& _scene_loader, float _sampling_rate, FbxSceneLoader& _scene_loader, float _sampling_rate,
RawFloat2Track* _track); RawFloat2Track* _track);
bool ExtractTrack(const char* _animation_name, const char* _node_name, OZZ_ANIMFBX_DLL bool ExtractTrack(const char* _animation_name,
const char* _node_name,
const char* _track_name, const char* _track_name,
OzzImporter::NodeProperty::Type _type, OzzImporter::NodeProperty::Type _type,
FbxSceneLoader& _scene_loader, float _sampling_rate, FbxSceneLoader& _scene_loader, float _sampling_rate,
RawFloat3Track* _track); RawFloat3Track* _track);
bool ExtractTrack(const char* _animation_name, const char* _node_name, OZZ_ANIMFBX_DLL bool ExtractTrack(const char* _animation_name,
const char* _node_name,
const char* _track_name, const char* _track_name,
OzzImporter::NodeProperty::Type _type, OzzImporter::NodeProperty::Type _type,
FbxSceneLoader& _scene_loader, float _sampling_rate, FbxSceneLoader& _scene_loader, float _sampling_rate,

View File

@ -28,6 +28,7 @@
#ifndef OZZ_OZZ_ANIMATION_OFFLINE_FBX_FBX_SKELETON_H_ #ifndef OZZ_OZZ_ANIMATION_OFFLINE_FBX_FBX_SKELETON_H_
#define OZZ_OZZ_ANIMATION_OFFLINE_FBX_FBX_SKELETON_H_ #define OZZ_OZZ_ANIMATION_OFFLINE_FBX_FBX_SKELETON_H_
#include "ozz/animation/offline/fbx/export.h"
#include "ozz/animation/offline/fbx/fbx.h" #include "ozz/animation/offline/fbx/fbx.h"
#include "ozz/animation/offline/tools/import2ozz.h" #include "ozz/animation/offline/tools/import2ozz.h"
@ -39,7 +40,7 @@ struct RawSkeleton;
namespace fbx { namespace fbx {
bool ExtractSkeleton(FbxSceneLoader& _loader, OZZ_ANIMFBX_DLL bool ExtractSkeleton(FbxSceneLoader& _loader,
const OzzImporter::NodeType& _types, const OzzImporter::NodeType& _types,
RawSkeleton* _skeleton); RawSkeleton* _skeleton);

View File

@ -28,6 +28,7 @@
#ifndef OZZ_OZZ_ANIMATION_OFFLINE_RAW_ANIMATION_H_ #ifndef OZZ_OZZ_ANIMATION_OFFLINE_RAW_ANIMATION_H_
#define OZZ_OZZ_ANIMATION_OFFLINE_RAW_ANIMATION_H_ #define OZZ_OZZ_ANIMATION_OFFLINE_RAW_ANIMATION_H_
#include "ozz/animation/offline/export.h"
#include "ozz/base/containers/string.h" #include "ozz/base/containers/string.h"
#include "ozz/base/containers/vector.h" #include "ozz/base/containers/vector.h"
#include "ozz/base/io/archive_traits.h" #include "ozz/base/io/archive_traits.h"
@ -55,7 +56,7 @@ namespace offline {
// 3. Keyframes' time are all within [0,animation duration] range. // 3. Keyframes' time are all within [0,animation duration] range.
// Animations that would fail this validation will fail to be converted by the // Animations that would fail this validation will fail to be converted by the
// AnimationBuilder. // AnimationBuilder.
struct RawAnimation { struct OZZ_ANIMOFFLINE_DLL RawAnimation {
// Constructs a valid RawAnimation with a 1s default duration. // Constructs a valid RawAnimation with a 1s default duration.
RawAnimation(); RawAnimation();
@ -146,7 +147,7 @@ OZZ_IO_TYPE_TAG("ozz-raw_animation", animation::offline::RawAnimation)
// Should not be called directly but through io::Archive << and >> operators. // Should not be called directly but through io::Archive << and >> operators.
template <> template <>
struct Extern<animation::offline::RawAnimation> { struct OZZ_ANIMOFFLINE_DLL Extern<animation::offline::RawAnimation> {
static void Save(OArchive& _archive, static void Save(OArchive& _archive,
const animation::offline::RawAnimation* _animations, const animation::offline::RawAnimation* _animations,
size_t _count); size_t _count);

View File

@ -28,6 +28,7 @@
#ifndef OZZ_OZZ_ANIMATION_OFFLINE_RAW_ANIMATION_UTILS_H_ #ifndef OZZ_OZZ_ANIMATION_OFFLINE_RAW_ANIMATION_UTILS_H_
#define OZZ_OZZ_ANIMATION_OFFLINE_RAW_ANIMATION_UTILS_H_ #define OZZ_OZZ_ANIMATION_OFFLINE_RAW_ANIMATION_UTILS_H_
#include "ozz/animation/offline/export.h"
#include "ozz/animation/offline/raw_animation.h" #include "ozz/animation/offline/raw_animation.h"
#include "ozz/base/maths/transform.h" #include "ozz/base/maths/transform.h"
@ -38,22 +39,25 @@ namespace animation {
namespace offline { namespace offline {
// Translation interpolation method. // Translation interpolation method.
math::Float3 LerpTranslation(const math::Float3& _a, const math::Float3& _b, OZZ_ANIMOFFLINE_DLL math::Float3 LerpTranslation(const math::Float3& _a,
const math::Float3& _b,
float _alpha); float _alpha);
// Rotation interpolation method. // Rotation interpolation method.
math::Quaternion LerpRotation(const math::Quaternion& _a, OZZ_ANIMOFFLINE_DLL math::Quaternion LerpRotation(const math::Quaternion& _a,
const math::Quaternion& _b, float _alpha); const math::Quaternion& _b, float _alpha);
// Scale interpolation method. // Scale interpolation method.
math::Float3 LerpScale(const math::Float3& _a, const math::Float3& _b, OZZ_ANIMOFFLINE_DLL math::Float3 LerpScale(const math::Float3& _a,
const math::Float3& _b,
float _alpha); float _alpha);
// Samples a RawAnimation track. This function shall be used for offline // Samples a RawAnimation track. This function shall be used for offline
// purpose. Use ozz::animation::Animation and ozz::animation::SamplingJob for // purpose. Use ozz::animation::Animation and ozz::animation::SamplingJob for
// runtime purpose. // runtime purpose.
// Returns false if track is invalid. // Returns false if track is invalid.
bool SampleTrack(const RawAnimation::JointTrack& _track, float _time, OZZ_ANIMOFFLINE_DLL bool SampleTrack(const RawAnimation::JointTrack& _track,
float _time,
ozz::math::Transform* _transform); ozz::math::Transform* _transform);
// Samples a RawAnimation. This function shall be used for offline // Samples a RawAnimation. This function shall be used for offline
@ -61,7 +65,8 @@ bool SampleTrack(const RawAnimation::JointTrack& _track, float _time,
// runtime purpose. // runtime purpose.
// _animation must be valid. // _animation must be valid.
// Returns false output range is too small or animation is invalid. // Returns false output range is too small or animation is invalid.
bool SampleAnimation(const RawAnimation& _animation, float _time, OZZ_ANIMOFFLINE_DLL bool SampleAnimation(
const RawAnimation& _animation, float _time,
const span<ozz::math::Transform>& _transforms); const span<ozz::math::Transform>& _transforms);
// Implement fixed rate keyframe time iteration. This utility purpose is to // Implement fixed rate keyframe time iteration. This utility purpose is to
@ -69,7 +74,7 @@ bool SampleAnimation(const RawAnimation& _animation, float _time,
// between consecutive time samples have a fixed period. // between consecutive time samples have a fixed period.
// This sounds trivial, but floating point error could occur if keyframe time // This sounds trivial, but floating point error could occur if keyframe time
// was accumulated for a long duration. // was accumulated for a long duration.
class FixedRateSamplingTime { class OZZ_ANIMOFFLINE_DLL FixedRateSamplingTime {
public: public:
FixedRateSamplingTime(float _duration, float _frequency); FixedRateSamplingTime(float _duration, float _frequency);

View File

@ -28,6 +28,7 @@
#ifndef OZZ_OZZ_ANIMATION_OFFLINE_RAW_SKELETON_H_ #ifndef OZZ_OZZ_ANIMATION_OFFLINE_RAW_SKELETON_H_
#define OZZ_OZZ_ANIMATION_OFFLINE_RAW_SKELETON_H_ #define OZZ_OZZ_ANIMATION_OFFLINE_RAW_SKELETON_H_
#include "ozz/animation/offline/export.h"
#include "ozz/base/containers/string.h" #include "ozz/base/containers/string.h"
#include "ozz/base/containers/vector.h" #include "ozz/base/containers/vector.h"
#include "ozz/base/io/archive_traits.h" #include "ozz/base/io/archive_traits.h"
@ -41,13 +42,13 @@ namespace offline {
// This skeleton type is not intended to be used in run time. It is used to // This skeleton type is not intended to be used in run time. It is used to
// define the offline skeleton object that can be converted to the runtime // define the offline skeleton object that can be converted to the runtime
// skeleton using the SkeletonBuilder. This skeleton structure exposes joints' // skeleton using the SkeletonBuilder. This skeleton structure exposes joints'
// hierarchy. A joint is defined with a name, a transformation (its bind pose), // hierarchy. A joint is defined with a name, a transformation (its rest_pose
// and its children. Children are exposed as a public std::vector of joints. // pose), and its children. Children are exposed as a public std::vector of
// This same type is used for skeleton roots, also exposed from the public API. // joints. This same type is used for skeleton roots, also exposed from the
// The public API exposed through std:vector's of joints can be used freely with // public API. The public API exposed through std:vector's of joints can be used
// the only restriction that the total number of joints does not exceed // freely with the only restriction that the total number of joints does not
// Skeleton::kMaxJoints. // exceed Skeleton::kMaxJoints.
struct RawSkeleton { struct OZZ_ANIMOFFLINE_DLL RawSkeleton {
// Construct an empty skeleton. // Construct an empty skeleton.
RawSkeleton(); RawSkeleton();
@ -65,7 +66,7 @@ struct RawSkeleton {
// The name of the joint. // The name of the joint.
ozz::string name; ozz::string name;
// Joint bind pose transformation in local space. // Joint rest pose transformation in local space.
math::Transform transform; math::Transform transform;
}; };
@ -139,7 +140,7 @@ OZZ_IO_TYPE_TAG("ozz-raw_skeleton", animation::offline::RawSkeleton)
// Should not be called directly but through io::Archive << and >> operators. // Should not be called directly but through io::Archive << and >> operators.
template <> template <>
struct Extern<animation::offline::RawSkeleton> { struct OZZ_ANIMOFFLINE_DLL Extern<animation::offline::RawSkeleton> {
static void Save(OArchive& _archive, static void Save(OArchive& _archive,
const animation::offline::RawSkeleton* _skeletons, const animation::offline::RawSkeleton* _skeletons,
size_t _count); size_t _count);

View File

@ -28,11 +28,10 @@
#ifndef OZZ_OZZ_ANIMATION_OFFLINE_RAW_TRACK_H_ #ifndef OZZ_OZZ_ANIMATION_OFFLINE_RAW_TRACK_H_
#define OZZ_OZZ_ANIMATION_OFFLINE_RAW_TRACK_H_ #define OZZ_OZZ_ANIMATION_OFFLINE_RAW_TRACK_H_
#include "ozz/animation/offline/export.h"
#include "ozz/base/containers/string.h" #include "ozz/base/containers/string.h"
#include "ozz/base/containers/vector.h" #include "ozz/base/containers/vector.h"
#include "ozz/base/io/archive_traits.h" #include "ozz/base/io/archive_traits.h"
#include "ozz/base/maths/quaternion.h" #include "ozz/base/maths/quaternion.h"
#include "ozz/base/maths/vec_float.h" #include "ozz/base/maths/vec_float.h"
@ -85,7 +84,7 @@ namespace internal {
// RawTrack that would fail this validation will fail to be converted by // RawTrack that would fail this validation will fail to be converted by
// the RawTrackBuilder. // the RawTrackBuilder.
template <typename _ValueType> template <typename _ValueType>
struct RawTrack { struct OZZ_ANIMOFFLINE_DLL RawTrack {
typedef _ValueType ValueType; typedef _ValueType ValueType;
typedef RawTrackKeyframe<ValueType> Keyframe; typedef RawTrackKeyframe<ValueType> Keyframe;
@ -109,11 +108,15 @@ struct RawTrack {
} // namespace internal } // namespace internal
// Offline user-channel animation track type instantiation. // Offline user-channel animation track type instantiation.
struct RawFloatTrack : public internal::RawTrack<float> {}; struct OZZ_ANIMOFFLINE_DLL RawFloatTrack : public internal::RawTrack<float> {};
struct RawFloat2Track : public internal::RawTrack<math::Float2> {}; struct OZZ_ANIMOFFLINE_DLL RawFloat2Track
struct RawFloat3Track : public internal::RawTrack<math::Float3> {}; : public internal::RawTrack<math::Float2> {};
struct RawFloat4Track : public internal::RawTrack<math::Float4> {}; struct OZZ_ANIMOFFLINE_DLL RawFloat3Track
struct RawQuaternionTrack : public internal::RawTrack<math::Quaternion> {}; : public internal::RawTrack<math::Float3> {};
struct OZZ_ANIMOFFLINE_DLL RawFloat4Track
: public internal::RawTrack<math::Float4> {};
struct OZZ_ANIMOFFLINE_DLL RawQuaternionTrack
: public internal::RawTrack<math::Quaternion> {};
} // namespace offline } // namespace offline
} // namespace animation } // namespace animation

View File

@ -28,6 +28,7 @@
#ifndef OZZ_OZZ_ANIMATION_OFFLINE_SKELETON_BUILDER_H_ #ifndef OZZ_OZZ_ANIMATION_OFFLINE_SKELETON_BUILDER_H_
#define OZZ_OZZ_ANIMATION_OFFLINE_SKELETON_BUILDER_H_ #define OZZ_OZZ_ANIMATION_OFFLINE_SKELETON_BUILDER_H_
#include "ozz/animation/offline/export.h"
#include "ozz/base/maths/transform.h" #include "ozz/base/maths/transform.h"
#include "ozz/base/memory/unique_ptr.h" #include "ozz/base/memory/unique_ptr.h"
@ -43,7 +44,7 @@ namespace offline {
struct RawSkeleton; struct RawSkeleton;
// Defines the class responsible of building Skeleton instances. // Defines the class responsible of building Skeleton instances.
class SkeletonBuilder { class OZZ_ANIMOFFLINE_DLL SkeletonBuilder {
public: public:
// Creates a Skeleton based on _raw_skeleton and *this builder parameters. // Creates a Skeleton based on _raw_skeleton and *this builder parameters.
// Returns a Skeleton instance on success, an empty unique_ptr on failure. See // Returns a Skeleton instance on success, an empty unique_ptr on failure. See

View File

@ -0,0 +1,44 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_ANIMATION_OFFLINE_TOOLS_EXPORT_H_
#define OZZ_OZZ_ANIMATION_OFFLINE_TOOLS_EXPORT_H_
#if defined(_MSC_VER) && defined(OZZ_USE_DYNAMIC_LINKING)
#ifdef OZZ_BUILD_ANIMATIONTOOLS_LIB
// Import/Export for dynamic linking while building ozz
#define OZZ_ANIMTOOLS_DLL __declspec(dllexport)
#else
#define OZZ_ANIMTOOLS_DLL __declspec(dllimport)
#endif
#else // defined(_MSC_VER) && defined(OZZ_USE_DYNAMIC_LINKING)
// Static or non msvc linking
#define OZZ_ANIMTOOLS_DLL
#endif // defined(_MSC_VER) && defined(OZZ_USE_DYNAMIC_LINKING)
#endif // OZZ_OZZ_ANIMATION_OFFLINE_TOOLS_EXPORT_H_

View File

@ -28,6 +28,8 @@
#ifndef OZZ_OZZ_ANIMATION_OFFLINE_TOOLS_IMPORT2OZZ_H_ #ifndef OZZ_OZZ_ANIMATION_OFFLINE_TOOLS_IMPORT2OZZ_H_
#define OZZ_OZZ_ANIMATION_OFFLINE_TOOLS_IMPORT2OZZ_H_ #define OZZ_OZZ_ANIMATION_OFFLINE_TOOLS_IMPORT2OZZ_H_
#include "ozz/animation/offline/tools/export.h"
#include "ozz/base/containers/string.h" #include "ozz/base/containers/string.h"
#include "ozz/base/containers/vector.h" #include "ozz/base/containers/vector.h"
@ -35,6 +37,8 @@
#include "ozz/animation/offline/raw_skeleton.h" #include "ozz/animation/offline/raw_skeleton.h"
#include "ozz/animation/offline/raw_track.h" #include "ozz/animation/offline/raw_track.h"
#include "ozz/base/platform.h"
namespace ozz { namespace ozz {
namespace animation { namespace animation {
@ -51,7 +55,7 @@ namespace offline {
// To import a new source data format, one will implement the pure virtual // To import a new source data format, one will implement the pure virtual
// functions of this interface. All the conversions end error processing are // functions of this interface. All the conversions end error processing are
// done by the tool. // done by the tool.
class OzzImporter { class OZZ_ANIMTOOLS_DLL OzzImporter {
public: public:
virtual ~OzzImporter() {} virtual ~OzzImporter() {}
@ -72,6 +76,7 @@ class OzzImporter {
bool camera : 1; // Uses camera nodes as skeleton joints. bool camera : 1; // Uses camera nodes as skeleton joints.
bool geometry : 1; // Uses geometry nodes as skeleton joints. bool geometry : 1; // Uses geometry nodes as skeleton joints.
bool light : 1; // Uses light nodes as skeleton joints. bool light : 1; // Uses light nodes as skeleton joints.
bool null : 1; // Uses null nodes as skeleton joints.
bool any : 1; // Uses any node type as skeleton joints, including those bool any : 1; // Uses any node type as skeleton joints, including those
// listed above and any other. // listed above and any other.
}; };

View File

@ -28,6 +28,7 @@
#ifndef OZZ_OZZ_ANIMATION_OFFLINE_TRACK_BUILDER_H_ #ifndef OZZ_OZZ_ANIMATION_OFFLINE_TRACK_BUILDER_H_
#define OZZ_OZZ_ANIMATION_OFFLINE_TRACK_BUILDER_H_ #define OZZ_OZZ_ANIMATION_OFFLINE_TRACK_BUILDER_H_
#include "ozz/animation/offline/export.h"
#include "ozz/base/memory/unique_ptr.h" #include "ozz/base/memory/unique_ptr.h"
namespace ozz { namespace ozz {
@ -53,7 +54,7 @@ struct RawQuaternionTrack;
// offline tracks.The input raw track is first validated. Runtime conversion of // offline tracks.The input raw track is first validated. Runtime conversion of
// a validated raw track cannot fail. Note that no optimization is performed on // a validated raw track cannot fail. Note that no optimization is performed on
// the data at all. // the data at all.
class TrackBuilder { class OZZ_ANIMOFFLINE_DLL TrackBuilder {
public: public:
// Creates a Track based on _raw_track and *this builder parameters. // Creates a Track based on _raw_track and *this builder parameters.
// Returns a track instance on success, an empty unique_ptr on failure. See // Returns a track instance on success, an empty unique_ptr on failure. See

View File

@ -28,6 +28,9 @@
#ifndef OZZ_OZZ_ANIMATION_OFFLINE_TRACK_OPTIMIZER_H_ #ifndef OZZ_OZZ_ANIMATION_OFFLINE_TRACK_OPTIMIZER_H_
#define OZZ_OZZ_ANIMATION_OFFLINE_TRACK_OPTIMIZER_H_ #define OZZ_OZZ_ANIMATION_OFFLINE_TRACK_OPTIMIZER_H_
#include "ozz/animation/offline/export.h"
#include "ozz/base/platform.h"
namespace ozz { namespace ozz {
namespace animation { namespace animation {
namespace offline { namespace offline {
@ -44,7 +47,7 @@ struct RawQuaternionTrack;
// keyframes (within a tolerance value) are removed from the track. Default // keyframes (within a tolerance value) are removed from the track. Default
// optimization tolerances are set in order to favor quality over runtime // optimization tolerances are set in order to favor quality over runtime
// performances and memory footprint. // performances and memory footprint.
class TrackOptimizer { class OZZ_ANIMOFFLINE_DLL TrackOptimizer {
public: public:
// Initializes the optimizer with default tolerances (favoring quality). // Initializes the optimizer with default tolerances (favoring quality).
TrackOptimizer(); TrackOptimizer();

View File

@ -28,6 +28,7 @@
#ifndef OZZ_OZZ_ANIMATION_RUNTIME_ANIMATION_H_ #ifndef OZZ_OZZ_ANIMATION_RUNTIME_ANIMATION_H_
#define OZZ_OZZ_ANIMATION_RUNTIME_ANIMATION_H_ #define OZZ_OZZ_ANIMATION_RUNTIME_ANIMATION_H_
#include "ozz/animation/runtime/export.h"
#include "ozz/base/io/archive_traits.h" #include "ozz/base/io/archive_traits.h"
#include "ozz/base/platform.h" #include "ozz/base/platform.h"
#include "ozz/base/span.h" #include "ozz/base/span.h"
@ -58,11 +59,19 @@ struct QuaternionKey;
// joints order of the runtime skeleton structure. In order to optimize cache // joints order of the runtime skeleton structure. In order to optimize cache
// coherency when sampling the animation, Keyframes in this array are sorted by // coherency when sampling the animation, Keyframes in this array are sorted by
// time, then by track number. // time, then by track number.
class Animation { class OZZ_ANIMATION_DLL Animation {
public: public:
// Builds a default animation. // Builds a default animation.
Animation(); Animation();
// Allow moves.
Animation(Animation&&);
Animation& operator=(Animation&&);
// Delete copies.
Animation(Animation const&) = delete;
Animation& operator=(Animation const&) = delete;
// Declares the public non-virtual destructor. // Declares the public non-virtual destructor.
~Animation(); ~Animation();
@ -80,9 +89,7 @@ class Animation {
const char* name() const { return name_ ? name_ : ""; } const char* name() const { return name_ ? name_ : ""; }
// Gets the buffer of translations keys. // Gets the buffer of translations keys.
span<const Float3Key> translations() const { span<const Float3Key> translations() const { return translations_; }
return translations_;
}
// Gets the buffer of rotation keys. // Gets the buffer of rotation keys.
span<const QuaternionKey> rotations() const { return rotations_; } span<const QuaternionKey> rotations() const { return rotations_; }
@ -98,12 +105,7 @@ class Animation {
void Save(ozz::io::OArchive& _archive) const; void Save(ozz::io::OArchive& _archive) const;
void Load(ozz::io::IArchive& _archive, uint32_t _version); void Load(ozz::io::IArchive& _archive, uint32_t _version);
protected:
private: private:
// Disables copy and assignation.
Animation(Animation const&);
void operator=(Animation const&);
// AnimationBuilder class is allowed to instantiate an Animation. // AnimationBuilder class is allowed to instantiate an Animation.
friend class offline::AnimationBuilder; friend class offline::AnimationBuilder;

View File

@ -28,6 +28,7 @@
#ifndef OZZ_OZZ_ANIMATION_RUNTIME_ANIMATION_UTILS_H_ #ifndef OZZ_OZZ_ANIMATION_RUNTIME_ANIMATION_UTILS_H_
#define OZZ_OZZ_ANIMATION_RUNTIME_ANIMATION_UTILS_H_ #define OZZ_OZZ_ANIMATION_RUNTIME_ANIMATION_UTILS_H_
#include "ozz/animation/runtime/export.h"
#include "ozz/animation/runtime/animation.h" #include "ozz/animation/runtime/animation.h"
namespace ozz { namespace ozz {
@ -35,9 +36,12 @@ namespace animation {
// Count translation, rotation or scale keyframes for a given track number. Use // Count translation, rotation or scale keyframes for a given track number. Use
// a negative _track value to count all tracks. // a negative _track value to count all tracks.
int CountTranslationKeyframes(const Animation& _animation, int _track = -1); OZZ_ANIMATION_DLL int CountTranslationKeyframes(const Animation& _animation,
int CountRotationKeyframes(const Animation& _animation, int _track = -1); int _track = -1);
int CountScaleKeyframes(const Animation& _animation, int _track = -1); OZZ_ANIMATION_DLL int CountRotationKeyframes(const Animation& _animation,
int _track = -1);
OZZ_ANIMATION_DLL int CountScaleKeyframes(const Animation& _animation,
int _track = -1);
} // namespace animation } // namespace animation
} // namespace ozz } // namespace ozz
#endif // OZZ_OZZ_ANIMATION_RUNTIME_ANIMATION_UTILS_H_ #endif // OZZ_OZZ_ANIMATION_RUNTIME_ANIMATION_UTILS_H_

View File

@ -28,6 +28,7 @@
#ifndef OZZ_OZZ_ANIMATION_RUNTIME_BLENDING_JOB_H_ #ifndef OZZ_OZZ_ANIMATION_RUNTIME_BLENDING_JOB_H_
#define OZZ_OZZ_ANIMATION_RUNTIME_BLENDING_JOB_H_ #define OZZ_OZZ_ANIMATION_RUNTIME_BLENDING_JOB_H_
#include "ozz/animation/runtime/export.h"
#include "ozz/base/maths/simd_math.h" #include "ozz/base/maths/simd_math.h"
#include "ozz/base/span.h" #include "ozz/base/span.h"
@ -44,15 +45,15 @@ namespace animation {
// (the result of a sampled animation) according to their respective weight, // (the result of a sampled animation) according to their respective weight,
// into one output pose. // into one output pose.
// The number of transforms/joints blended by the job is defined by the number // The number of transforms/joints blended by the job is defined by the number
// of transforms of the bind pose (note that this is a SoA format). This means // of transforms of the rest pose (note that this is a SoA format). This means
// that all buffers must be at least as big as the bind pose buffer. // that all buffers must be at least as big as the rest pose buffer.
// Partial animation blending is supported through optional joint weights that // Partial animation blending is supported through optional joint weights that
// can be specified with layers joint_weights buffer. Unspecified joint weights // can be specified with layers joint_weights buffer. Unspecified joint weights
// are considered as a unit weight of 1.f, allowing to mix full and partial // are considered as a unit weight of 1.f, allowing to mix full and partial
// blend operations in a single pass. // blend operations in a single pass.
// The job does not owned any buffers (input/output) and will thus not delete // The job does not owned any buffers (input/output) and will thus not delete
// them during job's destruction. // them during job's destruction.
struct BlendingJob { struct OZZ_ANIMATION_DLL BlendingJob {
// Default constructor, initializes default values. // Default constructor, initializes default values.
BlendingJob(); BlendingJob();
@ -63,7 +64,7 @@ struct BlendingJob {
// -if any layer is not valid. // -if any layer is not valid.
// -if output range is not valid. // -if output range is not valid.
// -if any buffer (including layers' content : transform, joint weights...) is // -if any buffer (including layers' content : transform, joint weights...) is
// smaller than the bind pose buffer. // smaller than the rest pose buffer.
// -if the threshold value is less than or equal to 0.f. // -if the threshold value is less than or equal to 0.f.
bool Validate() const; bool Validate() const;
@ -75,7 +76,7 @@ struct BlendingJob {
// Defines a layer of blending input data (local space transforms) and // Defines a layer of blending input data (local space transforms) and
// parameters (weights). // parameters (weights).
struct Layer { struct OZZ_ANIMATION_DLL Layer {
// Default constructor, initializes default values. // Default constructor, initializes default values.
Layer(); Layer();
@ -86,8 +87,8 @@ struct BlendingJob {
// The range [begin,end[ of input layer posture. This buffer expect to store // The range [begin,end[ of input layer posture. This buffer expect to store
// local space transforms, that are usually outputted from a sampling job. // local space transforms, that are usually outputted from a sampling job.
// This range must be at least as big as the bind pose buffer, even though // This range must be at least as big as the rest pose buffer, even though
// only the number of transforms defined by the bind pose buffer will be // only the number of transforms defined by the rest pose buffer will be
// processed. // processed.
span<const math::SoaTransform> transform; span<const math::SoaTransform> transform;
@ -95,8 +96,8 @@ struct BlendingJob {
// layer. // layer.
// If both pointers are nullptr (default case) then per joint weight // If both pointers are nullptr (default case) then per joint weight
// blending is disabled. A valid range is defined as being at least as big // blending is disabled. A valid range is defined as being at least as big
// as the bind pose buffer, even though only the number of transforms // as the rest pose buffer, even though only the number of transforms
// defined by the bind pose buffer will be processed. When a layer doesn't // defined by the rest pose buffer will be processed. When a layer doesn't
// specifies per joint weights, then it is implicitly considered as // specifies per joint weights, then it is implicitly considered as
// being 1.f. This default value is a reference value for the normalization // being 1.f. This default value is a reference value for the normalization
// process, which implies that the range of values for joint weights should // process, which implies that the range of values for joint weights should
@ -106,7 +107,7 @@ struct BlendingJob {
span<const math::SimdFloat4> joint_weights; span<const math::SimdFloat4> joint_weights;
}; };
// The job blends the bind pose to the output when the accumulated weight of // The job blends the rest pose to the output when the accumulated weight of
// all layers is less than this threshold value. // all layers is less than this threshold value.
// Must be greater than 0.f. // Must be greater than 0.f.
float threshold; float threshold;
@ -119,18 +120,18 @@ struct BlendingJob {
// The range of layers that must be added to the output. // The range of layers that must be added to the output.
span<const Layer> additive_layers; span<const Layer> additive_layers;
// The skeleton bind pose. The size of this buffer defines the number of // The skeleton rest pose. The size of this buffer defines the number of
// transforms to blend. This is the reference because this buffer is defined // transforms to blend. This is the reference because this buffer is defined
// by the skeleton that all the animations belongs to. // by the skeleton that all the animations belongs to.
// It is used when the accumulated weight for a bone on all layers is // It is used when the accumulated weight for a bone on all layers is
// less than the threshold value, in order to fall back on valid transforms. // less than the threshold value, in order to fall back on valid transforms.
span<const ozz::math::SoaTransform> bind_pose; span<const ozz::math::SoaTransform> rest_pose;
// Job output. // Job output.
// The range of output transforms to be filled with blended layer // The range of output transforms to be filled with blended layer
// transforms during job execution. // transforms during job execution.
// Must be at least as big as the bind pose buffer, but only the number of // Must be at least as big as the rest pose buffer, but only the number of
// transforms defined by the bind pose buffer size will be processed. // transforms defined by the rest pose buffer size will be processed.
span<ozz::math::SoaTransform> output; span<ozz::math::SoaTransform> output;
}; };
} // namespace animation } // namespace animation

View File

@ -0,0 +1,44 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_ANIMATION_RUNTIME_EXPORT_H_
#define OZZ_OZZ_ANIMATION_RUNTIME_EXPORT_H_
#if defined(_MSC_VER) && defined(OZZ_USE_DYNAMIC_LINKING)
#ifdef OZZ_BUILD_ANIMATION_LIB
// Import/Export for dynamic linking while building ozz
#define OZZ_ANIMATION_DLL __declspec(dllexport)
#else
#define OZZ_ANIMATION_DLL __declspec(dllimport)
#endif
#else // defined(_MSC_VER) && defined(OZZ_USE_DYNAMIC_LINKING)
// Static or non msvc linking
#define OZZ_ANIMATION_DLL
#endif // defined(_MSC_VER) && defined(OZZ_USE_DYNAMIC_LINKING)
#endif // OZZ_OZZ_ANIMATION_RUNTIME_EXPORT_H_

View File

@ -28,6 +28,7 @@
#ifndef OZZ_OZZ_ANIMATION_RUNTIME_IK_AIM_JOB_H_ #ifndef OZZ_OZZ_ANIMATION_RUNTIME_IK_AIM_JOB_H_
#define OZZ_OZZ_ANIMATION_RUNTIME_IK_AIM_JOB_H_ #define OZZ_OZZ_ANIMATION_RUNTIME_IK_AIM_JOB_H_
#include "ozz/animation/runtime/export.h"
#include "ozz/base/platform.h" #include "ozz/base/platform.h"
#include "ozz/base/maths/simd_math.h" #include "ozz/base/maths/simd_math.h"
@ -50,7 +51,7 @@ namespace animation {
// vector should aim the target. // vector should aim the target.
// Result is unstable if joint-to-target direction is parallel to pole vector, // Result is unstable if joint-to-target direction is parallel to pole vector,
// or if target is too close to joint position. // or if target is too close to joint position.
struct IKAimJob { struct OZZ_ANIMATION_DLL IKAimJob {
// Default constructor, initializes default values. // Default constructor, initializes default values.
IKAimJob(); IKAimJob();

View File

@ -28,6 +28,7 @@
#ifndef OZZ_OZZ_ANIMATION_RUNTIME_IK_TWO_BONE_JOB_H_ #ifndef OZZ_OZZ_ANIMATION_RUNTIME_IK_TWO_BONE_JOB_H_
#define OZZ_OZZ_ANIMATION_RUNTIME_IK_TWO_BONE_JOB_H_ #define OZZ_OZZ_ANIMATION_RUNTIME_IK_TWO_BONE_JOB_H_
#include "ozz/animation/runtime/export.h"
#include "ozz/base/platform.h" #include "ozz/base/platform.h"
#include "ozz/base/maths/simd_math.h" #include "ozz/base/maths/simd_math.h"
@ -51,7 +52,7 @@ namespace animation {
// ancestors (joints in-between will simply remain fixed). // ancestors (joints in-between will simply remain fixed).
// Implementation is inspired by Autodesk Maya 2 bone IK, improved stability // Implementation is inspired by Autodesk Maya 2 bone IK, improved stability
// wise and extended with Soften IK. // wise and extended with Soften IK.
struct IKTwoBoneJob { struct OZZ_ANIMATION_DLL IKTwoBoneJob {
// Constructor, initializes default values. // Constructor, initializes default values.
IKTwoBoneJob(); IKTwoBoneJob();

View File

@ -28,6 +28,7 @@
#ifndef OZZ_OZZ_ANIMATION_RUNTIME_LOCAL_TO_MODEL_JOB_H_ #ifndef OZZ_OZZ_ANIMATION_RUNTIME_LOCAL_TO_MODEL_JOB_H_
#define OZZ_OZZ_ANIMATION_RUNTIME_LOCAL_TO_MODEL_JOB_H_ #define OZZ_OZZ_ANIMATION_RUNTIME_LOCAL_TO_MODEL_JOB_H_
#include "ozz/animation/runtime/export.h"
#include "ozz/base/platform.h" #include "ozz/base/platform.h"
#include "ozz/base/span.h" #include "ozz/base/span.h"
@ -55,7 +56,7 @@ class Skeleton;
// ordered like skeleton's joints. Output are matrices, because the combination // ordered like skeleton's joints. Output are matrices, because the combination
// of affine transformations can contain shearing or complex transformation // of affine transformations can contain shearing or complex transformation
// that cannot be represented as Transform object. // that cannot be represented as Transform object.
struct LocalToModelJob { struct OZZ_ANIMATION_DLL LocalToModelJob {
// Default constructor, initializes default values. // Default constructor, initializes default values.
LocalToModelJob(); LocalToModelJob();

View File

@ -28,6 +28,7 @@
#ifndef OZZ_OZZ_ANIMATION_RUNTIME_SAMPLING_JOB_H_ #ifndef OZZ_OZZ_ANIMATION_RUNTIME_SAMPLING_JOB_H_
#define OZZ_OZZ_ANIMATION_RUNTIME_SAMPLING_JOB_H_ #define OZZ_OZZ_ANIMATION_RUNTIME_SAMPLING_JOB_H_
#include "ozz/animation/runtime/export.h"
#include "ozz/base/platform.h" #include "ozz/base/platform.h"
#include "ozz/base/span.h" #include "ozz/base/span.h"
@ -43,19 +44,16 @@ namespace animation {
// Forward declares the animation type to sample. // Forward declares the animation type to sample.
class Animation; class Animation;
// Forward declares the cache object used by the SamplingJob.
class SamplingCache;
// Samples an animation at a given time ratio in the unit interval [0,1] (where // Samples an animation at a given time ratio in the unit interval [0,1] (where
// 0 is the beginning of the animation, 1 is the end), to output the // 0 is the beginning of the animation, 1 is the end), to output the
// corresponding posture in local-space. // corresponding posture in local-space.
// SamplingJob uses a cache (aka SamplingCache) to store intermediate values // SamplingJob uses a context (aka SamplingJob::Context) to store intermediate
// (decompressed animation keyframes...) while sampling. This cache also stores // values (decompressed animation keyframes...) while sampling. This context
// pre-computed values that allows drastic optimization while playing/sampling // also stores pre-computed values that allows drastic optimization while
// the animation forward. Backward sampling works, but isn't optimized through // playing/sampling the animation forward. Backward sampling works, but isn't
// the cache. The job does not owned the buffers (in/output) and will thus not // optimized through the context. The job does not owned the buffers (in/output)
// delete them during job's destruction. // and will thus not delete them during job's destruction.
struct SamplingJob { struct OZZ_ANIMATION_DLL SamplingJob {
// Default constructor, initializes default values. // Default constructor, initializes default values.
SamplingJob(); SamplingJob();
@ -80,8 +78,11 @@ struct SamplingJob {
// The animation to sample. // The animation to sample.
const Animation* animation; const Animation* animation;
// A cache object that must be big enough to sample *this animation. // Forward declares the context object used by the SamplingJob.
SamplingCache* cache; class Context;
// A context object that must be big enough to sample *this animation.
Context* context;
// Job output. // Job output.
// The output range to be filled with sampled joints during job execution. // The output range to be filled with sampled joints during job execution.
@ -98,61 +99,62 @@ struct InterpSoaFloat3;
struct InterpSoaQuaternion; struct InterpSoaQuaternion;
} // namespace internal } // namespace internal
// Declares the cache object used by the workload to take advantage of the // Declares the context object used by the workload to take advantage of the
// frame coherency of animation sampling. // frame coherency of animation sampling.
class SamplingCache { class OZZ_ANIMATION_DLL SamplingJob::Context {
public: public:
// Constructs an empty cache. The cache needs to be resized with the // Constructs an empty context. The context needs to be resized with the
// appropriate number of tracks before it can be used with a SamplingJob. // appropriate number of tracks before it can be used with a SamplingJob.
SamplingCache(); Context();
// Constructs a cache that can be used to sample any animation with at most // Constructs a context that can be used to sample any animation with at most
// _max_tracks tracks. _num_tracks is internally aligned to a multiple of // _max_tracks tracks. _num_tracks is internally aligned to a multiple of
// soa size, which means max_tracks() can return a different (but bigger) // soa size, which means max_tracks() can return a different (but bigger)
// value than _max_tracks. // value than _max_tracks.
explicit SamplingCache(int _max_tracks); explicit Context(int _max_tracks);
// Deallocates cache. // Disables copy and assignation.
~SamplingCache(); Context(Context const&) = delete;
Context& operator=(Context const&) = delete;
// Resize the number of joints that the cache can support. // Deallocates context.
// This also implicitly invalidate the cache. ~Context();
// Resize the number of joints that the context can support.
// This also implicitly invalidate the context.
void Resize(int _max_tracks); void Resize(int _max_tracks);
// Invalidate the cache. // Invalidate the context.
// The SamplingJob automatically invalidates a cache when required // The SamplingJob automatically invalidates a context when required
// during sampling. This automatic mechanism is based on the animation // during sampling. This automatic mechanism is based on the animation
// address and sampling time ratio. The weak point is that it can result in a // address and sampling time ratio. The weak point is that it can result in a
// crash if ever the address of an animation is used again with another // crash if ever the address of an animation is used again with another
// animation (could be the result of successive call to delete / new). // animation (could be the result of successive call to delete / new).
// Therefore it is recommended to manually invalidate a cache when it is // Therefore it is recommended to manually invalidate a context when it is
// known that this cache will not be used for with an animation again. // known that this context will not be used for with an animation again.
void Invalidate(); void Invalidate();
// The maximum number of tracks that the cache can handle. // The maximum number of tracks that the context can handle.
int max_tracks() const { return max_soa_tracks_ * 4; } int max_tracks() const { return max_soa_tracks_ * 4; }
int max_soa_tracks() const { return max_soa_tracks_; } int max_soa_tracks() const { return max_soa_tracks_; }
private: private:
// Disables copy and assignation.
SamplingCache(SamplingCache const&);
void operator=(SamplingCache const&);
friend struct SamplingJob; friend struct SamplingJob;
// Steps the cache in order to use it for a potentially new animation and // Steps the context in order to use it for a potentially new animation and
// ratio. If the _animation is different from the animation currently cached, // ratio. If the _animation is different from the animation currently cached,
// or if the _ratio shows that the animation is played backward, then the // or if the _ratio shows that the animation is played backward, then the
// cache is invalidated and reseted for the new _animation and _ratio. // context is invalidated and reset for the new _animation and _ratio.
void Step(const Animation& _animation, float _ratio); void Step(const Animation& _animation, float _ratio);
// The animation this cache refers to. nullptr means that the cache is invalid. // The animation this context refers to. nullptr means that the context is
// invalid.
const Animation* animation_; const Animation* animation_;
// The current time ratio in the animation. // The current time ratio in the animation.
float ratio_; float ratio_;
// The number of soa tracks that can store this cache. // The number of soa tracks that can store this context.
int max_soa_tracks_; int max_soa_tracks_;
// Soa hot data to interpolate. // Soa hot data to interpolate.
@ -166,7 +168,7 @@ class SamplingCache {
int* rotation_keys_; int* rotation_keys_;
int* scale_keys_; int* scale_keys_;
// Current cursors in the animation. 0 means that the cache is invalid. // Current cursors in the animation. 0 means that the context is invalid.
int translation_cursor_; int translation_cursor_;
int rotation_cursor_; int rotation_cursor_;
int scale_cursor_; int scale_cursor_;

View File

@ -28,6 +28,7 @@
#ifndef OZZ_OZZ_ANIMATION_RUNTIME_SKELETON_H_ #ifndef OZZ_OZZ_ANIMATION_RUNTIME_SKELETON_H_
#define OZZ_OZZ_ANIMATION_RUNTIME_SKELETON_H_ #define OZZ_OZZ_ANIMATION_RUNTIME_SKELETON_H_
#include "ozz/animation/runtime/export.h"
#include "ozz/base/io/archive_traits.h" #include "ozz/base/io/archive_traits.h"
#include "ozz/base/platform.h" #include "ozz/base/platform.h"
#include "ozz/base/span.h" #include "ozz/base/span.h"
@ -48,16 +49,16 @@ class SkeletonBuilder;
} }
// This runtime skeleton data structure provides a const-only access to joint // This runtime skeleton data structure provides a const-only access to joint
// hierarchy, joint names and bind-pose. This structure is filled by the // hierarchy, joint names and rest-pose. This structure is filled by the
// SkeletonBuilder and can be serialize/deserialized. // SkeletonBuilder and can be serialize/deserialized.
// Joint names, bind-poses and hierarchy information are all stored in separate // Joint names, rest-poses and hierarchy information are all stored in separate
// arrays of data (as opposed to joint structures for the RawSkeleton), in order // arrays of data (as opposed to joint structures for the RawSkeleton), in order
// to closely match with the way runtime algorithms use them. Joint hierarchy is // to closely match with the way runtime algorithms use them. Joint hierarchy is
// packed as an array of parent jont indices (16 bits), stored in depth-first // packed as an array of parent jont indices (16 bits), stored in depth-first
// order. This is enough to traverse the whole joint hierarchy. See // order. This is enough to traverse the whole joint hierarchy. See
// IterateJointsDF() from skeleton_utils.h that implements a depth-first // IterateJointsDF() from skeleton_utils.h that implements a depth-first
// traversal utility. // traversal utility.
class Skeleton { class OZZ_ANIMATION_DLL Skeleton {
public: public:
// Defines Skeleton constant values. // Defines Skeleton constant values.
enum Constants { enum Constants {
@ -81,6 +82,14 @@ class Skeleton {
// Builds a default skeleton. // Builds a default skeleton.
Skeleton(); Skeleton();
// Allow move.
Skeleton(Skeleton&&);
Skeleton& operator=(Skeleton&&);
// Disables copy and assignation.
Skeleton(Skeleton const&) = delete;
Skeleton& operator=(Skeleton const&) = delete;
// Declares the public non-virtual destructor. // Declares the public non-virtual destructor.
~Skeleton(); ~Skeleton();
@ -91,9 +100,9 @@ class Skeleton {
// skeleton. This value is useful to allocate SoA runtime data structures. // skeleton. This value is useful to allocate SoA runtime data structures.
int num_soa_joints() const { return (num_joints() + 3) / 4; } int num_soa_joints() const { return (num_joints() + 3) / 4; }
// Returns joint's bind poses. Bind poses are stored in soa format. // Returns joint's rest poses. Rest poses are stored in soa format.
span<const math::SoaTransform> joint_bind_poses() const { span<const math::SoaTransform> joint_rest_poses() const {
return joint_bind_poses_; return joint_rest_poses_;
} }
// Returns joint's parent indices range. // Returns joint's parent indices range.
@ -110,10 +119,6 @@ class Skeleton {
void Load(ozz::io::IArchive& _archive, uint32_t _version); void Load(ozz::io::IArchive& _archive, uint32_t _version);
private: private:
// Disables copy and assignation.
Skeleton(Skeleton const&);
void operator=(Skeleton const&);
// Internal allocation/deallocation function. // Internal allocation/deallocation function.
// Allocate returns the beginning of the contiguous buffer of names. // Allocate returns the beginning of the contiguous buffer of names.
char* Allocate(size_t _char_count, size_t _num_joints); char* Allocate(size_t _char_count, size_t _num_joints);
@ -125,8 +130,8 @@ class Skeleton {
// Buffers below store joint informations in joing depth first order. Their // Buffers below store joint informations in joing depth first order. Their
// size is equal to the number of joints of the skeleton. // size is equal to the number of joints of the skeleton.
// Bind pose of every joint in local space. // Rest pose of every joint in local space.
span<math::SoaTransform> joint_bind_poses_; span<math::SoaTransform> joint_rest_poses_;
// Array of joint parent indexes. // Array of joint parent indexes.
span<int16_t> joint_parents_; span<int16_t> joint_parents_;

View File

@ -28,17 +28,18 @@
#ifndef OZZ_OZZ_ANIMATION_RUNTIME_SKELETON_UTILS_H_ #ifndef OZZ_OZZ_ANIMATION_RUNTIME_SKELETON_UTILS_H_
#define OZZ_OZZ_ANIMATION_RUNTIME_SKELETON_UTILS_H_ #define OZZ_OZZ_ANIMATION_RUNTIME_SKELETON_UTILS_H_
#include <cassert>
#include "ozz/animation/runtime/export.h"
#include "ozz/animation/runtime/skeleton.h" #include "ozz/animation/runtime/skeleton.h"
#include "ozz/base/maths/transform.h" #include "ozz/base/maths/transform.h"
#include <cassert>
namespace ozz { namespace ozz {
namespace animation { namespace animation {
// Get bind-pose of a skeleton joint. // Get rest-pose of a skeleton joint.
ozz::math::Transform GetJointLocalBindPose(const Skeleton& _skeleton, OZZ_ANIMATION_DLL ozz::math::Transform GetJointLocalRestPose(
int _joint); const Skeleton& _skeleton, int _joint);
// Test if a joint is a leaf. _joint number must be in range [0, num joints]. // Test if a joint is a leaf. _joint number must be in range [0, num joints].
// "_joint" is a leaf if it's the last joint, or next joint's parent isn't // "_joint" is a leaf if it's the last joint, or next joint's parent isn't
@ -51,12 +52,15 @@ inline bool IsLeaf(const Skeleton& _skeleton, int _joint) {
return next == num_joints || parents[next] != _joint; return next == num_joints || parents[next] != _joint;
} }
// Finds joint index by name. Uses a case sensitive comparison.
OZZ_ANIMATION_DLL int FindJoint(const Skeleton& _skeleton, const char* _name);
// Applies a specified functor to each joint in a depth-first order. // Applies a specified functor to each joint in a depth-first order.
// _Fct is of type void(int _current, int _parent) where the first argument is // _Fct is of type void(int _current, int _parent) where the first argument
// the child of the second argument. _parent is kNoParent if the // is the child of the second argument. _parent is kNoParent if the _current
// _current joint is a root. _from indicates the joint from which the joint // joint is a root. _from indicates the joint from which the joint hierarchy
// hierarchy traversal begins. Use Skeleton::kNoParent to traverse the // traversal begins. Use Skeleton::kNoParent to traverse the whole
// whole hierarchy, in case there are multiple roots. // hierarchy, in case there are multiple roots.
template <typename _Fct> template <typename _Fct>
inline _Fct IterateJointsDF(const Skeleton& _skeleton, _Fct _fct, inline _Fct IterateJointsDF(const Skeleton& _skeleton, _Fct _fct,
int _from = Skeleton::kNoParent) { int _from = Skeleton::kNoParent) {

View File

@ -28,12 +28,12 @@
#ifndef OZZ_OZZ_ANIMATION_RUNTIME_TRACK_H_ #ifndef OZZ_OZZ_ANIMATION_RUNTIME_TRACK_H_
#define OZZ_OZZ_ANIMATION_RUNTIME_TRACK_H_ #define OZZ_OZZ_ANIMATION_RUNTIME_TRACK_H_
#include "ozz/animation/runtime/export.h"
#include "ozz/base/io/archive_traits.h" #include "ozz/base/io/archive_traits.h"
#include "ozz/base/platform.h"
#include "ozz/base/span.h"
#include "ozz/base/maths/quaternion.h" #include "ozz/base/maths/quaternion.h"
#include "ozz/base/maths/vec_float.h" #include "ozz/base/maths/vec_float.h"
#include "ozz/base/platform.h"
#include "ozz/base/span.h"
namespace ozz { namespace ozz {
namespace animation { namespace animation {
@ -54,11 +54,20 @@ namespace internal {
// coherently. Ratios are usually accessed/read alone from the jobs that all // coherently. Ratios are usually accessed/read alone from the jobs that all
// start by looking up the keyframes to interpolate indeed. // start by looking up the keyframes to interpolate indeed.
template <typename _ValueType> template <typename _ValueType>
class Track { class OZZ_ANIMATION_DLL Track {
public: public:
typedef _ValueType ValueType; typedef _ValueType ValueType;
Track(); Track();
// Allow move.
Track(Track&& _other);
Track& operator=(Track&& _other);
// Disables copy and assignation.
Track(Track const&) = delete;
void operator=(Track const&) = delete;
~Track(); ~Track();
// Keyframe accessors. // Keyframe accessors.
@ -78,10 +87,6 @@ class Track {
void Load(ozz::io::IArchive& _archive, uint32_t _version); void Load(ozz::io::IArchive& _archive, uint32_t _version);
private: private:
// Disables copy and assignation.
Track(Track const&);
void operator=(Track const&);
// TrackBuilder class is allowed to allocate a Track. // TrackBuilder class is allowed to allocate a Track.
friend class offline::TrackBuilder; friend class offline::TrackBuilder;
@ -99,7 +104,7 @@ class Track {
span<uint8_t> steps_; span<uint8_t> steps_;
// Track name. // Track name.
char* name_; char* name_ = nullptr;
}; };
// Definition of operations policies per track value type. // Definition of operations policies per track value type.
@ -146,11 +151,12 @@ inline math::Quaternion TrackPolicy<math::Quaternion>::identity() {
} // namespace internal } // namespace internal
// Runtime track data structure instantiation. // Runtime track data structure instantiation.
class FloatTrack : public internal::Track<float> {}; class OZZ_ANIMATION_DLL FloatTrack : public internal::Track<float> {};
class Float2Track : public internal::Track<math::Float2> {}; class OZZ_ANIMATION_DLL Float2Track : public internal::Track<math::Float2> {};
class Float3Track : public internal::Track<math::Float3> {}; class OZZ_ANIMATION_DLL Float3Track : public internal::Track<math::Float3> {};
class Float4Track : public internal::Track<math::Float4> {}; class OZZ_ANIMATION_DLL Float4Track : public internal::Track<math::Float4> {};
class QuaternionTrack : public internal::Track<math::Quaternion> {}; class OZZ_ANIMATION_DLL QuaternionTrack
: public internal::Track<math::Quaternion> {};
} // namespace animation } // namespace animation
namespace io { namespace io {

View File

@ -28,6 +28,7 @@
#ifndef OZZ_OZZ_ANIMATION_RUNTIME_TRACK_SAMPLING_JOB_H_ #ifndef OZZ_OZZ_ANIMATION_RUNTIME_TRACK_SAMPLING_JOB_H_
#define OZZ_OZZ_ANIMATION_RUNTIME_TRACK_SAMPLING_JOB_H_ #define OZZ_OZZ_ANIMATION_RUNTIME_TRACK_SAMPLING_JOB_H_
#include "ozz/animation/runtime/export.h"
#include "ozz/animation/runtime/track.h" #include "ozz/animation/runtime/track.h"
namespace ozz { namespace ozz {
@ -65,14 +66,15 @@ struct TrackSamplingJob {
// Track sampling job implementation. Track sampling allows to query a track // Track sampling job implementation. Track sampling allows to query a track
// value for a specified ratio. This is a ratio rather than a time because // value for a specified ratio. This is a ratio rather than a time because
// tracks have no duration. // tracks have no duration.
struct FloatTrackSamplingJob : public internal::TrackSamplingJob<FloatTrack> {}; struct OZZ_ANIMATION_DLL FloatTrackSamplingJob
struct Float2TrackSamplingJob : public internal::TrackSamplingJob<Float2Track> { : public internal::TrackSamplingJob<FloatTrack> {};
}; struct OZZ_ANIMATION_DLL Float2TrackSamplingJob
struct Float3TrackSamplingJob : public internal::TrackSamplingJob<Float3Track> { : public internal::TrackSamplingJob<Float2Track> {};
}; struct OZZ_ANIMATION_DLL Float3TrackSamplingJob
struct Float4TrackSamplingJob : public internal::TrackSamplingJob<Float4Track> { : public internal::TrackSamplingJob<Float3Track> {};
}; struct OZZ_ANIMATION_DLL Float4TrackSamplingJob
struct QuaternionTrackSamplingJob : public internal::TrackSamplingJob<Float4Track> {};
struct OZZ_ANIMATION_DLL QuaternionTrackSamplingJob
: public internal::TrackSamplingJob<QuaternionTrack> {}; : public internal::TrackSamplingJob<QuaternionTrack> {};
} // namespace animation } // namespace animation

View File

@ -28,6 +28,7 @@
#ifndef OZZ_OZZ_ANIMATION_RUNTIME_TRACK_TRIGGERING_JOB_H_ #ifndef OZZ_OZZ_ANIMATION_RUNTIME_TRACK_TRIGGERING_JOB_H_
#define OZZ_OZZ_ANIMATION_RUNTIME_TRACK_TRIGGERING_JOB_H_ #define OZZ_OZZ_ANIMATION_RUNTIME_TRACK_TRIGGERING_JOB_H_
#include "ozz/animation/runtime/export.h"
#include "ozz/base/platform.h" #include "ozz/base/platform.h"
namespace ozz { namespace ozz {
@ -46,7 +47,7 @@ class FloatTrack;
// track types isn't possible. // track types isn't possible.
// The job execution actually performs a lazy evaluation of edges. It builds an // The job execution actually performs a lazy evaluation of edges. It builds an
// iterator that will process the next edge on each call to ++ operator. // iterator that will process the next edge on each call to ++ operator.
struct TrackTriggeringJob { struct OZZ_ANIMATION_DLL TrackTriggeringJob {
TrackTriggeringJob(); TrackTriggeringJob();
// Validates job parameters. // Validates job parameters.
@ -95,7 +96,7 @@ struct TrackTriggeringJob {
// Iterator implementation. Calls to ++ operator will compute the next edge. It // Iterator implementation. Calls to ++ operator will compute the next edge. It
// should be compared (using operator !=) to job's end iterator to test if the // should be compared (using operator !=) to job's end iterator to test if the
// last edge has been reached. // last edge has been reached.
class TrackTriggeringJob::Iterator { class OZZ_ANIMATION_DLL TrackTriggeringJob::Iterator {
public: public:
Iterator() : job_(nullptr), outer_(0.f), inner_(0) {} Iterator() : job_(nullptr), outer_(0.f), inner_(0) {}

View File

@ -28,6 +28,8 @@
#ifndef OZZ_OZZ_ANIMATION_RUNTIME_TRACK_TRIGGERING_JOB_TRAIT_H_ #ifndef OZZ_OZZ_ANIMATION_RUNTIME_TRACK_TRIGGERING_JOB_TRAIT_H_
#define OZZ_OZZ_ANIMATION_RUNTIME_TRACK_TRIGGERING_JOB_TRAIT_H_ #define OZZ_OZZ_ANIMATION_RUNTIME_TRACK_TRIGGERING_JOB_TRAIT_H_
#include "ozz/animation/runtime/export.h"
// Defines iterator traits required to use TrackTriggeringJob::Iterator // Defines iterator traits required to use TrackTriggeringJob::Iterator
// with stl algorithms. // with stl algorithms.
// This is a separate file from "track_triggering_job.h" to prevent everyone // This is a separate file from "track_triggering_job.h" to prevent everyone

View File

@ -0,0 +1,73 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_CONTAINERS_ARRAY_H_
#define OZZ_OZZ_BASE_CONTAINERS_ARRAY_H_
#include <array>
#include "ozz/base/platform.h"
namespace ozz {
// Redirects std::array to ozz::array .
template <class _Ty, size_t _N>
using array = std::array<_Ty, _N>;
// Extends std::array with two functions that gives access to the begin and the
// end of its array of elements.
// Returns the mutable begin of the array of elements, or nullptr if
// array's empty.
template <class _Ty, size_t _N>
inline _Ty* array_begin(std::array<_Ty, _N>& _array) {
return _array.data();
}
// Returns the non-mutable begin of the array of elements, or nullptr if
// array's empty.
template <class _Ty, size_t _N>
inline const _Ty* array_begin(const std::array<_Ty, _N>& _array) {
return _array.data();
}
// Returns the mutable end of the array of elements, or nullptr if
// array's empty. Array end is one element past the last element of the
// array, it cannot be dereferenced.
template <class _Ty, size_t _N>
inline _Ty* array_end(std::array<_Ty, _N>& _array) {
return _array.data() + _N;
}
// Returns the non-mutable end of the array of elements, or nullptr if
// array's empty. Array end is one element past the last element of the
// array, it cannot be dereferenced.
template <class _Ty, size_t _N>
inline const _Ty* array_end(const std::array<_Ty, _N>& _array) {
return _array.data() + _N;
}
} // namespace ozz
#endif // OZZ_OZZ_BASE_CONTAINERS_ARRAY_H_

View File

@ -0,0 +1,63 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_CONTAINERS_ARRAY_ARCHIVE_H_
#define OZZ_OZZ_BASE_CONTAINERS_ARRAY_ARCHIVE_H_
#include "ozz/base/containers/array.h"
#include "ozz/base/io/archive.h"
namespace ozz {
namespace io {
OZZ_IO_TYPE_NOT_VERSIONABLE_T2(class _Ty, size_t _N, std::array<_Ty, _N>)
template <class _Ty, size_t _N>
struct Extern<std::array<_Ty, _N>> {
inline static void Save(OArchive& _archive,
const std::array<_Ty, _N>* _values, size_t _count) {
if (void(0), _N != 0) {
for (size_t i = 0; i < _count; i++) {
const std::array<_Ty, _N>& array = _values[i];
_archive << ozz::io::MakeArray(array.data(), _N);
}
}
}
inline static void Load(IArchive& _archive, std::array<_Ty, _N>* _values,
size_t _count, uint32_t _version) {
(void)_version;
if (void(0), _N != 0) {
for (size_t i = 0; i < _count; i++) {
std::array<_Ty, _N>& array = _values[i];
_archive >> ozz::io::MakeArray(array.data(), _N);
}
}
}
};
} // namespace io
} // namespace ozz
#endif // OZZ_OZZ_BASE_CONTAINERS_ARRAY_ARCHIVE_H_

View File

@ -49,7 +49,7 @@ class StdAllocator {
StdAllocator(const StdAllocator&) noexcept {} StdAllocator(const StdAllocator&) noexcept {}
template <class _Other> template <class _Other>
StdAllocator<value_type>(const StdAllocator<_Other>&) noexcept {} StdAllocator(const StdAllocator<_Other>&) noexcept {}
template <class _Other> template <class _Other>
struct rebind { struct rebind {

View File

@ -38,7 +38,7 @@ namespace io {
OZZ_IO_TYPE_NOT_VERSIONABLE(ozz::string) OZZ_IO_TYPE_NOT_VERSIONABLE(ozz::string)
template <> template <>
struct Extern<ozz::string> { struct OZZ_BASE_DLL Extern<ozz::string> {
static void Save(OArchive& _archive, const ozz::string* _values, static void Save(OArchive& _archive, const ozz::string* _values,
size_t _count); size_t _count);
static void Load(IArchive& _archive, ozz::string* _values, size_t _count, static void Load(IArchive& _archive, ozz::string* _values, size_t _count,

View File

@ -48,7 +48,7 @@ struct Extern<std::vector<_Ty, _Allocator>> {
const uint32_t size = static_cast<uint32_t>(vector.size()); const uint32_t size = static_cast<uint32_t>(vector.size());
_archive << size; _archive << size;
if (size > 0) { if (size > 0) {
_archive << ozz::io::MakeArray(&vector[0], size); _archive << ozz::io::MakeArray(vector.data(), size);
} }
} }
} }
@ -62,7 +62,7 @@ struct Extern<std::vector<_Ty, _Allocator>> {
_archive >> size; _archive >> size;
vector.resize(size); vector.resize(size);
if (size > 0) { if (size > 0) {
_archive >> ozz::io::MakeArray(&vector[0], size); _archive >> ozz::io::MakeArray(vector.data(), size);
} }
} }
} }

View File

@ -68,18 +68,15 @@ struct EndianSwapper;
// Internal macro used to swap two bytes. // Internal macro used to swap two bytes.
#define OZZ_BYTE_SWAP(_a, _b) \ #define OZZ_BYTE_SWAP(_a, _b) \
do { \ do { \
const char temp = _a; \ const ozz::byte temp = (_a); \
_a = _b; \ (_a) = (_b); \
_b = temp; \ (_b) = temp; \
} while (0) } while (0)
// EndianSwapper specialization for 1 byte types. // EndianSwapper specialization for 1 byte types.
template <typename _Ty> template <typename _Ty>
struct EndianSwapper<_Ty, 1> { struct EndianSwapper<_Ty, 1> {
OZZ_INLINE static void Swap(_Ty* _ty, size_t _count) { OZZ_INLINE static void Swap(_Ty*, size_t) {}
(void)_ty;
(void)_count;
}
OZZ_INLINE static _Ty Swap(_Ty _ty) { return _ty; } OZZ_INLINE static _Ty Swap(_Ty _ty) { return _ty; }
}; };
@ -87,13 +84,13 @@ struct EndianSwapper<_Ty, 1> {
template <typename _Ty> template <typename _Ty>
struct EndianSwapper<_Ty, 2> { struct EndianSwapper<_Ty, 2> {
OZZ_INLINE static void Swap(_Ty* _ty, size_t _count) { OZZ_INLINE static void Swap(_Ty* _ty, size_t _count) {
char* alias = reinterpret_cast<char*>(_ty); byte* alias = reinterpret_cast<byte*>(_ty);
for (size_t i = 0; i < _count * 2; i += 2) { for (size_t i = 0; i < _count * 2; i += 2) {
OZZ_BYTE_SWAP(alias[i + 0], alias[i + 1]); OZZ_BYTE_SWAP(alias[i + 0], alias[i + 1]);
} }
} }
OZZ_INLINE static _Ty Swap(_Ty _ty) { // Pass by copy to swap _ty in-place. OZZ_INLINE static _Ty Swap(_Ty _ty) { // Pass by copy to swap _ty in-place.
char* alias = reinterpret_cast<char*>(&_ty); byte* alias = reinterpret_cast<byte*>(&_ty);
OZZ_BYTE_SWAP(alias[0], alias[1]); OZZ_BYTE_SWAP(alias[0], alias[1]);
return _ty; return _ty;
} }
@ -103,14 +100,14 @@ struct EndianSwapper<_Ty, 2> {
template <typename _Ty> template <typename _Ty>
struct EndianSwapper<_Ty, 4> { struct EndianSwapper<_Ty, 4> {
OZZ_INLINE static void Swap(_Ty* _ty, size_t _count) { OZZ_INLINE static void Swap(_Ty* _ty, size_t _count) {
char* alias = reinterpret_cast<char*>(_ty); byte* alias = reinterpret_cast<byte*>(_ty);
for (size_t i = 0; i < _count * 4; i += 4) { for (size_t i = 0; i < _count * 4; i += 4) {
OZZ_BYTE_SWAP(alias[i + 0], alias[i + 3]); OZZ_BYTE_SWAP(alias[i + 0], alias[i + 3]);
OZZ_BYTE_SWAP(alias[i + 1], alias[i + 2]); OZZ_BYTE_SWAP(alias[i + 1], alias[i + 2]);
} }
} }
OZZ_INLINE static _Ty Swap(_Ty _ty) { // Pass by copy to swap _ty in-place. OZZ_INLINE static _Ty Swap(_Ty _ty) { // Pass by copy to swap _ty in-place.
char* alias = reinterpret_cast<char*>(&_ty); byte* alias = reinterpret_cast<byte*>(&_ty);
OZZ_BYTE_SWAP(alias[0], alias[3]); OZZ_BYTE_SWAP(alias[0], alias[3]);
OZZ_BYTE_SWAP(alias[1], alias[2]); OZZ_BYTE_SWAP(alias[1], alias[2]);
return _ty; return _ty;
@ -121,7 +118,7 @@ struct EndianSwapper<_Ty, 4> {
template <typename _Ty> template <typename _Ty>
struct EndianSwapper<_Ty, 8> { struct EndianSwapper<_Ty, 8> {
OZZ_INLINE static void Swap(_Ty* _ty, size_t _count) { OZZ_INLINE static void Swap(_Ty* _ty, size_t _count) {
char* alias = reinterpret_cast<char*>(_ty); byte* alias = reinterpret_cast<byte*>(_ty);
for (size_t i = 0; i < _count * 8; i += 8) { for (size_t i = 0; i < _count * 8; i += 8) {
OZZ_BYTE_SWAP(alias[i + 0], alias[i + 7]); OZZ_BYTE_SWAP(alias[i + 0], alias[i + 7]);
OZZ_BYTE_SWAP(alias[i + 1], alias[i + 6]); OZZ_BYTE_SWAP(alias[i + 1], alias[i + 6]);
@ -130,7 +127,7 @@ struct EndianSwapper<_Ty, 8> {
} }
} }
OZZ_INLINE static _Ty Swap(_Ty _ty) { // Pass by copy to swap _ty in-place. OZZ_INLINE static _Ty Swap(_Ty _ty) { // Pass by copy to swap _ty in-place.
char* alias = reinterpret_cast<char*>(&_ty); byte* alias = reinterpret_cast<byte*>(&_ty);
OZZ_BYTE_SWAP(alias[0], alias[7]); OZZ_BYTE_SWAP(alias[0], alias[7]);
OZZ_BYTE_SWAP(alias[1], alias[6]); OZZ_BYTE_SWAP(alias[1], alias[6]);
OZZ_BYTE_SWAP(alias[2], alias[5]); OZZ_BYTE_SWAP(alias[2], alias[5]);

View File

@ -0,0 +1,44 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_EXPORT_H_
#define OZZ_OZZ_BASE_EXPORT_H_
#if defined(_MSC_VER) && defined(OZZ_USE_DYNAMIC_LINKING)
#ifdef OZZ_BUILD_BASE_LIB
// Import/Export for dynamic linking while building ozz
#define OZZ_BASE_DLL __declspec(dllexport)
#else
#define OZZ_BASE_DLL __declspec(dllimport)
#endif
#else // defined(_MSC_VER) && defined(OZZ_USE_DYNAMIC_LINKING)
// Static or non msvc linking
#define OZZ_BASE_DLL
#endif // defined(_MSC_VER) && defined(OZZ_USE_DYNAMIC_LINKING)
#endif // OZZ_OZZ_BASE_EXPORT_H_

View File

@ -77,16 +77,16 @@
// integrity, like data corruption or file truncation, must also be validated on // integrity, like data corruption or file truncation, must also be validated on
// the user side. // the user side.
#include <stdint.h>
#include <cassert>
#include "ozz/base/endianness.h" #include "ozz/base/endianness.h"
#include "ozz/base/io/archive_traits.h"
#include "ozz/base/io/stream.h" #include "ozz/base/io/stream.h"
#include "ozz/base/platform.h" #include "ozz/base/platform.h"
#include "ozz/base/span.h" #include "ozz/base/span.h"
#include <stdint.h>
#include <cassert>
#include "ozz/base/io/archive_traits.h"
namespace ozz { namespace ozz {
namespace io { namespace io {
namespace internal { namespace internal {
@ -102,7 +102,7 @@ struct Tagger;
// The output endianness mode is set at construction time. It is written to the // The output endianness mode is set at construction time. It is written to the
// stream to allow the IArchive to perform the required conversion to the native // stream to allow the IArchive to perform the required conversion to the native
// endianness mode while reading. // endianness mode while reading.
class OArchive { class OZZ_BASE_DLL OArchive {
public: public:
// Constructs an output archive from the Stream _stream that must be valid // Constructs an output archive from the Stream _stream that must be valid
// and opened for writing. // and opened for writing.
@ -171,7 +171,7 @@ class OArchive {
// Implements input archive concept used to load/de-serialize data to a Stream. // Implements input archive concept used to load/de-serialize data to a Stream.
// Endianness conversions are automatically performed according to the Archive // Endianness conversions are automatically performed according to the Archive
// and the native formats. // and the native formats.
class IArchive { class OZZ_BASE_DLL IArchive {
public: public:
// Constructs an input archive from the Stream _stream that must be opened for // Constructs an input archive from the Stream _stream that must be opened for
// reading, at the same tell (position in the stream) as when it was passed to // reading, at the same tell (position in the stream) as when it was passed to

View File

@ -31,16 +31,16 @@
// Provides Stream interface used to read/write a memory buffer or a file with // Provides Stream interface used to read/write a memory buffer or a file with
// Crt fread/fwrite/fseek/ftell like functions. // Crt fread/fwrite/fseek/ftell like functions.
#include "ozz/base/platform.h"
#include <cstddef> #include <cstddef>
#include "ozz/base/platform.h"
namespace ozz { namespace ozz {
namespace io { namespace io {
// Declares a stream access interface that conforms with CRT FILE API. // Declares a stream access interface that conforms with CRT FILE API.
// This interface should be used to remap io operations. // This interface should be used to remap io operations.
class Stream { class OZZ_BASE_DLL Stream {
public: public:
// Tests whether a file is opened. // Tests whether a file is opened.
virtual bool opened() const = 0; virtual bool opened() const = 0;
@ -86,7 +86,7 @@ class Stream {
}; };
// Implements Stream of type File. // Implements Stream of type File.
class File : public Stream { class OZZ_BASE_DLL File : public Stream {
public: public:
// Test if a file at path _filename exists. // Test if a file at path _filename exists.
// Note that this function is costly. If you aim to open the file right after, // Note that this function is costly. If you aim to open the file right after,
@ -133,7 +133,7 @@ class File : public Stream {
// Implements an in-memory Stream. Allows to use a memory buffer as a Stream. // Implements an in-memory Stream. Allows to use a memory buffer as a Stream.
// The opening mode is equivalent to fopen w+b (binary read/write). // The opening mode is equivalent to fopen w+b (binary read/write).
class MemoryStream : public Stream { class OZZ_BASE_DLL MemoryStream : public Stream {
public: public:
// Construct an empty memory stream opened in w+b mode. // Construct an empty memory stream opened in w+b mode.
MemoryStream(); MemoryStream();
@ -172,7 +172,7 @@ class MemoryStream : public Stream {
static const size_t kMaxSize; static const size_t kMaxSize;
// Buffer of data. // Buffer of data.
char* buffer_; byte* buffer_;
// The size of the buffer, which is greater or equal to the size of the data // The size of the buffer, which is greater or equal to the size of the data
// it contains (end_). // it contains (end_).

View File

@ -34,6 +34,8 @@
// So it is included here to ensure a portable behavior. // So it is included here to ensure a portable behavior.
#include <cstring> #include <cstring>
#include "platform.h"
// Proposes a logging interface that redirects logs to std::cout, clog and cerr // Proposes a logging interface that redirects logs to std::cout, clog and cerr
// output streams. This interface adds a logging level functionality (kSilent, // output streams. This interface adds a logging level functionality (kSilent,
// kStandard, kVerbose) to the std API, which can be set using // kStandard, kVerbose) to the std API, which can be set using
@ -50,17 +52,17 @@ enum Level {
}; };
// Sets the global logging level. // Sets the global logging level.
Level SetLevel(Level _level); OZZ_BASE_DLL Level SetLevel(Level _level);
// Gets the global logging level. // Gets the global logging level.
Level GetLevel(); OZZ_BASE_DLL Level GetLevel();
// Implements logging base class. // Implements logging base class.
// This class is not intended to be used publicly, it is derived by user // This class is not intended to be used publicly, it is derived by user
// classes LogV, Log, Out, Err... // classes LogV, Log, Out, Err...
// Forwards ostream::operator << to a standard ostream or a silent // Forwards ostream::operator << to a standard ostream or a silent
// ostringstream according to the logging level at construction time. // ostringstream according to the logging level at construction time.
class Logger { class OZZ_BASE_DLL Logger {
public: public:
// Forwards ostream::operator << for any type. // Forwards ostream::operator << for any type.
template <typename _T> template <typename _T>
@ -101,28 +103,28 @@ class Logger {
// Logs verbose output to the standard error stream (std::clog). // Logs verbose output to the standard error stream (std::clog).
// Enabled if logging level is Verbose. // Enabled if logging level is Verbose.
class LogV : public Logger { class OZZ_BASE_DLL LogV : public Logger {
public: public:
LogV(); LogV();
}; };
// Logs output to the standard error stream (std::clog). // Logs output to the standard error stream (std::clog).
// Enabled if logging level is not Silent. // Enabled if logging level is not Silent.
class Log : public Logger { class OZZ_BASE_DLL Log : public Logger {
public: public:
Log(); Log();
}; };
// Logs output to the standard output (std::cout). // Logs output to the standard output (std::cout).
// Enabled if logging level is not Silent. // Enabled if logging level is not Silent.
class Out : public Logger { class OZZ_BASE_DLL Out : public Logger {
public: public:
Out(); Out();
}; };
// Logs error to the standard error stream (std::cerr). // Logs error to the standard error stream (std::cerr).
// Enabled if logging level is not Silent. // Enabled if logging level is not Silent.
class Err : public Logger { class OZZ_BASE_DLL Err : public Logger {
public: public:
Err(); Err();
}; };
@ -131,7 +133,7 @@ class Err : public Logger {
// settings when exiting scope. // settings when exiting scope.
// User is reponsible for making sure stream still exist upon RAII destruction. // User is reponsible for making sure stream still exist upon RAII destruction.
// See std::setprecision() for more details. // See std::setprecision() for more details.
class FloatPrecision { class OZZ_BASE_DLL FloatPrecision {
public: public:
FloatPrecision(const Logger& _logger, int _precision); FloatPrecision(const Logger& _logger, int _precision);
~FloatPrecision(); ~FloatPrecision();

View File

@ -39,7 +39,7 @@ namespace math {
struct Float4x4; struct Float4x4;
// Defines an axis aligned box. // Defines an axis aligned box.
struct Box { struct OZZ_BASE_DLL Box {
// Constructs an invalid box. // Constructs an invalid box.
Box(); Box();
@ -78,7 +78,7 @@ OZZ_INLINE Box Merge(const Box& _a, const Box& _b) {
} }
// Compute box transformation by a matrix. // Compute box transformation by a matrix.
Box TransformBox(const Float4x4& _matrix, const Box& _box); OZZ_BASE_DLL Box TransformBox(const Float4x4& _matrix, const Box& _box);
} // namespace math } // namespace math
} // namespace ozz } // namespace ozz
#endif // OZZ_OZZ_BASE_MATHS_BOX_H_ #endif // OZZ_OZZ_BASE_MATHS_BOX_H_

View File

@ -152,7 +152,8 @@ typedef const SimdInt4& _SimdInt4;
} // namespace ozz } // namespace ozz
#endif // OZZ_SIMD_x #endif // OZZ_SIMD_x
// Native SIMD operator already exist on some compilers, so they have to be disable from ozz implementation // Native SIMD operator already exist on some compilers, so they have to be
// disable from ozz implementation
#if !defined(OZZ_SIMD_REF) && (defined(__GNUC__) || defined(__llvm__)) #if !defined(OZZ_SIMD_REF) && (defined(__GNUC__) || defined(__llvm__))
#define OZZ_DISABLE_SSE_NATIVE_OPERATORS #define OZZ_DISABLE_SSE_NATIVE_OPERATORS
#endif #endif

View File

@ -31,6 +31,7 @@
// SIMD refence implementation, based on scalar floats. // SIMD refence implementation, based on scalar floats.
#include <stdint.h> #include <stdint.h>
#include <cassert> #include <cassert>
#include <cmath> #include <cmath>
#include <cstddef> #include <cstddef>
@ -1820,22 +1821,9 @@ OZZ_INLINE bool ToAffine(const Float4x4& _m, SimdFloat4* _translation,
} }
OZZ_INLINE Float4x4 Float4x4::FromEuler(_SimdFloat4 _v) { OZZ_INLINE Float4x4 Float4x4::FromEuler(_SimdFloat4 _v) {
const float ch = std::cos(_v.x); return Float4x4::FromAxisAngle(simd_float4::y_axis(), SplatX(_v)) *
const float sh = std::sin(_v.x); Float4x4::FromAxisAngle(simd_float4::x_axis(), SplatY(_v)) *
const float ca = std::cos(_v.y); Float4x4::FromAxisAngle(simd_float4::z_axis(), SplatZ(_v));
const float sa = std::sin(_v.y);
const float cb = std::cos(_v.z);
const float sb = std::sin(_v.z);
const float sa_cb = sa * cb;
const float sa_sb = sa * sb;
const Float4x4 ret = {
{{ch * ca, sh * sb - ch * sa_cb, ch * sa_sb + sh * cb, 0.f},
{sa, ca * cb, -ca * sb, 0.f},
{-sh * ca, sh * sa_cb + ch * sb, -sh * sa_sb + ch * cb, 0.f},
{0.f, 0.f, 0.f, 1.f}}};
return ret;
} }
OZZ_INLINE Float4x4 Float4x4::FromAxisAngle(_SimdFloat4 _axis, OZZ_INLINE Float4x4 Float4x4::FromAxisAngle(_SimdFloat4 _axis,

View File

@ -31,6 +31,7 @@
// SIMD SSE2+ implementation, based on scalar floats. // SIMD SSE2+ implementation, based on scalar floats.
#include <stdint.h> #include <stdint.h>
#include <cassert> #include <cassert>
// Temporarly needed while trigonometric functions aren't implemented. // Temporarly needed while trigonometric functions aren't implemented.
@ -1775,26 +1776,9 @@ inline bool ToAffine(const Float4x4& _m, SimdFloat4* _translation,
} }
inline Float4x4 Float4x4::FromEuler(_SimdFloat4 _v) { inline Float4x4 Float4x4::FromEuler(_SimdFloat4 _v) {
const __m128 cos = Cos(_v); return Float4x4::FromAxisAngle(simd_float4::y_axis(), SplatX(_v)) *
const __m128 sin = Sin(_v); Float4x4::FromAxisAngle(simd_float4::x_axis(), SplatY(_v)) *
Float4x4::FromAxisAngle(simd_float4::z_axis(), SplatZ(_v));
const float cx = GetX(cos);
const float sx = GetX(sin);
const float cy = GetY(cos);
const float sy = GetY(sin);
const float cz = GetZ(cos);
const float sz = GetZ(sin);
const float sycz = sy * cz;
const float sysz = sy * sz;
const Float4x4 ret = {{simd_float4::Load(cx * cy, sx * sz - cx * sycz,
cx * sysz + sx * cz, 0.f),
simd_float4::Load(sy, cy * cz, -cy * sz, 0.f),
simd_float4::Load(-sx * cy, sx * sycz + cx * sz,
-sx * sysz + cx * cz, 0.f),
simd_float4::w_axis()}};
return ret;
} }
inline Float4x4 Float4x4::FromAxisAngle(_SimdFloat4 _axis, _SimdFloat4 _angle) { inline Float4x4 Float4x4::FromAxisAngle(_SimdFloat4 _axis, _SimdFloat4 _angle) {

View File

@ -45,7 +45,7 @@ struct RectInt;
namespace io { namespace io {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::Float2) OZZ_IO_TYPE_NOT_VERSIONABLE(math::Float2)
template <> template <>
struct Extern<math::Float2> { struct OZZ_BASE_DLL Extern<math::Float2> {
static void Save(OArchive& _archive, const math::Float2* _values, static void Save(OArchive& _archive, const math::Float2* _values,
size_t _count); size_t _count);
static void Load(IArchive& _archive, math::Float2* _values, size_t _count, static void Load(IArchive& _archive, math::Float2* _values, size_t _count,
@ -54,7 +54,7 @@ struct Extern<math::Float2> {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::Float3) OZZ_IO_TYPE_NOT_VERSIONABLE(math::Float3)
template <> template <>
struct Extern<math::Float3> { struct OZZ_BASE_DLL Extern<math::Float3> {
static void Save(OArchive& _archive, const math::Float3* _values, static void Save(OArchive& _archive, const math::Float3* _values,
size_t _count); size_t _count);
static void Load(IArchive& _archive, math::Float3* _values, size_t _count, static void Load(IArchive& _archive, math::Float3* _values, size_t _count,
@ -63,7 +63,7 @@ struct Extern<math::Float3> {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::Float4) OZZ_IO_TYPE_NOT_VERSIONABLE(math::Float4)
template <> template <>
struct Extern<math::Float4> { struct OZZ_BASE_DLL Extern<math::Float4> {
static void Save(OArchive& _archive, const math::Float4* _values, static void Save(OArchive& _archive, const math::Float4* _values,
size_t _count); size_t _count);
static void Load(IArchive& _archive, math::Float4* _values, size_t _count, static void Load(IArchive& _archive, math::Float4* _values, size_t _count,
@ -72,7 +72,7 @@ struct Extern<math::Float4> {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::Quaternion) OZZ_IO_TYPE_NOT_VERSIONABLE(math::Quaternion)
template <> template <>
struct Extern<math::Quaternion> { struct OZZ_BASE_DLL Extern<math::Quaternion> {
static void Save(OArchive& _archive, const math::Quaternion* _values, static void Save(OArchive& _archive, const math::Quaternion* _values,
size_t _count); size_t _count);
static void Load(IArchive& _archive, math::Quaternion* _values, size_t _count, static void Load(IArchive& _archive, math::Quaternion* _values, size_t _count,
@ -81,7 +81,7 @@ struct Extern<math::Quaternion> {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::Transform) OZZ_IO_TYPE_NOT_VERSIONABLE(math::Transform)
template <> template <>
struct Extern<math::Transform> { struct OZZ_BASE_DLL Extern<math::Transform> {
static void Save(OArchive& _archive, const math::Transform* _values, static void Save(OArchive& _archive, const math::Transform* _values,
size_t _count); size_t _count);
static void Load(IArchive& _archive, math::Transform* _values, size_t _count, static void Load(IArchive& _archive, math::Transform* _values, size_t _count,
@ -90,7 +90,7 @@ struct Extern<math::Transform> {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::Box) OZZ_IO_TYPE_NOT_VERSIONABLE(math::Box)
template <> template <>
struct Extern<math::Box> { struct OZZ_BASE_DLL Extern<math::Box> {
static void Save(OArchive& _archive, const math::Box* _values, size_t _count); static void Save(OArchive& _archive, const math::Box* _values, size_t _count);
static void Load(IArchive& _archive, math::Box* _values, size_t _count, static void Load(IArchive& _archive, math::Box* _values, size_t _count,
uint32_t _version); uint32_t _version);
@ -98,7 +98,7 @@ struct Extern<math::Box> {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::RectFloat) OZZ_IO_TYPE_NOT_VERSIONABLE(math::RectFloat)
template <> template <>
struct Extern<math::RectFloat> { struct OZZ_BASE_DLL Extern<math::RectFloat> {
static void Save(OArchive& _archive, const math::RectFloat* _values, static void Save(OArchive& _archive, const math::RectFloat* _values,
size_t _count); size_t _count);
static void Load(IArchive& _archive, math::RectFloat* _values, size_t _count, static void Load(IArchive& _archive, math::RectFloat* _values, size_t _count,
@ -107,7 +107,7 @@ struct Extern<math::RectFloat> {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::RectInt) OZZ_IO_TYPE_NOT_VERSIONABLE(math::RectInt)
template <> template <>
struct Extern<math::RectInt> { struct OZZ_BASE_DLL Extern<math::RectInt> {
static void Save(OArchive& _archive, const math::RectInt* _values, static void Save(OArchive& _archive, const math::RectInt* _values,
size_t _count); size_t _count);
static void Load(IArchive& _archive, math::RectInt* _values, size_t _count, static void Load(IArchive& _archive, math::RectInt* _values, size_t _count,

View File

@ -38,7 +38,7 @@
namespace ozz { namespace ozz {
namespace math { namespace math {
struct Quaternion { struct OZZ_BASE_DLL Quaternion {
float x, y, z, w; float x, y, z, w;
// Constructs an uninitialized quaternion. // Constructs an uninitialized quaternion.

View File

@ -28,12 +28,14 @@
#ifndef OZZ_OZZ_BASE_MATHS_RECT_H_ #ifndef OZZ_OZZ_BASE_MATHS_RECT_H_
#define OZZ_OZZ_BASE_MATHS_RECT_H_ #define OZZ_OZZ_BASE_MATHS_RECT_H_
#include "../platform.h"
namespace ozz { namespace ozz {
namespace math { namespace math {
// Defines a rectangle by the integer coordinates of its lower-left and // Defines a rectangle by the integer coordinates of its lower-left and
// width-height. // width-height.
struct RectInt { struct OZZ_BASE_DLL RectInt {
// Constructs a uninitialized rectangle. // Constructs a uninitialized rectangle.
RectInt() {} RectInt() {}
@ -65,7 +67,7 @@ struct RectInt {
// Defines a rectangle by the floating point coordinates of its lower-left // Defines a rectangle by the floating point coordinates of its lower-left
// and width-height. // and width-height.
struct RectFloat { struct OZZ_BASE_DLL RectFloat {
// Constructs a uninitialized rectangle. // Constructs a uninitialized rectangle.
RectFloat() {} RectFloat() {}

View File

@ -35,7 +35,7 @@ namespace ozz {
namespace math { namespace math {
// Returns SIMDimplementation name has decided at library build time. // Returns SIMDimplementation name has decided at library build time.
const char* SimdImplementationName(); OZZ_BASE_DLL const char* SimdImplementationName();
namespace simd_float4 { namespace simd_float4 {
// Returns a SimdFloat4 vector with all components set to 0. // Returns a SimdFloat4 vector with all components set to 0.
@ -241,10 +241,6 @@ OZZ_INLINE void Transpose4x1(const SimdFloat4 _in[4], SimdFloat4 _out[1]);
// Remaining y, z and w are set to 0. // Remaining y, z and w are set to 0.
OZZ_INLINE void Transpose1x4(const SimdFloat4 _in[1], SimdFloat4 _out[4]); OZZ_INLINE void Transpose1x4(const SimdFloat4 _in[1], SimdFloat4 _out[4]);
// Transposes the 1 SimdFloat4 of _in into the x components of the 4
// SimdFloat4 of _out. Remaining y, z and w are set to 0.
OZZ_INLINE void Transpose2x4(const SimdFloat4 _in[2], SimdFloat4 _out[4]);
// Transposes the x and y components of the 4 SimdFloat4 of _in into the 2 // Transposes the x and y components of the 4 SimdFloat4 of _in into the 2
// SimdFloat4 of _out. // SimdFloat4 of _out.
OZZ_INLINE void Transpose4x2(const SimdFloat4 _in[4], SimdFloat4 _out[2]); OZZ_INLINE void Transpose4x2(const SimdFloat4 _in[4], SimdFloat4 _out[2]);

View File

@ -36,7 +36,7 @@ namespace ozz {
namespace io { namespace io {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SimdFloat4) OZZ_IO_TYPE_NOT_VERSIONABLE(math::SimdFloat4)
template <> template <>
struct Extern<math::SimdFloat4> { struct OZZ_BASE_DLL Extern<math::SimdFloat4> {
static void Save(OArchive& _archive, const math::SimdFloat4* _values, static void Save(OArchive& _archive, const math::SimdFloat4* _values,
size_t _count); size_t _count);
static void Load(IArchive& _archive, math::SimdFloat4* _values, size_t _count, static void Load(IArchive& _archive, math::SimdFloat4* _values, size_t _count,
@ -45,7 +45,7 @@ struct Extern<math::SimdFloat4> {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SimdInt4) OZZ_IO_TYPE_NOT_VERSIONABLE(math::SimdInt4)
template <> template <>
struct Extern<math::SimdInt4> { struct OZZ_BASE_DLL Extern<math::SimdInt4> {
static void Save(OArchive& _archive, const math::SimdInt4* _values, static void Save(OArchive& _archive, const math::SimdInt4* _values,
size_t _count); size_t _count);
static void Load(IArchive& _archive, math::SimdInt4* _values, size_t _count, static void Load(IArchive& _archive, math::SimdInt4* _values, size_t _count,
@ -54,7 +54,7 @@ struct Extern<math::SimdInt4> {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::Float4x4) OZZ_IO_TYPE_NOT_VERSIONABLE(math::Float4x4)
template <> template <>
struct Extern<math::Float4x4> { struct OZZ_BASE_DLL Extern<math::Float4x4> {
static void Save(OArchive& _archive, const math::Float4x4* _values, static void Save(OArchive& _archive, const math::Float4x4* _values,
size_t _count); size_t _count);
static void Load(IArchive& _archive, math::Float4x4* _values, size_t _count, static void Load(IArchive& _archive, math::Float4x4* _values, size_t _count,

View File

@ -43,7 +43,7 @@ struct SoaTransform;
namespace io { namespace io {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaFloat2) OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaFloat2)
template <> template <>
struct Extern<math::SoaFloat2> { struct OZZ_BASE_DLL Extern<math::SoaFloat2> {
static void Save(OArchive& _archive, const math::SoaFloat2* _values, static void Save(OArchive& _archive, const math::SoaFloat2* _values,
size_t _count); size_t _count);
static void Load(IArchive& _archive, math::SoaFloat2* _values, size_t _count, static void Load(IArchive& _archive, math::SoaFloat2* _values, size_t _count,
@ -52,7 +52,7 @@ struct Extern<math::SoaFloat2> {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaFloat3) OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaFloat3)
template <> template <>
struct Extern<math::SoaFloat3> { struct OZZ_BASE_DLL Extern<math::SoaFloat3> {
static void Save(OArchive& _archive, const math::SoaFloat3* _values, static void Save(OArchive& _archive, const math::SoaFloat3* _values,
size_t _count); size_t _count);
static void Load(IArchive& _archive, math::SoaFloat3* _values, size_t _count, static void Load(IArchive& _archive, math::SoaFloat3* _values, size_t _count,
@ -61,7 +61,7 @@ struct Extern<math::SoaFloat3> {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaFloat4) OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaFloat4)
template <> template <>
struct Extern<math::SoaFloat4> { struct OZZ_BASE_DLL Extern<math::SoaFloat4> {
static void Save(OArchive& _archive, const math::SoaFloat4* _values, static void Save(OArchive& _archive, const math::SoaFloat4* _values,
size_t _count); size_t _count);
static void Load(IArchive& _archive, math::SoaFloat4* _values, size_t _count, static void Load(IArchive& _archive, math::SoaFloat4* _values, size_t _count,
@ -70,7 +70,7 @@ struct Extern<math::SoaFloat4> {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaQuaternion) OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaQuaternion)
template <> template <>
struct Extern<math::SoaQuaternion> { struct OZZ_BASE_DLL Extern<math::SoaQuaternion> {
static void Save(OArchive& _archive, const math::SoaQuaternion* _values, static void Save(OArchive& _archive, const math::SoaQuaternion* _values,
size_t _count); size_t _count);
static void Load(IArchive& _archive, math::SoaQuaternion* _values, static void Load(IArchive& _archive, math::SoaQuaternion* _values,
@ -79,7 +79,7 @@ struct Extern<math::SoaQuaternion> {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaFloat4x4) OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaFloat4x4)
template <> template <>
struct Extern<math::SoaFloat4x4> { struct OZZ_BASE_DLL Extern<math::SoaFloat4x4> {
static void Save(OArchive& _archive, const math::SoaFloat4x4* _values, static void Save(OArchive& _archive, const math::SoaFloat4x4* _values,
size_t _count); size_t _count);
static void Load(IArchive& _archive, math::SoaFloat4x4* _values, static void Load(IArchive& _archive, math::SoaFloat4x4* _values,
@ -88,7 +88,7 @@ struct Extern<math::SoaFloat4x4> {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaTransform) OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaTransform)
template <> template <>
struct Extern<math::SoaTransform> { struct OZZ_BASE_DLL Extern<math::SoaTransform> {
static void Save(OArchive& _archive, const math::SoaTransform* _values, static void Save(OArchive& _archive, const math::SoaTransform* _values,
size_t _count); size_t _count);
static void Load(IArchive& _archive, math::SoaTransform* _values, static void Load(IArchive& _archive, math::SoaTransform* _values,

View File

@ -37,7 +37,7 @@ namespace math {
// Stores an affine transformation with separate translation, rotation and scale // Stores an affine transformation with separate translation, rotation and scale
// attributes. // attributes.
struct Transform { struct OZZ_BASE_DLL Transform {
// Translation affine transformation component. // Translation affine transformation component.
Float3 translation; Float3 translation;

View File

@ -38,7 +38,7 @@ namespace ozz {
namespace math { namespace math {
// Declares a 2d float vector. // Declares a 2d float vector.
struct Float2 { struct OZZ_BASE_DLL Float2 {
float x, y; float x, y;
// Constructs an uninitialized vector. // Constructs an uninitialized vector.
@ -64,7 +64,7 @@ struct Float2 {
}; };
// Declares a 3d float vector. // Declares a 3d float vector.
struct Float3 { struct OZZ_BASE_DLL Float3 {
float x, y, z; float x, y, z;
// Constructs an uninitialized vector. // Constructs an uninitialized vector.
@ -96,7 +96,7 @@ struct Float3 {
}; };
// Declares a 4d float vector. // Declares a 4d float vector.
struct Float4 { struct OZZ_BASE_DLL Float4 {
float x, y, z, w; float x, y, z, w;
// Constructs an uninitialized vector. // Constructs an uninitialized vector.

View File

@ -41,18 +41,18 @@ namespace memory {
class Allocator; class Allocator;
// Defines the default allocator accessor. // Defines the default allocator accessor.
Allocator* default_allocator(); OZZ_BASE_DLL Allocator* default_allocator();
// Set the default allocator, used for all dynamic allocation inside ozz. // Set the default allocator, used for all dynamic allocation inside ozz.
// Returns current memory allocator, such that in can be restored if needed. // Returns current memory allocator, such that in can be restored if needed.
Allocator* SetDefaulAllocator(Allocator* _allocator); OZZ_BASE_DLL Allocator* SetDefaulAllocator(Allocator* _allocator);
// Defines an abstract allocator class. // Defines an abstract allocator class.
// Implements helper methods to allocate/deallocate POD typed objects instead of // Implements helper methods to allocate/deallocate POD typed objects instead of
// raw memory. // raw memory.
// Implements New and Delete function to allocate C++ objects, as a replacement // Implements New and Delete function to allocate C++ objects, as a replacement
// of new and delete operators. // of new and delete operators.
class Allocator { class OZZ_BASE_DLL Allocator {
public: public:
// Default virtual destructor. // Default virtual destructor.
virtual ~Allocator() {} virtual ~Allocator() {}

View File

@ -41,8 +41,13 @@
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include "ozz/base/export.h"
namespace ozz { namespace ozz {
// Defines a byte type, unsigned so right shift doesn't propagate sign bit.
typedef uint8_t byte;
// Finds the number of elements of a statically allocated array. // Finds the number of elements of a statically allocated array.
#define OZZ_ARRAY_SIZE(_array) (sizeof(_array) / sizeof(_array[0])) #define OZZ_ARRAY_SIZE(_array) (sizeof(_array) / sizeof(_array[0]))
@ -80,7 +85,7 @@ namespace ozz {
// Case sensitive wildcard string matching: // Case sensitive wildcard string matching:
// - a ? sign matches any character, except an empty string. // - a ? sign matches any character, except an empty string.
// - a * sign matches any string, including an empty string. // - a * sign matches any string, including an empty string.
bool strmatch(const char* _str, const char* _pattern); OZZ_BASE_DLL bool strmatch(const char* _str, const char* _pattern);
// Tests whether _block is aligned to _alignment boundary. // Tests whether _block is aligned to _alignment boundary.
template <typename _Ty> template <typename _Ty>

View File

@ -52,7 +52,8 @@ struct span {
span() : data_(nullptr), size_(0) {} span() : data_(nullptr), size_(0) {}
// Constructs a range from its extreme values. // Constructs a range from its extreme values.
span(_Ty* _begin, _Ty* _end) : data_(_begin), size_(static_cast<size_t>(_end - _begin)) { span(_Ty* _begin, _Ty* _end)
: data_(_begin), size_(static_cast<size_t>(_end - _begin)) {
assert(_begin <= _end && "Invalid range."); assert(_begin <= _end && "Invalid range.");
} }
@ -84,6 +85,25 @@ struct span {
// Implement cast operator to allow conversions to span<const _Ty>. // Implement cast operator to allow conversions to span<const _Ty>.
operator span<const _Ty>() const { return span<const _Ty>(data_, size_); } operator span<const _Ty>() const { return span<const _Ty>(data_, size_); }
// Subspan
span<element_type> first(index_type _count) const {
assert(_count <= size_ && "Count out of range");
return {data(), _count};
}
span<element_type> last(index_type _count) const {
assert(_count <= size_ && "Count out of range");
return {data() + size_ - _count, _count};
}
span<element_type> subspan(index_type _offset, index_type _count) const {
assert(_offset <= size_ && "Offset out of range");
assert(_count <= size_ && "Count out of range");
assert(_offset <= size_ - _count && "Offset + count out of range");
return {data_ + _offset, _count};
}
// Returns a const reference to element _i of range [begin,end[. // Returns a const reference to element _i of range [begin,end[.
_Ty& operator[](size_t _i) const { _Ty& operator[](size_t _i) const {
assert(_i < size_ && "Index out of range."); assert(_i < size_ && "Index out of range.");
@ -135,35 +155,25 @@ inline span<const typename _Container::value_type> make_span(
// As bytes // As bytes
template <typename _Ty> template <typename _Ty>
inline span<const char> as_bytes(const span<_Ty>& _span) { inline span<const byte> as_bytes(const span<_Ty>& _span) {
return {reinterpret_cast<const char*>(_span.data()), _span.size_bytes()}; return {reinterpret_cast<const byte*>(_span.data()), _span.size_bytes()};
} }
template <typename _Ty> template <typename _Ty>
inline span<char> as_writable_bytes(const span<_Ty>& _span) { inline span<byte> as_writable_bytes(const span<_Ty>& _span) {
// Compilation will fail here if _Ty is const. This prevents from writing to // Compilation will fail here if _Ty is const. This prevents from writing to
// const data. // const data.
return {reinterpret_cast<char*>(_span.data()), _span.size_bytes()}; return {reinterpret_cast<byte*>(_span.data()), _span.size_bytes()};
}
template <>
inline span<const char> as_bytes(const span<char>& _span) {
return _span;
}
template <>
inline span<char> as_writable_bytes(const span<char>& _span) {
return _span;
} }
// Fills a typed span from a byte source span. Source byte span is modified to // Fills a typed span from a byte source span. Source byte span is modified to
// reflect remain size. // reflect remain size.
template <typename _Ty> template <typename _Ty>
inline span<_Ty> fill_span(span<char>& _src, size_t _count) { inline span<_Ty> fill_span(span<byte>& _src, size_t _count) {
assert(ozz::IsAligned(_src.data(), alignof(_Ty)) && "Invalid alignment."); assert(ozz::IsAligned(_src.data(), alignof(_Ty)) && "Invalid alignment.");
const span<_Ty> ret = {reinterpret_cast<_Ty*>(_src.data()), _count}; const span<_Ty> ret = {reinterpret_cast<_Ty*>(_src.data()), _count};
// Validity assertion is done by span constructor. // Validity assertion is done by span constructor.
_src = {reinterpret_cast<char*>(ret.end()), _src.end()}; _src = {reinterpret_cast<byte*>(ret.end()), _src.end()};
return ret; return ret;
} }

View File

@ -0,0 +1,44 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_GEOMETRY_EXPORT_H_
#define OZZ_OZZ_GEOMETRY_EXPORT_H_
#if defined(_MSC_VER) && defined(OZZ_USE_DYNAMIC_LINKING)
#ifdef OZZ_BUILD_GEOMETRY_LIB
// Import/Export for dynamic linking while building ozz
#define OZZ_GEOMETRY_DLL __declspec(dllexport)
#else
#define OZZ_GEOMETRY_DLL __declspec(dllimport)
#endif
#else // defined(_MSC_VER) && defined(OZZ_USE_DYNAMIC_LINKING)
// Static or non msvc linking
#define OZZ_GEOMETRY_DLL
#endif // defined(_MSC_VER) && defined(OZZ_USE_DYNAMIC_LINKING)
#endif // OZZ_OZZ_GEOMETRY_EXPORT_H_

View File

@ -30,6 +30,7 @@
#include "ozz/base/platform.h" #include "ozz/base/platform.h"
#include "ozz/base/span.h" #include "ozz/base/span.h"
#include "ozz/geometry/runtime/export.h"
namespace ozz { namespace ozz {
namespace math { namespace math {
@ -73,7 +74,7 @@ namespace geometry {
// should only be used when input matrices have non uniform scaling or shearing. // should only be used when input matrices have non uniform scaling or shearing.
// The job does not owned the buffers (in/output) and will thus not delete them // The job does not owned the buffers (in/output) and will thus not delete them
// during job's destruction. // during job's destruction.
struct SkinningJob { struct OZZ_GEOMETRY_DLL SkinningJob {
// Default constructor, initializes default values. // Default constructor, initializes default values.
SkinningJob(); SkinningJob();

View File

@ -0,0 +1,44 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_OPTIONS_EXPORT_H_
#define OZZ_OZZ_OPTIONS_EXPORT_H_
#if defined(_MSC_VER) && defined(OZZ_USE_DYNAMIC_LINKING)
#ifdef OZZ_BUILD_OPTIONS_LIB
// Import/Export for dynamic linking while building ozz
#define OZZ_OPTIONS_DLL __declspec(dllexport)
#else
#define OZZ_OPTIONS_DLL __declspec(dllimport)
#endif
#else // defined(_MSC_VER) && defined(OZZ_USE_DYNAMIC_LINKING)
// Static or non msvc linking
#define OZZ_OPTIONS_DLL
#endif // defined(_MSC_VER) && defined(OZZ_USE_DYNAMIC_LINKING)
#endif // OZZ_OZZ_OPTIONS_EXPORT_H_

View File

@ -80,8 +80,8 @@
// registered options. // registered options.
// --version displays executable's version. // --version displays executable's version.
#include <cstddef> #include "ozz/options/export.h"
#include <string> #include "ozz/base/containers/string.h"
namespace ozz { namespace ozz {
namespace options { namespace options {
@ -108,26 +108,28 @@ enum ParseResult {
// _version and _usage are not copied, ParseCommandLine caller is in charge of // _version and _usage are not copied, ParseCommandLine caller is in charge of
// maintaining their allocation during application lifetime. // maintaining their allocation during application lifetime.
// See ParseResult for more details about returned values. // See ParseResult for more details about returned values.
ParseResult ParseCommandLine(int _argc, const char* const* _argv, OZZ_OPTIONS_DLL ParseResult ParseCommandLine(int _argc,
const char* _version, const char* _usage); const char* const* _argv,
const char* _version,
const char* _usage);
// Get the executable path that was extracted from the last call to // Get the executable path that was extracted from the last call to
// ParseCommandLine. // ParseCommandLine.
// If ParseCommandLine has never been called, then ParsedExecutablePath // If ParseCommandLine has never been called, then ParsedExecutablePath
// returns a default empty string. // returns a default empty string.
std::string ParsedExecutablePath(); OZZ_OPTIONS_DLL ozz::string ParsedExecutablePath();
// Get the executable name that was extracted from the last call to // Get the executable name that was extracted from the last call to
// ParseCommandLine. // ParseCommandLine.
// If ParseCommandLine has never been called, then ParsedExecutableName // If ParseCommandLine has never been called, then ParsedExecutableName
// returns a default empty string. // returns a default empty string.
const char* ParsedExecutableName(); OZZ_OPTIONS_DLL const char* ParsedExecutableName();
// Get the executable usage that was extracted from the last call to // Get the executable usage that was extracted from the last call to
// ParseCommandLine. // ParseCommandLine.
// If ParseCommandLine has never been called, then ParsedExecutableUsage // If ParseCommandLine has never been called, then ParsedExecutableUsage
// returns a default empty string. // returns a default empty string.
const char* ParsedExecutableUsage(); OZZ_OPTIONS_DLL const char* ParsedExecutableUsage();
#define OZZ_OPTIONS_DECLARE_BOOL(_name, _help, _default, _required) \ #define OZZ_OPTIONS_DECLARE_BOOL(_name, _help, _default, _required) \
OZZ_OPTIONS_DECLARE_VARIABLE(ozz::options::BoolOption, _name, _help, \ OZZ_OPTIONS_DECLARE_VARIABLE(ozz::options::BoolOption, _name, _help, \
@ -168,7 +170,7 @@ const char* ParsedExecutableUsage();
#_name, _help, _default, _required, _fn); #_name, _help, _default, _required, _fn);
// Defines option interface. // Defines option interface.
class Option { class OZZ_OPTIONS_DLL Option {
public: public:
// Returns option's name. // Returns option's name.
const char* name() const { return name_; } const char* name() const { return name_; }
@ -196,7 +198,7 @@ class Option {
void RestoreDefault(); void RestoreDefault();
// Outputs default value as a string. // Outputs default value as a string.
virtual std::string FormatDefault() const = 0; virtual ozz::string FormatDefault() const = 0;
// Outputs type of value as a c string. // Outputs type of value as a c string.
virtual const char* FormatType() const = 0; virtual const char* FormatType() const = 0;
@ -246,7 +248,7 @@ class Option {
// Defines a strongly typed option class // Defines a strongly typed option class
template <typename _Type> template <typename _Type>
class TypedOption : public Option { class OZZ_OPTIONS_DLL TypedOption : public Option {
public: public:
// Lets the type be known. // Lets the type be known.
typedef _Type Type; typedef _Type Type;
@ -277,7 +279,7 @@ class TypedOption : public Option {
virtual void RestoreDefaultImpl() { value_ = default_; } virtual void RestoreDefaultImpl() { value_ = default_; }
// Outputs default value as a string. // Outputs default value as a string.
virtual std::string FormatDefault() const; virtual ozz::string FormatDefault() const;
// Outputs type of value as a string. // Outputs type of value as a string.
virtual const char* FormatType() const; virtual const char* FormatType() const;
@ -298,7 +300,7 @@ typedef TypedOption<const char*> StringOption;
// Declares the option parser class. // Declares the option parser class.
// Option are registered by the parser and updated when command line arguments // Option are registered by the parser and updated when command line arguments
// are parsed. // are parsed.
class Parser { class OZZ_OPTIONS_DLL Parser {
public: public:
// Construct a parser with only built-in options. // Construct a parser with only built-in options.
Parser(); Parser();
@ -354,7 +356,7 @@ class Parser {
const char* version() const; const char* version() const;
// Returns the path of the executable that was extracted from argument 0. // Returns the path of the executable that was extracted from argument 0.
std::string executable_path() const; ozz::string executable_path() const;
// Returns the name of the executable that was extracted from argument 0. // Returns the name of the executable that was extracted from argument 0.
const char* executable_name() const; const char* executable_name() const;

View File

@ -5,16 +5,19 @@ add_custom_command(
"${CMAKE_CURRENT_LIST_DIR}/README.md" "${CMAKE_CURRENT_LIST_DIR}/README.md"
"${ozz_media_directory}/bin/pab_skeleton.ozz" "${ozz_media_directory}/bin/pab_skeleton.ozz"
"${ozz_media_directory}/bin/pab_walk.ozz" "${ozz_media_directory}/bin/pab_walk.ozz"
"${ozz_media_directory}/bin/pab_crackhead_additive.ozz" "${ozz_media_directory}/bin/pab_curl_additive.ozz"
"${ozz_media_directory}/bin/pab_splay_additive.ozz"
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/README.md" OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/README.md"
"${CMAKE_CURRENT_BINARY_DIR}/media/skeleton.ozz" "${CMAKE_CURRENT_BINARY_DIR}/media/skeleton.ozz"
"${CMAKE_CURRENT_BINARY_DIR}/media/animation_base.ozz" "${CMAKE_CURRENT_BINARY_DIR}/media/animation_base.ozz"
"${CMAKE_CURRENT_BINARY_DIR}/media/animation_additive.ozz" "${CMAKE_CURRENT_BINARY_DIR}/media/animation_curl_additive.ozz"
"${CMAKE_CURRENT_BINARY_DIR}/media/animation_splay_additive.ozz"
COMMAND ${CMAKE_COMMAND} -E make_directory media COMMAND ${CMAKE_COMMAND} -E make_directory media
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_LIST_DIR}/README.md" . COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_LIST_DIR}/README.md" .
COMMAND ${CMAKE_COMMAND} -E copy "${ozz_media_directory}/bin/pab_skeleton.ozz" "./media/skeleton.ozz" COMMAND ${CMAKE_COMMAND} -E copy "${ozz_media_directory}/bin/pab_skeleton.ozz" "./media/skeleton.ozz"
COMMAND ${CMAKE_COMMAND} -E copy "${ozz_media_directory}/bin/pab_walk.ozz" "./media/animation_base.ozz" COMMAND ${CMAKE_COMMAND} -E copy "${ozz_media_directory}/bin/pab_walk.ozz" "./media/animation_base.ozz"
COMMAND ${CMAKE_COMMAND} -E copy "${ozz_media_directory}/bin/pab_crackhead_additive.ozz" "./media/animation_additive.ozz" COMMAND ${CMAKE_COMMAND} -E copy "${ozz_media_directory}/bin/pab_curl_additive.ozz" "./media/animation_curl_additive.ozz"
COMMAND ${CMAKE_COMMAND} -E copy "${ozz_media_directory}/bin/pab_splay_additive.ozz" "./media/animation_splay_additive.ozz"
VERBATIM) VERBATIM)
add_executable(sample_additive add_executable(sample_additive
@ -22,10 +25,11 @@ add_executable(sample_additive
"${CMAKE_CURRENT_BINARY_DIR}/README.md" "${CMAKE_CURRENT_BINARY_DIR}/README.md"
"${CMAKE_CURRENT_BINARY_DIR}/media/skeleton.ozz" "${CMAKE_CURRENT_BINARY_DIR}/media/skeleton.ozz"
"${CMAKE_CURRENT_BINARY_DIR}/media/animation_base.ozz" "${CMAKE_CURRENT_BINARY_DIR}/media/animation_base.ozz"
"${CMAKE_CURRENT_BINARY_DIR}/media/animation_additive.ozz") "${CMAKE_CURRENT_BINARY_DIR}/media/animation_curl_additive.ozz"
"${CMAKE_CURRENT_BINARY_DIR}/media/animation_splay_additive.ozz")
target_link_libraries(sample_additive target_link_libraries(sample_additive
sample_framework) sample_framework)
target_copy_shared_libraries(sample_additive)
set_target_properties(sample_additive set_target_properties(sample_additive
PROPERTIES FOLDER "samples") PROPERTIES FOLDER "samples")
@ -46,10 +50,12 @@ else()
endif(EMSCRIPTEN) endif(EMSCRIPTEN)
add_test(NAME sample_additive COMMAND sample_additive "--max_idle_loops=${ozz_sample_testing_loops}" $<$<BOOL:${ozz_run_tests_headless}>:--norender>) add_test(NAME sample_additive COMMAND sample_additive "--max_idle_loops=${ozz_sample_testing_loops}" $<$<BOOL:${ozz_run_tests_headless}>:--norender>)
add_test(NAME sample_additive_path COMMAND sample_additive "--skeleton=media/skeleton.ozz" "--animation=media/animation_base.ozz" "--additive_animation=media/animation_additive.ozz" "--max_idle_loops=${ozz_sample_testing_loops}" $<$<BOOL:${ozz_run_tests_headless}>:--norender>) add_test(NAME sample_additive_path COMMAND sample_additive "--skeleton=media/skeleton.ozz" "--animation=media/animation_base.ozz" "--splay_animation=media/animation_splay_additive.ozz" "--curl_animation=media/animation_curl_additive.ozz" "--max_idle_loops=${ozz_sample_testing_loops}" $<$<BOOL:${ozz_run_tests_headless}>:--norender>)
add_test(NAME sample_additive_invalid_skeleton_path COMMAND sample_additive "--skeleton=media/bad_skeleton.ozz" $<$<BOOL:${ozz_run_tests_headless}>:--norender>) add_test(NAME sample_additive_invalid_skeleton_path COMMAND sample_additive "--skeleton=media/bad_skeleton.ozz" $<$<BOOL:${ozz_run_tests_headless}>:--norender>)
set_tests_properties(sample_additive_invalid_skeleton_path PROPERTIES WILL_FAIL true) set_tests_properties(sample_additive_invalid_skeleton_path PROPERTIES WILL_FAIL true)
add_test(NAME sample_additive_invalid_animation_path1 COMMAND sample_additive "--animation=media/bad_animation.ozz" $<$<BOOL:${ozz_run_tests_headless}>:--norender>) add_test(NAME sample_additive_invalid_animation_path1 COMMAND sample_additive "--animation=media/bad_animation.ozz" $<$<BOOL:${ozz_run_tests_headless}>:--norender>)
set_tests_properties(sample_additive_invalid_animation_path1 PROPERTIES WILL_FAIL true) set_tests_properties(sample_additive_invalid_animation_path1 PROPERTIES WILL_FAIL true)
add_test(NAME sample_additive_invalid_animation_path2 COMMAND sample_additive "--additive_animation=media/bad_animation.ozz" $<$<BOOL:${ozz_run_tests_headless}>:--norender>) add_test(NAME sample_additive_invalid_animation_path2 COMMAND sample_additive "--curl_animation=media/bad_animation.ozz" $<$<BOOL:${ozz_run_tests_headless}>:--norender>)
set_tests_properties(sample_additive_invalid_animation_path2 PROPERTIES WILL_FAIL true) set_tests_properties(sample_additive_invalid_animation_path2 PROPERTIES WILL_FAIL true)
add_test(NAME sample_additive_invalid_animation_path3 COMMAND sample_additive "--splay_animation=media/bad_animation.ozz" $<$<BOOL:${ozz_run_tests_headless}>:--norender>)
set_tests_properties(sample_additive_invalid_animation_path3 PROPERTIES WILL_FAIL true)

View File

@ -2,32 +2,25 @@
## Description ## Description
Additive blending is a key concept in run-time animation. By superimposing a movement on top of a playing animation, it allows to add variety while lessening animation count and complexity. Additive blending is a key concept in run-time animation. Superimposing a movement on top of a playing animation allows to add variety while lessening animation count and management complexity. In this sample, 2 *splay* and *curl* hand animations are a added to a *walk* cycle. A weight is associated to each additive layers independently, allowing to control fingers.
In this sample, a "cracking head" animation is added to a "walk" cycle. Note that no synchronization is required between the two animations.
## Concept ## Concept
Additive blending is different to normal blending because it does not interpolate from a pose to an other. Instead it combines poses, meaning you can see the two animations at the same time. In this example the walk cycle is never altered. The cracking head and shoulder movements from the additive animation are simply (visually speaking) added. Additive blending is different from normal blending because it does not interpolate from a pose to an other. Instead it combines poses, meaning the two animations can be seen at the same time. In this example the walk cycle is never altered. Fingers curl and splay poses coming from the additive animation are simply added (visually speaking) to the base animation. For the purpose of this sample, only the first frames of the 2 additive animations are used, aka a fixed pose for each (curl and splay poses).
Additive blending is performed by ozz::animation::BlendingJob. ozz::animation::BlendingJob exposes additive layers with the same input as normal blending layers: per joint local transforms, a global layer weight and optional per-joint weights. The main differences are that additive blending is done at the end of the normal blending pass, with a different equation. Additive blending is performed by ozz::animation::BlendingJob. BlendingJob exposes additive layers with the same input as normal blending layers: per joint local transforms, a global layer weight and optional per-joint weights. The main differences are that additive blending is done at the end of the normal blending pass, with a different equation.
The additive (or delta) animation is created by subtracting a reference pose from a source animation. ozz proposes a ozz::animation::offline::AdditiveAnimationBuilder utility to build additive animations. It uses the first frame of the animation as the reference pose. fbx2ozz supports additive configuration option to export delta animations from a source file. The additive (or delta) animation is created by subtracting a reference pose from a source animation. ozz proposes a ozz::animation::offline::AdditiveAnimationBuilder utility to build additive animations. It uses the first frame of the animation as the reference pose. fbx2ozz and gltf2ozz support additive configuration option to export delta animations from a source file.
Additionally, the sample uses an optional mask to blend the additive animation on the character upper body only. See partial blending sample for more details.
## Sample usage ## Sample usage
The sample proposes to modify main and additive layers weights: The sample proposes to tune base and additive (curl & splay) layers weights. Additive layers weight are exposed via 2d slider to make it easier to control together.
- Normal blending layer weight.
- Additive blending layer weight.
- Upper body masking activation and base joint selection.
Both main and additive animation playback parameters are exposed.
## Implementation ## Implementation
1. Loads main, additive animations, and their skeleton. See "playback" sample for more details. 1. Loads base, additive (curl and splay) animations, and their skeleton. See "playback" sample for more details.
2. Samples each animation to get local-space transformations. Sampling an additive animation is not different from a standard one. 2. At initialization time, the first frame of curl and splay animations are sampled in order to extract their respective local-space transformations. Sampling an additive animation is not different from a standard one. The 2 animations are deleted as only the extracted pose will be used further.
3. Setups ozz::animation::BlendingJob object. BlendingJob object takes as input two arrays of BlendingJob::Layer, one for standard blending, the other for additive blending. Each layer is setup with its weights and the local-space transforms outputted from the sampling stage. 3. At runtime, base animation is sampled to get skeleton base local-space transformations.
3. Setups ozz::animation::BlendingJob object. BlendingJob takes as input two arrays of BlendingJob::Layer, one for standard blending (base animation sampling output), the other for additive blending (the 2 curl and splay poses). Each layer is setup with its weights and the local-space transforms.
4. Convert local-space transformations to model-space matrices using ozz::animation::LocalToModelJob. It takes as input the skeleton (to know about joint's hierarchy) and local-space transforms outputted from the blending pass. Output is model-space matrices array. 4. Convert local-space transformations to model-space matrices using ozz::animation::LocalToModelJob. It takes as input the skeleton (to know about joint's hierarchy) and local-space transforms outputted from the blending pass. Output is model-space matrices array.
5. Model-space matrices array is then used for rendering skeleton posture. 5. Model-space matrices array is then used for rendering the animated skeleton pose (or the skinned mesh in a real world example).

View File

@ -39,6 +39,7 @@
#include "ozz/animation/runtime/skeleton_utils.h" #include "ozz/animation/runtime/skeleton_utils.h"
#include "ozz/base/containers/vector.h" #include "ozz/base/containers/vector.h"
#include "ozz/base/log.h" #include "ozz/base/log.h"
#include "ozz/base/maths/box.h"
#include "ozz/base/maths/simd_math.h" #include "ozz/base/maths/simd_math.h"
#include "ozz/base/maths/soa_transform.h" #include "ozz/base/maths/soa_transform.h"
#include "ozz/base/maths/vec_float.h" #include "ozz/base/maths/vec_float.h"
@ -56,68 +57,65 @@ OZZ_OPTIONS_DECLARE_STRING(animation,
// Additive animation archive can be specified as an option. // Additive animation archive can be specified as an option.
OZZ_OPTIONS_DECLARE_STRING( OZZ_OPTIONS_DECLARE_STRING(
additive_animation, "Path to the additive animation (ozz archive format).", splay_animation,
"media/animation_additive.ozz", false) "Path to the additive splay animation (ozz archive format).",
"media/animation_splay_additive.ozz", false)
OZZ_OPTIONS_DECLARE_STRING(
curl_animation, "Path to the additive curl animation (ozz archive format).",
"media/animation_curl_additive.ozz", false)
class AdditiveBlendSampleApplication : public ozz::sample::Application { class AdditiveBlendSampleApplication : public ozz::sample::Application {
public: public:
AdditiveBlendSampleApplication() AdditiveBlendSampleApplication()
: upper_body_root_(0), : base_weight_(0.f),
upper_body_mask_enable_(true), additive_weigths_{.3f, .9f},
upper_body_joint_weight_setting_(1.f), auto_animate_weights_(true) {}
threshold_(ozz::animation::BlendingJob().threshold) {}
protected: protected:
// Updates current animation time and skeleton pose. // Updates current animation time and skeleton pose.
virtual bool OnUpdate(float _dt, float) { virtual bool OnUpdate(float _dt, float) {
// Updates and samples both animations to their respective local space // For the sample purpose, animates additive weights automatically so the
// transform buffers. // hand moves.
for (int i = 0; i < kNumLayers; ++i) { if (auto_animate_weights_) {
Sampler& sampler = samplers_[i]; AnimateWeights(_dt);
}
// Updates animations time. // Updates base animation time for main animation.
sampler.controller.Update(sampler.animation, _dt); controller_.Update(base_animation_, _dt);
// Setup sampling job. // Setup sampling job.
ozz::animation::SamplingJob sampling_job; ozz::animation::SamplingJob sampling_job;
sampling_job.animation = &sampler.animation; sampling_job.animation = &base_animation_;
sampling_job.cache = &sampler.cache; sampling_job.context = &context_;
sampling_job.ratio = sampler.controller.time_ratio(); sampling_job.ratio = controller_.time_ratio();
sampling_job.output = make_span(sampler.locals); sampling_job.output = make_span(locals_);
// Samples animation. // Samples animation.
if (!sampling_job.Run()) { if (!sampling_job.Run()) {
return false; return false;
} }
}
// Blends animations. // Setups blending job layers.
// Blends the local spaces transforms computed by sampling all animations
// (1st stage just above), and outputs the result to the local space
// transform buffer blended_locals_
// Prepares standard blending layers. // Main animation is used as-is.
ozz::animation::BlendingJob::Layer layers[1]; ozz::animation::BlendingJob::Layer layers[1];
layers[0].transform = make_span(samplers_[kMainAnimation].locals); layers[0].transform = make_span(locals_);
layers[0].weight = samplers_[kMainAnimation].weight_setting; layers[0].weight = base_weight_;
layers[0].joint_weights = make_span(base_joint_weights_);
// Prepares additive blending layers. // The two additive layers (curl and splay) are blended on top of the main
ozz::animation::BlendingJob::Layer additive_layers[1]; // layer.
additive_layers[0].transform = ozz::animation::BlendingJob::Layer additive_layers[kNumLayers];
make_span(samplers_[kAdditiveAnimation].locals); for (size_t i = 0; i < kNumLayers; ++i) {
additive_layers[0].weight = samplers_[kAdditiveAnimation].weight_setting; additive_layers[i].transform = make_span(additive_locals_[i]);
additive_layers[i].weight = additive_weigths_[i];
// Set per-joint weights for the additive blended layer.
if (upper_body_mask_enable_) {
additive_layers[0].joint_weights = make_span(upper_body_joint_weights_);
} }
// Setups blending job. // Setups blending job.
ozz::animation::BlendingJob blend_job; ozz::animation::BlendingJob blend_job;
blend_job.threshold = threshold_;
blend_job.layers = layers; blend_job.layers = layers;
blend_job.additive_layers = additive_layers; blend_job.additive_layers = additive_layers;
blend_job.bind_pose = skeleton_.joint_bind_poses(); blend_job.rest_pose = skeleton_.joint_rest_poses();
blend_job.output = make_span(blended_locals_); blend_job.output = make_span(blended_locals_);
// Blends. // Blends.
@ -141,12 +139,34 @@ class AdditiveBlendSampleApplication : public ozz::sample::Application {
return true; return true;
} }
void AnimateWeights(float _dt) {
static float t = 0.f;
t += _dt;
additive_weigths_[0] = .5f + std::cos(t * 1.7f) * .5f;
additive_weigths_[1] = .5f + std::cos(t * 2.5f) * .5f;
}
// Samples animation, transforms to model space and renders. // Samples animation, transforms to model space and renders.
virtual bool OnDisplay(ozz::sample::Renderer* _renderer) { virtual bool OnDisplay(ozz::sample::Renderer* _renderer) {
return _renderer->DrawPosture(skeleton_, make_span(models_), return _renderer->DrawPosture(skeleton_, make_span(models_),
ozz::math::Float4x4::identity()); ozz::math::Float4x4::identity());
} }
bool SetJointWeights(const char* _name, float _weight) {
const auto set_joint = [this, _weight](int _joint, int) {
ozz::math::SimdFloat4& soa_weight = base_joint_weights_[_joint / 4];
soa_weight = ozz::math::SetI(
soa_weight, ozz::math::simd_float4::Load1(_weight), _joint % 4);
};
const int joint = FindJoint(skeleton_, _name);
if (joint >= 0) {
ozz::animation::IterateJointsDF(skeleton_, set_joint, joint);
return true;
}
return false;
}
virtual bool OnInitialize() { virtual bool OnInitialize() {
// Reading skeleton. // Reading skeleton.
if (!ozz::sample::LoadSkeleton(OPTIONS_skeleton, &skeleton_)) { if (!ozz::sample::LoadSkeleton(OPTIONS_skeleton, &skeleton_)) {
@ -155,81 +175,70 @@ class AdditiveBlendSampleApplication : public ozz::sample::Application {
const int num_soa_joints = skeleton_.num_soa_joints(); const int num_soa_joints = skeleton_.num_soa_joints();
const int num_joints = skeleton_.num_joints(); const int num_joints = skeleton_.num_joints();
// Reading animations. // Reads base animation.
const char* filenames[] = {OPTIONS_animation, OPTIONS_additive_animation}; if (!ozz::sample::LoadAnimation(OPTIONS_animation, &base_animation_)) {
for (int i = 0; i < kNumLayers; ++i) {
Sampler& sampler = samplers_[i];
if (!ozz::sample::LoadAnimation(filenames[i], &sampler.animation)) {
return false; return false;
} }
// Allocates sampler runtime buffers. if (num_joints != base_animation_.num_tracks()) {
sampler.locals.resize(num_soa_joints); return false;
// Allocates a cache that matches animation requirements.
sampler.cache.Resize(num_joints);
} }
// Default weight settings. // Allocates sampling context.
samplers_[kMainAnimation].weight_setting = 1.f; context_.Resize(num_joints);
upper_body_joint_weight_setting_ = 1.f; // Allocates local space runtime buffers for base animation.
samplers_[kAdditiveAnimation].weight_setting = 1.f; locals_.resize(num_soa_joints);
// Allocates local space runtime buffers of blended data.
blended_locals_.resize(num_soa_joints);
// Allocates model space runtime buffers of blended data. // Allocates model space runtime buffers of blended data.
models_.resize(num_joints); models_.resize(num_joints);
// Allocates per-joint weights used for the partial additive animation. // Storage for blending stage output.
// Note that this is a Soa structure. blended_locals_.resize(num_soa_joints);
upper_body_joint_weights_.resize(num_soa_joints);
// Finds the "Spine1" joint in the joint hierarchy. // Allocates and sets base animation mask weights to one.
for (int i = 0; i < num_joints; ++i) { base_joint_weights_.resize(num_soa_joints, ozz::math::simd_float4::one());
if (std::strstr(skeleton_.joint_names()[i], "Spine1")) { SetJointWeights("Lefthand", 0.f);
upper_body_root_ = i; SetJointWeights("RightHand", 0.f);
break;
// Reads and extract additive animations pose.
const char* filenames[] = {OPTIONS_splay_animation, OPTIONS_curl_animation};
for (int i = 0; i < kNumLayers; ++i) {
// Reads animation on the stack as it won't need to be maintained in
// memory. Only the pose is needed.
ozz::animation::Animation animation;
if (!ozz::sample::LoadAnimation(filenames[i], &animation)) {
return false;
} }
if (num_joints != animation.num_tracks()) {
return false;
}
// Allocates additive poses, aka buffers of Soa tranforms.
additive_locals_[i].resize(num_soa_joints);
// Samples the first frame pose.
ozz::animation::SamplingJob sampling_job;
sampling_job.animation = &animation;
sampling_job.context = &context_;
sampling_job.ratio = 0.f; // Only needs the first frame pose
sampling_job.output = make_span(additive_locals_[i]);
// Samples animation.
if (!sampling_job.Run()) {
return false;
}
// Invalidates context which will be re-used for another animation.
// This is usually not needed, animation address on the stack is the same
// each loop, hence creating an issue as animation content is changing.
context_.Invalidate();
} }
SetupPerJointWeights();
return true; return true;
} }
// Helper functor used to set weights while traversing joints hierarchy.
struct WeightSetupIterator {
WeightSetupIterator(ozz::vector<ozz::math::SimdFloat4>* _weights,
float _weight_setting)
: weights(_weights), weight_setting(_weight_setting) {}
void operator()(int _joint, int) {
ozz::math::SimdFloat4& soa_weight = weights->at(_joint / 4);
soa_weight = ozz::math::SetI(
soa_weight, ozz::math::simd_float4::Load1(weight_setting),
_joint % 4);
}
ozz::vector<ozz::math::SimdFloat4>* weights;
float weight_setting;
};
void SetupPerJointWeights() {
// Setup partial animation mask. This mask is defined by a weight_setting
// assigned to each joint of the hierarchy. Joint to disable are set to a
// weight_setting of 0.f, and enabled joints are set to 1.f.
// Disables all joints: set all weights to 0.
for (int i = 0; i < skeleton_.num_soa_joints(); ++i) {
upper_body_joint_weights_[i] = ozz::math::simd_float4::zero();
}
// Extracts the list of children of the shoulder
WeightSetupIterator it(&upper_body_joint_weights_,
upper_body_joint_weight_setting_);
IterateJointsDF(skeleton_, it, upper_body_root_);
}
virtual void OnDestroy() {} virtual void OnDestroy() {}
virtual bool OnGui(ozz::sample::ImGui* _im_gui) { virtual bool OnGui(ozz::sample::ImGui* _im_gui) {
@ -241,69 +250,31 @@ class AdditiveBlendSampleApplication : public ozz::sample::Application {
ozz::sample::ImGui::OpenClose oc(_im_gui, "Blending parameters", &open); ozz::sample::ImGui::OpenClose oc(_im_gui, "Blending parameters", &open);
if (open) { if (open) {
_im_gui->DoLabel("Main layer:"); _im_gui->DoLabel("Main layer:");
std::sprintf(label, "Layer weight: %.2f", std::sprintf(label, "Layer weight: %.2f", base_weight_);
samplers_[kMainAnimation].weight_setting); _im_gui->DoSlider(label, 0.f, 1.f, &base_weight_, 1.f);
_im_gui->DoSlider(label, 0.f, 1.f,
&samplers_[kMainAnimation].weight_setting, 1.f);
_im_gui->DoLabel("Additive layer:"); _im_gui->DoLabel("Additive layer:");
std::sprintf(label, "Layer weight: %.2f", _im_gui->DoCheckBox("Animates weights", &auto_animate_weights_);
samplers_[kAdditiveAnimation].weight_setting); ozz::array<float, OZZ_ARRAY_SIZE(additive_weigths_)> weights;
_im_gui->DoSlider(label, -1.f, 1.f, std::memcpy(weights.data(), additive_weigths_,
&samplers_[kAdditiveAnimation].weight_setting, 1.f); sizeof(additive_weigths_));
_im_gui->DoLabel("Global settings:");
std::sprintf(label, "Threshold: %.2f", threshold_); std::sprintf(label, "Weights\nCurl: %.2f\nSplay: %.2f",
_im_gui->DoSlider(label, .01f, 1.f, &threshold_); additive_weigths_[kCurl], additive_weigths_[kSplay]);
if (_im_gui->DoSlider2D(label, {{0.f, 0.f}}, {{1.f, 1.f}}, &weights)) {
auto_animate_weights_ = false; // User interacted.
std::memcpy(additive_weigths_, weights.data(),
sizeof(additive_weigths_));
} }
} }
// Exposes selection of the root of the partial blending hierarchy.
{
static bool open = true;
ozz::sample::ImGui::OpenClose oc(_im_gui, "Upper body masking", &open);
if (open) {
bool rebuild_joint_weights = false;
rebuild_joint_weights |=
_im_gui->DoCheckBox("Enable mask", &upper_body_mask_enable_);
std::sprintf(label, "Joints weight: %.2f",
upper_body_joint_weight_setting_);
rebuild_joint_weights |= _im_gui->DoSlider(
label, 0.f, 1.f, &upper_body_joint_weight_setting_, 1.f,
upper_body_mask_enable_);
if (skeleton_.num_joints() != 0) {
_im_gui->DoLabel("Root of the upper body hierarchy:",
ozz::sample::ImGui::kLeft, false);
std::sprintf(label, "%s (%d)",
skeleton_.joint_names()[upper_body_root_],
upper_body_root_);
rebuild_joint_weights |= _im_gui->DoSlider(
label, 0, skeleton_.num_joints() - 1, &upper_body_root_, 1.f,
upper_body_mask_enable_);
} }
// Rebuilds per-joint weights if something has changed. // Exposes base animation runtime playback controls.
if (rebuild_joint_weights) {
SetupPerJointWeights();
}
}
}
// Exposes animations runtime playback controls.
{ {
static bool oc_open = true; static bool oc_open = true;
ozz::sample::ImGui::OpenClose oc(_im_gui, "Animation control", &oc_open); ozz::sample::ImGui::OpenClose oc(_im_gui, "Animation control", &oc_open);
if (oc_open) { if (oc_open) {
static bool open[kNumLayers] = {true, true}; controller_.OnGui(base_animation_, _im_gui);
const char* oc_names[kNumLayers] = {"Main animation",
"Additive animation"};
for (int i = 0; i < kNumLayers; ++i) {
Sampler& sampler = samplers_[i];
ozz::sample::ImGui::OpenClose loc(_im_gui, oc_names[i], nullptr);
if (open[i]) {
sampler.controller.OnGui(sampler.animation, _im_gui);
}
}
} }
} }
@ -311,62 +282,55 @@ class AdditiveBlendSampleApplication : public ozz::sample::Application {
} }
virtual void GetSceneBounds(ozz::math::Box* _bound) const { virtual void GetSceneBounds(ozz::math::Box* _bound) const {
// Finds the "hand" joint in the joint hierarchy.
const int hand = FindJoint(skeleton_, "Lefthand");
// Creates a bounding volume around the hand.
if (hand != -1) {
const ozz::math::Float4x4& hand_matrix = models_[hand];
ozz::math::Float3 hand_position;
ozz::math::Store3PtrU(hand_matrix.cols[3], &hand_position.x);
const ozz::math::Float3 extent(.15f);
_bound->min = hand_position - extent;
_bound->max = hand_position + extent;
} else {
ozz::sample::ComputePostureBounds(make_span(models_), _bound); ozz::sample::ComputePostureBounds(make_span(models_), _bound);
} }
}
private: private:
// Runtime skeleton. // Runtime skeleton.
ozz::animation::Skeleton skeleton_; ozz::animation::Skeleton skeleton_;
// The number of layers to blend. // The number of additive layers to blend.
enum { enum { kSplay, kCurl, kNumLayers };
kMainAnimation = 0,
kAdditiveAnimation = 1,
kNumLayers = 2,
};
// Sampler structure contains all the data required to sample a single
// animation.
struct Sampler {
// Constructor, default initialization.
Sampler() : weight_setting(1.f) {}
// Playback animation controller. This is a utility class that helps with
// controlling animation playback time.
ozz::sample::PlaybackController controller;
// Blending weight_setting for the layer.
float weight_setting;
// Runtime animation. // Runtime animation.
ozz::animation::Animation animation; ozz::animation::Animation base_animation_;
// Sampling cache. // Per-joint weights used to define the base animation mask. Allows to remove
ozz::animation::SamplingCache cache; // hands from base animations.
ozz::vector<ozz::math::SimdFloat4> base_joint_weights_;
// Buffer of local transforms as sampled from animation_. // Main animation controller. This is a utility class that helps with
ozz::vector<ozz::math::SoaTransform> locals; // controlling animation playback time.
ozz::sample::PlaybackController controller_;
} samplers_[kNumLayers]; // kNumLayers animations to blend. // Sampling context.
ozz::animation::SamplingJob::Context context_;
// Index of the joint at the base of the upper body hierarchy. // Buffer of local transforms as sampled from main animation_.
int upper_body_root_; ozz::vector<ozz::math::SoaTransform> locals_;
// Enables upper boddy per-joint weights. // Blending weight of the base animation layer.
bool upper_body_mask_enable_; float base_weight_;
// Blending weight_setting setting of the joints of this layer that are // Poses of local transforms as sampled from curl and splay animations.
// affected // They are sampled during initialization, as a single pose is used.
// by the masking. ozz::vector<ozz::math::SoaTransform> additive_locals_[kNumLayers];
float upper_body_joint_weight_setting_;
// Per-joint weights used to define the partial animation mask. Allows to // Blending weight of the additive animation layer.
// select which joints are considered during blending, and their individual float additive_weigths_[kNumLayers];
// weight_setting.
ozz::vector<ozz::math::SimdFloat4> upper_body_joint_weights_;
// Blending job bind pose threshold.
float threshold_;
// Buffer of local transforms which stores the blending result. // Buffer of local transforms which stores the blending result.
ozz::vector<ozz::math::SoaTransform> blended_locals_; ozz::vector<ozz::math::SoaTransform> blended_locals_;
@ -374,7 +338,10 @@ class AdditiveBlendSampleApplication : public ozz::sample::Application {
// Buffer of model space matrices. These are computed by the local-to-model // Buffer of model space matrices. These are computed by the local-to-model
// job after the blending stage. // job after the blending stage.
ozz::vector<ozz::math::Float4x4> models_; ozz::vector<ozz::math::Float4x4> models_;
};
// Automatically animates additive weights.
bool auto_animate_weights_;
};
int main(int _argc, const char** _argv) { int main(int _argc, const char** _argv) {
const char* title = "Ozz-animation sample: Additive animations blending"; const char* title = "Ozz-animation sample: Additive animations blending";

View File

@ -21,7 +21,7 @@ add_executable(sample_attach
target_link_libraries(sample_attach target_link_libraries(sample_attach
sample_framework) sample_framework)
target_copy_shared_libraries(sample_attach)
set_target_properties(sample_attach set_target_properties(sample_attach
PROPERTIES FOLDER "samples") PROPERTIES FOLDER "samples")

View File

@ -25,24 +25,21 @@
// // // //
//----------------------------------------------------------------------------// //----------------------------------------------------------------------------//
#include "ozz/animation/runtime/animation.h"
#include "ozz/animation/runtime/local_to_model_job.h"
#include "ozz/animation/runtime/sampling_job.h"
#include "ozz/animation/runtime/skeleton.h"
#include "ozz/base/log.h"
#include "ozz/base/maths/box.h"
#include "ozz/base/maths/simd_math.h"
#include "ozz/base/maths/soa_transform.h"
#include "ozz/base/maths/vec_float.h"
#include "ozz/options/options.h"
#include "framework/application.h" #include "framework/application.h"
#include "framework/imgui.h" #include "framework/imgui.h"
#include "framework/renderer.h" #include "framework/renderer.h"
#include "framework/utils.h" #include "framework/utils.h"
#include "ozz/animation/runtime/animation.h"
#include "ozz/animation/runtime/local_to_model_job.h"
#include "ozz/animation/runtime/sampling_job.h"
#include "ozz/animation/runtime/skeleton.h"
#include "ozz/animation/runtime/skeleton_utils.h"
#include "ozz/base/log.h"
#include "ozz/base/maths/box.h"
#include "ozz/base/maths/simd_math.h"
#include "ozz/base/maths/soa_transform.h"
#include "ozz/base/maths/vec_float.h"
#include "ozz/options/options.h"
// Skeleton archive can be specified as an option. // Skeleton archive can be specified as an option.
OZZ_OPTIONS_DECLARE_STRING(skeleton, OZZ_OPTIONS_DECLARE_STRING(skeleton,
@ -67,7 +64,7 @@ class AttachSampleApplication : public ozz::sample::Application {
// Samples optimized animation at t = animation_time_. // Samples optimized animation at t = animation_time_.
ozz::animation::SamplingJob sampling_job; ozz::animation::SamplingJob sampling_job;
sampling_job.animation = &animation_; sampling_job.animation = &animation_;
sampling_job.cache = &cache_; sampling_job.context = &context_;
sampling_job.ratio = controller_.time_ratio(); sampling_job.ratio = controller_.time_ratio();
sampling_job.output = make_span(locals_); sampling_job.output = make_span(locals_);
if (!sampling_job.Run()) { if (!sampling_job.Run()) {
@ -133,15 +130,13 @@ class AttachSampleApplication : public ozz::sample::Application {
locals_.resize(num_soa_joints); locals_.resize(num_soa_joints);
models_.resize(num_joints); models_.resize(num_joints);
// Allocates a cache that matches animation requirements. // Allocates a context that matches animation requirements.
cache_.Resize(num_joints); context_.Resize(num_joints);
// Finds the joint where the object should be attached. // Finds the joint where the object should be attached.
for (int i = 0; i < num_joints; i++) { attachment_ = FindJoint(skeleton_, "LeftHandMiddle1");
if (std::strstr(skeleton_.joint_names()[i], "LeftHandMiddle")) { if (attachment_ < 0) {
attachment_ = i; return false;
break;
}
} }
return true; return true;
@ -198,8 +193,8 @@ class AttachSampleApplication : public ozz::sample::Application {
// Runtime animation. // Runtime animation.
ozz::animation::Animation animation_; ozz::animation::Animation animation_;
// Sampling cache. // Sampling context.
ozz::animation::SamplingCache cache_; ozz::animation::SamplingJob::Context context_;
// Buffer of local transforms as sampled from animation_. // Buffer of local transforms as sampled from animation_.
ozz::vector<ozz::math::SoaTransform> locals_; ozz::vector<ozz::math::SoaTransform> locals_;

View File

@ -23,6 +23,7 @@ add_executable(sample_baked
target_link_libraries(sample_baked target_link_libraries(sample_baked
sample_framework) sample_framework)
target_copy_shared_libraries(sample_baked)
set_target_properties(sample_baked set_target_properties(sample_baked
PROPERTIES FOLDER "samples") PROPERTIES FOLDER "samples")

View File

@ -25,24 +25,20 @@
// // // //
//----------------------------------------------------------------------------// //----------------------------------------------------------------------------//
#include "ozz/animation/runtime/animation.h"
#include "ozz/animation/runtime/local_to_model_job.h"
#include "ozz/animation/runtime/sampling_job.h"
#include "ozz/animation/runtime/skeleton.h"
#include "ozz/base/log.h"
#include "ozz/base/maths/box.h"
#include "ozz/base/maths/simd_math.h"
#include "ozz/base/maths/soa_transform.h"
#include "ozz/base/maths/vec_float.h"
#include "ozz/options/options.h"
#include "framework/application.h" #include "framework/application.h"
#include "framework/imgui.h" #include "framework/imgui.h"
#include "framework/renderer.h" #include "framework/renderer.h"
#include "framework/utils.h" #include "framework/utils.h"
#include "ozz/animation/runtime/animation.h"
#include "ozz/animation/runtime/local_to_model_job.h"
#include "ozz/animation/runtime/sampling_job.h"
#include "ozz/animation/runtime/skeleton.h"
#include "ozz/base/log.h"
#include "ozz/base/maths/box.h"
#include "ozz/base/maths/simd_math.h"
#include "ozz/base/maths/soa_transform.h"
#include "ozz/base/maths/vec_float.h"
#include "ozz/options/options.h"
// Skeleton archive can be specified as an option. // Skeleton archive can be specified as an option.
OZZ_OPTIONS_DECLARE_STRING(skeleton, OZZ_OPTIONS_DECLARE_STRING(skeleton,
@ -67,7 +63,7 @@ class BakedSampleApplication : public ozz::sample::Application {
// Samples optimized animation at t = animation_time_. // Samples optimized animation at t = animation_time_.
ozz::animation::SamplingJob sampling_job; ozz::animation::SamplingJob sampling_job;
sampling_job.animation = &animation_; sampling_job.animation = &animation_;
sampling_job.cache = &cache_; sampling_job.context = &context_;
sampling_job.ratio = controller_.time_ratio(); sampling_job.ratio = controller_.time_ratio();
sampling_job.output = make_span(locals_); sampling_job.output = make_span(locals_);
if (!sampling_job.Run()) { if (!sampling_job.Run()) {
@ -103,8 +99,8 @@ class BakedSampleApplication : public ozz::sample::Application {
locals_.resize(num_soa_joints); locals_.resize(num_soa_joints);
models_.resize(num_joints); models_.resize(num_joints);
// Allocates a cache that matches animation requirements. // Allocates a context that matches animation requirements.
cache_.Resize(num_joints); context_.Resize(num_joints);
// Look for a "camera" joint. // Look for a "camera" joint.
for (int i = 0; i < num_joints; i++) { for (int i = 0; i < num_joints; i++) {
@ -167,8 +163,8 @@ class BakedSampleApplication : public ozz::sample::Application {
// Runtime animation. // Runtime animation.
ozz::animation::Animation animation_; ozz::animation::Animation animation_;
// Sampling cache. // Sampling context.
ozz::animation::SamplingCache cache_; ozz::animation::SamplingJob::Context context_;
// Buffer of local transforms as sampled from animation_. // Buffer of local transforms as sampled from animation_.
ozz::vector<ozz::math::SoaTransform> locals_; ozz::vector<ozz::math::SoaTransform> locals_;

View File

@ -31,6 +31,7 @@ add_executable(sample_blend
target_link_libraries(sample_blend target_link_libraries(sample_blend
sample_framework) sample_framework)
target_copy_shared_libraries(sample_blend)
set_target_properties(sample_blend set_target_properties(sample_blend
PROPERTIES FOLDER "samples") PROPERTIES FOLDER "samples")

View File

@ -23,6 +23,6 @@ There are two ways to use the sample:
1. Load animations and skeleton. See "playback" sample for more details. 1. Load animations and skeleton. See "playback" sample for more details.
2. Compute each animation time (in order to sync their duration) and samples each of them to get local-space transformations. 2. Compute each animation time (in order to sync their duration) and samples each of them to get local-space transformations.
3. Compute each animation (layer) blend weight and fills ozz::animation::BlendingJob object. BlendingJob object takes as input an array of BlendingJob::Layer representing each layer to blend: weight and local-space transformations (as outputed from the sampling stage). It also takes as input the skeleton bind-pose, which represents the default transformation of each joint. It is used by the blending algorithm as a fall-back when the accumulated layer weight is too small (under a threshold value which is also an input) to be used. The output of the blending job is a set of local-space transformations. 3. Compute each animation (layer) blend weight and fills ozz::animation::BlendingJob object. BlendingJob object takes as input an array of BlendingJob::Layer representing each layer to blend: weight and local-space transformations (as outputed from the sampling stage). It also takes as input the skeleton rest-pose, which represents the default transformation of each joint. It is used by the blending algorithm as a fall-back when the accumulated layer weight is too small (under a threshold value which is also an input) to be used. The output of the blending job is a set of local-space transformations.
4. Convert local-space transformations to model-space matrices using ozz::animation::LocalToModelJob. It takes as input the skeleton (to know about joint's hierarchy) and local-space transforms. Output is model-space matrices array. 4. Convert local-space transformations to model-space matrices using ozz::animation::LocalToModelJob. It takes as input the skeleton (to know about joint's hierarchy) and local-space transforms. Output is model-space matrices array.
5. Model-space matrices array can then be used for rendering (to skin a mesh) or updating the scene graph. 5. Model-space matrices array can then be used for rendering (to skin a mesh) or updating the scene graph.

View File

@ -25,26 +25,22 @@
// // // //
//----------------------------------------------------------------------------// //----------------------------------------------------------------------------//
#include "framework/application.h"
#include "framework/imgui.h"
#include "framework/renderer.h"
#include "framework/utils.h"
#include "ozz/animation/runtime/animation.h" #include "ozz/animation/runtime/animation.h"
#include "ozz/animation/runtime/blending_job.h" #include "ozz/animation/runtime/blending_job.h"
#include "ozz/animation/runtime/local_to_model_job.h" #include "ozz/animation/runtime/local_to_model_job.h"
#include "ozz/animation/runtime/sampling_job.h" #include "ozz/animation/runtime/sampling_job.h"
#include "ozz/animation/runtime/skeleton.h" #include "ozz/animation/runtime/skeleton.h"
#include "ozz/base/log.h" #include "ozz/base/log.h"
#include "ozz/base/maths/math_ex.h" #include "ozz/base/maths/math_ex.h"
#include "ozz/base/maths/simd_math.h" #include "ozz/base/maths/simd_math.h"
#include "ozz/base/maths/soa_transform.h" #include "ozz/base/maths/soa_transform.h"
#include "ozz/base/maths/vec_float.h" #include "ozz/base/maths/vec_float.h"
#include "ozz/options/options.h" #include "ozz/options/options.h"
#include "framework/application.h"
#include "framework/imgui.h"
#include "framework/renderer.h"
#include "framework/utils.h"
// Skeleton archive can be specified as an option. // Skeleton archive can be specified as an option.
OZZ_OPTIONS_DECLARE_STRING(skeleton, OZZ_OPTIONS_DECLARE_STRING(skeleton,
"Path to the skeleton (ozz archive format).", "Path to the skeleton (ozz archive format).",
@ -97,7 +93,7 @@ class BlendSampleApplication : public ozz::sample::Application {
// Setup sampling job. // Setup sampling job.
ozz::animation::SamplingJob sampling_job; ozz::animation::SamplingJob sampling_job;
sampling_job.animation = &sampler.animation; sampling_job.animation = &sampler.animation;
sampling_job.cache = &sampler.cache; sampling_job.context = &sampler.context;
sampling_job.ratio = sampler.controller.time_ratio(); sampling_job.ratio = sampler.controller.time_ratio();
sampling_job.output = make_span(sampler.locals); sampling_job.output = make_span(sampler.locals);
@ -123,7 +119,7 @@ class BlendSampleApplication : public ozz::sample::Application {
ozz::animation::BlendingJob blend_job; ozz::animation::BlendingJob blend_job;
blend_job.threshold = threshold_; blend_job.threshold = threshold_;
blend_job.layers = layers; blend_job.layers = layers;
blend_job.bind_pose = skeleton_.joint_bind_poses(); blend_job.rest_pose = skeleton_.joint_rest_poses();
blend_job.output = make_span(blended_locals_); blend_job.output = make_span(blended_locals_);
// Blends. // Blends.
@ -216,8 +212,8 @@ class BlendSampleApplication : public ozz::sample::Application {
// Allocates sampler runtime buffers. // Allocates sampler runtime buffers.
sampler.locals.resize(num_soa_joints); sampler.locals.resize(num_soa_joints);
// Allocates a cache that matches animation requirements. // Allocates a context that matches animation requirements.
sampler.cache.Resize(num_joints); sampler.context.Resize(num_joints);
} }
// Allocates local space runtime buffers of blended data. // Allocates local space runtime buffers of blended data.
@ -319,14 +315,14 @@ class BlendSampleApplication : public ozz::sample::Application {
// Runtime animation. // Runtime animation.
ozz::animation::Animation animation; ozz::animation::Animation animation;
// Sampling cache. // Sampling context.
ozz::animation::SamplingCache cache; ozz::animation::SamplingJob::Context context;
// Buffer of local transforms as sampled from animation_. // Buffer of local transforms as sampled from animation_.
ozz::vector<ozz::math::SoaTransform> locals; ozz::vector<ozz::math::SoaTransform> locals;
} samplers_[kNumLayers]; // kNumLayers animations to blend. } samplers_[kNumLayers]; // kNumLayers animations to blend.
// Blending job bind pose threshold. // Blending job rest pose threshold.
float threshold_; float threshold_;
// Buffer of local transforms which stores the blending result. // Buffer of local transforms which stores the blending result.

BIN
3rdparty/ozz-animation/samples/demo.zip vendored Normal file

Binary file not shown.

View File

@ -29,6 +29,7 @@ add_executable(sample_foot_ik
"${CMAKE_CURRENT_BINARY_DIR}/media/floor.ozz") "${CMAKE_CURRENT_BINARY_DIR}/media/floor.ozz")
target_link_libraries(sample_foot_ik target_link_libraries(sample_foot_ik
sample_framework) sample_framework)
target_copy_shared_libraries(sample_foot_ik)
set_target_properties(sample_foot_ik set_target_properties(sample_foot_ik
PROPERTIES FOLDER "samples") PROPERTIES FOLDER "samples")

View File

@ -25,34 +25,28 @@
// // // //
//----------------------------------------------------------------------------// //----------------------------------------------------------------------------//
#include <limits>
#include "framework/application.h"
#include "framework/imgui.h"
#include "framework/mesh.h"
#include "framework/renderer.h"
#include "framework/utils.h"
#include "ozz/animation/runtime/animation.h" #include "ozz/animation/runtime/animation.h"
#include "ozz/animation/runtime/ik_aim_job.h" #include "ozz/animation/runtime/ik_aim_job.h"
#include "ozz/animation/runtime/ik_two_bone_job.h" #include "ozz/animation/runtime/ik_two_bone_job.h"
#include "ozz/animation/runtime/local_to_model_job.h" #include "ozz/animation/runtime/local_to_model_job.h"
#include "ozz/animation/runtime/sampling_job.h" #include "ozz/animation/runtime/sampling_job.h"
#include "ozz/animation/runtime/skeleton.h" #include "ozz/animation/runtime/skeleton.h"
#include "ozz/base/log.h" #include "ozz/base/log.h"
#include "ozz/base/maths/box.h" #include "ozz/base/maths/box.h"
#include "ozz/base/maths/math_ex.h" #include "ozz/base/maths/math_ex.h"
#include "ozz/base/maths/simd_math.h" #include "ozz/base/maths/simd_math.h"
#include "ozz/base/maths/simd_quaternion.h" #include "ozz/base/maths/simd_quaternion.h"
#include "ozz/base/maths/soa_transform.h" #include "ozz/base/maths/soa_transform.h"
#include "ozz/base/maths/vec_float.h" #include "ozz/base/maths/vec_float.h"
#include "ozz/options/options.h" #include "ozz/options/options.h"
#include "framework/application.h"
#include "framework/imgui.h"
#include "framework/mesh.h"
#include "framework/utils.h"
#include "framework/renderer.h"
#include "framework/utils.h"
#include <limits>
// Skeleton archive can be specified as an option. // Skeleton archive can be specified as an option.
OZZ_OPTIONS_DECLARE_STRING(skeleton, OZZ_OPTIONS_DECLARE_STRING(skeleton,
"Path to the skeleton (ozz archive format).", "Path to the skeleton (ozz archive format).",
@ -107,7 +101,7 @@ class FootIKSampleApplication : public ozz::sample::Application {
FootIKSampleApplication() FootIKSampleApplication()
: pelvis_offset_(0.f, 0.f, 0.f), : pelvis_offset_(0.f, 0.f, 0.f),
root_translation_(2.17f, 2.f, -2.06f), root_translation_(2.17f, 2.f, -2.06f),
root_yaw_(2.f), root_yaw_(-2.f),
foot_heigh_(.12f), foot_heigh_(.12f),
weight_(1.f), weight_(1.f),
soften_(1.f), soften_(1.f),
@ -186,7 +180,7 @@ class FootIKSampleApplication : public ozz::sample::Application {
// Samples optimized animation at t = animation_time. // Samples optimized animation at t = animation_time.
ozz::animation::SamplingJob sampling_job; ozz::animation::SamplingJob sampling_job;
sampling_job.animation = &animation_; sampling_job.animation = &animation_;
sampling_job.cache = &cache_; sampling_job.context = &context_;
sampling_job.ratio = controller_.time_ratio(); sampling_job.ratio = controller_.time_ratio();
sampling_job.output = make_span(locals_); sampling_job.output = make_span(locals_);
if (!sampling_job.Run()) { if (!sampling_job.Run()) {
@ -481,8 +475,8 @@ class FootIKSampleApplication : public ozz::sample::Application {
} }
} else { } else {
// Renders skeleton only. // Renders skeleton only.
success &= _renderer->DrawPosture(skeleton_, make_span(models_), success &=
offsetted_root); _renderer->DrawPosture(skeleton_, make_span(models_), offsetted_root);
} }
// Showing joints // Showing joints
@ -557,8 +551,8 @@ class FootIKSampleApplication : public ozz::sample::Application {
const int num_joints = skeleton_.num_joints(); const int num_joints = skeleton_.num_joints();
models_.resize(num_joints); models_.resize(num_joints);
// Allocates a cache that matches animation requirements. // Allocates a context that matches animation requirements.
cache_.Resize(num_joints); context_.Resize(num_joints);
// Finds left and right joints. // Finds left and right joints.
if (!SetupLeg(skeleton_, kLeftJointNames, &legs_setup_[kLeft]) || if (!SetupLeg(skeleton_, kLeftJointNames, &legs_setup_[kLeft]) ||
@ -597,7 +591,7 @@ class FootIKSampleApplication : public ozz::sample::Application {
bool SetupLeg(const ozz::animation::Skeleton& _skeleton, bool SetupLeg(const ozz::animation::Skeleton& _skeleton,
const char* _joint_names[3], LegSetup* _leg) { const char* _joint_names[3], LegSetup* _leg) {
int found = 0; int found = 0;
int joints[3] = {0, 0, 0}; int joints[3] = {0};
for (int i = 0; i < _skeleton.num_joints() && found != 3; i++) { for (int i = 0; i < _skeleton.num_joints() && found != 3; i++) {
const char* joint_name = _skeleton.joint_names()[i]; const char* joint_name = _skeleton.joint_names()[i];
if (std::strcmp(joint_name, _joint_names[found]) == 0) { if (std::strcmp(joint_name, _joint_names[found]) == 0) {
@ -742,8 +736,8 @@ class FootIKSampleApplication : public ozz::sample::Application {
// Runtime animation. // Runtime animation.
ozz::animation::Animation animation_; ozz::animation::Animation animation_;
// Sampling cache. // Sampling context.
ozz::animation::SamplingCache cache_; ozz::animation::SamplingJob::Context context_;
// Buffer of local transforms as sampled from animation_. // Buffer of local transforms as sampled from animation_.
ozz::vector<ozz::math::SoaTransform> locals_; ozz::vector<ozz::math::SoaTransform> locals_;
@ -752,7 +746,7 @@ class FootIKSampleApplication : public ozz::sample::Application {
ozz::vector<ozz::math::Float4x4> models_; ozz::vector<ozz::math::Float4x4> models_;
// Buffer of skinning matrices, result of the joint multiplication of the // Buffer of skinning matrices, result of the joint multiplication of the
// inverse bind pose with the model space matrix. // inverse rest pose with the model space matrix.
ozz::vector<ozz::math::Float4x4> skinning_matrices_; ozz::vector<ozz::math::Float4x4> skinning_matrices_;
// The mesh used by the sample. // The mesh used by the sample.

View File

@ -29,9 +29,7 @@ add_library(sample_framework STATIC
# Samples requires OpenGL package. # Samples requires OpenGL package.
if(NOT EMSCRIPTEN) if(NOT EMSCRIPTEN)
add_subdirectory(${PROJECT_SOURCE_DIR}/extern/glfw glfw) add_subdirectory(${PROJECT_SOURCE_DIR}/extern/glfw glfw)
target_link_libraries(sample_framework glfw)
target_link_libraries(sample_framework
glfw)
endif() endif()
target_link_libraries(sample_framework target_link_libraries(sample_framework
@ -43,7 +41,6 @@ if(TARGET BUILD_DATA_SAMPLE)
add_dependencies(sample_framework BUILD_DATA_SAMPLE) add_dependencies(sample_framework BUILD_DATA_SAMPLE)
endif() endif()
set_target_properties(sample_framework set_target_properties(sample_framework PROPERTIES FOLDER "samples")
PROPERTIES FOLDER "samples")
add_subdirectory(tools) add_subdirectory(tools)

View File

@ -476,6 +476,12 @@ bool Application::Gui() {
// Downcast to public imgui. // Downcast to public imgui.
ImGui* im_gui = im_gui_.get(); ImGui* im_gui = im_gui_.get();
// Do floating gui.
if (!show_help_) {
success = OnFloatingGui(im_gui);
}
// Help gui. // Help gui.
{ {
math::RectFloat rect(kGuiMargin, kGuiMargin, math::RectFloat rect(kGuiMargin, kGuiMargin,
@ -658,6 +664,31 @@ bool Application::FrameworkGui() {
return true; return true;
} }
bool Application::OnInitialize() { return true; }
void Application::OnDestroy() {}
bool Application::OnUpdate(float _dt, float _time) {
(void)_dt;
(void)_time;
return true;
}
bool Application::OnGui(ImGui* _im_gui) {
(void)_im_gui;
return true;
}
bool Application::OnFloatingGui(ImGui* _im_gui) {
(void)_im_gui;
return true;
}
bool Application::OnDisplay(Renderer* _renderer) {
(void)_renderer;
return true;
}
bool Application::GetCameraInitialSetup(math::Float3* _center, bool Application::GetCameraInitialSetup(math::Float3* _center,
math::Float2* _angles, math::Float2* _angles,
float* _distance) const { float* _distance) const {
@ -674,6 +705,23 @@ bool Application::GetCameraOverride(math::Float4x4* _transform) const {
return false; return false;
} }
void Application::GetSceneBounds(math::Box* _bound) const { (void)_bound; }
math::Float2 Application::WorldToScreen(const math::Float3& _world) const {
const math::SimdFloat4 ndc =
(camera_->projection() * camera_->view()) *
math::simd_float4::Load(_world.x, _world.y, _world.z, 1.f);
const math::SimdFloat4 resolution = math::simd_float4::FromInt(
math::simd_int4::Load(resolution_.width, resolution_.height, 0, 0));
const ozz::math::SimdFloat4 screen =
resolution * ((ndc / math::SplatW(ndc)) + math::simd_float4::one()) /
math::simd_float4::Load1(2.f);
math::Float2 ret;
math::Store2PtrU(screen, &ret.x);
return ret;
}
void Application::ResizeCbk(int _width, int _height) { void Application::ResizeCbk(int _width, int _height) {
// Stores new resolution settings. // Stores new resolution settings.
application_->resolution_.width = _width; application_->resolution_.width = _width;

View File

@ -29,6 +29,7 @@
#define OZZ_SAMPLES_FRAMEWORK_APPLICATION_H_ #define OZZ_SAMPLES_FRAMEWORK_APPLICATION_H_
#include <cstddef> #include <cstddef>
#include "ozz/base/containers/string.h" #include "ozz/base/containers/string.h"
#include "ozz/base/memory/unique_ptr.h" #include "ozz/base/memory/unique_ptr.h"
@ -78,36 +79,47 @@ class Application {
int Run(int _argc, const char** _argv, const char* _version, int Run(int _argc, const char** _argv, const char* _version,
const char* _title); const char* _title);
protected:
// Allows application to convert from world space to screen coordinates.
math::Float2 WorldToScreen(const math::Float3& _world) const;
private: private:
// Provides initialization event to the inheriting application. Called while // Provides initialization event to the inheriting application. Called while
// the help screen is being displayed. // the help screen is being displayed.
// OnInitialize can return false which will in turn skip the display loop and // OnInitialize can return false which will in turn skip the display loop and
// exit the application with EXIT_FAILURE. Note that OnDestroy is called in // exit the application with EXIT_FAILURE. Note that OnDestroy is called in
// any case. // any case.
virtual bool OnInitialize() = 0; virtual bool OnInitialize();
// Provides de-initialization event to the inheriting application. // Provides de-initialization event to the inheriting application.
// OnDestroy is called even if OnInitialize failed and returned an error. // OnDestroy is called even if OnInitialize failed and returned an error.
virtual void OnDestroy() = 0; virtual void OnDestroy();
// Provides update event to the inheriting application. // Provides update event to the inheriting application.
// _dt is the elapsed time (in seconds) since the last update. // _dt is the elapsed time (in seconds) since the last update.
// _time is application time including scaling (aka accumulated _dt). // _time is application time including scaling (aka accumulated _dt).
// OnUpdate can return false which will in turn stop the loop and exit the // OnUpdate can return false which will in turn stop the loop and exit the
// application with EXIT_FAILURE. Note that OnDestroy is called in any case. // application with EXIT_FAILURE. Note that OnDestroy is called in any case.
virtual bool OnUpdate(float _dt, float _time) = 0; virtual bool OnUpdate(float _dt, float _time);
// Provides immediate mode gui display event to the inheriting application. // Provides immediate mode gui display event to the inheriting application.
// This function is called in between the OnDisplay and swap functions. // This function is called in between the OnDisplay and swap functions.
// OnGui can return false which will in turn stop the loop and exit the // OnGui can return false which will in turn stop the loop and exit the
// application with EXIT_FAILURE. Note that OnDestroy is called in any case. // application with EXIT_FAILURE. Note that OnDestroy is called in any case.
virtual bool OnGui(ImGui* _im_gui) = 0; virtual bool OnGui(ImGui* _im_gui);
// Provides immediate mode floating gui display event to the inheriting
// application. Floating gui allows to render a Gui anywere one screen. User
// must provide the form. OnFloatingGui can return false which will in turn
// stop the loop and exit the application with EXIT_FAILURE. Note that
// OnDestroy is called in any case.
virtual bool OnFloatingGui(ImGui* _im_gui);
// Provides display event to the inheriting application. // Provides display event to the inheriting application.
// This function is called in between the clear and swap functions. // This function is called in between the clear and swap functions.
// OnDisplay can return false which will in turn stop the loop and exit the // OnDisplay can return false which will in turn stop the loop and exit the
// application with EXIT_FAILURE. Note that OnDestroy is called in any case. // application with EXIT_FAILURE. Note that OnDestroy is called in any case.
virtual bool OnDisplay(Renderer* _renderer) = 0; virtual bool OnDisplay(Renderer* _renderer);
// Initial camera values. These will only be considered if function returns // Initial camera values. These will only be considered if function returns
// true; // true;
@ -125,7 +137,7 @@ class Application {
// the camera to frame all the scene. // the camera to frame all the scene.
// This function is never called before a first OnUpdate. // This function is never called before a first OnUpdate.
// If _bound is set to "invalid", then camera won't be updated. // If _bound is set to "invalid", then camera won't be updated.
virtual void GetSceneBounds(math::Box* _bound) const = 0; virtual void GetSceneBounds(math::Box* _bound) const;
// Implements framework internal loop function. // Implements framework internal loop function.
bool Loop(); bool Loop();

View File

@ -28,12 +28,14 @@
#ifndef OZZ_SAMPLES_FRAMEWORK_IMGUI_H_ #ifndef OZZ_SAMPLES_FRAMEWORK_IMGUI_H_
#define OZZ_SAMPLES_FRAMEWORK_IMGUI_H_ #define OZZ_SAMPLES_FRAMEWORK_IMGUI_H_
#include <ozz/base/containers/array.h>
#include <cstdio> #include <cstdio>
namespace ozz { namespace ozz {
namespace math { namespace math {
struct RectFloat; struct RectFloat;
} } // namespace math
namespace sample { namespace sample {
// Interface for immediate mode graphical user interface rendering. // Interface for immediate mode graphical user interface rendering.
@ -54,8 +56,9 @@ class ImGui {
// A form is a root in the frame's container stack. // A form is a root in the frame's container stack.
// The _rect argument is relative to the parent's rect and is automatically // The _rect argument is relative to the parent's rect and is automatically
// shrunk to fit inside parent's rect and to the size of its widgets. // shrunk to fit inside parent's rect and to the size of its widgets.
// Providing a non nullptr _title argument displays a title on top of the form. // Providing a non nullptr _title argument displays a title on top of the
// Providing a non nullptr _open argument enables the open/close mechanism. // form. Providing a non nullptr _open argument enables the open/close
// mechanism.
class Form { class Form {
public: public:
Form(ImGui* _im_gui, const char* _title, const math::RectFloat& _rect, Form(ImGui* _im_gui, const char* _title, const math::RectFloat& _rect,
@ -115,6 +118,11 @@ class ImGui {
float* _value, float _pow = 1.f, float* _value, float _pow = 1.f,
bool _enabled = true) = 0; bool _enabled = true) = 0;
virtual bool DoSlider2D(const char* _label, ozz::array<float, 2> _min,
ozz::array<float, 2> _max,
ozz::array<float, 2>* _value,
bool _enabled = true) = 0;
// Adds an integer slider to the current context and returns true if _value // Adds an integer slider to the current context and returns true if _value
// was modified. // was modified.
// _value is the in-out parameter that stores slider value. It's clamped // _value is the in-out parameter that stores slider value. It's clamped
@ -172,9 +180,9 @@ class ImGui {
// container automatically shrinks to fit the size of the widgets it contains. // container automatically shrinks to fit the size of the widgets it contains.
// Providing a non nullptr _title argument displays a title on top of the // Providing a non nullptr _title argument displays a title on top of the
// container. // container.
// Providing a nullptr _rect argument means that the container will use all its // Providing a nullptr _rect argument means that the container will use all
// parent size. // its parent size. Providing a non nullptr _open argument enables the
// Providing a non nullptr _open argument enables the open/close mechanism. // open/close mechanism.
virtual void BeginContainer(const char* _title, const math::RectFloat* _rect, virtual void BeginContainer(const char* _title, const math::RectFloat* _rect,
bool* _open, bool _constrain) = 0; bool* _open, bool _constrain) = 0;

View File

@ -34,11 +34,11 @@
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include "immediate.h"
#include "ozz/base/maths/math_constant.h" #include "ozz/base/maths/math_constant.h"
#include "ozz/base/maths/math_ex.h" #include "ozz/base/maths/math_ex.h"
#include "ozz/base/maths/vec_float.h"
#include "ozz/base/memory/allocator.h" #include "ozz/base/memory/allocator.h"
#include "immediate.h"
#include "renderer_impl.h" #include "renderer_impl.h"
namespace ozz { namespace ozz {
@ -211,6 +211,11 @@ bool ImGuiImpl::AddWidget(float _height, math::RectFloat* _rect) {
// Get current container. // Get current container.
Container& container = containers_.back(); Container& container = containers_.back();
// Make it a square if height is negative.
if (_height < 0) {
_height = container.rect.width - kWidgetMarginX * 2.f;
}
// Early out if outside of the container. // Early out if outside of the container.
// But don't modify current container's state. // But don't modify current container's state.
if (container.offset_y < kWidgetMarginY + _height) { if (container.offset_y < kWidgetMarginY + _height) {
@ -740,6 +745,33 @@ void ImGuiImpl::DoGraph(const char* _label, float _min, float _max, float _mean,
} }
} }
namespace {
float SliderControl(float _value, float _min, float _max, float _pow,
int _mouse, int _mouse_max, bool _enabled, bool _active,
float* _cursor) {
const float pow_min = powf(_min, _pow);
const float pow_max = powf(_max, _pow);
const float clamped_value = ozz::math::Clamp(_min, _value, _max);
float pow_value = powf(clamped_value, _pow);
// Finds cursor position and rect.
*_cursor = floorf((_mouse_max * (pow_value - pow_min)) / (pow_max - pow_min));
if (_enabled) {
if (_active) {
_mouse = ozz::math::Clamp(0, _mouse, _mouse_max);
pow_value = (_mouse * (pow_max - pow_min)) / _mouse_max + pow_min;
return ozz::math::Clamp(_min, powf(pow_value, 1.f / _pow), _max);
} else {
// Clamping is only applied if the widget is enabled.
return clamped_value;
}
}
return _value;
}
} // namespace
bool ImGuiImpl::DoSlider(const char* _label, float _min, float _max, bool ImGuiImpl::DoSlider(const char* _label, float _min, float _max,
float* _value, float _pow, bool _enabled) { float* _value, float _pow, bool _enabled) {
math::RectFloat rect; math::RectFloat rect;
@ -751,7 +783,6 @@ bool ImGuiImpl::DoSlider(const char* _label, float _min, float _max,
// Calculate mouse cursor's relative y offset. // Calculate mouse cursor's relative y offset.
const float initial_value = *_value; const float initial_value = *_value;
const float clamped_value = ozz::math::Clamp(_min, initial_value, _max);
// Check for hotness. // Check for hotness.
bool hot = false, active = false; bool hot = false, active = false;
@ -795,24 +826,100 @@ bool ImGuiImpl::DoSlider(const char* _label, float _min, float _max,
} }
// Update widget value. // Update widget value.
const float pow_min = powf(_min, _pow); float cursor;
const float pow_max = powf(_max, _pow); *_value =
float pow_value = powf(clamped_value, _pow); SliderControl(initial_value, _min, _max, _pow,
inputs_.mouse_x - static_cast<int>(rect.left),
static_cast<int>(rect.width), _enabled, active, &cursor);
// Renders slider's rail.
const math::RectFloat rail_rect(rect.left, rect.bottom, rect.width,
rect.height);
FillRect(rail_rect, kSliderRoundRectRadius, background_color);
StrokeRect(rail_rect, kSliderRoundRectRadius, border_color);
const math::RectFloat cursor_rect(
rect.left + cursor - kWidgetCursorWidth / 2.f, rect.bottom - 1.f,
kWidgetCursorWidth, rect.height + 2.f);
FillRect(cursor_rect, kSliderRoundRectRadius, slider_color);
StrokeRect(cursor_rect, kSliderRoundRectRadius, slider_border_color);
const math::RectFloat text_rect(
rail_rect.left + kSliderRoundRectRadius, rail_rect.bottom,
rail_rect.width - kSliderRoundRectRadius * 2.f, rail_rect.height);
Print(_label, text_rect, kMiddle, text_color);
// Returns true if the value has changed or if it was clamped in _min / _max
// bounds.
return initial_value != *_value;
}
bool ImGuiImpl::DoSlider2D(const char* _label, ozz::array<float, 2> _min,
ozz::array<float, 2> _max,
ozz::array<float, 2>* _value, bool _enabled) {
math::RectFloat rect;
if (!AddWidget(-1.f, &rect)) {
return false;
}
auto_gen_id_++;
// Calculate mouse cursor's relative y offset.
const ozz::array<float, 2> initial_value = *_value;
// Check for hotness.
bool hot = false, active = false;
if (_enabled) { if (_enabled) {
// Includes the cursor size in the pick region.
math::RectFloat pick_rect = rect;
pick_rect.left -= kWidgetHeight / 2.f;
pick_rect.width += kWidgetHeight;
pick_rect.bottom -= kWidgetHeight / 2.f;
pick_rect.height += kWidgetHeight;
ButtonLogic(pick_rect, auto_gen_id_, &hot, &active);
// A slider is active on lmb pressed, not released. It's different to the
// usual button behavior.
active &= inputs_.lmb_pressed;
}
// Render the scrollbar
const GLubyte* background_color = kSliderBackgroundColor;
const GLubyte* border_color = kWidgetBorderColor;
const GLubyte* slider_color = kSliderCursorColor;
const GLubyte* slider_border_color = kWidgetBorderColor;
const GLubyte* text_color = kWidgetTextColor;
if (!_enabled) {
background_color = kWidgetDisabledBackgroundColor;
border_color = kWidgetDisabledBorderColor;
slider_color = kSliderDisabledCursorColor;
slider_border_color = kWidgetDisabledBorderColor;
text_color = kWidgetDisabledTextColor;
} else if (hot) {
if (active) { if (active) {
int mousepos = inputs_.mouse_x - static_cast<int>(rect.left); // Button is both 'hot' and 'active'.
if (mousepos < 0) { slider_color = kWidgetActiveBackgroundColor;
mousepos = 0; slider_border_color = kWidgetActiveBorderColor;
}
if (mousepos > rect.width) {
mousepos = static_cast<int>(rect.width);
}
pow_value = (mousepos * (pow_max - pow_min)) / rect.width + pow_min;
*_value = ozz::math::Clamp(_min, powf(pow_value, 1.f / _pow), _max);
} else { } else {
// Clamping is only applied if the widget is enabled. // Button is merely 'hot'.
*_value = clamped_value; slider_color = kSliderCursorHotColor;
slider_border_color = kWidgetHotBorderColor;
} }
} else {
// button is not hot, but it may be active. Use default colors.
}
// Update widget value.
ozz::array<float, 2> cursor;
const int mouse[2] = {inputs_.mouse_x - static_cast<int>(rect.left),
inputs_.mouse_y - static_cast<int>(rect.bottom)};
const int mouse_max[2] = {static_cast<int>(rect.width),
static_cast<int>(rect.height)};
for (size_t i = 0; i < 2; ++i) {
_value->at(i) =
SliderControl(initial_value[i], _min[i], _max[i], 1.f, mouse[i],
mouse_max[i], _enabled, active, &cursor[i]);
} }
// Renders slider's rail. // Renders slider's rail.
@ -822,14 +929,24 @@ bool ImGuiImpl::DoSlider(const char* _label, float _min, float _max,
StrokeRect(rail_rect, kSliderRoundRectRadius, border_color); StrokeRect(rail_rect, kSliderRoundRectRadius, border_color);
// Finds cursor position and rect. // Finds cursor position and rect.
const float cursor =
floorf((rect.width * (pow_value - pow_min)) / (pow_max - pow_min));
const math::RectFloat cursor_rect( const math::RectFloat cursor_rect(
rect.left + cursor - kWidgetCursorWidth / 2.f, rect.bottom - 1.f, rect.left + cursor[0] - kWidgetHeight / 2.f,
kWidgetCursorWidth, rect.height + 2.f); rect.bottom + cursor[1] - kWidgetHeight / 2.f, kWidgetHeight,
kWidgetHeight);
// Cursor cross
const math::RectFloat cross_hrect(rect.left, rect.bottom + cursor[1],
rect.width, 1);
StrokeRect(cross_hrect, 0.f, slider_color);
const math::RectFloat cross_vrect(rect.left + cursor[0], rect.bottom, 1,
rect.height);
StrokeRect(cross_vrect, 0.f, slider_color);
// Draw slider
FillRect(cursor_rect, kSliderRoundRectRadius, slider_color); FillRect(cursor_rect, kSliderRoundRectRadius, slider_color);
StrokeRect(cursor_rect, kSliderRoundRectRadius, slider_border_color); StrokeRect(cursor_rect, kSliderRoundRectRadius, slider_border_color);
// Text
const math::RectFloat text_rect( const math::RectFloat text_rect(
rail_rect.left + kSliderRoundRectRadius, rail_rect.bottom, rail_rect.left + kSliderRoundRectRadius, rail_rect.bottom,
rail_rect.width - kSliderRoundRectRadius * 2.f, rail_rect.height); rail_rect.width - kSliderRoundRectRadius * 2.f, rail_rect.height);
@ -1361,7 +1478,9 @@ float ImGuiImpl::Print(const char* _text, const math::RectFloat& _rect,
ly = _rect.bottom + (line_count - 1) * (font_.glyph_height + interlign); ly = _rect.bottom + (line_count - 1) * (font_.glyph_height + interlign);
break; break;
} }
default: { break; } default: {
break;
}
} }
GL(BindTexture(GL_TEXTURE_2D, glyph_texture_)); GL(BindTexture(GL_TEXTURE_2D, glyph_texture_));
@ -1385,7 +1504,9 @@ float ImGuiImpl::Print(const char* _text, const math::RectFloat& _rect,
lx = _rect.right() - (line_char_count * font_.glyph_width); lx = _rect.right() - (line_char_count * font_.glyph_width);
break; break;
} }
default: { break; } default: {
break;
}
} }
// Loops through all characters of the current line, and renders them using // Loops through all characters of the current line, and renders them using

View File

@ -36,10 +36,8 @@
// See imgui.h for details about function specifications. // See imgui.h for details about function specifications.
#include "framework/imgui.h" #include "framework/imgui.h"
#include "ozz/base/containers/vector.h" #include "ozz/base/containers/vector.h"
#include "ozz/base/maths/rect.h" #include "ozz/base/maths/rect.h"
#include "renderer_impl.h" #include "renderer_impl.h"
namespace ozz { namespace ozz {
@ -90,6 +88,10 @@ class ImGuiImpl : public ImGui {
virtual bool DoSlider(const char* _label, float _min, float _max, virtual bool DoSlider(const char* _label, float _min, float _max,
float* _value, float _pow, bool _enabled); float* _value, float _pow, bool _enabled);
virtual bool DoSlider2D(const char* _label, ozz::array<float, 2> _min,
ozz::array<float, 2> _max,
ozz::array<float, 2>* _value, bool _enabled);
virtual bool DoSlider(const char* _label, int _min, int _max, int* _value, virtual bool DoSlider(const char* _label, int _min, int _max, int* _value,
float _pow, bool _enabled); float _pow, bool _enabled);

View File

@ -132,6 +132,12 @@ bool RendererImpl::Initialize() {
} }
} }
// Instantiate instanced ambient rendering shader.
points_shader = PointsShader::Build();
if (!points_shader) {
return false;
}
return true; return true;
} }
@ -239,7 +245,7 @@ bool RendererImpl::DrawGrid(int _cell_count, float _cell_size) {
return true; return true;
} }
// Computes the model space bind pose and renders it. // Computes the model space rest pose and renders it.
bool RendererImpl::DrawSkeleton(const ozz::animation::Skeleton& _skeleton, bool RendererImpl::DrawSkeleton(const ozz::animation::Skeleton& _skeleton,
const ozz::math::Float4x4& _transform, const ozz::math::Float4x4& _transform,
bool _draw_joints) { bool _draw_joints) {
@ -253,9 +259,9 @@ bool RendererImpl::DrawSkeleton(const ozz::animation::Skeleton& _skeleton,
// Reallocate matrix array if necessary. // Reallocate matrix array if necessary.
prealloc_models_.resize(num_joints); prealloc_models_.resize(num_joints);
// Compute model space bind pose. // Compute model space rest pose.
ozz::animation::LocalToModelJob job; ozz::animation::LocalToModelJob job;
job.input = _skeleton.joint_bind_poses(); job.input = _skeleton.joint_rest_poses();
job.output = make_span(prealloc_models_); job.output = make_span(prealloc_models_);
job.skeleton = &_skeleton; job.skeleton = &_skeleton;
if (!job.Run()) { if (!job.Run()) {
@ -460,10 +466,7 @@ int DrawPosture_FillUniforms(const ozz::animation::Skeleton& _skeleton,
// Copy parent joint's raw matrix, to render a bone between the parent // Copy parent joint's raw matrix, to render a bone between the parent
// and current matrix. // and current matrix.
float* uniform = _uniforms + instances * 16; float* uniform = _uniforms + instances * 16;
math::StorePtr(parent.cols[0], uniform + 0); std::memcpy(uniform, parent.cols, 16 * sizeof(float));
math::StorePtr(parent.cols[1], uniform + 4);
math::StorePtr(parent.cols[2], uniform + 8);
math::StorePtr(parent.cols[3], uniform + 12);
// Set bone direction (bone_dir). The shader expects to find it at index // Set bone direction (bone_dir). The shader expects to find it at index
// [3,7,11] of the matrix. // [3,7,11] of the matrix.
@ -483,11 +486,7 @@ int DrawPosture_FillUniforms(const ozz::animation::Skeleton& _skeleton,
// Only the joint is rendered for leaves, the bone model isn't. // Only the joint is rendered for leaves, the bone model isn't.
if (IsLeaf(_skeleton, i)) { if (IsLeaf(_skeleton, i)) {
// Copy current joint's raw matrix. // Copy current joint's raw matrix.
uniform = _uniforms + instances * 16; std::memcpy(uniform, current.cols, 16 * sizeof(float));
math::StorePtr(current.cols[0], uniform + 0);
math::StorePtr(current.cols[1], uniform + 4);
math::StorePtr(current.cols[2], uniform + 8);
math::StorePtr(current.cols[3], uniform + 12);
// Re-use bone_dir to fix the size of the leaf (same as previous bone). // Re-use bone_dir to fix the size of the leaf (same as previous bone).
// The shader expects to find it at index [3,7,11] of the matrix. // The shader expects to find it at index [3,7,11] of the matrix.
@ -621,6 +620,84 @@ bool RendererImpl::DrawPosture(const ozz::animation::Skeleton& _skeleton,
return true; return true;
} }
bool RendererImpl::DrawPoints(const ozz::span<const float>& _positions,
const ozz::span<const float>& _sizes,
const ozz::span<const Color>& _colors,
const ozz::math::Float4x4& _transform,
bool _round, bool _screen_space) {
// Early out if no instance to render.
if (_positions.size() == 0) {
return true;
}
// Sizes and colors must be of size 1 or equal to _positions' size.
if (_sizes.size() != 1 && _sizes.size() != _positions.size() / 3) {
return false;
}
if (_colors.size() != 1 && _colors.size() != _positions.size() / 3) {
return false;
}
const GLsizei positions_size = static_cast<GLsizei>(_positions.size_bytes());
const GLsizei colors_size =
static_cast<GLsizei>(_colors.size() == 1 ? 0 : _colors.size_bytes());
const GLsizei sizes_size =
static_cast<GLsizei>(_sizes.size() == 1 ? 0 : _sizes.size_bytes());
const GLsizei buffer_size = positions_size + colors_size + sizes_size;
const GLsizei positions_offset = 0;
const GLsizei colors_offset = positions_offset + positions_size;
const GLsizei sizes_offset = colors_offset + colors_size;
// Reallocate vertex buffer.
GL(BindBuffer(GL_ARRAY_BUFFER, dynamic_array_bo_));
GL(BufferData(GL_ARRAY_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW));
GL(BufferSubData(GL_ARRAY_BUFFER, positions_offset, positions_size,
_positions.data()));
GL(BufferSubData(GL_ARRAY_BUFFER, colors_offset, colors_size,
_colors.data()));
GL(BufferSubData(GL_ARRAY_BUFFER, sizes_offset, sizes_size, _sizes.data()));
// Square or round sprites. Beware msaa makes sprites round if GL_POINT_SPRITE
// isn't enabled
if (_round) {
GL(Enable(GL_POINT_SMOOTH));
GL(Disable(GL_POINT_SPRITE));
} else {
GL(Disable(GL_POINT_SMOOTH));
GL(Enable(GL_POINT_SPRITE));
}
// Size is managed in vertex shader side.
GL(Enable(GL_PROGRAM_POINT_SIZE));
const PointsShader::GenericAttrib attrib =
points_shader->Bind(_transform, camera()->view_proj(), 12,
positions_offset, colors_size ? 4 : 0, colors_offset,
sizes_size ? 4 : 0, sizes_offset, _screen_space);
GL(BindBuffer(GL_ARRAY_BUFFER, 0));
// Apply remaining general attributes
if (_colors.size() <= 1) {
const Color color = _colors.empty() ? kWhite : _colors[0];
GL(VertexAttrib4f(attrib.color, color.r / 255.f, color.g / 255.f,
color.b / 255.f, color.a / 255.f));
}
if (_sizes.size() <= 1) {
const float size = _sizes.empty() ? 1.f : _sizes[0];
GL(VertexAttrib1f(attrib.size, size));
}
// Draws the mesh.
GL(DrawArrays(GL_POINTS, 0, static_cast<GLsizei>(_positions.size() / 3)));
// Unbinds.
points_shader->Unbind();
return true;
}
bool RendererImpl::DrawBoxIm(const ozz::math::Box& _box, bool RendererImpl::DrawBoxIm(const ozz::math::Box& _box,
const ozz::math::Float4x4& _transform, const ozz::math::Float4x4& _transform,
const Color _colors[2]) { const Color _colors[2]) {
@ -1218,13 +1295,14 @@ bool RendererImpl::DrawMesh(const Mesh& _mesh,
vertex_offset += part_vertex_count; vertex_offset += part_vertex_count;
} }
if (_options.triangles) {
// Binds shader with this array buffer, depending on rendering options. // Binds shader with this array buffer, depending on rendering options.
Shader* shader = nullptr; Shader* shader = nullptr;
if (_options.texture) { if (_options.texture) {
ambient_textured_shader->Bind(_transform, camera()->view_proj(), ambient_textured_shader->Bind(
positions_stride, positions_offset, _transform, camera()->view_proj(), positions_stride, positions_offset,
normals_stride, normals_offset, colors_stride, normals_stride, normals_offset, colors_stride, colors_offset,
colors_offset, uvs_stride, uvs_offset); uvs_stride, uvs_offset);
shader = ambient_textured_shader.get(); shader = ambient_textured_shader.get();
// Binds default texture // Binds default texture
@ -1254,6 +1332,7 @@ bool RendererImpl::DrawMesh(const Mesh& _mesh,
GL(BindTexture(GL_TEXTURE_2D, 0)); GL(BindTexture(GL_TEXTURE_2D, 0));
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
shader->Unbind(); shader->Unbind();
}
if (_options.wireframe) { if (_options.wireframe) {
#ifndef EMSCRIPTEN #ifndef EMSCRIPTEN
@ -1261,6 +1340,25 @@ bool RendererImpl::DrawMesh(const Mesh& _mesh,
#endif // EMSCRIPTEN #endif // EMSCRIPTEN
} }
// Renders debug vertices.
if (_options.vertices) {
for (size_t i = 0; i < _mesh.parts.size(); ++i) {
const Mesh::Part& part = _mesh.parts[i];
ozz::sample::Color color = ozz::sample::kWhite;
span<const ozz::sample::Color> colors;
if (_options.colors && part.colors.size() == part.positions.size() / 3) {
colors = {
reinterpret_cast<const ozz::sample::Color*>(part.colors.data()),
part.positions.size() / 3};
} else {
colors = {&color, 1};
}
const float size = 2.f;
DrawPoints({part.positions.data(), part.positions.size()}, {&size, 1},
{&color, 1}, _transform, true, true);
}
}
// Renders debug normals. // Renders debug normals.
if (_options.normals) { if (_options.normals) {
for (size_t i = 0; i < _mesh.parts.size(); ++i) { for (size_t i = 0; i < _mesh.parts.size(); ++i) {
@ -1313,7 +1411,7 @@ bool RendererImpl::DrawSkinnedMesh(
const Mesh& _mesh, const span<math::Float4x4> _skinning_matrices, const Mesh& _mesh, const span<math::Float4x4> _skinning_matrices,
const ozz::math::Float4x4& _transform, const Options& _options) { const ozz::math::Float4x4& _transform, const Options& _options) {
// Forward to DrawMesh function is skinning is disabled. // Forward to DrawMesh function is skinning is disabled.
if (_options.skip_skinning) { if (_options.skip_skinning || !_mesh.skinned()) {
return DrawMesh(_mesh, _transform, _options); return DrawMesh(_mesh, _transform, _options);
} }
@ -1327,13 +1425,16 @@ bool RendererImpl::DrawSkinnedMesh(
// Positions and normals are interleaved to improve caching while executing // Positions and normals are interleaved to improve caching while executing
// skinning job. // skinning job.
const GLsizei positions_offset = 0; const GLsizei positions_offset = 0;
const GLsizei normals_offset = sizeof(float) * 3; const GLsizei positions_stride = sizeof(float) * 3;
const GLsizei tangents_offset = sizeof(float) * 6; const GLsizei normals_offset = vertex_count * positions_stride;
const GLsizei positions_stride = sizeof(float) * 9; const GLsizei normals_stride = sizeof(float) * 3;
const GLsizei normals_stride = positions_stride; const GLsizei tangents_offset =
const GLsizei tangents_stride = positions_stride; normals_offset + vertex_count * normals_stride;
const GLsizei skinned_data_size = vertex_count * positions_stride; const GLsizei tangents_stride = sizeof(float) * 3;
const GLsizei skinned_data_size =
tangents_offset + vertex_count * tangents_stride;
// Colors and uvs are contiguous. They aren't transformed, so they can be // Colors and uvs are contiguous. They aren't transformed, so they can be
// directly copied from source mesh which is non-interleaved as-well. // directly copied from source mesh which is non-interleaved as-well.
@ -1542,6 +1643,7 @@ bool RendererImpl::DrawSkinnedMesh(
processed_vertex_count += part_vertex_count; processed_vertex_count += part_vertex_count;
} }
if (_options.triangles) {
// Updates dynamic vertex buffer with skinned data. // Updates dynamic vertex buffer with skinned data.
GL(BindBuffer(GL_ARRAY_BUFFER, dynamic_array_bo_)); GL(BindBuffer(GL_ARRAY_BUFFER, dynamic_array_bo_));
GL(BufferData(GL_ARRAY_BUFFER, vbo_size, nullptr, GL_STREAM_DRAW)); GL(BufferData(GL_ARRAY_BUFFER, vbo_size, nullptr, GL_STREAM_DRAW));
@ -1550,10 +1652,10 @@ bool RendererImpl::DrawSkinnedMesh(
// Binds shader with this array buffer, depending on rendering options. // Binds shader with this array buffer, depending on rendering options.
Shader* shader = nullptr; Shader* shader = nullptr;
if (_options.texture) { if (_options.texture) {
ambient_textured_shader->Bind(_transform, camera()->view_proj(), ambient_textured_shader->Bind(
positions_stride, positions_offset, _transform, camera()->view_proj(), positions_stride, positions_offset,
normals_stride, normals_offset, colors_stride, normals_stride, normals_offset, colors_stride, colors_offset,
colors_offset, uvs_stride, uvs_offset); uvs_stride, uvs_offset);
shader = ambient_textured_shader.get(); shader = ambient_textured_shader.get();
// Binds default texture // Binds default texture
@ -1583,6 +1685,7 @@ bool RendererImpl::DrawSkinnedMesh(
GL(BindTexture(GL_TEXTURE_2D, 0)); GL(BindTexture(GL_TEXTURE_2D, 0));
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
shader->Unbind(); shader->Unbind();
}
if (_options.wireframe) { if (_options.wireframe) {
#ifndef EMSCRIPTEN #ifndef EMSCRIPTEN
@ -1590,6 +1693,26 @@ bool RendererImpl::DrawSkinnedMesh(
#endif // EMSCRIPTEN #endif // EMSCRIPTEN
} }
// Renders debug vertices.
if (_options.vertices) {
ozz::sample::Color color = ozz::sample::kWhite;
span<const ozz::sample::Color> colors;
if (_options.colors) {
colors = {reinterpret_cast<const ozz::sample::Color*>(
ozz::PointerStride(vbo_map, colors_offset)),
static_cast<size_t>(vertex_count)};
} else {
colors = {&color, 1};
}
const span<const float> vertices{
reinterpret_cast<const float*>(
ozz::PointerStride(vbo_map, positions_offset)),
static_cast<size_t>(vertex_count * 3)};
const float size = 2.f;
DrawPoints(vertices, {&size, 1}, colors, _transform, true, true);
}
return true; return true;
} }

View File

@ -59,7 +59,6 @@
// Include features as extentions // Include features as extentions
#include "GL/glext.h" #include "GL/glext.h"
#include "framework/renderer.h" #include "framework/renderer.h"
#include "ozz/base/containers/vector.h" #include "ozz/base/containers/vector.h"
#include "ozz/base/memory/unique_ptr.h" #include "ozz/base/memory/unique_ptr.h"
@ -91,6 +90,7 @@ namespace sample {
namespace internal { namespace internal {
class Camera; class Camera;
class Shader; class Shader;
class PointsShader;
class SkeletonShader; class SkeletonShader;
class AmbientShader; class AmbientShader;
class AmbientTexturedShader; class AmbientTexturedShader;
@ -119,6 +119,12 @@ class RendererImpl : public Renderer {
const ozz::math::Float4x4& _transform, const ozz::math::Float4x4& _transform,
bool _draw_joints); bool _draw_joints);
virtual bool DrawPoints(
const ozz::span<const float>& _positions,
const ozz::span<const float>& _sizes,
const ozz::span<const Color>& _colors,
const ozz::math::Float4x4& _transform, bool _round, bool _screen_space);
virtual bool DrawBoxIm(const ozz::math::Box& _box, virtual bool DrawBoxIm(const ozz::math::Box& _box,
const ozz::math::Float4x4& _transform, const ozz::math::Float4x4& _transform,
const Color _colors[2]); const Color _colors[2]);
@ -241,6 +247,7 @@ class RendererImpl : public Renderer {
ozz::unique_ptr<AmbientShader> ambient_shader; ozz::unique_ptr<AmbientShader> ambient_shader;
ozz::unique_ptr<AmbientTexturedShader> ambient_textured_shader; ozz::unique_ptr<AmbientTexturedShader> ambient_textured_shader;
ozz::unique_ptr<AmbientShaderInstanced> ambient_shader_instanced; ozz::unique_ptr<AmbientShaderInstanced> ambient_shader_instanced;
ozz::unique_ptr<PointsShader> points_shader;
// Checkered texture // Checkered texture
unsigned int checkered_texture_; unsigned int checkered_texture_;

View File

@ -326,6 +326,91 @@ void ImmediatePTCShader::Bind(const math::Float4x4& _model,
GL(Uniform1i(texture, 0)); GL(Uniform1i(texture, 0));
} }
ozz::unique_ptr<PointsShader> PointsShader::Build() {
bool success = true;
const char* kSimplePointsVS =
"uniform mat4 u_mvp;\n"
"attribute vec3 a_position;\n"
"attribute vec4 a_color;\n"
"attribute float a_size;\n"
"attribute float a_screen_space;\n"
"varying vec4 v_vertex_color;\n"
"void main() {\n"
" vec4 vertex = vec4(a_position.xyz, 1.);\n"
" gl_Position = u_mvp * vertex;\n"
" gl_PointSize = a_screen_space == 0. ? a_size / gl_Position.w : a_size;\n"
" v_vertex_color = a_color;\n"
"}\n";
const char* kSimplePointsPS =
"varying vec4 v_vertex_color;\n"
"void main() {\n"
" gl_FragColor = v_vertex_color;\n"
"}\n";
const char* vs[] = {kPlatformSpecivicVSHeader, kSimplePointsVS};
const char* fs[] = {kPlatformSpecivicFSHeader, kSimplePointsPS};
ozz::unique_ptr<PointsShader> shader = make_unique<PointsShader>();
success &=
shader->BuildFromSource(OZZ_ARRAY_SIZE(vs), vs, OZZ_ARRAY_SIZE(fs), fs);
// Binds default attributes
success &= shader->FindAttrib("a_position");
success &= shader->FindAttrib("a_color");
success &= shader->FindAttrib("a_size");
success &= shader->FindAttrib("a_screen_space");
// Binds default uniforms
success &= shader->BindUniform("u_mvp");
if (!success) {
shader.reset();
}
return shader;
}
PointsShader::GenericAttrib PointsShader::Bind(
const math::Float4x4& _model, const math::Float4x4& _view_proj,
GLsizei _pos_stride, GLsizei _pos_offset, GLsizei _color_stride,
GLsizei _color_offset, GLsizei _size_stride, GLsizei _size_offset,
bool _screen_space) {
GL(UseProgram(program()));
const GLint position_attrib = attrib(0);
GL(EnableVertexAttribArray(position_attrib));
GL(VertexAttribPointer(position_attrib, 3, GL_FLOAT, GL_FALSE, _pos_stride,
GL_PTR_OFFSET(_pos_offset)));
const GLint color_attrib = attrib(1);
if (_color_stride) {
GL(EnableVertexAttribArray(color_attrib));
GL(VertexAttribPointer(color_attrib, 4, GL_UNSIGNED_BYTE, GL_TRUE,
_color_stride, GL_PTR_OFFSET(_color_offset)));
}
const GLint size_attrib = attrib(2);
if (_size_stride) {
GL(EnableVertexAttribArray(size_attrib));
GL(VertexAttribPointer(size_attrib, 1, GL_FLOAT, GL_TRUE, _size_stride,
GL_PTR_OFFSET(_size_offset)));
}
const GLint screen_space_attrib = attrib(3);
GL(VertexAttrib1f(screen_space_attrib, 1.f * _screen_space));
// Binds mvp uniform
const GLint mvp_uniform = uniform(0);
const ozz::math::Float4x4 mvp = _view_proj * _model;
float values[16];
math::StorePtrU(mvp.cols[0], values + 0);
math::StorePtrU(mvp.cols[1], values + 4);
math::StorePtrU(mvp.cols[2], values + 8);
math::StorePtrU(mvp.cols[3], values + 12);
GL(UniformMatrix4fv(mvp_uniform, 1, false, values));
return {_color_stride ? -1 : color_attrib, _size_stride ? -1 : size_attrib};
}
namespace { namespace {
const char* kPassUv = const char* kPassUv =
"attribute vec2 a_uv;\n" "attribute vec2 a_uv;\n"

View File

@ -126,6 +126,29 @@ class ImmediatePTCShader : public Shader {
GLsizei _tex_offset, GLsizei _color_stride, GLsizei _color_offset); GLsizei _tex_offset, GLsizei _color_stride, GLsizei _color_offset);
}; };
class PointsShader : public Shader {
public:
PointsShader() {}
virtual ~PointsShader() {}
// Constructs the shader.
// Returns nullptr if shader compilation failed or a valid Shader pointer on
// success. The shader must then be deleted using default allocator Delete
// function.
static ozz::unique_ptr<PointsShader> Build();
// Binds the shader.
struct GenericAttrib {
GLint color;
GLint size;
};
GenericAttrib Bind(const math::Float4x4& _model,
const math::Float4x4& _view_proj, GLsizei _pos_stride,
GLsizei _pos_offset, GLsizei _color_stride,
GLsizei _color_offset, GLsizei _size_stride,
GLsizei _size_offset, bool _screen_space);
};
class SkeletonShader : public Shader { class SkeletonShader : public Shader {
public: public:
SkeletonShader() {} SkeletonShader() {}

View File

@ -69,12 +69,7 @@ struct Mesh {
// Test if the mesh has skinning informations. // Test if the mesh has skinning informations.
bool skinned() const { bool skinned() const {
for (size_t i = 0; i < parts.size(); ++i) { return !inverse_bind_poses.empty();
if (parts[i].influences_count() != 0) {
return true;
}
}
return false;
} }
// Returns the number of joints used to skin the mesh. // Returns the number of joints used to skin the mesh.

View File

@ -79,7 +79,7 @@ class Renderer {
// has a size of _cell_size. // has a size of _cell_size.
virtual bool DrawGrid(int _cell_count, float _cell_size) = 0; virtual bool DrawGrid(int _cell_count, float _cell_size) = 0;
// Renders a skeleton in its bind pose posture. // Renders a skeleton in its rest pose posture.
virtual bool DrawSkeleton(const animation::Skeleton& _skeleton, virtual bool DrawSkeleton(const animation::Skeleton& _skeleton,
const ozz::math::Float4x4& _transform, const ozz::math::Float4x4& _transform,
bool _draw_joints = true) = 0; bool _draw_joints = true) = 0;
@ -93,6 +93,17 @@ class Renderer {
const ozz::math::Float4x4& _transform, const ozz::math::Float4x4& _transform,
bool _draw_joints = true) = 0; bool _draw_joints = true) = 0;
// Renders points.
// _sizes and _colors must be either of ize 1 or equal to _positions' size.
// If _screen_space is true, then points size is fixed in screen-space,
// otherwise it changes with screen depth.
virtual bool DrawPoints(
const ozz::span<const float>& _positions,
const ozz::span<const float>& _sizes,
const ozz::span<const Color>& _colors,
const ozz::math::Float4x4& _transform, bool _round = true,
bool _screen_space = false) = 0;
// Renders a box at a specified location. // Renders a box at a specified location.
// The 2 slots of _colors array respectively defines color of the filled // The 2 slots of _colors array respectively defines color of the filled
// faces and color of the box outlines. // faces and color of the box outlines.
@ -116,7 +127,9 @@ class Renderer {
Color _color) = 0; Color _color) = 0;
struct Options { struct Options {
bool triangles; // Show triangles mesh.
bool texture; // Show texture (default checkered texture). bool texture; // Show texture (default checkered texture).
bool vertices; // Show vertices as points.
bool normals; // Show normals. bool normals; // Show normals.
bool tangents; // Show tangents. bool tangents; // Show tangents.
bool binormals; // Show binormals, computed from the normal and tangent. bool binormals; // Show binormals, computed from the normal and tangent.
@ -125,7 +138,9 @@ class Renderer {
bool skip_skinning; // Show texture (default checkered texture). bool skip_skinning; // Show texture (default checkered texture).
Options() Options()
: texture(false), : triangles(true),
texture(false),
vertices(false),
normals(false), normals(false),
tangents(false), tangents(false),
binormals(false), binormals(false),
@ -133,9 +148,12 @@ class Renderer {
wireframe(false), wireframe(false),
skip_skinning(false) {} skip_skinning(false) {}
Options(bool _texture, bool _normals, bool _tangents, bool _binormals, Options(bool _triangles, bool _texture, bool _vertices, bool _normals,
bool _colors, bool _wireframe, bool _skip_skinning) bool _tangents, bool _binormals, bool _colors, bool _wireframe,
: texture(_texture), bool _skip_skinning)
: triangles(_triangles),
texture(_texture),
vertices(_vertices),
normals(_normals), normals(_normals),
tangents(_tangents), tangents(_tangents),
binormals(_binormals), binormals(_binormals),

Some files were not shown because too many files have changed in this diff Show More