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

@ -9,4 +9,8 @@ The following authors have all licensed their contributions to ozz-animation und
- Kyle Rocha <kyle@luminawesome.com>
- Andreas Streichardt <andreas.streichardt@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
----------------------
@ -52,7 +73,7 @@ Release version 0.11.0
* Library
- [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] 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.

View File

@ -5,11 +5,12 @@ project(ozz)
# Current version
set(OZZ_VERSION_MAJOR 0)
set(OZZ_VERSION_MINOR 13)
set(OZZ_VERSION_MINOR 14)
set(OZZ_VERSION_PATCH 0)
set(OZZ_VERSION ${OZZ_VERSION_MAJOR}.${OZZ_VERSION_MINOR}.${OZZ_VERSION_PATCH})
# Add project build options
option(BUILD_SHARED_LIBS "Build ozz as shared libraries" OFF)
option(ozz_build_tools "Build tools" ON)
option(ozz_build_fbx "Build Fbx pipeline (Requires Fbx SDK)" 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_tests "Build unit tests" ON)
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_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(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/fuse_target.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
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)
# 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})
# 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.")
set(ozz_build_fbx OFF)
endif()
else()
# Disables fbx if tools are disabled
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)
message("-- ---------------------------------------------------------")
message("-- Selected options:")
message("-- - BUILD_SHARED_LIBS: " ${BUILD_SHARED_LIBS})
message("-- - ozz_build_tools: " ${ozz_build_tools})
message("-- - ozz_build_fbx: " ${ozz_build_fbx})
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
------------
| | 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) |
| 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) |
| 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 | [![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/).

View File

@ -30,33 +30,34 @@ set(cxx_all_flags
# Cross compiler compilation flags
# 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_EXTENSIONS OFF)
# Simd math force 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()
# Disables crt secure warnings
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
#--------------------------------------
# Modify default MSVC compilation flags
if(MSVC)
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
#---------------------------
# 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
set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "/MP")
add_compile_options(/MP)
# Set the warning level to W4
set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "/W4")
add_compile_options(/W4)
# 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.
foreach(flag ${cxx_all_flags})
@ -68,40 +69,35 @@ if(MSVC)
endforeach()
#--------------------------------------
# else consider the compiler as GCC compatible
# Modify default GCC compilation flags
# else consider the compiler as GCC compatible (inc clang)
else()
# Set the warning level to Wall
set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "-Wall")
add_compile_options(-Wall)
# Enable extra level of warning
#set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "-Wextra")
#add_compile_options(-Wextra)
# 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)
if(W_IGNORED_ATTRIBUTES)
set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "-Wno-ignored-attributes")
add_compile_options(-Wno-ignored-attributes)
endif()
# Disables c98 retrocompatibility warnings
check_cxx_compiler_flag("-Wc++98-compat-pedantic" W_98_COMPAT_PEDANTIC)
if(W_98_COMPAT_PEDANTIC)
add_compile_options(-Wno-c++98-compat-pedantic)
endif()
# Enables warning: sign comparison warnings
check_cxx_compiler_flag("-Wsign-compare" W_SIGN_COMPARE)
if(W_SIGN_COMPARE)
set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS "-Wsign-compare")
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("-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
if(EMSCRIPTEN)
@ -157,4 +153,4 @@ if(ozz_build_postfix)
set(CMAKE_RELEASE_POSTFIX "_r")
set(CMAKE_MINSIZEREL_POSTFIX "_rs")
set(CMAKE_RELWITHDEBINFO_POSTFIX "_rd")
endif()
endif()

View File

@ -9,11 +9,18 @@ function(fuse_target _target_name)
# Get all target 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(
OUTPUT ${output_file}
DEPENDS ${target_source_files}
${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})
set_target_properties(BUILD_FUSE_${_target_name} PROPERTIES FOLDER "ozz/fuse")

View File

@ -2,18 +2,25 @@
#----------------------------------------------------------
# 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.
string (REPLACE " " ";" ozz_target_source_files "${ozz_target_source_files}")
# Patches arguments so that cmake take them as a list.
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.
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.
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}" "${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}" )
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}")
endforeach()
# Output new file
file(WRITE "${ozz_fuse_output_file}" "${output_content}")

View File

@ -9,9 +9,15 @@
# FBX_INCLUDE_DIRS - The Fbx SDK include directories
# FBX_LIBRARIES - The libraries needed to use 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:
#
# 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
# static library version of the Visual C++ runtime library.
# Default is ON (aka, DLL version: /MD).
@ -52,7 +58,7 @@
###############################################################################
# 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:
# - Windows: \lib\<compiler_version>\<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.
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")
elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19)
set(FBX_CP_PATH "vs2015")
@ -90,19 +98,25 @@ function(FindFbxLibrariesGeneric _FBX_ROOT_DIR _OUT_FBX_LIBRARIES _OUT_FBX_LIBRA
endif()
endif()
# Set libraries names to search, sorted by preference.
set(FBX_SEARCH_LIB_NAMES fbxsdk-static.a libfbxsdk.a fbxsdk.a)
# 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.
if (NOT DEFINED FBX_MSVC_RT_DLL OR FBX_MSVC_RT_DLL)
set(FBX_SEARCH_LIB_NAMES ${FBX_SEARCH_LIB_NAMES} libfbxsdk-md.lib)
# Select whether to use the DLL version or the static library version of fbx sdk.
if (FBX_SHARED)
# Dynamic libraries
set(FBX_SEARCH_LIB_NAMES ${FBX_SEARCH_LIB_NAMES} libfbxsdk.lib libfbxsdk.dylib libfbxsdk.so)
else()
set(FBX_SEARCH_LIB_NAMES ${FBX_SEARCH_LIB_NAMES} libfbxsdk-mt.lib)
endif()
# 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.
# Default is "md", aka use the multithread DLL version of the run-time library.
if (NOT DEFINED FBX_MSVC_RT_DLL OR FBX_MSVC_RT_DLL)
set(FBX_SEARCH_LIB_NAMES ${FBX_SEARCH_LIB_NAMES} libfbxsdk-md.lib)
else()
set(FBX_SEARCH_LIB_NAMES ${FBX_SEARCH_LIB_NAMES} libfbxsdk-mt.lib)
endif()
endif()
# 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
${FBX_SEARCH_LIB_NAMES}
@ -114,21 +128,42 @@ function(FindFbxLibrariesGeneric _FBX_ROOT_DIR _OUT_FBX_LIBRARIES _OUT_FBX_LIBRA
${FBX_SEARCH_LIB_NAMES}
HINTS "${FBX_SEARCH_LIB_PATH}/debug/")
if(UNIX)
if(APPLE) # APPLE requires to link with Carbon framework
find_library(CARBON_FRAMEWORK Carbon)
list(APPEND FBX_LIB ${CARBON_FRAMEWORK})
list(APPEND FBX_LIB_DEBUG ${CARBON_FRAMEWORK})
else()
find_package(Threads)
list(APPEND FBX_LIB ${CMAKE_THREAD_LIBS_INIT} dl)
list(APPEND FBX_LIB_DEBUG ${CMAKE_THREAD_LIBS_INIT} dl)
endif()
# Looks for shared libraries
if (FBX_SHARED)
set(FBX_SEARCH_SHARED_LIB_NAMES libfbxsdk.dll libfbxsdk.so libfbxsdk.dylib)
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()
add_library(fbx::sdk STATIC IMPORTED GLOBAL)
set_property(TARGET fbx::sdk PROPERTY IMPORTED_LOCATION ${FBX_LIB})
set_property(TARGET fbx::sdk PROPERTY IMPORTED_LOCATION_DEBUG ${FBX_LIB_DEBUG})
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)
# 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("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
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
${XML_SEARCH_LIB_NAMES}
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
${XML_SEARCH_LIB_NAMES}
HINTS ${ADDITIONAL_LIB_SEARCH_PATH_DEBUG})
find_library(Z_LIB_DEBUG
${Z_SEARCH_LIB_NAMES}
HINTS ${ADDITIONAL_LIB_SEARCH_PATH_DEBUG})
# for whatever reason on apple it will need iconv as well?!
if(APPLE)
find_library(ICONV_LIB
iconv)
# 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)
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()
if(NOT Z_LIB)
find_library(Z_LIB
${Z_SEARCH_LIB_NAMES}
HINTS ${ADDITIONAL_LIB_SEARCH_PATH_RELEASE})
find_library(Z_LIB_DEBUG
${Z_SEARCH_LIB_NAMES}
HINTS ${ADDITIONAL_LIB_SEARCH_PATH_DEBUG})
if(Z_LIB AND Z_LIB_DEBUG)
target_link_libraries(fbx::sdk INTERFACE optimized ${Z_LIB})
target_link_libraries(fbx::sdk INTERFACE debug ${Z_LIB_DEBUG})
else()
message(WARNING "FBX found but required zlib was not found!")
endif()
list(APPEND FBX_LIB ${XML_LIB} ${Z_LIB})
list(APPEND FBX_LIB_DEBUG ${XML_LIB_DEBUG} ${Z_LIB_DEBUG})
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_DEBUG} ${FBX_LIB_DEBUG} PARENT_SCOPE)
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()
# Deduce fbx sdk version
endfunction()
###############################################################################
@ -257,7 +315,7 @@ if(FBX_INCLUDE_DIR)
set(FBX_INCLUDE_DIRS "${FBX_INCLUDE_DIR}/include")
# 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()
# 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-all.cc
fused-src/gtest/gtest.h)
@ -12,4 +12,3 @@ target_link_libraries(gtest
target_include_directories(gtest PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/extern/gtest/fused-src>)

View File

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

View File

@ -6,8 +6,18 @@ add_library(json
set_target_properties(json
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
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
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/extern/jsoncpp/dist>)

View File

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

View File

@ -4,6 +4,7 @@ add_executable(load_from_file
load_from_file.cc)
target_link_libraries(load_from_file
ozz_animation)
target_copy_shared_libraries(load_from_file)
set_target_properties(load_from_file
PROPERTIES FOLDER "howtos")
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)
target_link_libraries(custom_skeleton_importer
ozz_animation_offline)
target_copy_shared_libraries(custom_skeleton_importer)
set_target_properties(custom_skeleton_importer
PROPERTIES FOLDER "howtos")
add_test(NAME custom_skeleton_importer COMMAND custom_skeleton_importer)
@ -28,6 +30,7 @@ add_executable(custom_animation_importer
custom_animation_importer.cc)
target_link_libraries(custom_animation_importer
ozz_animation_offline)
target_copy_shared_libraries(custom_animation_importer)
set_target_properties(custom_animation_importer
PROPERTIES FOLDER "howtos")
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/skeleton_builder.h"
#include "ozz/animation/runtime/skeleton.h"
#include <cstdlib>
// Code for ozz-animation HowTo: "How to write a custon skeleton importer?"
int main(int argc, char const* argv[]) {
@ -52,7 +51,7 @@ int main(int argc, char const* argv[]) {
// Setup root joints name.
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
// used as a fallback when there's no animation for a joint.
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_
#define OZZ_OZZ_ANIMATION_OFFLINE_ADDITIVE_ANIMATION_BUILDER_H_
#include "ozz/animation/offline/export.h"
#include "ozz/base/platform.h"
#include "ozz/base/span.h"
@ -46,7 +47,7 @@ struct RawAnimation;
// Defines the class responsible for building a delta animation from an offline
// raw animation. This is used to create animations compatible with additive
// blending.
class AdditiveAnimationBuilder {
class OZZ_ANIMOFFLINE_DLL AdditiveAnimationBuilder {
public:
// Initializes the builder.
AdditiveAnimationBuilder();

View File

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

View File

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

View File

@ -28,6 +28,8 @@
#ifndef 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/tools/import2ozz.h"
@ -51,34 +53,40 @@ struct RawquaternionTrack;
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,
float _sampling_rate, RawAnimation* _animation);
OzzImporter::NodeProperties GetNodeProperties(FbxSceneLoader& _scene_loader,
OZZ_ANIMFBX_DLL OzzImporter::NodeProperties GetNodeProperties(
FbxSceneLoader& _scene_loader,
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,
OzzImporter::NodeProperty::Type _type,
FbxSceneLoader& _scene_loader, float _sampling_rate,
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,
OzzImporter::NodeProperty::Type _type,
FbxSceneLoader& _scene_loader, float _sampling_rate,
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,
OzzImporter::NodeProperty::Type _type,
FbxSceneLoader& _scene_loader, float _sampling_rate,
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,
OzzImporter::NodeProperty::Type _type,
FbxSceneLoader& _scene_loader, float _sampling_rate,

View File

@ -28,6 +28,7 @@
#ifndef 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/tools/import2ozz.h"
@ -39,7 +40,7 @@ struct RawSkeleton;
namespace fbx {
bool ExtractSkeleton(FbxSceneLoader& _loader,
OZZ_ANIMFBX_DLL bool ExtractSkeleton(FbxSceneLoader& _loader,
const OzzImporter::NodeType& _types,
RawSkeleton* _skeleton);

View File

@ -28,6 +28,7 @@
#ifndef 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/vector.h"
#include "ozz/base/io/archive_traits.h"
@ -55,7 +56,7 @@ namespace offline {
// 3. Keyframes' time are all within [0,animation duration] range.
// Animations that would fail this validation will fail to be converted by the
// AnimationBuilder.
struct RawAnimation {
struct OZZ_ANIMOFFLINE_DLL RawAnimation {
// Constructs a valid RawAnimation with a 1s default duration.
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.
template <>
struct Extern<animation::offline::RawAnimation> {
struct OZZ_ANIMOFFLINE_DLL Extern<animation::offline::RawAnimation> {
static void Save(OArchive& _archive,
const animation::offline::RawAnimation* _animations,
size_t _count);

View File

@ -28,6 +28,7 @@
#ifndef 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/base/maths/transform.h"
@ -38,22 +39,25 @@ namespace animation {
namespace offline {
// 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);
// 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);
// 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);
// Samples a RawAnimation track. This function shall be used for offline
// purpose. Use ozz::animation::Animation and ozz::animation::SamplingJob for
// runtime purpose.
// 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);
// Samples a RawAnimation. This function shall be used for offline
@ -61,7 +65,8 @@ bool SampleTrack(const RawAnimation::JointTrack& _track, float _time,
// runtime purpose.
// _animation must be valid.
// 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);
// 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.
// This sounds trivial, but floating point error could occur if keyframe time
// was accumulated for a long duration.
class FixedRateSamplingTime {
class OZZ_ANIMOFFLINE_DLL FixedRateSamplingTime {
public:
FixedRateSamplingTime(float _duration, float _frequency);

View File

@ -28,6 +28,7 @@
#ifndef 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/vector.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
// define the offline skeleton object that can be converted to the runtime
// skeleton using the SkeletonBuilder. This skeleton structure exposes joints'
// hierarchy. A joint is defined with a name, a transformation (its bind pose),
// and its children. Children are exposed as a public std::vector of joints.
// This same type is used for skeleton roots, also exposed from the public API.
// The public API exposed through std:vector's of joints can be used freely with
// the only restriction that the total number of joints does not exceed
// Skeleton::kMaxJoints.
struct RawSkeleton {
// hierarchy. A joint is defined with a name, a transformation (its rest_pose
// pose), and its children. Children are exposed as a public std::vector of
// joints. This same type is used for skeleton roots, also exposed from the
// public API. The public API exposed through std:vector's of joints can be used
// freely with the only restriction that the total number of joints does not
// exceed Skeleton::kMaxJoints.
struct OZZ_ANIMOFFLINE_DLL RawSkeleton {
// Construct an empty skeleton.
RawSkeleton();
@ -65,7 +66,7 @@ struct RawSkeleton {
// The name of the joint.
ozz::string name;
// Joint bind pose transformation in local space.
// Joint rest pose transformation in local space.
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.
template <>
struct Extern<animation::offline::RawSkeleton> {
struct OZZ_ANIMOFFLINE_DLL Extern<animation::offline::RawSkeleton> {
static void Save(OArchive& _archive,
const animation::offline::RawSkeleton* _skeletons,
size_t _count);

View File

@ -28,11 +28,10 @@
#ifndef 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/vector.h"
#include "ozz/base/io/archive_traits.h"
#include "ozz/base/maths/quaternion.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
// the RawTrackBuilder.
template <typename _ValueType>
struct RawTrack {
struct OZZ_ANIMOFFLINE_DLL RawTrack {
typedef _ValueType ValueType;
typedef RawTrackKeyframe<ValueType> Keyframe;
@ -109,11 +108,15 @@ struct RawTrack {
} // namespace internal
// Offline user-channel animation track type instantiation.
struct RawFloatTrack : public internal::RawTrack<float> {};
struct RawFloat2Track : public internal::RawTrack<math::Float2> {};
struct RawFloat3Track : public internal::RawTrack<math::Float3> {};
struct RawFloat4Track : public internal::RawTrack<math::Float4> {};
struct RawQuaternionTrack : public internal::RawTrack<math::Quaternion> {};
struct OZZ_ANIMOFFLINE_DLL RawFloatTrack : public internal::RawTrack<float> {};
struct OZZ_ANIMOFFLINE_DLL RawFloat2Track
: public internal::RawTrack<math::Float2> {};
struct OZZ_ANIMOFFLINE_DLL RawFloat3Track
: 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 animation

View File

@ -28,6 +28,7 @@
#ifndef 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/memory/unique_ptr.h"
@ -43,7 +44,7 @@ namespace offline {
struct RawSkeleton;
// Defines the class responsible of building Skeleton instances.
class SkeletonBuilder {
class OZZ_ANIMOFFLINE_DLL SkeletonBuilder {
public:
// Creates a Skeleton based on _raw_skeleton and *this builder parameters.
// 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_
#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/vector.h"
@ -35,6 +37,8 @@
#include "ozz/animation/offline/raw_skeleton.h"
#include "ozz/animation/offline/raw_track.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace animation {
@ -51,7 +55,7 @@ namespace offline {
// To import a new source data format, one will implement the pure virtual
// functions of this interface. All the conversions end error processing are
// done by the tool.
class OzzImporter {
class OZZ_ANIMTOOLS_DLL OzzImporter {
public:
virtual ~OzzImporter() {}
@ -72,6 +76,7 @@ class OzzImporter {
bool camera : 1; // Uses camera nodes as skeleton joints.
bool geometry : 1; // Uses geometry 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
// listed above and any other.
};

View File

@ -28,6 +28,7 @@
#ifndef 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"
namespace ozz {
@ -53,7 +54,7 @@ struct RawQuaternionTrack;
// 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
// the data at all.
class TrackBuilder {
class OZZ_ANIMOFFLINE_DLL TrackBuilder {
public:
// Creates a Track based on _raw_track and *this builder parameters.
// 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_
#define OZZ_OZZ_ANIMATION_OFFLINE_TRACK_OPTIMIZER_H_
#include "ozz/animation/offline/export.h"
#include "ozz/base/platform.h"
namespace ozz {
namespace animation {
namespace offline {
@ -44,7 +47,7 @@ struct RawQuaternionTrack;
// keyframes (within a tolerance value) are removed from the track. Default
// optimization tolerances are set in order to favor quality over runtime
// performances and memory footprint.
class TrackOptimizer {
class OZZ_ANIMOFFLINE_DLL TrackOptimizer {
public:
// Initializes the optimizer with default tolerances (favoring quality).
TrackOptimizer();

View File

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

View File

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

View File

@ -28,6 +28,7 @@
#ifndef 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/span.h"
@ -44,15 +45,15 @@ namespace animation {
// (the result of a sampled animation) according to their respective weight,
// into one output pose.
// 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
// that all buffers must be at least as big as the bind pose buffer.
// 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 rest pose buffer.
// Partial animation blending is supported through optional joint weights that
// 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
// blend operations in a single pass.
// The job does not owned any buffers (input/output) and will thus not delete
// them during job's destruction.
struct BlendingJob {
struct OZZ_ANIMATION_DLL BlendingJob {
// Default constructor, initializes default values.
BlendingJob();
@ -63,7 +64,7 @@ struct BlendingJob {
// -if any layer is not valid.
// -if output range is not valid.
// -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.
bool Validate() const;
@ -75,7 +76,7 @@ struct BlendingJob {
// Defines a layer of blending input data (local space transforms) and
// parameters (weights).
struct Layer {
struct OZZ_ANIMATION_DLL Layer {
// Default constructor, initializes default values.
Layer();
@ -86,8 +87,8 @@ struct BlendingJob {
// The range [begin,end[ of input layer posture. This buffer expect to store
// 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
// only the number of transforms defined by the bind pose buffer will be
// This range must be at least as big as the rest pose buffer, even though
// only the number of transforms defined by the rest pose buffer will be
// processed.
span<const math::SoaTransform> transform;
@ -95,8 +96,8 @@ struct BlendingJob {
// layer.
// 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
// as the bind pose buffer, even though only the number of transforms
// defined by the bind pose buffer will be processed. When a layer doesn't
// as the rest pose buffer, even though only the number of transforms
// defined by the rest pose buffer will be processed. When a layer doesn't
// specifies per joint weights, then it is implicitly considered as
// 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
@ -106,7 +107,7 @@ struct BlendingJob {
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.
// Must be greater than 0.f.
float threshold;
@ -119,18 +120,18 @@ struct BlendingJob {
// The range of layers that must be added to the output.
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
// by the skeleton that all the animations belongs to.
// 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.
span<const ozz::math::SoaTransform> bind_pose;
span<const ozz::math::SoaTransform> rest_pose;
// Job output.
// The range of output transforms to be filled with blended layer
// transforms during job execution.
// Must be at least as big as the bind pose buffer, but only the number of
// transforms defined by the bind pose buffer size will be processed.
// Must be at least as big as the rest pose buffer, but only the number of
// transforms defined by the rest pose buffer size will be processed.
span<ozz::math::SoaTransform> output;
};
} // 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_
#define OZZ_OZZ_ANIMATION_RUNTIME_IK_AIM_JOB_H_
#include "ozz/animation/runtime/export.h"
#include "ozz/base/platform.h"
#include "ozz/base/maths/simd_math.h"
@ -50,7 +51,7 @@ namespace animation {
// vector should aim the target.
// Result is unstable if joint-to-target direction is parallel to pole vector,
// or if target is too close to joint position.
struct IKAimJob {
struct OZZ_ANIMATION_DLL IKAimJob {
// Default constructor, initializes default values.
IKAimJob();

View File

@ -28,6 +28,7 @@
#ifndef 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/maths/simd_math.h"
@ -51,7 +52,7 @@ namespace animation {
// ancestors (joints in-between will simply remain fixed).
// Implementation is inspired by Autodesk Maya 2 bone IK, improved stability
// wise and extended with Soften IK.
struct IKTwoBoneJob {
struct OZZ_ANIMATION_DLL IKTwoBoneJob {
// Constructor, initializes default values.
IKTwoBoneJob();

View File

@ -28,6 +28,7 @@
#ifndef 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/span.h"
@ -55,7 +56,7 @@ class Skeleton;
// ordered like skeleton's joints. Output are matrices, because the combination
// of affine transformations can contain shearing or complex transformation
// that cannot be represented as Transform object.
struct LocalToModelJob {
struct OZZ_ANIMATION_DLL LocalToModelJob {
// Default constructor, initializes default values.
LocalToModelJob();

View File

@ -28,6 +28,7 @@
#ifndef 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/span.h"
@ -43,19 +44,16 @@ namespace animation {
// Forward declares the animation type to sample.
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
// 0 is the beginning of the animation, 1 is the end), to output the
// corresponding posture in local-space.
// SamplingJob uses a cache (aka SamplingCache) to store intermediate values
// (decompressed animation keyframes...) while sampling. This cache also stores
// pre-computed values that allows drastic optimization while playing/sampling
// the animation forward. Backward sampling works, but isn't optimized through
// the cache. The job does not owned the buffers (in/output) and will thus not
// delete them during job's destruction.
struct SamplingJob {
// SamplingJob uses a context (aka SamplingJob::Context) to store intermediate
// values (decompressed animation keyframes...) while sampling. This context
// also stores pre-computed values that allows drastic optimization while
// playing/sampling the animation forward. Backward sampling works, but isn't
// optimized through the context. The job does not owned the buffers (in/output)
// and will thus not delete them during job's destruction.
struct OZZ_ANIMATION_DLL SamplingJob {
// Default constructor, initializes default values.
SamplingJob();
@ -80,8 +78,11 @@ struct SamplingJob {
// The animation to sample.
const Animation* animation;
// A cache object that must be big enough to sample *this animation.
SamplingCache* cache;
// Forward declares the context object used by the SamplingJob.
class Context;
// A context object that must be big enough to sample *this animation.
Context* context;
// Job output.
// The output range to be filled with sampled joints during job execution.
@ -98,61 +99,62 @@ struct InterpSoaFloat3;
struct InterpSoaQuaternion;
} // 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.
class SamplingCache {
class OZZ_ANIMATION_DLL SamplingJob::Context {
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.
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
// soa size, which means max_tracks() can return a different (but bigger)
// value than _max_tracks.
explicit SamplingCache(int _max_tracks);
explicit Context(int _max_tracks);
// Deallocates cache.
~SamplingCache();
// Disables copy and assignation.
Context(Context const&) = delete;
Context& operator=(Context const&) = delete;
// Resize the number of joints that the cache can support.
// This also implicitly invalidate the cache.
// Deallocates context.
~Context();
// Resize the number of joints that the context can support.
// This also implicitly invalidate the context.
void Resize(int _max_tracks);
// Invalidate the cache.
// The SamplingJob automatically invalidates a cache when required
// Invalidate the context.
// The SamplingJob automatically invalidates a context when required
// 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
// crash if ever the address of an animation is used again with another
// animation (could be the result of successive call to delete / new).
// Therefore it is recommended to manually invalidate a cache when it is
// known that this cache will not be used for with an animation again.
// Therefore it is recommended to manually invalidate a context when it is
// known that this context will not be used for with an animation again.
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_soa_tracks() const { return max_soa_tracks_; }
private:
// Disables copy and assignation.
SamplingCache(SamplingCache const&);
void operator=(SamplingCache const&);
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,
// 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);
// 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_;
// The current time ratio in the animation.
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_;
// Soa hot data to interpolate.
@ -166,7 +168,7 @@ class SamplingCache {
int* rotation_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 rotation_cursor_;
int scale_cursor_;

View File

@ -28,6 +28,7 @@
#ifndef 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/platform.h"
#include "ozz/base/span.h"
@ -48,16 +49,16 @@ class SkeletonBuilder;
}
// 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.
// 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
// 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
// order. This is enough to traverse the whole joint hierarchy. See
// IterateJointsDF() from skeleton_utils.h that implements a depth-first
// traversal utility.
class Skeleton {
class OZZ_ANIMATION_DLL Skeleton {
public:
// Defines Skeleton constant values.
enum Constants {
@ -81,6 +82,14 @@ class Skeleton {
// Builds a default 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.
~Skeleton();
@ -91,9 +100,9 @@ class Skeleton {
// skeleton. This value is useful to allocate SoA runtime data structures.
int num_soa_joints() const { return (num_joints() + 3) / 4; }
// Returns joint's bind poses. Bind poses are stored in soa format.
span<const math::SoaTransform> joint_bind_poses() const {
return joint_bind_poses_;
// Returns joint's rest poses. Rest poses are stored in soa format.
span<const math::SoaTransform> joint_rest_poses() const {
return joint_rest_poses_;
}
// Returns joint's parent indices range.
@ -110,10 +119,6 @@ class Skeleton {
void Load(ozz::io::IArchive& _archive, uint32_t _version);
private:
// Disables copy and assignation.
Skeleton(Skeleton const&);
void operator=(Skeleton const&);
// Internal allocation/deallocation function.
// Allocate returns the beginning of the contiguous buffer of names.
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
// size is equal to the number of joints of the skeleton.
// Bind pose of every joint in local space.
span<math::SoaTransform> joint_bind_poses_;
// Rest pose of every joint in local space.
span<math::SoaTransform> joint_rest_poses_;
// Array of joint parent indexes.
span<int16_t> joint_parents_;

View File

@ -28,17 +28,18 @@
#ifndef 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/base/maths/transform.h"
#include <cassert>
namespace ozz {
namespace animation {
// Get bind-pose of a skeleton joint.
ozz::math::Transform GetJointLocalBindPose(const Skeleton& _skeleton,
int _joint);
// Get rest-pose of a skeleton joint.
OZZ_ANIMATION_DLL ozz::math::Transform GetJointLocalRestPose(
const Skeleton& _skeleton, int _joint);
// 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
@ -51,12 +52,15 @@ inline bool IsLeaf(const Skeleton& _skeleton, int _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.
// _Fct is of type void(int _current, int _parent) where the first argument is
// the child of the second argument. _parent is kNoParent if the
// _current joint is a root. _from indicates the joint from which the joint
// hierarchy traversal begins. Use Skeleton::kNoParent to traverse the
// whole hierarchy, in case there are multiple roots.
// _Fct is of type void(int _current, int _parent) where the first argument
// is the child of the second argument. _parent is kNoParent if the _current
// joint is a root. _from indicates the joint from which the joint hierarchy
// traversal begins. Use Skeleton::kNoParent to traverse the whole
// hierarchy, in case there are multiple roots.
template <typename _Fct>
inline _Fct IterateJointsDF(const Skeleton& _skeleton, _Fct _fct,
int _from = Skeleton::kNoParent) {

View File

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

View File

@ -28,6 +28,7 @@
#ifndef 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"
namespace ozz {
@ -65,14 +66,15 @@ struct TrackSamplingJob {
// 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
// tracks have no duration.
struct FloatTrackSamplingJob : public internal::TrackSamplingJob<FloatTrack> {};
struct Float2TrackSamplingJob : public internal::TrackSamplingJob<Float2Track> {
};
struct Float3TrackSamplingJob : public internal::TrackSamplingJob<Float3Track> {
};
struct Float4TrackSamplingJob : public internal::TrackSamplingJob<Float4Track> {
};
struct QuaternionTrackSamplingJob
struct OZZ_ANIMATION_DLL FloatTrackSamplingJob
: public internal::TrackSamplingJob<FloatTrack> {};
struct OZZ_ANIMATION_DLL Float2TrackSamplingJob
: public internal::TrackSamplingJob<Float2Track> {};
struct OZZ_ANIMATION_DLL Float3TrackSamplingJob
: public internal::TrackSamplingJob<Float3Track> {};
struct OZZ_ANIMATION_DLL Float4TrackSamplingJob
: public internal::TrackSamplingJob<Float4Track> {};
struct OZZ_ANIMATION_DLL QuaternionTrackSamplingJob
: public internal::TrackSamplingJob<QuaternionTrack> {};
} // namespace animation

View File

@ -28,6 +28,7 @@
#ifndef 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"
namespace ozz {
@ -46,7 +47,7 @@ class FloatTrack;
// track types isn't possible.
// 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.
struct TrackTriggeringJob {
struct OZZ_ANIMATION_DLL TrackTriggeringJob {
TrackTriggeringJob();
// Validates job parameters.
@ -95,7 +96,7 @@ struct TrackTriggeringJob {
// 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
// last edge has been reached.
class TrackTriggeringJob::Iterator {
class OZZ_ANIMATION_DLL TrackTriggeringJob::Iterator {
public:
Iterator() : job_(nullptr), outer_(0.f), inner_(0) {}

View File

@ -28,6 +28,8 @@
#ifndef 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
// with stl algorithms.
// 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 {}
template <class _Other>
StdAllocator<value_type>(const StdAllocator<_Other>&) noexcept {}
StdAllocator(const StdAllocator<_Other>&) noexcept {}
template <class _Other>
struct rebind {

View File

@ -38,7 +38,7 @@ namespace io {
OZZ_IO_TYPE_NOT_VERSIONABLE(ozz::string)
template <>
struct Extern<ozz::string> {
struct OZZ_BASE_DLL Extern<ozz::string> {
static void Save(OArchive& _archive, const 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());
_archive << size;
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;
vector.resize(size);
if (size > 0) {
_archive >> ozz::io::MakeArray(&vector[0], size);
_archive >> ozz::io::MakeArray(vector.data(), size);
}
}
}

View File

@ -66,20 +66,17 @@ template <typename _Ty, size_t _size = sizeof(_Ty)>
struct EndianSwapper;
// Internal macro used to swap two bytes.
#define OZZ_BYTE_SWAP(_a, _b) \
do { \
const char temp = _a; \
_a = _b; \
_b = temp; \
#define OZZ_BYTE_SWAP(_a, _b) \
do { \
const ozz::byte temp = (_a); \
(_a) = (_b); \
(_b) = temp; \
} while (0)
// EndianSwapper specialization for 1 byte types.
template <typename _Ty>
struct EndianSwapper<_Ty, 1> {
OZZ_INLINE static void Swap(_Ty* _ty, size_t _count) {
(void)_ty;
(void)_count;
}
OZZ_INLINE static void Swap(_Ty*, size_t) {}
OZZ_INLINE static _Ty Swap(_Ty _ty) { return _ty; }
};
@ -87,13 +84,13 @@ struct EndianSwapper<_Ty, 1> {
template <typename _Ty>
struct EndianSwapper<_Ty, 2> {
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) {
OZZ_BYTE_SWAP(alias[i + 0], alias[i + 1]);
}
}
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]);
return _ty;
}
@ -103,14 +100,14 @@ struct EndianSwapper<_Ty, 2> {
template <typename _Ty>
struct EndianSwapper<_Ty, 4> {
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) {
OZZ_BYTE_SWAP(alias[i + 0], alias[i + 3]);
OZZ_BYTE_SWAP(alias[i + 1], alias[i + 2]);
}
}
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[1], alias[2]);
return _ty;
@ -121,7 +118,7 @@ struct EndianSwapper<_Ty, 4> {
template <typename _Ty>
struct EndianSwapper<_Ty, 8> {
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) {
OZZ_BYTE_SWAP(alias[i + 0], alias[i + 7]);
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.
char* alias = reinterpret_cast<char*>(&_ty);
byte* alias = reinterpret_cast<byte*>(&_ty);
OZZ_BYTE_SWAP(alias[0], alias[7]);
OZZ_BYTE_SWAP(alias[1], alias[6]);
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
// the user side.
#include <stdint.h>
#include <cassert>
#include "ozz/base/endianness.h"
#include "ozz/base/io/archive_traits.h"
#include "ozz/base/io/stream.h"
#include "ozz/base/platform.h"
#include "ozz/base/span.h"
#include <stdint.h>
#include <cassert>
#include "ozz/base/io/archive_traits.h"
namespace ozz {
namespace io {
namespace internal {
@ -102,7 +102,7 @@ struct Tagger;
// 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
// endianness mode while reading.
class OArchive {
class OZZ_BASE_DLL OArchive {
public:
// Constructs an output archive from the Stream _stream that must be valid
// and opened for writing.
@ -126,7 +126,7 @@ class OArchive {
}
// Primitive type saving.
#define OZZ_IO_PRIMITIVE_TYPE(_type) \
#define OZZ_IO_PRIMITIVE_TYPE(_type) \
void operator<<(_type _v) { \
_type v = endian_swap_ ? EndianSwapper<_type>::Swap(_v) : _v; \
OZZ_IF_DEBUG(size_t size =) stream_->Write(&v, sizeof(v)); \
@ -171,7 +171,7 @@ class OArchive {
// Implements input archive concept used to load/de-serialize data to a Stream.
// Endianness conversions are automatically performed according to the Archive
// and the native formats.
class IArchive {
class OZZ_BASE_DLL IArchive {
public:
// 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
@ -199,7 +199,7 @@ class IArchive {
}
// Primitive type loading.
#define OZZ_IO_PRIMITIVE_TYPE(_type) \
#define OZZ_IO_PRIMITIVE_TYPE(_type) \
void operator>>(_type& _v) { \
_type v; \
OZZ_IF_DEBUG(size_t size =) stream_->Read(&v, sizeof(v)); \
@ -314,7 +314,7 @@ struct Version<const Array<_Ty>> {
};
// Specializes Array Save/Load for primitive types.
#define OZZ_IO_PRIMITIVE_TYPE(_type) \
#define OZZ_IO_PRIMITIVE_TYPE(_type) \
template <> \
inline void Array<const _type>::Save(OArchive& _archive) const { \
if (_archive.endian_swap()) { \

View File

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

View File

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

View File

@ -39,7 +39,7 @@ namespace math {
struct Float4x4;
// Defines an axis aligned box.
struct Box {
struct OZZ_BASE_DLL Box {
// Constructs an invalid box.
Box();
@ -78,7 +78,7 @@ OZZ_INLINE Box Merge(const Box& _a, const Box& _b) {
}
// 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 ozz
#endif // OZZ_OZZ_BASE_MATHS_BOX_H_

View File

@ -152,7 +152,8 @@ typedef const SimdInt4& _SimdInt4;
} // namespace ozz
#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__))
#define OZZ_DISABLE_SSE_NATIVE_OPERATORS
#endif

View File

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

View File

@ -31,6 +31,7 @@
// SIMD SSE2+ implementation, based on scalar floats.
#include <stdint.h>
#include <cassert>
// Temporarly needed while trigonometric functions aren't implemented.
@ -1294,7 +1295,7 @@ OZZ_INLINE SimdInt4 Sign(_SimdInt4 _v) {
OZZ_INLINE SimdInt4 Min(_SimdInt4 _a, _SimdInt4 _b) {
#ifdef OZZ_SIMD_SSE4_1
return _mm_min_epi32(_a, _b);
#else // OZZ_SIMD_SSE4_1
#else // OZZ_SIMD_SSE4_1
return OZZ_SSE_SELECT_I(_mm_cmplt_epi32(_a, _b), _a, _b);
#endif // OZZ_SIMD_SSE4_1
}
@ -1302,7 +1303,7 @@ OZZ_INLINE SimdInt4 Min(_SimdInt4 _a, _SimdInt4 _b) {
OZZ_INLINE SimdInt4 Max(_SimdInt4 _a, _SimdInt4 _b) {
#ifdef OZZ_SIMD_SSE4_1
return _mm_max_epi32(_a, _b);
#else // OZZ_SIMD_SSE4_1
#else // OZZ_SIMD_SSE4_1
return OZZ_SSE_SELECT_I(_mm_cmpgt_epi32(_a, _b), _a, _b);
#endif // OZZ_SIMD_SSE4_1
}
@ -1775,26 +1776,9 @@ inline bool ToAffine(const Float4x4& _m, SimdFloat4* _translation,
}
inline Float4x4 Float4x4::FromEuler(_SimdFloat4 _v) {
const __m128 cos = Cos(_v);
const __m128 sin = Sin(_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;
return Float4x4::FromAxisAngle(simd_float4::y_axis(), SplatX(_v)) *
Float4x4::FromAxisAngle(simd_float4::x_axis(), SplatY(_v)) *
Float4x4::FromAxisAngle(simd_float4::z_axis(), SplatZ(_v));
}
inline Float4x4 Float4x4::FromAxisAngle(_SimdFloat4 _axis, _SimdFloat4 _angle) {

View File

@ -45,7 +45,7 @@ struct RectInt;
namespace io {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::Float2)
template <>
struct Extern<math::Float2> {
struct OZZ_BASE_DLL Extern<math::Float2> {
static void Save(OArchive& _archive, const 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)
template <>
struct Extern<math::Float3> {
struct OZZ_BASE_DLL Extern<math::Float3> {
static void Save(OArchive& _archive, const 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)
template <>
struct Extern<math::Float4> {
struct OZZ_BASE_DLL Extern<math::Float4> {
static void Save(OArchive& _archive, const 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)
template <>
struct Extern<math::Quaternion> {
struct OZZ_BASE_DLL Extern<math::Quaternion> {
static void Save(OArchive& _archive, const 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)
template <>
struct Extern<math::Transform> {
struct OZZ_BASE_DLL Extern<math::Transform> {
static void Save(OArchive& _archive, const 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)
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 Load(IArchive& _archive, math::Box* _values, size_t _count,
uint32_t _version);
@ -98,7 +98,7 @@ struct Extern<math::Box> {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::RectFloat)
template <>
struct Extern<math::RectFloat> {
struct OZZ_BASE_DLL Extern<math::RectFloat> {
static void Save(OArchive& _archive, const 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)
template <>
struct Extern<math::RectInt> {
struct OZZ_BASE_DLL Extern<math::RectInt> {
static void Save(OArchive& _archive, const 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 math {
struct Quaternion {
struct OZZ_BASE_DLL Quaternion {
float x, y, z, w;
// Constructs an uninitialized quaternion.

View File

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

View File

@ -35,7 +35,7 @@ namespace ozz {
namespace math {
// Returns SIMDimplementation name has decided at library build time.
const char* SimdImplementationName();
OZZ_BASE_DLL const char* SimdImplementationName();
namespace simd_float4 {
// 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.
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
// SimdFloat4 of _out.
OZZ_INLINE void Transpose4x2(const SimdFloat4 _in[4], SimdFloat4 _out[2]);

View File

@ -36,7 +36,7 @@ namespace ozz {
namespace io {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SimdFloat4)
template <>
struct Extern<math::SimdFloat4> {
struct OZZ_BASE_DLL Extern<math::SimdFloat4> {
static void Save(OArchive& _archive, const 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)
template <>
struct Extern<math::SimdInt4> {
struct OZZ_BASE_DLL Extern<math::SimdInt4> {
static void Save(OArchive& _archive, const 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)
template <>
struct Extern<math::Float4x4> {
struct OZZ_BASE_DLL Extern<math::Float4x4> {
static void Save(OArchive& _archive, const 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 {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaFloat2)
template <>
struct Extern<math::SoaFloat2> {
struct OZZ_BASE_DLL Extern<math::SoaFloat2> {
static void Save(OArchive& _archive, const 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)
template <>
struct Extern<math::SoaFloat3> {
struct OZZ_BASE_DLL Extern<math::SoaFloat3> {
static void Save(OArchive& _archive, const 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)
template <>
struct Extern<math::SoaFloat4> {
struct OZZ_BASE_DLL Extern<math::SoaFloat4> {
static void Save(OArchive& _archive, const 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)
template <>
struct Extern<math::SoaQuaternion> {
struct OZZ_BASE_DLL Extern<math::SoaQuaternion> {
static void Save(OArchive& _archive, const math::SoaQuaternion* _values,
size_t _count);
static void Load(IArchive& _archive, math::SoaQuaternion* _values,
@ -79,7 +79,7 @@ struct Extern<math::SoaQuaternion> {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaFloat4x4)
template <>
struct Extern<math::SoaFloat4x4> {
struct OZZ_BASE_DLL Extern<math::SoaFloat4x4> {
static void Save(OArchive& _archive, const math::SoaFloat4x4* _values,
size_t _count);
static void Load(IArchive& _archive, math::SoaFloat4x4* _values,
@ -88,7 +88,7 @@ struct Extern<math::SoaFloat4x4> {
OZZ_IO_TYPE_NOT_VERSIONABLE(math::SoaTransform)
template <>
struct Extern<math::SoaTransform> {
struct OZZ_BASE_DLL Extern<math::SoaTransform> {
static void Save(OArchive& _archive, const math::SoaTransform* _values,
size_t _count);
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
// attributes.
struct Transform {
struct OZZ_BASE_DLL Transform {
// Translation affine transformation component.
Float3 translation;

View File

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

View File

@ -41,18 +41,18 @@ namespace memory {
class Allocator;
// 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.
// 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.
// Implements helper methods to allocate/deallocate POD typed objects instead of
// raw memory.
// Implements New and Delete function to allocate C++ objects, as a replacement
// of new and delete operators.
class Allocator {
class OZZ_BASE_DLL Allocator {
public:
// Default virtual destructor.
virtual ~Allocator() {}

View File

@ -41,8 +41,13 @@
#include <cassert>
#include <cstddef>
#include "ozz/base/export.h"
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.
#define OZZ_ARRAY_SIZE(_array) (sizeof(_array) / sizeof(_array[0]))
@ -80,7 +85,7 @@ namespace ozz {
// Case sensitive wildcard string matching:
// - a ? sign matches any character, except 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.
template <typename _Ty>

View File

@ -52,7 +52,8 @@ struct span {
span() : data_(nullptr), size_(0) {}
// 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.");
}
@ -84,6 +85,25 @@ struct span {
// Implement cast operator to allow conversions to span<const _Ty>.
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[.
_Ty& operator[](size_t _i) const {
assert(_i < size_ && "Index out of range.");
@ -135,35 +155,25 @@ inline span<const typename _Container::value_type> make_span(
// As bytes
template <typename _Ty>
inline span<const char> as_bytes(const span<_Ty>& _span) {
return {reinterpret_cast<const char*>(_span.data()), _span.size_bytes()};
inline span<const byte> as_bytes(const span<_Ty>& _span) {
return {reinterpret_cast<const byte*>(_span.data()), _span.size_bytes()};
}
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
// const data.
return {reinterpret_cast<char*>(_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;
return {reinterpret_cast<byte*>(_span.data()), _span.size_bytes()};
}
// Fills a typed span from a byte source span. Source byte span is modified to
// reflect remain size.
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.");
const span<_Ty> ret = {reinterpret_cast<_Ty*>(_src.data()), _count};
// 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;
}

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

View File

@ -5,16 +5,19 @@ add_custom_command(
"${CMAKE_CURRENT_LIST_DIR}/README.md"
"${ozz_media_directory}/bin/pab_skeleton.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"
"${CMAKE_CURRENT_BINARY_DIR}/media/skeleton.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 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_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)
add_executable(sample_additive
@ -22,10 +25,11 @@ add_executable(sample_additive
"${CMAKE_CURRENT_BINARY_DIR}/README.md"
"${CMAKE_CURRENT_BINARY_DIR}/media/skeleton.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
sample_framework)
target_copy_shared_libraries(sample_additive)
set_target_properties(sample_additive
PROPERTIES FOLDER "samples")
@ -46,10 +50,12 @@ else()
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_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>)
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>)
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)
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
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.
In this sample, a "cracking head" animation is added to a "walk" cycle. Note that no synchronization is required between the two animations.
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.
## 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.
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.
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.
## Sample usage
The sample proposes to modify main and additive layers weights:
- 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.
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.
## Implementation
1. Loads main, additive 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.
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.
1. Loads base, additive (curl and splay) animations, and their skeleton. See "playback" sample for more details.
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. 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.
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/base/containers/vector.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"
@ -56,68 +57,65 @@ OZZ_OPTIONS_DECLARE_STRING(animation,
// Additive animation archive can be specified as an option.
OZZ_OPTIONS_DECLARE_STRING(
additive_animation, "Path to the additive animation (ozz archive format).",
"media/animation_additive.ozz", false)
splay_animation,
"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 {
public:
AdditiveBlendSampleApplication()
: upper_body_root_(0),
upper_body_mask_enable_(true),
upper_body_joint_weight_setting_(1.f),
threshold_(ozz::animation::BlendingJob().threshold) {}
: base_weight_(0.f),
additive_weigths_{.3f, .9f},
auto_animate_weights_(true) {}
protected:
// Updates current animation time and skeleton pose.
virtual bool OnUpdate(float _dt, float) {
// Updates and samples both animations to their respective local space
// transform buffers.
for (int i = 0; i < kNumLayers; ++i) {
Sampler& sampler = samplers_[i];
// Updates animations time.
sampler.controller.Update(sampler.animation, _dt);
// Setup sampling job.
ozz::animation::SamplingJob sampling_job;
sampling_job.animation = &sampler.animation;
sampling_job.cache = &sampler.cache;
sampling_job.ratio = sampler.controller.time_ratio();
sampling_job.output = make_span(sampler.locals);
// Samples animation.
if (!sampling_job.Run()) {
return false;
}
// For the sample purpose, animates additive weights automatically so the
// hand moves.
if (auto_animate_weights_) {
AnimateWeights(_dt);
}
// Blends animations.
// 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_
// Updates base animation time for main animation.
controller_.Update(base_animation_, _dt);
// Prepares standard blending layers.
// Setup sampling job.
ozz::animation::SamplingJob sampling_job;
sampling_job.animation = &base_animation_;
sampling_job.context = &context_;
sampling_job.ratio = controller_.time_ratio();
sampling_job.output = make_span(locals_);
// Samples animation.
if (!sampling_job.Run()) {
return false;
}
// Setups blending job layers.
// Main animation is used as-is.
ozz::animation::BlendingJob::Layer layers[1];
layers[0].transform = make_span(samplers_[kMainAnimation].locals);
layers[0].weight = samplers_[kMainAnimation].weight_setting;
layers[0].transform = make_span(locals_);
layers[0].weight = base_weight_;
layers[0].joint_weights = make_span(base_joint_weights_);
// Prepares additive blending layers.
ozz::animation::BlendingJob::Layer additive_layers[1];
additive_layers[0].transform =
make_span(samplers_[kAdditiveAnimation].locals);
additive_layers[0].weight = samplers_[kAdditiveAnimation].weight_setting;
// 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_);
// The two additive layers (curl and splay) are blended on top of the main
// layer.
ozz::animation::BlendingJob::Layer additive_layers[kNumLayers];
for (size_t i = 0; i < kNumLayers; ++i) {
additive_layers[i].transform = make_span(additive_locals_[i]);
additive_layers[i].weight = additive_weigths_[i];
}
// Setups blending job.
ozz::animation::BlendingJob blend_job;
blend_job.threshold = threshold_;
blend_job.layers = 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_);
// Blends.
@ -141,12 +139,34 @@ class AdditiveBlendSampleApplication : public ozz::sample::Application {
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.
virtual bool OnDisplay(ozz::sample::Renderer* _renderer) {
return _renderer->DrawPosture(skeleton_, make_span(models_),
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() {
// Reading 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_joints = skeleton_.num_joints();
// Reading animations.
const char* filenames[] = {OPTIONS_animation, OPTIONS_additive_animation};
for (int i = 0; i < kNumLayers; ++i) {
Sampler& sampler = samplers_[i];
if (!ozz::sample::LoadAnimation(filenames[i], &sampler.animation)) {
return false;
}
// Allocates sampler runtime buffers.
sampler.locals.resize(num_soa_joints);
// Allocates a cache that matches animation requirements.
sampler.cache.Resize(num_joints);
// Reads base animation.
if (!ozz::sample::LoadAnimation(OPTIONS_animation, &base_animation_)) {
return false;
}
// Default weight settings.
samplers_[kMainAnimation].weight_setting = 1.f;
if (num_joints != base_animation_.num_tracks()) {
return false;
}
upper_body_joint_weight_setting_ = 1.f;
samplers_[kAdditiveAnimation].weight_setting = 1.f;
// Allocates sampling context.
context_.Resize(num_joints);
// Allocates local space runtime buffers of blended data.
blended_locals_.resize(num_soa_joints);
// Allocates local space runtime buffers for base animation.
locals_.resize(num_soa_joints);
// Allocates model space runtime buffers of blended data.
models_.resize(num_joints);
// Allocates per-joint weights used for the partial additive animation.
// Note that this is a Soa structure.
upper_body_joint_weights_.resize(num_soa_joints);
// Storage for blending stage output.
blended_locals_.resize(num_soa_joints);
// Finds the "Spine1" joint in the joint hierarchy.
for (int i = 0; i < num_joints; ++i) {
if (std::strstr(skeleton_.joint_names()[i], "Spine1")) {
upper_body_root_ = i;
break;
// Allocates and sets base animation mask weights to one.
base_joint_weights_.resize(num_soa_joints, ozz::math::simd_float4::one());
SetJointWeights("Lefthand", 0.f);
SetJointWeights("RightHand", 0.f);
// 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;
}
// 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 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);
if (open) {
_im_gui->DoLabel("Main layer:");
std::sprintf(label, "Layer weight: %.2f",
samplers_[kMainAnimation].weight_setting);
_im_gui->DoSlider(label, 0.f, 1.f,
&samplers_[kMainAnimation].weight_setting, 1.f);
std::sprintf(label, "Layer weight: %.2f", base_weight_);
_im_gui->DoSlider(label, 0.f, 1.f, &base_weight_, 1.f);
_im_gui->DoLabel("Additive layer:");
std::sprintf(label, "Layer weight: %.2f",
samplers_[kAdditiveAnimation].weight_setting);
_im_gui->DoSlider(label, -1.f, 1.f,
&samplers_[kAdditiveAnimation].weight_setting, 1.f);
_im_gui->DoLabel("Global settings:");
std::sprintf(label, "Threshold: %.2f", threshold_);
_im_gui->DoSlider(label, .01f, 1.f, &threshold_);
}
}
// 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);
_im_gui->DoCheckBox("Animates weights", &auto_animate_weights_);
ozz::array<float, OZZ_ARRAY_SIZE(additive_weigths_)> weights;
std::memcpy(weights.data(), additive_weigths_,
sizeof(additive_weigths_));
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.
if (rebuild_joint_weights) {
SetupPerJointWeights();
std::sprintf(label, "Weights\nCurl: %.2f\nSplay: %.2f",
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 animations runtime playback controls.
// Exposes base animation runtime playback controls.
{
static bool oc_open = true;
ozz::sample::ImGui::OpenClose oc(_im_gui, "Animation control", &oc_open);
if (oc_open) {
static bool open[kNumLayers] = {true, true};
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);
}
}
controller_.OnGui(base_animation_, _im_gui);
}
}
@ -311,62 +282,55 @@ class AdditiveBlendSampleApplication : public ozz::sample::Application {
}
virtual void GetSceneBounds(ozz::math::Box* _bound) const {
ozz::sample::ComputePostureBounds(make_span(models_), _bound);
// 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);
}
}
private:
// Runtime skeleton.
ozz::animation::Skeleton skeleton_;
// The number of layers to blend.
enum {
kMainAnimation = 0,
kAdditiveAnimation = 1,
kNumLayers = 2,
};
// The number of additive layers to blend.
enum { kSplay, kCurl, kNumLayers };
// Sampler structure contains all the data required to sample a single
// animation.
struct Sampler {
// Constructor, default initialization.
Sampler() : weight_setting(1.f) {}
// Runtime animation.
ozz::animation::Animation base_animation_;
// Playback animation controller. This is a utility class that helps with
// controlling animation playback time.
ozz::sample::PlaybackController controller;
// Per-joint weights used to define the base animation mask. Allows to remove
// hands from base animations.
ozz::vector<ozz::math::SimdFloat4> base_joint_weights_;
// Blending weight_setting for the layer.
float weight_setting;
// Main animation controller. This is a utility class that helps with
// controlling animation playback time.
ozz::sample::PlaybackController controller_;
// Runtime animation.
ozz::animation::Animation animation;
// Sampling context.
ozz::animation::SamplingJob::Context context_;
// Sampling cache.
ozz::animation::SamplingCache cache;
// Buffer of local transforms as sampled from main animation_.
ozz::vector<ozz::math::SoaTransform> locals_;
// Buffer of local transforms as sampled from animation_.
ozz::vector<ozz::math::SoaTransform> locals;
// Blending weight of the base animation layer.
float base_weight_;
} samplers_[kNumLayers]; // kNumLayers animations to blend.
// Poses of local transforms as sampled from curl and splay animations.
// They are sampled during initialization, as a single pose is used.
ozz::vector<ozz::math::SoaTransform> additive_locals_[kNumLayers];
// Index of the joint at the base of the upper body hierarchy.
int upper_body_root_;
// Enables upper boddy per-joint weights.
bool upper_body_mask_enable_;
// Blending weight_setting setting of the joints of this layer that are
// affected
// by the masking.
float upper_body_joint_weight_setting_;
// Per-joint weights used to define the partial animation mask. Allows to
// select which joints are considered during blending, and their individual
// weight_setting.
ozz::vector<ozz::math::SimdFloat4> upper_body_joint_weights_;
// Blending job bind pose threshold.
float threshold_;
// Blending weight of the additive animation layer.
float additive_weigths_[kNumLayers];
// Buffer of local transforms which stores the blending result.
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
// job after the blending stage.
ozz::vector<ozz::math::Float4x4> models_;
};
// Automatically animates additive weights.
bool auto_animate_weights_;
};
int main(int _argc, const char** _argv) {
const char* title = "Ozz-animation sample: Additive animations blending";

View File

@ -21,7 +21,7 @@ add_executable(sample_attach
target_link_libraries(sample_attach
sample_framework)
target_copy_shared_libraries(sample_attach)
set_target_properties(sample_attach
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/imgui.h"
#include "framework/renderer.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.
OZZ_OPTIONS_DECLARE_STRING(skeleton,
@ -67,7 +64,7 @@ class AttachSampleApplication : public ozz::sample::Application {
// Samples optimized animation at t = animation_time_.
ozz::animation::SamplingJob sampling_job;
sampling_job.animation = &animation_;
sampling_job.cache = &cache_;
sampling_job.context = &context_;
sampling_job.ratio = controller_.time_ratio();
sampling_job.output = make_span(locals_);
if (!sampling_job.Run()) {
@ -133,15 +130,13 @@ class AttachSampleApplication : public ozz::sample::Application {
locals_.resize(num_soa_joints);
models_.resize(num_joints);
// Allocates a cache that matches animation requirements.
cache_.Resize(num_joints);
// Allocates a context that matches animation requirements.
context_.Resize(num_joints);
// Finds the joint where the object should be attached.
for (int i = 0; i < num_joints; i++) {
if (std::strstr(skeleton_.joint_names()[i], "LeftHandMiddle")) {
attachment_ = i;
break;
}
attachment_ = FindJoint(skeleton_, "LeftHandMiddle1");
if (attachment_ < 0) {
return false;
}
return true;
@ -198,8 +193,8 @@ class AttachSampleApplication : public ozz::sample::Application {
// Runtime animation.
ozz::animation::Animation animation_;
// Sampling cache.
ozz::animation::SamplingCache cache_;
// Sampling context.
ozz::animation::SamplingJob::Context context_;
// Buffer of local transforms as sampled from animation_.
ozz::vector<ozz::math::SoaTransform> locals_;

View File

@ -23,6 +23,7 @@ add_executable(sample_baked
target_link_libraries(sample_baked
sample_framework)
target_copy_shared_libraries(sample_baked)
set_target_properties(sample_baked
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/imgui.h"
#include "framework/renderer.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.
OZZ_OPTIONS_DECLARE_STRING(skeleton,
@ -67,7 +63,7 @@ class BakedSampleApplication : public ozz::sample::Application {
// Samples optimized animation at t = animation_time_.
ozz::animation::SamplingJob sampling_job;
sampling_job.animation = &animation_;
sampling_job.cache = &cache_;
sampling_job.context = &context_;
sampling_job.ratio = controller_.time_ratio();
sampling_job.output = make_span(locals_);
if (!sampling_job.Run()) {
@ -103,8 +99,8 @@ class BakedSampleApplication : public ozz::sample::Application {
locals_.resize(num_soa_joints);
models_.resize(num_joints);
// Allocates a cache that matches animation requirements.
cache_.Resize(num_joints);
// Allocates a context that matches animation requirements.
context_.Resize(num_joints);
// Look for a "camera" joint.
for (int i = 0; i < num_joints; i++) {
@ -167,8 +163,8 @@ class BakedSampleApplication : public ozz::sample::Application {
// Runtime animation.
ozz::animation::Animation animation_;
// Sampling cache.
ozz::animation::SamplingCache cache_;
// Sampling context.
ozz::animation::SamplingJob::Context context_;
// Buffer of local transforms as sampled from animation_.
ozz::vector<ozz::math::SoaTransform> locals_;

View File

@ -31,6 +31,7 @@ add_executable(sample_blend
target_link_libraries(sample_blend
sample_framework)
target_copy_shared_libraries(sample_blend)
set_target_properties(sample_blend
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.
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.
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/blending_job.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/math_ex.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/imgui.h"
#include "framework/renderer.h"
#include "framework/utils.h"
// Skeleton archive can be specified as an option.
OZZ_OPTIONS_DECLARE_STRING(skeleton,
"Path to the skeleton (ozz archive format).",
@ -97,7 +93,7 @@ class BlendSampleApplication : public ozz::sample::Application {
// Setup sampling job.
ozz::animation::SamplingJob sampling_job;
sampling_job.animation = &sampler.animation;
sampling_job.cache = &sampler.cache;
sampling_job.context = &sampler.context;
sampling_job.ratio = sampler.controller.time_ratio();
sampling_job.output = make_span(sampler.locals);
@ -123,7 +119,7 @@ class BlendSampleApplication : public ozz::sample::Application {
ozz::animation::BlendingJob blend_job;
blend_job.threshold = threshold_;
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_);
// Blends.
@ -216,8 +212,8 @@ class BlendSampleApplication : public ozz::sample::Application {
// Allocates sampler runtime buffers.
sampler.locals.resize(num_soa_joints);
// Allocates a cache that matches animation requirements.
sampler.cache.Resize(num_joints);
// Allocates a context that matches animation requirements.
sampler.context.Resize(num_joints);
}
// Allocates local space runtime buffers of blended data.
@ -319,14 +315,14 @@ class BlendSampleApplication : public ozz::sample::Application {
// Runtime animation.
ozz::animation::Animation animation;
// Sampling cache.
ozz::animation::SamplingCache cache;
// Sampling context.
ozz::animation::SamplingJob::Context context;
// Buffer of local transforms as sampled from animation_.
ozz::vector<ozz::math::SoaTransform> locals;
} samplers_[kNumLayers]; // kNumLayers animations to blend.
// Blending job bind pose threshold.
// Blending job rest pose threshold.
float threshold_;
// 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")
target_link_libraries(sample_foot_ik
sample_framework)
target_copy_shared_libraries(sample_foot_ik)
set_target_properties(sample_foot_ik
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/ik_aim_job.h"
#include "ozz/animation/runtime/ik_two_bone_job.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/math_ex.h"
#include "ozz/base/maths/simd_math.h"
#include "ozz/base/maths/simd_quaternion.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/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.
OZZ_OPTIONS_DECLARE_STRING(skeleton,
"Path to the skeleton (ozz archive format).",
@ -107,7 +101,7 @@ class FootIKSampleApplication : public ozz::sample::Application {
FootIKSampleApplication()
: pelvis_offset_(0.f, 0.f, 0.f),
root_translation_(2.17f, 2.f, -2.06f),
root_yaw_(2.f),
root_yaw_(-2.f),
foot_heigh_(.12f),
weight_(1.f),
soften_(1.f),
@ -186,7 +180,7 @@ class FootIKSampleApplication : public ozz::sample::Application {
// Samples optimized animation at t = animation_time.
ozz::animation::SamplingJob sampling_job;
sampling_job.animation = &animation_;
sampling_job.cache = &cache_;
sampling_job.context = &context_;
sampling_job.ratio = controller_.time_ratio();
sampling_job.output = make_span(locals_);
if (!sampling_job.Run()) {
@ -481,8 +475,8 @@ class FootIKSampleApplication : public ozz::sample::Application {
}
} else {
// Renders skeleton only.
success &= _renderer->DrawPosture(skeleton_, make_span(models_),
offsetted_root);
success &=
_renderer->DrawPosture(skeleton_, make_span(models_), offsetted_root);
}
// Showing joints
@ -557,8 +551,8 @@ class FootIKSampleApplication : public ozz::sample::Application {
const int num_joints = skeleton_.num_joints();
models_.resize(num_joints);
// Allocates a cache that matches animation requirements.
cache_.Resize(num_joints);
// Allocates a context that matches animation requirements.
context_.Resize(num_joints);
// Finds left and right joints.
if (!SetupLeg(skeleton_, kLeftJointNames, &legs_setup_[kLeft]) ||
@ -597,7 +591,7 @@ class FootIKSampleApplication : public ozz::sample::Application {
bool SetupLeg(const ozz::animation::Skeleton& _skeleton,
const char* _joint_names[3], LegSetup* _leg) {
int found = 0;
int joints[3] = {0, 0, 0};
int joints[3] = {0};
for (int i = 0; i < _skeleton.num_joints() && found != 3; i++) {
const char* joint_name = _skeleton.joint_names()[i];
if (std::strcmp(joint_name, _joint_names[found]) == 0) {
@ -742,8 +736,8 @@ class FootIKSampleApplication : public ozz::sample::Application {
// Runtime animation.
ozz::animation::Animation animation_;
// Sampling cache.
ozz::animation::SamplingCache cache_;
// Sampling context.
ozz::animation::SamplingJob::Context context_;
// Buffer of local transforms as sampled from animation_.
ozz::vector<ozz::math::SoaTransform> locals_;
@ -752,7 +746,7 @@ class FootIKSampleApplication : public ozz::sample::Application {
ozz::vector<ozz::math::Float4x4> models_;
// 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_;
// The mesh used by the sample.

View File

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

View File

@ -476,6 +476,12 @@ bool Application::Gui() {
// Downcast to public imgui.
ImGui* im_gui = im_gui_.get();
// Do floating gui.
if (!show_help_) {
success = OnFloatingGui(im_gui);
}
// Help gui.
{
math::RectFloat rect(kGuiMargin, kGuiMargin,
@ -658,6 +664,31 @@ bool Application::FrameworkGui() {
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,
math::Float2* _angles,
float* _distance) const {
@ -674,6 +705,23 @@ bool Application::GetCameraOverride(math::Float4x4* _transform) const {
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) {
// Stores new resolution settings.
application_->resolution_.width = _width;

View File

@ -29,6 +29,7 @@
#define OZZ_SAMPLES_FRAMEWORK_APPLICATION_H_
#include <cstddef>
#include "ozz/base/containers/string.h"
#include "ozz/base/memory/unique_ptr.h"
@ -78,36 +79,47 @@ class Application {
int Run(int _argc, const char** _argv, const char* _version,
const char* _title);
protected:
// Allows application to convert from world space to screen coordinates.
math::Float2 WorldToScreen(const math::Float3& _world) const;
private:
// Provides initialization event to the inheriting application. Called while
// the help screen is being displayed.
// 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
// any case.
virtual bool OnInitialize() = 0;
virtual bool OnInitialize();
// Provides de-initialization event to the inheriting application.
// 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.
// _dt is the elapsed time (in seconds) since the last update.
// _time is application time including scaling (aka accumulated _dt).
// 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.
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.
// 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
// 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.
// 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
// 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
// true;
@ -125,7 +137,7 @@ class Application {
// the camera to frame all the scene.
// This function is never called before a first OnUpdate.
// 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.
bool Loop();

View File

@ -28,12 +28,14 @@
#ifndef OZZ_SAMPLES_FRAMEWORK_IMGUI_H_
#define OZZ_SAMPLES_FRAMEWORK_IMGUI_H_
#include <ozz/base/containers/array.h>
#include <cstdio>
namespace ozz {
namespace math {
struct RectFloat;
}
} // namespace math
namespace sample {
// 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.
// 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.
// Providing a non nullptr _title argument displays a title on top of the form.
// Providing a non nullptr _open argument enables the open/close mechanism.
// Providing a non nullptr _title argument displays a title on top of the
// form. Providing a non nullptr _open argument enables the open/close
// mechanism.
class Form {
public:
Form(ImGui* _im_gui, const char* _title, const math::RectFloat& _rect,
@ -115,6 +118,11 @@ class ImGui {
float* _value, float _pow = 1.f,
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
// was modified.
// _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.
// Providing a non nullptr _title argument displays a title on top of the
// container.
// Providing a nullptr _rect argument means that the container will use all its
// parent size.
// Providing a non nullptr _open argument enables the open/close mechanism.
// Providing a nullptr _rect argument means that the container will use all
// its parent size. Providing a non nullptr _open argument enables the
// open/close mechanism.
virtual void BeginContainer(const char* _title, const math::RectFloat* _rect,
bool* _open, bool _constrain) = 0;

View File

@ -34,11 +34,11 @@
#include <cstdio>
#include <cstring>
#include "immediate.h"
#include "ozz/base/maths/math_constant.h"
#include "ozz/base/maths/math_ex.h"
#include "ozz/base/maths/vec_float.h"
#include "ozz/base/memory/allocator.h"
#include "immediate.h"
#include "renderer_impl.h"
namespace ozz {
@ -211,6 +211,11 @@ bool ImGuiImpl::AddWidget(float _height, math::RectFloat* _rect) {
// Get current container.
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.
// But don't modify current container's state.
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,
float* _value, float _pow, bool _enabled) {
math::RectFloat rect;
@ -751,7 +783,6 @@ bool ImGuiImpl::DoSlider(const char* _label, float _min, float _max,
// Calculate mouse cursor's relative y offset.
const float initial_value = *_value;
const float clamped_value = ozz::math::Clamp(_min, initial_value, _max);
// Check for hotness.
bool hot = false, active = false;
@ -795,24 +826,100 @@ bool ImGuiImpl::DoSlider(const char* _label, float _min, float _max,
}
// Update widget value.
const float pow_min = powf(_min, _pow);
const float pow_max = powf(_max, _pow);
float pow_value = powf(clamped_value, _pow);
float cursor;
*_value =
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) {
// 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) {
int mousepos = inputs_.mouse_x - static_cast<int>(rect.left);
if (mousepos < 0) {
mousepos = 0;
}
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);
// Button is both 'hot' and 'active'.
slider_color = kWidgetActiveBackgroundColor;
slider_border_color = kWidgetActiveBorderColor;
} else {
// Clamping is only applied if the widget is enabled.
*_value = clamped_value;
// Button is merely 'hot'.
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.
@ -822,14 +929,24 @@ bool ImGuiImpl::DoSlider(const char* _label, float _min, float _max,
StrokeRect(rail_rect, kSliderRoundRectRadius, border_color);
// Finds cursor position and rect.
const float cursor =
floorf((rect.width * (pow_value - pow_min)) / (pow_max - pow_min));
const math::RectFloat cursor_rect(
rect.left + cursor - kWidgetCursorWidth / 2.f, rect.bottom - 1.f,
kWidgetCursorWidth, rect.height + 2.f);
rect.left + cursor[0] - kWidgetHeight / 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);
StrokeRect(cursor_rect, kSliderRoundRectRadius, slider_border_color);
// Text
const math::RectFloat text_rect(
rail_rect.left + kSliderRoundRectRadius, rail_rect.bottom,
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);
break;
}
default: { break; }
default: {
break;
}
}
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);
break;
}
default: { break; }
default: {
break;
}
}
// 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.
#include "framework/imgui.h"
#include "ozz/base/containers/vector.h"
#include "ozz/base/maths/rect.h"
#include "renderer_impl.h"
namespace ozz {
@ -90,6 +88,10 @@ class ImGuiImpl : public ImGui {
virtual bool DoSlider(const char* _label, float _min, float _max,
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,
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;
}
@ -239,7 +245,7 @@ bool RendererImpl::DrawGrid(int _cell_count, float _cell_size) {
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,
const ozz::math::Float4x4& _transform,
bool _draw_joints) {
@ -253,9 +259,9 @@ bool RendererImpl::DrawSkeleton(const ozz::animation::Skeleton& _skeleton,
// Reallocate matrix array if necessary.
prealloc_models_.resize(num_joints);
// Compute model space bind pose.
// Compute model space rest pose.
ozz::animation::LocalToModelJob job;
job.input = _skeleton.joint_bind_poses();
job.input = _skeleton.joint_rest_poses();
job.output = make_span(prealloc_models_);
job.skeleton = &_skeleton;
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
// and current matrix.
float* uniform = _uniforms + instances * 16;
math::StorePtr(parent.cols[0], uniform + 0);
math::StorePtr(parent.cols[1], uniform + 4);
math::StorePtr(parent.cols[2], uniform + 8);
math::StorePtr(parent.cols[3], uniform + 12);
std::memcpy(uniform, parent.cols, 16 * sizeof(float));
// Set bone direction (bone_dir). The shader expects to find it at index
// [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.
if (IsLeaf(_skeleton, i)) {
// Copy current joint's raw matrix.
uniform = _uniforms + instances * 16;
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);
std::memcpy(uniform, current.cols, 16 * sizeof(float));
// 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.
@ -621,6 +620,84 @@ bool RendererImpl::DrawPosture(const ozz::animation::Skeleton& _skeleton,
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,
const ozz::math::Float4x4& _transform,
const Color _colors[2]) {
@ -1218,49 +1295,70 @@ bool RendererImpl::DrawMesh(const Mesh& _mesh,
vertex_offset += part_vertex_count;
}
// Binds shader with this array buffer, depending on rendering options.
Shader* shader = nullptr;
if (_options.texture) {
ambient_textured_shader->Bind(_transform, camera()->view_proj(),
positions_stride, positions_offset,
normals_stride, normals_offset, colors_stride,
colors_offset, uvs_stride, uvs_offset);
shader = ambient_textured_shader.get();
if (_options.triangles) {
// Binds shader with this array buffer, depending on rendering options.
Shader* shader = nullptr;
if (_options.texture) {
ambient_textured_shader->Bind(
_transform, camera()->view_proj(), positions_stride, positions_offset,
normals_stride, normals_offset, colors_stride, colors_offset,
uvs_stride, uvs_offset);
shader = ambient_textured_shader.get();
// Binds default texture
GL(BindTexture(GL_TEXTURE_2D, checkered_texture_));
} else {
ambient_shader->Bind(_transform, camera()->view_proj(), positions_stride,
positions_offset, normals_stride, normals_offset,
colors_stride, colors_offset);
shader = ambient_shader.get();
// Binds default texture
GL(BindTexture(GL_TEXTURE_2D, checkered_texture_));
} else {
ambient_shader->Bind(_transform, camera()->view_proj(), positions_stride,
positions_offset, normals_stride, normals_offset,
colors_stride, colors_offset);
shader = ambient_shader.get();
}
// Maps the index dynamic buffer and update it.
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, dynamic_index_bo_));
const Mesh::TriangleIndices& indices = _mesh.triangle_indices;
GL(BufferData(GL_ELEMENT_ARRAY_BUFFER,
indices.size() * sizeof(Mesh::TriangleIndices::value_type),
array_begin(indices), GL_STREAM_DRAW));
// Draws the mesh.
static_assert(sizeof(Mesh::TriangleIndices::value_type) == 2,
"Expects 2 bytes indices.");
GL(DrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()),
GL_UNSIGNED_SHORT, 0));
// Unbinds.
GL(BindBuffer(GL_ARRAY_BUFFER, 0));
GL(BindTexture(GL_TEXTURE_2D, 0));
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
shader->Unbind();
}
// Maps the index dynamic buffer and update it.
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, dynamic_index_bo_));
const Mesh::TriangleIndices& indices = _mesh.triangle_indices;
GL(BufferData(GL_ELEMENT_ARRAY_BUFFER,
indices.size() * sizeof(Mesh::TriangleIndices::value_type),
array_begin(indices), GL_STREAM_DRAW));
// Draws the mesh.
static_assert(sizeof(Mesh::TriangleIndices::value_type) == 2,
"Expects 2 bytes indices.");
GL(DrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()),
GL_UNSIGNED_SHORT, 0));
// Unbinds.
GL(BindBuffer(GL_ARRAY_BUFFER, 0));
GL(BindTexture(GL_TEXTURE_2D, 0));
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
shader->Unbind();
if (_options.wireframe) {
#ifndef EMSCRIPTEN
GL(PolygonMode(GL_FRONT_AND_BACK, GL_FILL));
#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.
if (_options.normals) {
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 ozz::math::Float4x4& _transform, const Options& _options) {
// Forward to DrawMesh function is skinning is disabled.
if (_options.skip_skinning) {
if (_options.skip_skinning || !_mesh.skinned()) {
return DrawMesh(_mesh, _transform, _options);
}
@ -1327,13 +1425,16 @@ bool RendererImpl::DrawSkinnedMesh(
// Positions and normals are interleaved to improve caching while executing
// skinning job.
const GLsizei positions_offset = 0;
const GLsizei normals_offset = sizeof(float) * 3;
const GLsizei tangents_offset = sizeof(float) * 6;
const GLsizei positions_stride = sizeof(float) * 9;
const GLsizei normals_stride = positions_stride;
const GLsizei tangents_stride = positions_stride;
const GLsizei skinned_data_size = vertex_count * positions_stride;
const GLsizei positions_stride = sizeof(float) * 3;
const GLsizei normals_offset = vertex_count * positions_stride;
const GLsizei normals_stride = sizeof(float) * 3;
const GLsizei tangents_offset =
normals_offset + vertex_count * normals_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
// directly copied from source mesh which is non-interleaved as-well.
@ -1542,54 +1643,76 @@ bool RendererImpl::DrawSkinnedMesh(
processed_vertex_count += part_vertex_count;
}
// Updates dynamic vertex buffer with skinned data.
GL(BindBuffer(GL_ARRAY_BUFFER, dynamic_array_bo_));
GL(BufferData(GL_ARRAY_BUFFER, vbo_size, nullptr, GL_STREAM_DRAW));
GL(BufferSubData(GL_ARRAY_BUFFER, 0, vbo_size, vbo_map));
if (_options.triangles) {
// Updates dynamic vertex buffer with skinned data.
GL(BindBuffer(GL_ARRAY_BUFFER, dynamic_array_bo_));
GL(BufferData(GL_ARRAY_BUFFER, vbo_size, nullptr, GL_STREAM_DRAW));
GL(BufferSubData(GL_ARRAY_BUFFER, 0, vbo_size, vbo_map));
// Binds shader with this array buffer, depending on rendering options.
Shader* shader = nullptr;
if (_options.texture) {
ambient_textured_shader->Bind(_transform, camera()->view_proj(),
positions_stride, positions_offset,
normals_stride, normals_offset, colors_stride,
colors_offset, uvs_stride, uvs_offset);
shader = ambient_textured_shader.get();
// Binds shader with this array buffer, depending on rendering options.
Shader* shader = nullptr;
if (_options.texture) {
ambient_textured_shader->Bind(
_transform, camera()->view_proj(), positions_stride, positions_offset,
normals_stride, normals_offset, colors_stride, colors_offset,
uvs_stride, uvs_offset);
shader = ambient_textured_shader.get();
// Binds default texture
GL(BindTexture(GL_TEXTURE_2D, checkered_texture_));
} else {
ambient_shader->Bind(_transform, camera()->view_proj(), positions_stride,
positions_offset, normals_stride, normals_offset,
colors_stride, colors_offset);
shader = ambient_shader.get();
// Binds default texture
GL(BindTexture(GL_TEXTURE_2D, checkered_texture_));
} else {
ambient_shader->Bind(_transform, camera()->view_proj(), positions_stride,
positions_offset, normals_stride, normals_offset,
colors_stride, colors_offset);
shader = ambient_shader.get();
}
// Maps the index dynamic buffer and update it.
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, dynamic_index_bo_));
const Mesh::TriangleIndices& indices = _mesh.triangle_indices;
GL(BufferData(GL_ELEMENT_ARRAY_BUFFER,
indices.size() * sizeof(Mesh::TriangleIndices::value_type),
array_begin(indices), GL_STREAM_DRAW));
// Draws the mesh.
static_assert(sizeof(Mesh::TriangleIndices::value_type) == 2,
"Expects 2 bytes indices.");
GL(DrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()),
GL_UNSIGNED_SHORT, 0));
// Unbinds.
GL(BindBuffer(GL_ARRAY_BUFFER, 0));
GL(BindTexture(GL_TEXTURE_2D, 0));
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
shader->Unbind();
}
// Maps the index dynamic buffer and update it.
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, dynamic_index_bo_));
const Mesh::TriangleIndices& indices = _mesh.triangle_indices;
GL(BufferData(GL_ELEMENT_ARRAY_BUFFER,
indices.size() * sizeof(Mesh::TriangleIndices::value_type),
array_begin(indices), GL_STREAM_DRAW));
// Draws the mesh.
static_assert(sizeof(Mesh::TriangleIndices::value_type) == 2,
"Expects 2 bytes indices.");
GL(DrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()),
GL_UNSIGNED_SHORT, 0));
// Unbinds.
GL(BindBuffer(GL_ARRAY_BUFFER, 0));
GL(BindTexture(GL_TEXTURE_2D, 0));
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
shader->Unbind();
if (_options.wireframe) {
#ifndef EMSCRIPTEN
GL(PolygonMode(GL_FRONT_AND_BACK, GL_FILL));
#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;
}

View File

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

View File

@ -326,6 +326,91 @@ void ImmediatePTCShader::Bind(const math::Float4x4& _model,
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 {
const char* kPassUv =
"attribute vec2 a_uv;\n"

View File

@ -126,6 +126,29 @@ class ImmediatePTCShader : public Shader {
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 {
public:
SkeletonShader() {}

View File

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

View File

@ -79,7 +79,7 @@ class Renderer {
// has a size of _cell_size.
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,
const ozz::math::Float4x4& _transform,
bool _draw_joints = true) = 0;
@ -93,6 +93,17 @@ class Renderer {
const ozz::math::Float4x4& _transform,
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.
// The 2 slots of _colors array respectively defines color of the filled
// faces and color of the box outlines.
@ -116,16 +127,20 @@ class Renderer {
Color _color) = 0;
struct Options {
bool triangles; // Show triangles mesh.
bool texture; // Show texture (default checkered texture).
bool vertices; // Show vertices as points.
bool normals; // Show normals.
bool tangents; // Show tangents.
bool binormals; // Show binormals, computed from the normal and tangent.
bool colors; // Show vertex colors.
bool wireframe; // Show vertex colors.
bool wireframe; // Show vertex colors.
bool skip_skinning; // Show texture (default checkered texture).
Options()
: texture(false),
: triangles(true),
texture(false),
vertices(false),
normals(false),
tangents(false),
binormals(false),
@ -133,9 +148,12 @@ class Renderer {
wireframe(false),
skip_skinning(false) {}
Options(bool _texture, bool _normals, bool _tangents, bool _binormals,
bool _colors, bool _wireframe, bool _skip_skinning)
: texture(_texture),
Options(bool _triangles, bool _texture, bool _vertices, bool _normals,
bool _tangents, bool _binormals, bool _colors, bool _wireframe,
bool _skip_skinning)
: triangles(_triangles),
texture(_texture),
vertices(_vertices),
normals(_normals),
tangents(_tangents),
binormals(_binormals),

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