Basic Alembic support
All in all, this patch adds an Alembic importer, an Alembic exporter, and a new CacheFile data block which, for now, wraps around an Alembic archive. This data block is made available through a new modifier ("Mesh Sequence Cache") as well as a new constraint ("Transform Cache") to somewhat properly support respectively geometric and transformation data streaming from alembic caches. A more in-depth documentation is to be found on the wiki, as well as a guide to compile alembic: https://wiki.blender.org/index.php/ User:Kevindietrich/AlembicBasicIo. Many thanks to everyone involved in this little project, and huge shout out to "cgstrive" for the thorough testings with Maya, 3ds Max, Houdini and Realflow as well as @fjuhec, @jensverwiebe and @jasperge for the custom builds and compile fixes. Reviewers: sergey, campbellbarton, mont29 Reviewed By: sergey, campbellbarton, mont29 Differential Revision: https://developer.blender.org/D2060
This commit is contained in:
parent
4158737cb2
commit
61050f75b1
@ -323,6 +323,10 @@ option(WITH_CODEC_AVI "Enable Blenders own AVI file support (raw/jpeg)
|
||||
option(WITH_CODEC_FFMPEG "Enable FFMPeg Support (http://ffmpeg.org)" ${_init_CODEC_FFMPEG})
|
||||
option(WITH_CODEC_SNDFILE "Enable libsndfile Support (http://www.mega-nerd.com/libsndfile)" OFF)
|
||||
|
||||
# Alembic support
|
||||
option(WITH_ALEMBIC "Enable Alembic Support" OFF)
|
||||
option(WITH_ALEMBIC_HDF5 "Enable Legacy Alembic Support (not officially supported)" OFF)
|
||||
|
||||
if(APPLE)
|
||||
option(WITH_CODEC_QUICKTIME "Enable Quicktime Support" ON)
|
||||
endif()
|
||||
@ -720,6 +724,11 @@ if(WITH_OPENIMAGEIO)
|
||||
set(WITH_IMAGE_TIFF ON)
|
||||
endif()
|
||||
|
||||
# auto enable alembic linking dependencies
|
||||
if(WITH_ALEMBIC)
|
||||
set(WITH_IMAGE_OPENEXR ON)
|
||||
endif()
|
||||
|
||||
# don't store paths to libs for portable distribution
|
||||
if(WITH_INSTALL_PORTABLE)
|
||||
set(CMAKE_SKIP_BUILD_RPATH TRUE)
|
||||
@ -1091,6 +1100,21 @@ if(UNIX AND NOT APPLE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
set(ALEMBIC_ROOT_DIR ${LIBDIR}/alembic)
|
||||
find_package_wrapper(Alembic)
|
||||
|
||||
if(WITH_ALEMBIC_HDF5)
|
||||
set(HDF5_ROOT_DIR ${LIBDIR}/hdf5)
|
||||
find_package_wrapper(HDF5)
|
||||
endif()
|
||||
|
||||
if(NOT ALEMBIC_FOUND OR (WITH_ALEMBIC_HDF5 AND NOT HDF5_FOUND))
|
||||
set(WITH_ALEMBIC OFF)
|
||||
set(WITH_ALEMBIC_HDF5 OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_BOOST)
|
||||
# uses in build instructions to override include and library variables
|
||||
if(NOT BOOST_CUSTOM)
|
||||
@ -1660,6 +1684,21 @@ elseif(WIN32)
|
||||
set(OPENVDB_LIBPATH ${LIBDIR}/openvdb/lib)
|
||||
endif()
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
set(ALEMBIC_ROOT_DIR ${LIBDIR}/alembic)
|
||||
find_package(Alembic)
|
||||
|
||||
if(WITH_ALEMBIC_HDF5)
|
||||
set(HDF5_ROOT_DIR ${LIBDIR}/hdf5)
|
||||
find_package(HDF5)
|
||||
endif()
|
||||
|
||||
if(NOT ALEMBIC_FOUND OR (WITH_ALEMBIC_HDF5 AND NOT HDF5_FOUND))
|
||||
set(WITH_ALEMBIC OFF)
|
||||
set(WITH_ALEMBIC_HDF5 OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_MOD_CLOTH_ELTOPO)
|
||||
set(LAPACK ${LIBDIR}/lapack)
|
||||
# set(LAPACK_INCLUDE_DIR ${LAPACK}/include)
|
||||
@ -1959,6 +1998,21 @@ elseif(WIN32)
|
||||
set(OPENVDB_DEFINITIONS)
|
||||
endif()
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
set(ALEMBIC_ROOT_DIR ${LIBDIR}/alembic)
|
||||
find_package_wrapper(Alembic)
|
||||
|
||||
if(WITH_ALEMBIC_HDF5)
|
||||
set(HDF5_ROOT_DIR ${LIBDIR}/hdf5)
|
||||
find_package_wrapper(HDF5)
|
||||
endif()
|
||||
|
||||
if(NOT ALEMBIC_FOUND OR (WITH_ALEMBIC_HDF5 AND NOT HDF5_FOUND))
|
||||
set(WITH_ALEMBIC OFF)
|
||||
set(WITH_ALEMBIC_HDF5 OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(PLATFORM_LINKFLAGS "-Xlinker --stack=2097152")
|
||||
|
||||
## DISABLE - causes linking errors
|
||||
@ -2043,6 +2097,20 @@ elseif(APPLE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
set(ALEMBIC_ROOT_DIR ${LIBDIR}/alembic)
|
||||
find_package(Alembic)
|
||||
if(WITH_ALEMBIC_HDF5)
|
||||
set(HDF5_ROOT_DIR ${LIBDIR}/hdf5)
|
||||
find_package(HDF5)
|
||||
endif()
|
||||
|
||||
if(NOT ALEMBIC_FOUND OR (WITH_ALEMBIC_HDF5 AND NOT HDF5_FOUND))
|
||||
set(WITH_ALEMBIC OFF)
|
||||
set(WITH_ALEMBIC_HDF5 OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_OPENSUBDIV)
|
||||
set(OPENSUBDIV ${LIBDIR}/opensubdiv)
|
||||
set(OPENSUBDIV_LIBPATH ${OPENSUBDIV}/lib)
|
||||
@ -3215,6 +3283,7 @@ if(FIRST_RUN)
|
||||
info_cfg_option(WITH_FREESTYLE)
|
||||
info_cfg_option(WITH_OPENCOLORIO)
|
||||
info_cfg_option(WITH_OPENVDB)
|
||||
info_cfg_option(WITH_ALEMBIC)
|
||||
|
||||
info_cfg_text("Compiler Options:")
|
||||
info_cfg_option(WITH_BUILDINFO)
|
||||
|
@ -29,13 +29,13 @@ getopt \
|
||||
ver-ocio:,ver-oiio:,ver-llvm:,ver-osl:,ver-osd:,ver-openvdb:,\
|
||||
force-all,force-python,force-numpy,force-boost,\
|
||||
force-ocio,force-openexr,force-oiio,force-llvm,force-osl,force-osd,force-openvdb,\
|
||||
force-ffmpeg,force-opencollada,\
|
||||
force-ffmpeg,force-opencollada,force-alembic,\
|
||||
build-all,build-python,build-numpy,build-boost,\
|
||||
build-ocio,build-openexr,build-oiio,build-llvm,build-osl,build-osd,build-openvdb,\
|
||||
build-ffmpeg,build-opencollada,\
|
||||
build-ffmpeg,build-opencollada,build-alembic,\
|
||||
skip-python,skip-numpy,skip-boost,\
|
||||
skip-ocio,skip-openexr,skip-oiio,skip-llvm,skip-osl,skip-osd,skip-openvdb,\
|
||||
skip-ffmpeg,skip-opencollada \
|
||||
skip-ffmpeg,skip-opencollada,skip-alembic \
|
||||
-- "$@" \
|
||||
)
|
||||
|
||||
@ -167,6 +167,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
|
||||
--build-openvdb
|
||||
Force the build of OpenVDB.
|
||||
|
||||
--build-alembic
|
||||
Force the build of Alembic.
|
||||
|
||||
--build-opencollada
|
||||
Force the build of OpenCOLLADA.
|
||||
|
||||
@ -216,6 +219,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
|
||||
--force-openvdb
|
||||
Force the rebuild of OpenVDB.
|
||||
|
||||
--force-alembic
|
||||
Force the rebuild of Alembic.
|
||||
|
||||
--force-opencollada
|
||||
Force the rebuild of OpenCOLLADA.
|
||||
|
||||
@ -258,6 +264,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
|
||||
--skip-openvdb
|
||||
Unconditionally skip OpenVDB installation/building.
|
||||
|
||||
--skip-alembic
|
||||
Unconditionally skip Alembic installation/building.
|
||||
|
||||
--skip-opencollada
|
||||
Unconditionally skip OpenCOLLADA installation/building.
|
||||
|
||||
@ -343,6 +352,13 @@ OPENVDB_FORCE_BUILD=false
|
||||
OPENVDB_FORCE_REBUILD=false
|
||||
OPENVDB_SKIP=false
|
||||
|
||||
# Alembic needs to be compiled for now
|
||||
ALEMBIC_VERSION="1.6.0"
|
||||
ALEMBIC_VERSION_MIN=$ALEMBIC_VERSION
|
||||
ALEMBIC_FORCE_BUILD=false
|
||||
ALEMBIC_FORCE_REBUILD=false
|
||||
ALEMBIC_SKIP=false
|
||||
|
||||
# Version??
|
||||
OPENCOLLADA_VERSION="1.3"
|
||||
OPENCOLLADA_FORCE_BUILD=false
|
||||
@ -525,6 +541,7 @@ while true; do
|
||||
OPENVDB_FORCE_BUILD=true
|
||||
OPENCOLLADA_FORCE_BUILD=true
|
||||
FFMPEG_FORCE_BUILD=true
|
||||
ALEMBIC_FORCE_BUILD=true
|
||||
shift; continue
|
||||
;;
|
||||
--build-python)
|
||||
@ -567,6 +584,9 @@ while true; do
|
||||
--build-ffmpeg)
|
||||
FFMPEG_FORCE_BUILD=true; shift; continue
|
||||
;;
|
||||
--build-alembic)
|
||||
ALEMBIC_FORCE_BUILD=true; shift; continue
|
||||
;;
|
||||
--force-all)
|
||||
PYTHON_FORCE_REBUILD=true
|
||||
NUMPY_FORCE_REBUILD=true
|
||||
@ -580,6 +600,7 @@ while true; do
|
||||
OPENVDB_FORCE_REBUILD=true
|
||||
OPENCOLLADA_FORCE_REBUILD=true
|
||||
FFMPEG_FORCE_REBUILD=true
|
||||
ALEMBIC_FORCE_REBUILD=true
|
||||
shift; continue
|
||||
;;
|
||||
--force-python)
|
||||
@ -620,6 +641,9 @@ while true; do
|
||||
--force-ffmpeg)
|
||||
FFMPEG_FORCE_REBUILD=true; shift; continue
|
||||
;;
|
||||
--force-alembic)
|
||||
ALEMBIC_FORCE_REBUILD=true; shift; continue
|
||||
;;
|
||||
--skip-python)
|
||||
PYTHON_SKIP=true; shift; continue
|
||||
;;
|
||||
@ -656,6 +680,9 @@ while true; do
|
||||
--skip-ffmpeg)
|
||||
FFMPEG_SKIP=true; shift; continue
|
||||
;;
|
||||
--skip-alembic)
|
||||
ALEMBIC_SKIP=true; shift; continue
|
||||
;;
|
||||
--)
|
||||
# no more arguments to parse
|
||||
break
|
||||
@ -683,7 +710,7 @@ NUMPY_SOURCE=( "http://sourceforge.net/projects/numpy/files/NumPy/$NUMPY_VERSION
|
||||
|
||||
_boost_version_nodots=`echo "$BOOST_VERSION" | sed -r 's/\./_/g'`
|
||||
BOOST_SOURCE=( "http://sourceforge.net/projects/boost/files/boost/$BOOST_VERSION/boost_$_boost_version_nodots.tar.bz2/download" )
|
||||
BOOST_BUILD_MODULES="--with-system --with-filesystem --with-thread --with-regex --with-locale --with-date_time --with-wave --with-iostreams"
|
||||
BOOST_BUILD_MODULES="--with-system --with-filesystem --with-thread --with-regex --with-locale --with-date_time --with-wave --with-iostreams --with-python --with-program_options"
|
||||
|
||||
OCIO_SOURCE=( "https://github.com/imageworks/OpenColorIO/tarball/v$OCIO_VERSION" )
|
||||
|
||||
@ -727,6 +754,12 @@ OPENVDB_SOURCE=( "https://github.com/dreamworksanimation/openvdb/archive/v${OPEN
|
||||
#~ OPENVDB_SOURCE_REPO_UID="404659fffa659da075d1c9416e4fc939139a84ee"
|
||||
#~ OPENVDB_SOURCE_REPO_BRANCH="dev"
|
||||
|
||||
ALEMBIC_USE_REPO=false
|
||||
ALEMBIC_SOURCE=( "https://github.com/alembic/alembic/archive/${ALEMBIC_VERSION}.tar.gz" )
|
||||
# ALEMBIC_SOURCE_REPO=( "https://github.com/alembic/alembic.git" )
|
||||
# ALEMBIC_SOURCE_REPO_UID="e6c90d4faa32c4550adeaaf3f556dad4b73a92bb"
|
||||
# ALEMBIC_SOURCE_REPO_BRANCH="master"
|
||||
|
||||
OPENCOLLADA_SOURCE=( "https://github.com/KhronosGroup/OpenCOLLADA.git" )
|
||||
OPENCOLLADA_REPO_UID="3335ac164e68b2512a40914b14c74db260e6ff7d"
|
||||
OPENCOLLADA_REPO_BRANCH="master"
|
||||
@ -767,7 +800,8 @@ You may also want to build them yourself (optional ones are [between brackets]):
|
||||
* [OpenShadingLanguage $OSL_VERSION_MIN] (from $OSL_SOURCE_REPO, branch $OSL_SOURCE_REPO_BRANCH, commit $OSL_SOURCE_REPO_UID).
|
||||
* [OpenSubDiv $OSD_VERSION_MIN] (from $OSD_SOURCE_REPO, branch $OSD_SOURCE_REPO_BRANCH, commit $OSD_SOURCE_REPO_UID).
|
||||
* [OpenVDB $OPENVDB_VERSION_MIN] (from $OPENVDB_SOURCE), [Blosc $OPENVDB_BLOSC_VERSION] (from $OPENVDB_BLOSC_SOURCE).
|
||||
* [OpenCollada] (from $OPENCOLLADA_SOURCE, branch $OPENCOLLADA_REPO_BRANCH, commit $OPENCOLLADA_REPO_UID).\""
|
||||
* [OpenCollada] (from $OPENCOLLADA_SOURCE, branch $OPENCOLLADA_REPO_BRANCH, commit $OPENCOLLADA_REPO_UID).
|
||||
* [Alembic $ALEMBIC_VERSION] (from $ALEMBIC_SOURCE).\""
|
||||
|
||||
if [ "$DO_SHOW_DEPS" = true ]; then
|
||||
PRINT ""
|
||||
@ -1118,7 +1152,7 @@ compile_Boost() {
|
||||
fi
|
||||
|
||||
# To be changed each time we make edits that would modify the compiled result!
|
||||
boost_magic=10
|
||||
boost_magic=11
|
||||
|
||||
_init_boost
|
||||
|
||||
@ -2138,6 +2172,102 @@ compile_OPENVDB() {
|
||||
run_ldconfig "openvdb"
|
||||
}
|
||||
|
||||
#### Build Alembic ####
|
||||
_init_alembic() {
|
||||
_src=$SRC/alembic-$ALEMBIC_VERSION
|
||||
_git=false
|
||||
_inst=$INST/alembic-$ALEMBIC_VERSION
|
||||
_inst_shortcut=$INST/alembic
|
||||
}
|
||||
|
||||
clean_ALEMBIC() {
|
||||
_init_alembic
|
||||
_clean
|
||||
}
|
||||
|
||||
compile_ALEMBIC() {
|
||||
if [ "$NO_BUILD" = true ]; then
|
||||
WARNING "--no-build enabled, Alembic will not be compiled!"
|
||||
return
|
||||
fi
|
||||
|
||||
compile_HDF5
|
||||
PRINT ""
|
||||
|
||||
# To be changed each time we make edits that would modify the compiled result!
|
||||
alembic_magic=2
|
||||
_init_alembic
|
||||
|
||||
# Clean install if needed!
|
||||
magic_compile_check alembic-$ALEMBIC_VERSION $alembic_magic
|
||||
if [ $? -eq 1 -o "$ALEMBIC_FORCE_REBUILD" = true ]; then
|
||||
clean_ALEMBIC
|
||||
fi
|
||||
|
||||
if [ ! -d $_inst ]; then
|
||||
INFO "Building Alembic-$ALEMBIC_VERSION"
|
||||
|
||||
prepare_opt
|
||||
|
||||
if [ ! -d $_src -o true ]; then
|
||||
mkdir -p $SRC
|
||||
download ALEMBIC_SOURCE[@] "$_src.tar.gz"
|
||||
|
||||
INFO "Unpacking Alembic-$ALEMBIC_VERSION"
|
||||
tar -C $SRC -xf $_src.tar.gz
|
||||
fi
|
||||
|
||||
cd $_src
|
||||
|
||||
cmake_d="-D CMAKE_INSTALL_PREFIX=$_inst"
|
||||
|
||||
if [ -d $INST/boost ]; then
|
||||
cmake_d="$cmake_d -D BOOST_ROOT=$INST/boost"
|
||||
cmake_d="$cmake_d -D USE_STATIC_BOOST=ON"
|
||||
else
|
||||
cmake_d="$cmake_d -D USE_STATIC_BOOST=OFF"
|
||||
fi
|
||||
|
||||
if [ "$_with_built_openexr" = true ]; then
|
||||
cmake_d="$cmake_d -D ILMBASE_ROOT=$INST/openexr"
|
||||
cmake_d="$cmake_d -D USE_ARNOLD=OFF"
|
||||
cmake_d="$cmake_d -D USE_BINARIES=OFF"
|
||||
cmake_d="$cmake_d -D USE_EXAMPLES=OFF"
|
||||
cmake_d="$cmake_d -D USE_HDF5=OFF"
|
||||
cmake_d="$cmake_d -D USE_MAYA=OFF"
|
||||
cmake_d="$cmake_d -D USE_PRMAN=OFF"
|
||||
cmake_d="$cmake_d -D USE_PYALEMBIC=OFF"
|
||||
cmake_d="$cmake_d -D USE_STATIC_HDF5=OFF"
|
||||
cmake_d="$cmake_d -D ALEMBIC_ILMBASE_LINK_STATIC=OFF"
|
||||
cmake_d="$cmake_d -D ALEMBIC_SHARED_LIBS=OFF"
|
||||
cmake_d="$cmake_d -D ALEMBIC_LIB_USES_BOOST=ON"
|
||||
cmake_d="$cmake_d -D ALEMBIC_LIB_USES_TR1=OFF"
|
||||
INFO "ILMBASE_ROOT=$INST/openexr"
|
||||
fi
|
||||
|
||||
cmake $cmake_d ./
|
||||
make -j$THREADS install
|
||||
make clean
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
ERROR "Alembic-$ALEMBIC_VERSION failed to compile, exiting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
magic_compile_set alembic-$ALEMBIC_VERSION $alembic_magic
|
||||
|
||||
cd $CWD
|
||||
INFO "Done compiling Alembic-$ALEMBIC_VERSION!"
|
||||
else
|
||||
INFO "Own Alembic-$ALEMBIC_VERSION is up to date, nothing to do!"
|
||||
INFO "If you want to force rebuild of this lib, use the --force-alembic option."
|
||||
fi
|
||||
|
||||
run_ldconfig "alembic"
|
||||
}
|
||||
|
||||
#### Build OpenCOLLADA ####
|
||||
_init_opencollada() {
|
||||
_src=$SRC/OpenCOLLADA-$OPENCOLLADA_VERSION
|
||||
@ -2746,6 +2876,17 @@ install_DEB() {
|
||||
fi
|
||||
fi
|
||||
|
||||
PRINT ""
|
||||
if [ "$ALEMBIC_SKIP" = true ]; then
|
||||
WARNING "Skipping Alembic installation, as requested..."
|
||||
elif [ "$ALEMBIC_FORCE_BUILD" = true ]; then
|
||||
INFO "Forced Alembic building, as requested..."
|
||||
compile_ALEMBIC
|
||||
else
|
||||
# No package currently, only HDF5!
|
||||
compile_ALEMBIC
|
||||
fi
|
||||
|
||||
|
||||
if [ "$WITH_OPENCOLLADA" = true ]; then
|
||||
_do_compile_collada=false
|
||||
@ -3283,6 +3424,17 @@ install_RPM() {
|
||||
compile_OPENVDB
|
||||
fi
|
||||
|
||||
PRINT ""
|
||||
if [ "$ALEMBIC_SKIP" = true ]; then
|
||||
WARNING "Skipping Alembic installation, as requested..."
|
||||
elif [ "$ALEMBIC_FORCE_BUILD" = true ]; then
|
||||
INFO "Forced Alembic building, as requested..."
|
||||
compile_ALEMBIC
|
||||
else
|
||||
# No package currently!
|
||||
compile_ALEMBIC
|
||||
fi
|
||||
|
||||
|
||||
if [ "$WITH_OPENCOLLADA" = true ]; then
|
||||
PRINT ""
|
||||
@ -3693,6 +3845,16 @@ install_ARCH() {
|
||||
fi
|
||||
fi
|
||||
|
||||
PRINT ""
|
||||
if [ "$ALEMBIC_SKIP" = true ]; then
|
||||
WARNING "Skipping Alembic installation, as requested..."
|
||||
elif [ "$ALEMBIC_FORCE_BUILD" = true ]; then
|
||||
INFO "Forced Alembic building, as requested..."
|
||||
compile_ALEMBIC
|
||||
else
|
||||
compile_ALEMBIC
|
||||
fi
|
||||
|
||||
|
||||
if [ "$WITH_OPENCOLLADA" = true ]; then
|
||||
PRINT ""
|
||||
@ -4000,7 +4162,7 @@ print_info() {
|
||||
|
||||
_buildargs="-U *SNDFILE* -U *PYTHON* -U *BOOST* -U *Boost*"
|
||||
_buildargs="$_buildargs -U *OPENCOLORIO* -U *OPENEXR* -U *OPENIMAGEIO* -U *LLVM* -U *CYCLES*"
|
||||
_buildargs="$_buildargs -U *OPENSUBDIV* -U *OPENVDB* -U *COLLADA* -U *FFMPEG*"
|
||||
_buildargs="$_buildargs -U *OPENSUBDIV* -U *OPENVDB* -U *COLLADA* -U *FFMPEG* -U *ALEMBIC*"
|
||||
|
||||
_1="-D WITH_CODEC_SNDFILE=ON"
|
||||
PRINT " $_1"
|
||||
@ -4106,6 +4268,17 @@ print_info() {
|
||||
_buildargs="$_buildargs $_1"
|
||||
fi
|
||||
|
||||
if [ "$ALEMBIC_SKIP" = false ]; then
|
||||
_1="-D WITH_ALEMBIC=ON"
|
||||
PRINT " $_1"
|
||||
_buildargs="$_buildargs $_1"
|
||||
if [ -d $INST/alembic ]; then
|
||||
_1="-D ALEMBIC_ROOT_DIR=$INST/alembic"
|
||||
PRINT " $_1"
|
||||
_buildargs="$_buildargs $_1"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$NO_SYSTEM_GLEW" = true ]; then
|
||||
_1="-D WITH_SYSTEM_GLEW=OFF"
|
||||
PRINT " $_1"
|
||||
|
70
build_files/cmake/Modules/FindAlembic.cmake
Normal file
70
build_files/cmake/Modules/FindAlembic.cmake
Normal file
@ -0,0 +1,70 @@
|
||||
# - Find Alembic library
|
||||
# Find the native Alembic includes and libraries
|
||||
# This module defines
|
||||
# ALEMBIC_INCLUDE_DIRS, where to find Alembic headers, Set when
|
||||
# ALEMBIC_INCLUDE_DIR is found.
|
||||
# ALEMBIC_LIBRARIES, libraries to link against to use Alembic.
|
||||
# ALEMBIC_ROOT_DIR, The base directory to search for Alembic.
|
||||
# This can also be an environment variable.
|
||||
# ALEMBIC_FOUND, If false, do not try to use Alembic.
|
||||
#
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2016 Blender Foundation.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
|
||||
# If ALEMBIC_ROOT_DIR was defined in the environment, use it.
|
||||
IF(NOT ALEMBIC_ROOT_DIR AND NOT $ENV{ALEMBIC_ROOT_DIR} STREQUAL "")
|
||||
SET(ALEMBIC_ROOT_DIR $ENV{ALEMBIC_ROOT_DIR})
|
||||
ENDIF()
|
||||
|
||||
SET(_alembic_SEARCH_DIRS
|
||||
${ALEMBIC_ROOT_DIR}
|
||||
/usr/local
|
||||
/sw # Fink
|
||||
/opt/local # DarwinPorts
|
||||
/opt/csw # Blastwave
|
||||
/opt/lib/alembic
|
||||
)
|
||||
|
||||
FIND_PATH(ALEMBIC_INCLUDE_DIR
|
||||
NAMES
|
||||
Alembic/Abc/All.h
|
||||
HINTS
|
||||
${_alembic_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
include
|
||||
)
|
||||
|
||||
FIND_LIBRARY(ALEMBIC_LIBRARY
|
||||
NAMES
|
||||
Alembic
|
||||
HINTS
|
||||
${_alembic_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
lib64 lib lib/static
|
||||
)
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set ALEMBIC_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(ALEMBIC DEFAULT_MSG ALEMBIC_LIBRARY ALEMBIC_INCLUDE_DIR)
|
||||
|
||||
IF(ALEMBIC_FOUND)
|
||||
SET(ALEMBIC_LIBRARIES ${ALEMBIC_LIBRARY})
|
||||
SET(ALEMBIC_INCLUDE_DIRS ${ALEMBIC_INCLUDE_DIR})
|
||||
ENDIF(ALEMBIC_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
ALEMBIC_INCLUDE_DIR
|
||||
ALEMBIC_LIBRARY
|
||||
)
|
||||
|
||||
UNSET(_alembic_SEARCH_DIRS)
|
69
build_files/cmake/Modules/FindHDF5.cmake
Normal file
69
build_files/cmake/Modules/FindHDF5.cmake
Normal file
@ -0,0 +1,69 @@
|
||||
# - Find HDF5 library
|
||||
# Find the native HDF5 includes and libraries
|
||||
# This module defines
|
||||
# HDF5_INCLUDE_DIRS, where to find hdf5.h, Set when HDF5_INCLUDE_DIR is found.
|
||||
# HDF5_LIBRARIES, libraries to link against to use HDF5.
|
||||
# HDF5_ROOT_DIR, The base directory to search for HDF5.
|
||||
# This can also be an environment variable.
|
||||
# HDF5_FOUND, If false, do not try to use HDF5.
|
||||
#
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2016 Blender Foundation.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
|
||||
# If HDF5_ROOT_DIR was defined in the environment, use it.
|
||||
IF(NOT HDF5_ROOT_DIR AND NOT $ENV{HDF5_ROOT_DIR} STREQUAL "")
|
||||
SET(HDF5_ROOT_DIR $ENV{HDF5_ROOT_DIR})
|
||||
ENDIF()
|
||||
|
||||
SET(_hdf5_SEARCH_DIRS
|
||||
${HDF5_ROOT_DIR}
|
||||
/usr/local
|
||||
/sw # Fink
|
||||
/opt/local # DarwinPorts
|
||||
/opt/csw # Blastwave
|
||||
/opt/lib/hdf5
|
||||
)
|
||||
|
||||
FIND_LIBRARY(HDF5_LIBRARY
|
||||
NAMES
|
||||
hdf5
|
||||
HINTS
|
||||
${_hdf5_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
lib64 lib
|
||||
)
|
||||
|
||||
FIND_PATH(HDF5_INCLUDE_DIR
|
||||
NAMES
|
||||
hdf5.h
|
||||
HINTS
|
||||
${_hdf5_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
include
|
||||
)
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set HDF5_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(HDF5 DEFAULT_MSG HDF5_LIBRARY HDF5_INCLUDE_DIR)
|
||||
|
||||
IF(HDF5_FOUND)
|
||||
SET(HDF5_LIBRARIES ${HDF5_LIBRARY})
|
||||
SET(HDF5_INCLUDE_DIRS ${HDF5_INCLUDE_DIR})
|
||||
ENDIF(HDF5_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
HDF5_INCLUDE_DIR
|
||||
HDF5_LIBRARY
|
||||
)
|
||||
|
||||
UNSET(_hdf5_SEARCH_DIRS)
|
@ -4,6 +4,7 @@
|
||||
# cmake -C../blender/build_files/cmake/config/blender_full.cmake ../blender
|
||||
#
|
||||
|
||||
set(WITH_ALEMBIC ON CACHE BOOL "" FORCE)
|
||||
set(WITH_BUILDINFO ON CACHE BOOL "" FORCE)
|
||||
set(WITH_BULLET ON CACHE BOOL "" FORCE)
|
||||
set(WITH_CODEC_AVI ON CACHE BOOL "" FORCE)
|
||||
|
@ -8,6 +8,7 @@
|
||||
set(WITH_INSTALL_PORTABLE ON CACHE BOOL "" FORCE)
|
||||
set(WITH_SYSTEM_GLEW ON CACHE BOOL "" FORCE)
|
||||
|
||||
set(WITH_ALEMBIC OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_BUILDINFO OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_BULLET OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_CODEC_AVI OFF CACHE BOOL "" FORCE)
|
||||
|
@ -32,3 +32,4 @@ set(WITH_OPENCOLLADA OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_INTERNATIONAL OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_BULLET OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENVDB OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_ALEMBIC OFF CACHE BOOL "" FORCE)
|
||||
|
@ -333,6 +333,11 @@ function(SETUP_LIBDIRS)
|
||||
link_directories(${LLVM_LIBPATH})
|
||||
endif()
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
link_directories(${ALEMBIC_LIBPATH})
|
||||
link_directories(${HDF5_LIBPATH})
|
||||
endif()
|
||||
|
||||
if(WIN32 AND NOT UNIX)
|
||||
link_directories(${PTHREADS_LIBPATH})
|
||||
endif()
|
||||
@ -434,6 +439,9 @@ function(setup_liblinks
|
||||
endif()
|
||||
endif()
|
||||
target_link_libraries(${target} ${JPEG_LIBRARIES})
|
||||
if(WITH_ALEMBIC)
|
||||
target_link_libraries(${target} ${ALEMBIC_LIBRARIES} ${HDF5_LIBRARIES})
|
||||
endif()
|
||||
if(WITH_IMAGE_OPENEXR)
|
||||
target_link_libraries(${target} ${OPENEXR_LIBRARIES})
|
||||
endif()
|
||||
@ -607,6 +615,7 @@ function(SETUP_BLENDER_SORTED_LIBS)
|
||||
bf_imbuf_openimageio
|
||||
bf_imbuf_dds
|
||||
bf_collada
|
||||
bf_alembic
|
||||
bf_intern_elbeem
|
||||
bf_intern_memutil
|
||||
bf_intern_guardedalloc
|
||||
|
@ -158,6 +158,13 @@ def write_sysinfo(filepath):
|
||||
else:
|
||||
output.write("Blender was built without OpenVDB support\n")
|
||||
|
||||
alembic = bpy.app.alembic
|
||||
output.write("Alembic: ")
|
||||
if alembic.supported:
|
||||
output.write("%s\n" % alembic.version_string)
|
||||
else:
|
||||
output.write("Blender was built without Alembic support\n")
|
||||
|
||||
if not bpy.app.build_options.sdl:
|
||||
output.write("SDL: Blender was built without SDL support\n")
|
||||
|
||||
|
@ -880,6 +880,19 @@ class ConstraintButtonsPanel:
|
||||
|
||||
layout.operator("clip.constraint_to_fcurve")
|
||||
|
||||
def TRANSFORM_CACHE(self, context, layout, con):
|
||||
layout.label(text="Cache File Properties:")
|
||||
box = layout.box()
|
||||
box.template_cache_file(con, "cache_file")
|
||||
|
||||
cache_file = con.cache_file
|
||||
|
||||
layout.label(text="Constraint Properties:")
|
||||
box = layout.box()
|
||||
|
||||
if cache_file is not None:
|
||||
box.prop_search(con, "object_path", cache_file, "object_paths")
|
||||
|
||||
def SCRIPT(self, context, layout, con):
|
||||
layout.label("Blender 2.6 doesn't support python constraints yet")
|
||||
|
||||
|
@ -181,6 +181,9 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
|
||||
layout.prop(md, "cache_format")
|
||||
layout.prop(md, "filepath")
|
||||
|
||||
if md.cache_format == 'ABC':
|
||||
layout.prop(md, "sub_object")
|
||||
|
||||
layout.label(text="Evaluation:")
|
||||
layout.prop(md, "factor", slider=True)
|
||||
layout.prop(md, "deform_mode")
|
||||
@ -215,6 +218,22 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
|
||||
row = split.row()
|
||||
row.prop(md, "flip_axis")
|
||||
|
||||
def MESH_SEQUENCE_CACHE(self, layout, ob, md):
|
||||
layout.label(text="Cache File Properties:")
|
||||
box = layout.box()
|
||||
box.template_cache_file(md, "cache_file")
|
||||
|
||||
cache_file = md.cache_file
|
||||
|
||||
layout.label(text="Modifier Properties:")
|
||||
box = layout.box()
|
||||
|
||||
if cache_file is not None:
|
||||
box.prop_search(md, "object_path", cache_file, "object_paths")
|
||||
|
||||
if ob.type == 'MESH':
|
||||
box.row().prop(md, "read_data")
|
||||
|
||||
def CAST(self, layout, ob, md):
|
||||
split = layout.split(percentage=0.25)
|
||||
|
||||
|
@ -158,6 +158,8 @@ class INFO_MT_file_import(Menu):
|
||||
def draw(self, context):
|
||||
if bpy.app.build_options.collada:
|
||||
self.layout.operator("wm.collada_import", text="Collada (Default) (.dae)")
|
||||
if bpy.app.build_options.alembic:
|
||||
self.layout.operator("wm.alembic_import", text="Alembic (.abc)")
|
||||
|
||||
|
||||
class INFO_MT_file_export(Menu):
|
||||
@ -167,6 +169,8 @@ class INFO_MT_file_export(Menu):
|
||||
def draw(self, context):
|
||||
if bpy.app.build_options.collada:
|
||||
self.layout.operator("wm.collada_export", text="Collada (Default) (.dae)")
|
||||
if bpy.app.build_options.alembic:
|
||||
self.layout.operator("wm.alembic_export", text="Alembic (.abc)")
|
||||
|
||||
|
||||
class INFO_MT_file_external_data(Menu):
|
||||
|
@ -31,6 +31,7 @@ set(SRC_DNA_INC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_armature_types.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_boid_types.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_brush_types.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_cachefile_types.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_camera_types.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_cloth_types.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_color_types.h
|
||||
@ -153,3 +154,6 @@ if(WITH_FREESTYLE)
|
||||
add_subdirectory(freestyle)
|
||||
endif()
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
add_subdirectory(alembic)
|
||||
endif()
|
||||
|
110
source/blender/alembic/ABC_alembic.h
Normal file
110
source/blender/alembic/ABC_alembic.h
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __ABC_ALEMBIC_H__
|
||||
#define __ABC_ALEMBIC_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct bContext;
|
||||
struct DerivedMesh;
|
||||
struct ListBase;
|
||||
struct Object;
|
||||
struct Scene;
|
||||
|
||||
typedef struct AbcArchiveHandle AbcArchiveHandle;
|
||||
|
||||
enum {
|
||||
ABC_ARCHIVE_OGAWA = 0,
|
||||
ABC_ARCHIVE_HDF5 = 1,
|
||||
};
|
||||
|
||||
int ABC_get_version(void);
|
||||
|
||||
struct AlembicExportParams {
|
||||
double frame_start;
|
||||
double frame_end;
|
||||
|
||||
double frame_step_xform;
|
||||
double frame_step_shape;
|
||||
|
||||
double shutter_open;
|
||||
double shutter_close;
|
||||
|
||||
/* bools */
|
||||
unsigned int selected_only : 1;
|
||||
unsigned int uvs : 1;
|
||||
unsigned int normals : 1;
|
||||
unsigned int vcolors : 1;
|
||||
unsigned int apply_subdiv : 1;
|
||||
unsigned int flatten_hierarchy : 1;
|
||||
unsigned int visible_layers_only : 1;
|
||||
unsigned int renderable_only : 1;
|
||||
unsigned int face_sets : 1;
|
||||
unsigned int use_subdiv_schema : 1;
|
||||
unsigned int packuv : 1;
|
||||
|
||||
unsigned int compression_type : 1;
|
||||
float global_scale;
|
||||
};
|
||||
|
||||
void ABC_export(
|
||||
struct Scene *scene,
|
||||
struct bContext *C,
|
||||
const char *filepath,
|
||||
const struct AlembicExportParams *params);
|
||||
|
||||
void ABC_import(struct bContext *C,
|
||||
const char *filepath,
|
||||
float scale,
|
||||
bool is_sequence,
|
||||
bool set_frame_range,
|
||||
int sequence_len,
|
||||
int offset,
|
||||
bool validate_meshes);
|
||||
|
||||
AbcArchiveHandle *ABC_create_handle(const char *filename, struct ListBase *object_paths);
|
||||
|
||||
void ABC_free_handle(AbcArchiveHandle *handle);
|
||||
|
||||
void ABC_get_transform(AbcArchiveHandle *handle,
|
||||
struct Object *ob,
|
||||
const char *object_path,
|
||||
float r_mat[4][4],
|
||||
float time,
|
||||
float scale);
|
||||
|
||||
struct DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle,
|
||||
struct Object *ob,
|
||||
struct DerivedMesh *dm,
|
||||
const char *object_path,
|
||||
const float time,
|
||||
const char **err_str,
|
||||
int flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ABC_ALEMBIC_H__ */
|
81
source/blender/alembic/CMakeLists.txt
Normal file
81
source/blender/alembic/CMakeLists.txt
Normal file
@ -0,0 +1,81 @@
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# The Original Code is Copyright (C) 2006, Blender Foundation
|
||||
# All rights reserved.
|
||||
#
|
||||
# The Original Code is: all of this file.
|
||||
#
|
||||
# Contributor(s): Kevin Dietrich.
|
||||
#
|
||||
# ***** END GPL LICENSE BLOCK *****
|
||||
|
||||
set(INC
|
||||
.
|
||||
../blenkernel
|
||||
../blenlib
|
||||
../blenloader
|
||||
../editors/include
|
||||
../makesdna
|
||||
../makesrna
|
||||
../windowmanager
|
||||
../../../intern/guardedalloc
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
${ALEMBIC_INCLUDE_DIRS}
|
||||
${HDF5_INCLUDE_DIRS}
|
||||
${OPENEXR_INCLUDE_DIRS}
|
||||
)
|
||||
if(APPLE)
|
||||
list(APPEND INC_SYS
|
||||
${BOOST_INCLUDE_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
set(SRC
|
||||
intern/abc_camera.cc
|
||||
intern/abc_customdata.cc
|
||||
intern/abc_curves.cc
|
||||
intern/abc_exporter.cc
|
||||
intern/abc_hair.cc
|
||||
intern/abc_mesh.cc
|
||||
intern/abc_nurbs.cc
|
||||
intern/abc_object.cc
|
||||
intern/abc_points.cc
|
||||
intern/abc_transform.cc
|
||||
intern/abc_util.cc
|
||||
intern/alembic_capi.cc
|
||||
|
||||
ABC_alembic.h
|
||||
intern/abc_camera.h
|
||||
intern/abc_customdata.h
|
||||
intern/abc_curves.h
|
||||
intern/abc_exporter.h
|
||||
intern/abc_hair.h
|
||||
intern/abc_mesh.h
|
||||
intern/abc_nurbs.h
|
||||
intern/abc_object.h
|
||||
intern/abc_points.h
|
||||
intern/abc_transform.h
|
||||
intern/abc_util.h
|
||||
)
|
||||
|
||||
if(WITH_ALEMBIC_HDF5)
|
||||
add_definitions(-DWITH_ALEMBIC_HDF5)
|
||||
endif()
|
||||
|
||||
blender_add_lib(bf_alembic "${SRC}" "${INC}" "${INC_SYS}")
|
162
source/blender/alembic/intern/abc_camera.cc
Normal file
162
source/blender/alembic/intern/abc_camera.cc
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "abc_camera.h"
|
||||
|
||||
#include "abc_transform.h"
|
||||
#include "abc_util.h"
|
||||
|
||||
extern "C" {
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BKE_camera.h"
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_string.h"
|
||||
}
|
||||
|
||||
using Alembic::AbcGeom::ICamera;
|
||||
using Alembic::AbcGeom::ICompoundProperty;
|
||||
using Alembic::AbcGeom::IFloatProperty;
|
||||
using Alembic::AbcGeom::ISampleSelector;
|
||||
|
||||
using Alembic::AbcGeom::OCamera;
|
||||
using Alembic::AbcGeom::OFloatProperty;
|
||||
|
||||
using Alembic::AbcGeom::CameraSample;
|
||||
using Alembic::AbcGeom::kWrapExisting;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcCameraWriter::AbcCameraWriter(Scene *scene,
|
||||
Object *ob,
|
||||
AbcTransformWriter *parent,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings)
|
||||
: AbcObjectWriter(scene, ob, time_sampling, settings, parent)
|
||||
{
|
||||
OCamera camera(parent->alembicXform(), m_name, m_time_sampling);
|
||||
m_camera_schema = camera.getSchema();
|
||||
|
||||
m_custom_data_container = m_camera_schema.getUserProperties();
|
||||
m_stereo_distance = OFloatProperty(m_custom_data_container, "stereoDistance", m_time_sampling);
|
||||
m_eye_separation = OFloatProperty(m_custom_data_container, "eyeSeparation", m_time_sampling);
|
||||
}
|
||||
|
||||
void AbcCameraWriter::do_write()
|
||||
{
|
||||
Camera *cam = static_cast<Camera *>(m_object->data);
|
||||
|
||||
m_stereo_distance.set(cam->stereo.convergence_distance);
|
||||
m_eye_separation.set(cam->stereo.interocular_distance);
|
||||
|
||||
const double apperture_x = cam->sensor_x / 10.0;
|
||||
const double apperture_y = cam->sensor_y / 10.0;
|
||||
const double film_aspect = apperture_x / apperture_y;
|
||||
|
||||
m_camera_sample.setFocalLength(cam->lens);
|
||||
m_camera_sample.setHorizontalAperture(apperture_x);
|
||||
m_camera_sample.setVerticalAperture(apperture_y);
|
||||
m_camera_sample.setHorizontalFilmOffset(apperture_x * cam->shiftx);
|
||||
m_camera_sample.setVerticalFilmOffset(apperture_y * cam->shifty * film_aspect);
|
||||
m_camera_sample.setNearClippingPlane(cam->clipsta);
|
||||
m_camera_sample.setFarClippingPlane(cam->clipend);
|
||||
|
||||
if (cam->dof_ob) {
|
||||
Imath::V3f v(m_object->loc[0] - cam->dof_ob->loc[0],
|
||||
m_object->loc[1] - cam->dof_ob->loc[1],
|
||||
m_object->loc[2] - cam->dof_ob->loc[2]);
|
||||
m_camera_sample.setFocusDistance(v.length());
|
||||
}
|
||||
else {
|
||||
m_camera_sample.setFocusDistance(cam->gpu_dof.focus_distance);
|
||||
}
|
||||
|
||||
/* Blender camera does not have an fstop param, so try to find a custom prop
|
||||
* instead. */
|
||||
m_camera_sample.setFStop(cam->gpu_dof.fstop);
|
||||
|
||||
m_camera_sample.setLensSqueezeRatio(1.0);
|
||||
m_camera_schema.set(m_camera_sample);
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcCameraReader::AbcCameraReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
|
||||
: AbcObjectReader(object, settings)
|
||||
{
|
||||
ICamera abc_cam(m_iobject, kWrapExisting);
|
||||
m_schema = abc_cam.getSchema();
|
||||
|
||||
get_min_max_time(m_schema, m_min_time, m_max_time);
|
||||
}
|
||||
|
||||
bool AbcCameraReader::valid() const
|
||||
{
|
||||
return m_schema.valid();
|
||||
}
|
||||
|
||||
void AbcCameraReader::readObjectData(Main *bmain, float time)
|
||||
{
|
||||
Camera *bcam = static_cast<Camera *>(BKE_camera_add(bmain, "abc_camera"));
|
||||
|
||||
ISampleSelector sample_sel(time);
|
||||
CameraSample cam_sample;
|
||||
m_schema.get(cam_sample, sample_sel);
|
||||
|
||||
ICompoundProperty customDataContainer = m_schema.getUserProperties();
|
||||
|
||||
if (customDataContainer.valid() &&
|
||||
customDataContainer.getPropertyHeader("stereoDistance") &&
|
||||
customDataContainer.getPropertyHeader("eyeSeparation"))
|
||||
{
|
||||
IFloatProperty convergence_plane(customDataContainer, "stereoDistance");
|
||||
IFloatProperty eye_separation(customDataContainer, "eyeSeparation");
|
||||
|
||||
bcam->stereo.interocular_distance = eye_separation.getValue(sample_sel);
|
||||
bcam->stereo.convergence_distance = convergence_plane.getValue(sample_sel);
|
||||
}
|
||||
|
||||
const float lens = cam_sample.getFocalLength();
|
||||
const float apperture_x = cam_sample.getHorizontalAperture();
|
||||
const float apperture_y = cam_sample.getVerticalAperture();
|
||||
const float h_film_offset = cam_sample.getHorizontalFilmOffset();
|
||||
const float v_film_offset = cam_sample.getVerticalFilmOffset();
|
||||
const float film_aspect = apperture_x / apperture_y;
|
||||
|
||||
bcam->lens = lens;
|
||||
bcam->sensor_x = apperture_x * 10;
|
||||
bcam->sensor_y = apperture_y * 10;
|
||||
bcam->shiftx = h_film_offset / apperture_x;
|
||||
bcam->shifty = v_film_offset / apperture_y / film_aspect;
|
||||
bcam->clipsta = max_ff(0.1f, cam_sample.getNearClippingPlane());
|
||||
bcam->clipend = cam_sample.getFarClippingPlane();
|
||||
bcam->gpu_dof.focus_distance = cam_sample.getFocusDistance();
|
||||
bcam->gpu_dof.fstop = cam_sample.getFStop();
|
||||
|
||||
BLI_strncpy(bcam->id.name + 2, m_data_name.c_str(), m_data_name.size() + 1);
|
||||
|
||||
m_object = BKE_object_add_only_object(bmain, OB_CAMERA, m_object_name.c_str());
|
||||
m_object->data = bcam;
|
||||
}
|
61
source/blender/alembic/intern/abc_camera.h
Normal file
61
source/blender/alembic/intern/abc_camera.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __ABC_CAMERA_H__
|
||||
#define __ABC_CAMERA_H__
|
||||
|
||||
#include "abc_object.h"
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcCameraWriter : public AbcObjectWriter {
|
||||
Alembic::AbcGeom::OCameraSchema m_camera_schema;
|
||||
Alembic::AbcGeom::CameraSample m_camera_sample;
|
||||
Alembic::AbcGeom::OCompoundProperty m_custom_data_container;
|
||||
Alembic::AbcGeom::OFloatProperty m_stereo_distance;
|
||||
Alembic::AbcGeom::OFloatProperty m_eye_separation;
|
||||
|
||||
public:
|
||||
AbcCameraWriter(Scene *scene,
|
||||
Object *ob,
|
||||
AbcTransformWriter *parent,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings);
|
||||
|
||||
private:
|
||||
virtual void do_write();
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcCameraReader : public AbcObjectReader {
|
||||
Alembic::AbcGeom::ICameraSchema m_schema;
|
||||
|
||||
public:
|
||||
AbcCameraReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
|
||||
|
||||
bool valid() const;
|
||||
|
||||
void readObjectData(Main *bmain, float time);
|
||||
};
|
||||
|
||||
#endif /* __ABC_CAMERA_H__ */
|
355
source/blender/alembic/intern/abc_curves.cc
Normal file
355
source/blender/alembic/intern/abc_curves.cc
Normal file
@ -0,0 +1,355 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Kévin Dietrich.
|
||||
* All rights reserved.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*
|
||||
*/
|
||||
|
||||
#include "abc_curves.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include "abc_transform.h"
|
||||
#include "abc_util.h"
|
||||
|
||||
extern "C" {
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "ED_curve.h"
|
||||
}
|
||||
|
||||
using Alembic::Abc::IInt32ArrayProperty;
|
||||
using Alembic::Abc::Int32ArraySamplePtr;
|
||||
using Alembic::Abc::FloatArraySamplePtr;
|
||||
using Alembic::Abc::P3fArraySamplePtr;
|
||||
using Alembic::Abc::UcharArraySamplePtr;
|
||||
|
||||
using Alembic::AbcGeom::ICurves;
|
||||
using Alembic::AbcGeom::ICurvesSchema;
|
||||
using Alembic::AbcGeom::IFloatGeomParam;
|
||||
using Alembic::AbcGeom::ISampleSelector;
|
||||
using Alembic::AbcGeom::kWrapExisting;
|
||||
using Alembic::AbcGeom::CurvePeriodicity;
|
||||
|
||||
using Alembic::AbcGeom::OCurves;
|
||||
using Alembic::AbcGeom::OCurvesSchema;
|
||||
using Alembic::AbcGeom::ON3fGeomParam;
|
||||
using Alembic::AbcGeom::OV2fGeomParam;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcCurveWriter::AbcCurveWriter(Scene *scene,
|
||||
Object *ob,
|
||||
AbcTransformWriter *parent,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings)
|
||||
: AbcObjectWriter(scene, ob, time_sampling, settings, parent)
|
||||
{
|
||||
OCurves curves(parent->alembicXform(), m_name, m_time_sampling);
|
||||
m_schema = curves.getSchema();
|
||||
}
|
||||
|
||||
void AbcCurveWriter::do_write()
|
||||
{
|
||||
Curve *curve = static_cast<Curve *>(m_object->data);
|
||||
|
||||
std::vector<Imath::V3f> verts;
|
||||
std::vector<int32_t> vert_counts;
|
||||
std::vector<float> widths;
|
||||
std::vector<float> weights;
|
||||
std::vector<float> knots;
|
||||
std::vector<uint8_t> orders;
|
||||
Imath::V3f temp_vert;
|
||||
|
||||
Alembic::AbcGeom::BasisType curve_basis;
|
||||
Alembic::AbcGeom::CurveType curve_type;
|
||||
Alembic::AbcGeom::CurvePeriodicity periodicity;
|
||||
|
||||
Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
|
||||
for (; nurbs; nurbs = nurbs->next) {
|
||||
if (nurbs->bp) {
|
||||
curve_basis = Alembic::AbcGeom::kNoBasis;
|
||||
curve_type = Alembic::AbcGeom::kLinear;
|
||||
|
||||
const int totpoint = nurbs->pntsu * nurbs->pntsv;
|
||||
|
||||
const BPoint *point = nurbs->bp;
|
||||
|
||||
for (int i = 0; i < totpoint; ++i, ++point) {
|
||||
copy_zup_yup(temp_vert.getValue(), point->vec);
|
||||
verts.push_back(temp_vert);
|
||||
weights.push_back(point->vec[3]);
|
||||
widths.push_back(point->radius);
|
||||
}
|
||||
}
|
||||
else if (nurbs->bezt) {
|
||||
curve_basis = Alembic::AbcGeom::kBezierBasis;
|
||||
curve_type = Alembic::AbcGeom::kCubic;
|
||||
|
||||
const int totpoint = nurbs->pntsu;
|
||||
|
||||
const BezTriple *bezier = nurbs->bezt;
|
||||
|
||||
/* TODO(kevin): store info about handles, Alembic doesn't have this. */
|
||||
for (int i = 0; i < totpoint; ++i, ++bezier) {
|
||||
copy_zup_yup(temp_vert.getValue(), bezier->vec[1]);
|
||||
verts.push_back(temp_vert);
|
||||
widths.push_back(bezier->radius);
|
||||
}
|
||||
}
|
||||
|
||||
if ((nurbs->flagu & CU_NURB_ENDPOINT) != 0) {
|
||||
periodicity = Alembic::AbcGeom::kNonPeriodic;
|
||||
}
|
||||
else if ((nurbs->flagu & CU_NURB_CYCLIC) != 0) {
|
||||
periodicity = Alembic::AbcGeom::kPeriodic;
|
||||
|
||||
/* Duplicate the start points to indicate that the curve is actually
|
||||
* cyclic since other software need those.
|
||||
*/
|
||||
|
||||
for (int i = 0; i < nurbs->orderu; ++i) {
|
||||
verts.push_back(verts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (nurbs->knotsu != NULL) {
|
||||
const size_t num_knots = KNOTSU(nurbs);
|
||||
|
||||
/* Add an extra knot at the beggining and end of the array since most apps
|
||||
* require/expect them. */
|
||||
knots.resize(num_knots + 2);
|
||||
|
||||
for (int i = 0; i < num_knots; ++i) {
|
||||
knots[i + 1] = nurbs->knotsu[i];
|
||||
}
|
||||
|
||||
if ((nurbs->flagu & CU_NURB_CYCLIC) != 0) {
|
||||
knots[0] = nurbs->knotsu[0];
|
||||
knots[num_knots - 1] = nurbs->knotsu[num_knots - 1];
|
||||
}
|
||||
else {
|
||||
knots[0] = (2.0f * nurbs->knotsu[0] - nurbs->knotsu[1]);
|
||||
knots[num_knots - 1] = (2.0f * nurbs->knotsu[num_knots - 1] - nurbs->knotsu[num_knots - 2]);
|
||||
}
|
||||
}
|
||||
|
||||
orders.push_back(nurbs->orderu + 1);
|
||||
vert_counts.push_back(verts.size());
|
||||
}
|
||||
|
||||
Alembic::AbcGeom::OFloatGeomParam::Sample width_sample;
|
||||
width_sample.setVals(widths);
|
||||
|
||||
m_sample = OCurvesSchema::Sample(verts,
|
||||
vert_counts,
|
||||
curve_type,
|
||||
periodicity,
|
||||
width_sample,
|
||||
OV2fGeomParam::Sample(), /* UVs */
|
||||
ON3fGeomParam::Sample(), /* normals */
|
||||
curve_basis,
|
||||
weights,
|
||||
orders,
|
||||
knots);
|
||||
|
||||
m_sample.setSelfBounds(bounds());
|
||||
m_schema.set(m_sample);
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcCurveReader::AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
|
||||
: AbcObjectReader(object, settings)
|
||||
{
|
||||
ICurves abc_curves(object, kWrapExisting);
|
||||
m_curves_schema = abc_curves.getSchema();
|
||||
|
||||
get_min_max_time(m_curves_schema, m_min_time, m_max_time);
|
||||
}
|
||||
|
||||
bool AbcCurveReader::valid() const
|
||||
{
|
||||
return m_curves_schema.valid();
|
||||
}
|
||||
|
||||
void AbcCurveReader::readObjectData(Main *bmain, float time)
|
||||
{
|
||||
Curve *cu = BKE_curve_add(bmain, m_data_name.c_str(), OB_CURVE);
|
||||
|
||||
cu->flag |= CU_DEFORM_FILL | CU_3D;
|
||||
cu->actvert = CU_ACT_NONE;
|
||||
|
||||
m_object = BKE_object_add_only_object(bmain, OB_CURVE, m_object_name.c_str());
|
||||
m_object->data = cu;
|
||||
|
||||
read_curve_sample(cu, m_curves_schema, time);
|
||||
|
||||
if (has_animations(m_curves_schema, m_settings)) {
|
||||
addCacheModifier();
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time)
|
||||
{
|
||||
const ISampleSelector sample_sel(time);
|
||||
ICurvesSchema::Sample smp = schema.getValue(sample_sel);
|
||||
const Int32ArraySamplePtr num_vertices = smp.getCurvesNumVertices();
|
||||
const P3fArraySamplePtr positions = smp.getPositions();
|
||||
const FloatArraySamplePtr weights = smp.getPositionWeights();
|
||||
const FloatArraySamplePtr knots = smp.getKnots();
|
||||
const CurvePeriodicity periodicity = smp.getWrap();
|
||||
const UcharArraySamplePtr orders = smp.getOrders();
|
||||
|
||||
const IFloatGeomParam widths_param = schema.getWidthsParam();
|
||||
FloatArraySamplePtr radiuses;
|
||||
|
||||
if (widths_param.valid()) {
|
||||
IFloatGeomParam::Sample wsample = widths_param.getExpandedValue(sample_sel);
|
||||
radiuses = wsample.getVals();
|
||||
}
|
||||
|
||||
int knot_offset = 0;
|
||||
|
||||
size_t idx = 0;
|
||||
for (size_t i = 0; i < num_vertices->size(); ++i) {
|
||||
const int num_verts = (*num_vertices)[i];
|
||||
|
||||
Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "abc_getnurb"));
|
||||
nu->resolu = cu->resolu;
|
||||
nu->resolv = cu->resolv;
|
||||
nu->pntsu = num_verts;
|
||||
nu->pntsv = 1;
|
||||
nu->flag |= CU_SMOOTH;
|
||||
|
||||
nu->orderu = num_verts;
|
||||
|
||||
if (smp.getType() == Alembic::AbcGeom::kCubic) {
|
||||
nu->orderu = 3;
|
||||
}
|
||||
else if (orders && orders->size() > i) {
|
||||
nu->orderu = static_cast<short>((*orders)[i] - 1);
|
||||
}
|
||||
|
||||
if (periodicity == Alembic::AbcGeom::kNonPeriodic) {
|
||||
nu->flagu |= CU_NURB_ENDPOINT;
|
||||
}
|
||||
else if (periodicity == Alembic::AbcGeom::kPeriodic) {
|
||||
nu->flagu |= CU_NURB_CYCLIC;
|
||||
|
||||
/* Check the number of points which overlap, we don't have
|
||||
* overlapping points in Blender, but other software do use them to
|
||||
* indicate that a curve is actually cyclic. Usually the number of
|
||||
* overlapping points is equal to the order/degree of the curve.
|
||||
*/
|
||||
|
||||
const int start = idx;
|
||||
const int end = idx + num_verts;
|
||||
int overlap = 0;
|
||||
|
||||
for (int j = start, k = end - nu->orderu; j < nu->orderu; ++j, ++k) {
|
||||
const Imath::V3f &p1 = (*positions)[j];
|
||||
const Imath::V3f &p2 = (*positions)[k];
|
||||
|
||||
if (p1 != p2) {
|
||||
break;
|
||||
}
|
||||
|
||||
++overlap;
|
||||
}
|
||||
|
||||
/* TODO: Special case, need to figure out how it coincides with knots. */
|
||||
if (overlap == 0 && num_verts > 2 && (*positions)[start] == (*positions)[end - 1]) {
|
||||
overlap = 1;
|
||||
}
|
||||
|
||||
/* There is no real cycles. */
|
||||
if (overlap == 0) {
|
||||
nu->flagu &= ~CU_NURB_CYCLIC;
|
||||
nu->flagu |= CU_NURB_ENDPOINT;
|
||||
}
|
||||
|
||||
nu->pntsu -= overlap;
|
||||
}
|
||||
|
||||
const bool do_weights = (weights != NULL) && (weights->size() > 1);
|
||||
float weight = 1.0f;
|
||||
|
||||
const bool do_radius = (radiuses != NULL) && (radiuses->size() > 1);
|
||||
float radius = (radiuses && radiuses->size() == 1) ? (*radiuses)[0] : 1.0f;
|
||||
|
||||
nu->type = CU_NURBS;
|
||||
|
||||
nu->bp = static_cast<BPoint *>(MEM_callocN(sizeof(BPoint) * nu->pntsu, "abc_getnurb"));
|
||||
BPoint *bp = nu->bp;
|
||||
|
||||
for (int j = 0; j < nu->pntsu; ++j, ++bp, ++idx) {
|
||||
const Imath::V3f &pos = (*positions)[idx];
|
||||
|
||||
if (do_radius) {
|
||||
radius = (*radiuses)[idx];
|
||||
}
|
||||
|
||||
if (do_weights) {
|
||||
weight = (*weights)[idx];
|
||||
}
|
||||
|
||||
copy_yup_zup(bp->vec, pos.getValue());
|
||||
bp->vec[3] = weight;
|
||||
bp->f1 = SELECT;
|
||||
bp->radius = radius;
|
||||
bp->weight = 1.0f;
|
||||
}
|
||||
|
||||
if (knots && knots->size() != 0) {
|
||||
nu->knotsu = static_cast<float *>(MEM_callocN(KNOTSU(nu) * sizeof(float), "abc_setsplineknotsu"));
|
||||
|
||||
/* TODO: second check is temporary, for until the check for cycles is rock solid. */
|
||||
if (periodicity == Alembic::AbcGeom::kPeriodic && (KNOTSU(nu) == knots->size() - 2)) {
|
||||
/* Skip first and last knots. */
|
||||
for (size_t i = 1; i < knots->size() - 1; ++i) {
|
||||
nu->knotsu[i - 1] = (*knots)[knot_offset + i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* TODO: figure out how to use the knots array from other
|
||||
* software in this case. */
|
||||
BKE_nurb_knot_calc_u(nu);
|
||||
}
|
||||
|
||||
knot_offset += knots->size();
|
||||
}
|
||||
else {
|
||||
BKE_nurb_knot_calc_u(nu);
|
||||
}
|
||||
|
||||
BLI_addtail(BKE_curve_nurbs_get(cu), nu);
|
||||
}
|
||||
}
|
65
source/blender/alembic/intern/abc_curves.h
Normal file
65
source/blender/alembic/intern/abc_curves.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Kévin Dietrich.
|
||||
* All rights reserved.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ABC_CURVES_H__
|
||||
#define __ABC_CURVES_H__
|
||||
|
||||
#include "abc_object.h"
|
||||
|
||||
struct Curve;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcCurveWriter : public AbcObjectWriter {
|
||||
Alembic::AbcGeom::OCurvesSchema m_schema;
|
||||
Alembic::AbcGeom::OCurvesSchema::Sample m_sample;
|
||||
|
||||
public:
|
||||
AbcCurveWriter(Scene *scene,
|
||||
Object *ob,
|
||||
AbcTransformWriter *parent,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings);
|
||||
|
||||
void do_write();
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcCurveReader : public AbcObjectReader {
|
||||
Alembic::AbcGeom::ICurvesSchema m_curves_schema;
|
||||
|
||||
public:
|
||||
AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
|
||||
|
||||
bool valid() const;
|
||||
|
||||
void readObjectData(Main *bmain, float time);
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
void read_curve_sample(Curve *cu, const Alembic::AbcGeom::ICurvesSchema &schema, const float time);
|
||||
|
||||
#endif /* __ABC_CURVES_H__ */
|
379
source/blender/alembic/intern/abc_customdata.cc
Normal file
379
source/blender/alembic/intern/abc_customdata.cc
Normal file
@ -0,0 +1,379 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Kévin Dietrich.
|
||||
* All rights reserved.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*
|
||||
*/
|
||||
|
||||
#include "abc_customdata.h"
|
||||
|
||||
#include <Alembic/AbcGeom/All.h>
|
||||
#include <algorithm>
|
||||
|
||||
extern "C" {
|
||||
#include "DNA_customdata_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
||||
#include "BKE_customdata.h"
|
||||
}
|
||||
|
||||
/* NOTE: for now only UVs and Vertex Colors are supported for streaming.
|
||||
* Although Alembic only allows for a single UV layer per {I|O}Schema, and does
|
||||
* not have a vertex color concept, there is a convention between DCCs to write
|
||||
* such data in a way that lets other DCC know what they are for. See comments
|
||||
* in the write code for the conventions. */
|
||||
|
||||
using Alembic::AbcGeom::kVertexScope;
|
||||
using Alembic::AbcGeom::kFacevaryingScope;
|
||||
|
||||
using Alembic::Abc::C4fArraySample;
|
||||
using Alembic::Abc::UInt32ArraySample;
|
||||
using Alembic::Abc::V2fArraySample;
|
||||
|
||||
using Alembic::AbcGeom::OV2fGeomParam;
|
||||
using Alembic::AbcGeom::OC4fGeomParam;
|
||||
|
||||
static void get_uvs(const CDStreamConfig &config,
|
||||
std::vector<Imath::V2f> &uvs,
|
||||
std::vector<uint32_t> &uvidx,
|
||||
void *cd_data)
|
||||
{
|
||||
MLoopUV *mloopuv_array = static_cast<MLoopUV *>(cd_data);
|
||||
|
||||
if (!mloopuv_array) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int num_poly = config.totpoly;
|
||||
MPoly *polygons = config.mpoly;
|
||||
|
||||
if (!config.pack_uvs) {
|
||||
int cnt = 0;
|
||||
uvidx.resize(config.totloop);
|
||||
uvs.resize(config.totloop);
|
||||
|
||||
for (int i = 0; i < num_poly; ++i) {
|
||||
MPoly ¤t_poly = polygons[i];
|
||||
MLoopUV *loopuvpoly = mloopuv_array + current_poly.loopstart + current_poly.totloop;
|
||||
|
||||
for (int j = 0; j < current_poly.totloop; ++j, ++cnt) {
|
||||
--loopuvpoly;
|
||||
|
||||
uvidx[cnt] = cnt;
|
||||
uvs[cnt][0] = loopuvpoly->uv[0];
|
||||
uvs[cnt][1] = loopuvpoly->uv[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < num_poly; ++i) {
|
||||
MPoly ¤t_poly = polygons[i];
|
||||
MLoopUV *loopuvpoly = mloopuv_array + current_poly.loopstart + current_poly.totloop;
|
||||
|
||||
for (int j = 0; j < current_poly.totloop; ++j) {
|
||||
loopuvpoly--;
|
||||
Imath::V2f uv(loopuvpoly->uv[0], loopuvpoly->uv[1]);
|
||||
|
||||
std::vector<Imath::V2f>::iterator it = std::find(uvs.begin(), uvs.end(), uv);
|
||||
|
||||
if (it == uvs.end()) {
|
||||
uvidx.push_back(uvs.size());
|
||||
uvs.push_back(uv);
|
||||
}
|
||||
else {
|
||||
uvidx.push_back(std::distance(uvs.begin(), it));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, CustomData *data)
|
||||
{
|
||||
const int active_uvlayer = CustomData_get_active_layer(data, CD_MLOOPUV);
|
||||
|
||||
if (active_uvlayer < 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
void *cd_data = CustomData_get_layer_n(data, CD_MLOOPUV, active_uvlayer);
|
||||
|
||||
get_uvs(config, sample.uvs, sample.indices, cd_data);
|
||||
|
||||
return CustomData_get_layer_name(data, CD_MLOOPUV, active_uvlayer);
|
||||
}
|
||||
|
||||
/* Convention to write UVs:
|
||||
* - V2fGeomParam on the arbGeomParam
|
||||
* - set scope as face varying
|
||||
* - (optional due to its behaviour) tag as UV using Alembic::AbcGeom::SetIsUV
|
||||
*/
|
||||
static void write_uv(const OCompoundProperty &prop, const CDStreamConfig &config, void *data, const char *name)
|
||||
{
|
||||
std::vector<uint32_t> indices;
|
||||
std::vector<Imath::V2f> uvs;
|
||||
|
||||
get_uvs(config, uvs, indices, data);
|
||||
|
||||
if (indices.empty() || uvs.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
OV2fGeomParam param(prop, name, true, kFacevaryingScope, 1);
|
||||
|
||||
OV2fGeomParam::Sample sample(
|
||||
V2fArraySample(&uvs.front(), uvs.size()),
|
||||
UInt32ArraySample(&indices.front(), indices.size()),
|
||||
kFacevaryingScope);
|
||||
|
||||
param.set(sample);
|
||||
}
|
||||
|
||||
/* Convention to write Vertex Colors:
|
||||
* - C3fGeomParam/C4fGeomParam on the arbGeomParam
|
||||
* - set scope as vertex varying
|
||||
*/
|
||||
static void write_mcol(const OCompoundProperty &prop, const CDStreamConfig &config, void *data, const char *name)
|
||||
{
|
||||
const float cscale = 1.0f / 255.0f;
|
||||
MPoly *polys = config.mpoly;
|
||||
MLoop *mloops = config.mloop;
|
||||
MCol *cfaces = static_cast<MCol *>(data);
|
||||
|
||||
std::vector<Imath::C4f> buffer(config.totvert);
|
||||
|
||||
Imath::C4f col;
|
||||
|
||||
for (int i = 0; i < config.totpoly; ++i) {
|
||||
MPoly *p = &polys[i];
|
||||
MCol *cface = &cfaces[p->loopstart + p->totloop];
|
||||
MLoop *mloop = &mloops[p->loopstart + p->totloop];
|
||||
|
||||
for (int j = 0; j < p->totloop; ++j) {
|
||||
cface--;
|
||||
mloop--;
|
||||
|
||||
col[0] = cface->a * cscale;
|
||||
col[1] = cface->r * cscale;
|
||||
col[2] = cface->g * cscale;
|
||||
col[3] = cface->b * cscale;
|
||||
|
||||
buffer[mloop->v] = col;
|
||||
}
|
||||
}
|
||||
|
||||
OC4fGeomParam param(prop, name, true, kFacevaryingScope, 1);
|
||||
|
||||
OC4fGeomParam::Sample sample(
|
||||
C4fArraySample(&buffer.front(), buffer.size()),
|
||||
kVertexScope);
|
||||
|
||||
param.set(sample);
|
||||
}
|
||||
|
||||
void write_custom_data(const OCompoundProperty &prop, const CDStreamConfig &config, CustomData *data, int data_type)
|
||||
{
|
||||
CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
|
||||
|
||||
if (!CustomData_has_layer(data, cd_data_type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int active_layer = CustomData_get_active_layer(data, cd_data_type);
|
||||
const int tot_layers = CustomData_number_of_layers(data, cd_data_type);
|
||||
|
||||
for (int i = 0; i < tot_layers; ++i) {
|
||||
void *cd_data = CustomData_get_layer_n(data, cd_data_type, i);
|
||||
const char *name = CustomData_get_layer_name(data, cd_data_type, i);
|
||||
|
||||
if (cd_data_type == CD_MLOOPUV) {
|
||||
/* Already exported. */
|
||||
if (i == active_layer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
write_uv(prop, config, cd_data, name);
|
||||
}
|
||||
else if (cd_data_type == CD_MLOOPCOL) {
|
||||
write_mcol(prop, config, cd_data, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
using Alembic::Abc::C3fArraySamplePtr;
|
||||
using Alembic::Abc::C4fArraySamplePtr;
|
||||
using Alembic::Abc::PropertyHeader;
|
||||
|
||||
using Alembic::AbcGeom::IC3fGeomParam;
|
||||
using Alembic::AbcGeom::IC4fGeomParam;
|
||||
using Alembic::AbcGeom::IV2fGeomParam;
|
||||
|
||||
static void read_mcols(const CDStreamConfig &config, void *data,
|
||||
const C3fArraySamplePtr &c3f_ptr, const C4fArraySamplePtr &c4f_ptr)
|
||||
{
|
||||
MCol *cfaces = static_cast<MCol *>(data);
|
||||
MPoly *polys = config.mpoly;
|
||||
MLoop *mloops = config.mloop;
|
||||
|
||||
if (c3f_ptr) {
|
||||
for (int i = 0; i < config.totpoly; ++i) {
|
||||
MPoly *p = &polys[i];
|
||||
MCol *cface = &cfaces[p->loopstart + p->totloop];
|
||||
MLoop *mloop = &mloops[p->loopstart + p->totloop];
|
||||
|
||||
for (int j = 0; j < p->totloop; ++j) {
|
||||
cface--;
|
||||
mloop--;
|
||||
const Imath::C3f &color = (*c3f_ptr)[mloop->v];
|
||||
cface->a = FTOCHAR(color[0]);
|
||||
cface->r = FTOCHAR(color[1]);
|
||||
cface->g = FTOCHAR(color[2]);
|
||||
cface->b = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (c4f_ptr) {
|
||||
for (int i = 0; i < config.totpoly; ++i) {
|
||||
MPoly *p = &polys[i];
|
||||
MCol *cface = &cfaces[p->loopstart + p->totloop];
|
||||
MLoop *mloop = &mloops[p->loopstart + p->totloop];
|
||||
|
||||
for (int j = 0; j < p->totloop; ++j) {
|
||||
cface--;
|
||||
mloop--;
|
||||
const Imath::C4f &color = (*c4f_ptr)[mloop->v];
|
||||
cface->a = FTOCHAR(color[0]);
|
||||
cface->r = FTOCHAR(color[1]);
|
||||
cface->g = FTOCHAR(color[2]);
|
||||
cface->b = FTOCHAR(color[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void read_uvs(const CDStreamConfig &config, void *data,
|
||||
const Alembic::AbcGeom::V2fArraySamplePtr &uvs,
|
||||
const Alembic::AbcGeom::UInt32ArraySamplePtr &indices)
|
||||
{
|
||||
MPoly *mpolys = config.mpoly;
|
||||
MLoopUV *mloopuvs = static_cast<MLoopUV *>(data);
|
||||
|
||||
unsigned int uv_index, loop_index;
|
||||
|
||||
for (int i = 0; i < config.totpoly; ++i) {
|
||||
MPoly &poly = mpolys[i];
|
||||
|
||||
for (int f = 0; f < poly.totloop; ++f) {
|
||||
loop_index = poly.loopstart + f;
|
||||
uv_index = (*indices)[loop_index];
|
||||
const Imath::V2f &uv = (*uvs)[uv_index];
|
||||
|
||||
MLoopUV &loopuv = mloopuvs[loop_index];
|
||||
loopuv.uv[0] = uv[0];
|
||||
loopuv.uv[1] = uv[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void read_custom_data_ex(const ICompoundProperty &prop,
|
||||
const PropertyHeader &prop_header,
|
||||
const CDStreamConfig &config,
|
||||
const Alembic::Abc::ISampleSelector &iss,
|
||||
int data_type)
|
||||
{
|
||||
if (data_type == CD_MLOOPCOL) {
|
||||
C3fArraySamplePtr c3f_ptr = C3fArraySamplePtr();
|
||||
C4fArraySamplePtr c4f_ptr = C4fArraySamplePtr();
|
||||
|
||||
if (IC3fGeomParam::matches(prop_header)) {
|
||||
IC3fGeomParam color_param(prop, prop_header.getName());
|
||||
IC3fGeomParam::Sample sample;
|
||||
color_param.getIndexed(sample, iss);
|
||||
|
||||
c3f_ptr = sample.getVals();
|
||||
}
|
||||
else if (IC4fGeomParam::matches(prop_header)) {
|
||||
IC4fGeomParam color_param(prop, prop_header.getName());
|
||||
IC4fGeomParam::Sample sample;
|
||||
color_param.getIndexed(sample, iss);
|
||||
|
||||
c4f_ptr = sample.getVals();
|
||||
}
|
||||
|
||||
void *cd_data = config.add_customdata_cb(config.user_data,
|
||||
prop_header.getName().c_str(),
|
||||
data_type);
|
||||
|
||||
read_mcols(config, cd_data, c3f_ptr, c4f_ptr);
|
||||
}
|
||||
else if (data_type == CD_MLOOPUV) {
|
||||
IV2fGeomParam uv_param(prop, prop_header.getName());
|
||||
IV2fGeomParam::Sample sample;
|
||||
uv_param.getIndexed(sample, iss);
|
||||
|
||||
if (uv_param.getScope() != kFacevaryingScope) {
|
||||
return;
|
||||
}
|
||||
|
||||
void *cd_data = config.add_customdata_cb(config.user_data,
|
||||
prop_header.getName().c_str(),
|
||||
data_type);
|
||||
|
||||
read_uvs(config, cd_data, sample.getVals(), sample.getIndices());
|
||||
}
|
||||
}
|
||||
|
||||
void read_custom_data(const ICompoundProperty &prop, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss)
|
||||
{
|
||||
if (!prop.valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int num_uvs = 0;
|
||||
int num_colors = 0;
|
||||
|
||||
const size_t num_props = prop.getNumProperties();
|
||||
|
||||
for (size_t i = 0; i < num_props; ++i) {
|
||||
const Alembic::Abc::PropertyHeader &prop_header = prop.getPropertyHeader(i);
|
||||
|
||||
/* Read UVs according to convention. */
|
||||
if (IV2fGeomParam::matches(prop_header) && Alembic::AbcGeom::isUV(prop_header)) {
|
||||
if (++num_uvs > MAX_MTFACE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
read_custom_data_ex(prop, prop_header, config, iss, CD_MLOOPUV);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Read vertex colors according to convention. */
|
||||
if (IC3fGeomParam::matches(prop_header) || IC4fGeomParam::matches(prop_header)) {
|
||||
if (++num_colors > MAX_MCOL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
read_custom_data_ex(prop, prop_header, config, iss, CD_MLOOPCOL);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
93
source/blender/alembic/intern/abc_customdata.h
Normal file
93
source/blender/alembic/intern/abc_customdata.h
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Kévin Dietrich.
|
||||
* All rights reserved.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ABC_CUSTOMDATA_H__
|
||||
#define __ABC_CUSTOMDATA_H__
|
||||
|
||||
#include <Alembic/Abc/All.h>
|
||||
|
||||
struct CustomData;
|
||||
struct MLoop;
|
||||
struct MLoopUV;
|
||||
struct MPoly;
|
||||
struct MVert;
|
||||
|
||||
using Alembic::Abc::ICompoundProperty;
|
||||
using Alembic::Abc::OCompoundProperty;
|
||||
|
||||
struct UVSample {
|
||||
std::vector<Imath::V2f> uvs;
|
||||
std::vector<uint32_t> indices;
|
||||
};
|
||||
|
||||
struct CDStreamConfig {
|
||||
MLoop *mloop;
|
||||
int totloop;
|
||||
|
||||
MPoly *mpoly;
|
||||
int totpoly;
|
||||
|
||||
MVert *mvert;
|
||||
int totvert;
|
||||
|
||||
MLoopUV *mloopuv;
|
||||
|
||||
CustomData *loopdata;
|
||||
|
||||
bool pack_uvs;
|
||||
|
||||
/* TODO(kevin): might need a better way to handle adding and/or updating
|
||||
* custom datas such that it updates the custom data holder and its pointers
|
||||
* properly. */
|
||||
void *user_data;
|
||||
void *(*add_customdata_cb)(void *user_data, const char *name, int data_type);
|
||||
|
||||
CDStreamConfig()
|
||||
: mloop(NULL)
|
||||
, totloop(0)
|
||||
, mpoly(NULL)
|
||||
, totpoly(0)
|
||||
, totvert(0)
|
||||
, pack_uvs(false)
|
||||
, user_data(NULL)
|
||||
, add_customdata_cb(NULL)
|
||||
{}
|
||||
};
|
||||
|
||||
/* Get the UVs for the main UV property on a OSchema.
|
||||
* Returns the name of the UV layer.
|
||||
*
|
||||
* For now the active layer is used, maybe needs a better way to choose this. */
|
||||
const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, CustomData *data);
|
||||
|
||||
void write_custom_data(const OCompoundProperty &prop,
|
||||
const CDStreamConfig &config,
|
||||
CustomData *data,
|
||||
int data_type);
|
||||
|
||||
void read_custom_data(const ICompoundProperty &prop,
|
||||
const CDStreamConfig &config,
|
||||
const Alembic::Abc::ISampleSelector &iss);
|
||||
|
||||
#endif /* __ABC_CUSTOMDATA_H__ */
|
600
source/blender/alembic/intern/abc_exporter.cc
Normal file
600
source/blender/alembic/intern/abc_exporter.cc
Normal file
@ -0,0 +1,600 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "abc_exporter.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#ifdef WITH_ALEMBIC_HDF5
|
||||
# include <Alembic/AbcCoreHDF5/All.h>
|
||||
#endif
|
||||
|
||||
#include <Alembic/AbcCoreOgawa/All.h>
|
||||
|
||||
#include "abc_camera.h"
|
||||
#include "abc_curves.h"
|
||||
#include "abc_hair.h"
|
||||
#include "abc_mesh.h"
|
||||
#include "abc_nurbs.h"
|
||||
#include "abc_points.h"
|
||||
#include "abc_transform.h"
|
||||
#include "abc_util.h"
|
||||
|
||||
extern "C" {
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_space_types.h" /* for FILE_MAX */
|
||||
|
||||
#include "BLI_string.h"
|
||||
|
||||
#ifdef WIN32
|
||||
/* needed for MSCV because of snprintf from BLI_string */
|
||||
# include "BLI_winstuff.h"
|
||||
#endif
|
||||
|
||||
#include "BKE_anim.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_idprop.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_particle.h"
|
||||
#include "BKE_scene.h"
|
||||
}
|
||||
|
||||
using Alembic::Abc::TimeSamplingPtr;
|
||||
using Alembic::Abc::OBox3dProperty;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
ExportSettings::ExportSettings()
|
||||
: scene(NULL)
|
||||
, selected_only(false)
|
||||
, visible_layers_only(false)
|
||||
, renderable_only(false)
|
||||
, frame_start(1)
|
||||
, frame_end(1)
|
||||
, frame_step_xform(1)
|
||||
, frame_step_shape(1)
|
||||
, shutter_open(0.0)
|
||||
, shutter_close(1.0)
|
||||
, global_scale(1.0f)
|
||||
, flatten_hierarchy(false)
|
||||
, export_normals(false)
|
||||
, export_uvs(false)
|
||||
, export_vcols(false)
|
||||
, export_face_sets(false)
|
||||
, export_vweigths(false)
|
||||
, apply_subdiv(false)
|
||||
, use_subdiv_schema(false)
|
||||
, export_child_hairs(true)
|
||||
, export_ogawa(true)
|
||||
, pack_uv(false)
|
||||
, do_convert_axis(false)
|
||||
{}
|
||||
|
||||
static bool object_is_smoke_sim(Object *ob)
|
||||
{
|
||||
ModifierData *md = modifiers_findByType(ob, eModifierType_Smoke);
|
||||
|
||||
if (md) {
|
||||
SmokeModifierData *smd = reinterpret_cast<SmokeModifierData *>(md);
|
||||
return (smd->type == MOD_SMOKE_TYPE_DOMAIN);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool object_is_shape(Object *ob)
|
||||
{
|
||||
switch (ob->type) {
|
||||
case OB_MESH:
|
||||
if (object_is_smoke_sim(ob)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
case OB_CURVE:
|
||||
case OB_SURF:
|
||||
case OB_CAMERA:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool export_object(const ExportSettings * const settings, Object *ob)
|
||||
{
|
||||
if (settings->selected_only && !parent_selected(ob)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (settings->visible_layers_only && !(settings->scene->lay & ob->lay)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (settings->renderable_only && (ob->restrictflag & OB_RESTRICT_RENDER)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcExporter::AbcExporter(Scene *scene, const char *filename, ExportSettings &settings)
|
||||
: m_settings(settings)
|
||||
, m_filename(filename)
|
||||
, m_trans_sampling_index(0)
|
||||
, m_shape_sampling_index(0)
|
||||
, m_scene(scene)
|
||||
{}
|
||||
|
||||
AbcExporter::~AbcExporter()
|
||||
{
|
||||
std::map<std::string, AbcTransformWriter*>::iterator it, e;
|
||||
for (it = m_xforms.begin(), e = m_xforms.end(); it != e; ++it) {
|
||||
delete it->second;
|
||||
}
|
||||
|
||||
for (int i = 0, e = m_shapes.size(); i != e; ++i) {
|
||||
delete m_shapes[i];
|
||||
}
|
||||
}
|
||||
|
||||
void AbcExporter::getShutterSamples(double step, bool time_relative,
|
||||
std::vector<double> &samples)
|
||||
{
|
||||
samples.clear();
|
||||
|
||||
const double time_factor = time_relative ? m_scene->r.frs_sec : 1.0;
|
||||
const double shutter_open = m_settings.shutter_open;
|
||||
const double shutter_close = m_settings.shutter_close;
|
||||
|
||||
/* sample all frame */
|
||||
if (shutter_open == 0.0 && shutter_close == 1.0) {
|
||||
for (double t = 0; t < 1.0; t += step) {
|
||||
samples.push_back(t / time_factor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* sample between shutter open & close */
|
||||
const int nsamples = std::max((1.0 / step) - 1.0, 1.0);
|
||||
const double time_inc = (shutter_close - shutter_open) / nsamples;
|
||||
|
||||
for (double t = shutter_open; t <= shutter_close; t += time_inc) {
|
||||
samples.push_back(t / time_factor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Alembic::Abc::TimeSamplingPtr AbcExporter::createTimeSampling(double step)
|
||||
{
|
||||
TimeSamplingPtr time_sampling;
|
||||
std::vector<double> samples;
|
||||
|
||||
if (m_settings.frame_start == m_settings.frame_end) {
|
||||
time_sampling.reset(new Alembic::Abc::TimeSampling());
|
||||
return time_sampling;
|
||||
}
|
||||
|
||||
getShutterSamples(step, true, samples);
|
||||
|
||||
Alembic::Abc::TimeSamplingType ts(static_cast<uint32_t>(samples.size()), 1.0 / m_scene->r.frs_sec);
|
||||
time_sampling.reset(new Alembic::Abc::TimeSampling(ts, samples));
|
||||
|
||||
return time_sampling;
|
||||
}
|
||||
|
||||
void AbcExporter::getFrameSet(double step, std::set<double> &frames)
|
||||
{
|
||||
frames.clear();
|
||||
|
||||
std::vector<double> shutter_samples;
|
||||
|
||||
getShutterSamples(step, false, shutter_samples);
|
||||
|
||||
for (int frame = m_settings.frame_start; frame <= m_settings.frame_end; ++frame) {
|
||||
for (int j = 0, e = shutter_samples.size(); j < e; ++j) {
|
||||
frames.insert(frame + shutter_samples[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled)
|
||||
{
|
||||
std::string scene_name;
|
||||
|
||||
if (bmain->name[0] != '\0') {
|
||||
char scene_file_name[FILE_MAX];
|
||||
BLI_strncpy(scene_file_name, bmain->name, FILE_MAX);
|
||||
scene_name = scene_file_name;
|
||||
}
|
||||
else {
|
||||
scene_name = "untitled";
|
||||
}
|
||||
|
||||
Scene *scene = m_scene;
|
||||
const int fps = FPS;
|
||||
char buf[16];
|
||||
snprintf(buf, 15, "%d", fps);
|
||||
const std::string str_fps = buf;
|
||||
|
||||
Alembic::AbcCoreAbstract::MetaData md;
|
||||
md.set("FramesPerTimeUnit", str_fps);
|
||||
|
||||
Alembic::Abc::Argument arg(md);
|
||||
|
||||
#ifdef WITH_ALEMBIC_HDF5
|
||||
if (!m_settings.export_ogawa) {
|
||||
m_archive = Alembic::Abc::CreateArchiveWithInfo(Alembic::AbcCoreHDF5::WriteArchive(),
|
||||
m_filename,
|
||||
"Blender",
|
||||
scene_name,
|
||||
Alembic::Abc::ErrorHandler::kThrowPolicy,
|
||||
arg);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
m_archive = Alembic::Abc::CreateArchiveWithInfo(Alembic::AbcCoreOgawa::WriteArchive(),
|
||||
m_filename,
|
||||
"Blender",
|
||||
scene_name,
|
||||
Alembic::Abc::ErrorHandler::kThrowPolicy,
|
||||
arg);
|
||||
}
|
||||
|
||||
/* Create time samplings for transforms and shapes. */
|
||||
|
||||
TimeSamplingPtr trans_time = createTimeSampling(m_settings.frame_step_xform);
|
||||
|
||||
m_trans_sampling_index = m_archive.addTimeSampling(*trans_time);
|
||||
|
||||
TimeSamplingPtr shape_time;
|
||||
|
||||
if ((m_settings.frame_step_shape == m_settings.frame_step_xform) ||
|
||||
(m_settings.frame_start == m_settings.frame_end))
|
||||
{
|
||||
shape_time = trans_time;
|
||||
m_shape_sampling_index = m_trans_sampling_index;
|
||||
}
|
||||
else {
|
||||
shape_time = createTimeSampling(m_settings.frame_step_shape);
|
||||
m_shape_sampling_index = m_archive.addTimeSampling(*shape_time);
|
||||
}
|
||||
|
||||
OBox3dProperty archive_bounds_prop = Alembic::AbcGeom::CreateOArchiveBounds(m_archive, m_trans_sampling_index);
|
||||
|
||||
if (m_settings.flatten_hierarchy) {
|
||||
createTransformWritersFlat();
|
||||
}
|
||||
else {
|
||||
createTransformWritersHierarchy(bmain->eval_ctx);
|
||||
}
|
||||
|
||||
createShapeWriters(bmain->eval_ctx);
|
||||
|
||||
/* Make a list of frames to export. */
|
||||
|
||||
std::set<double> xform_frames;
|
||||
getFrameSet(m_settings.frame_step_xform, xform_frames);
|
||||
|
||||
std::set<double> shape_frames;
|
||||
getFrameSet(m_settings.frame_step_shape, shape_frames);
|
||||
|
||||
/* Merge all frames needed. */
|
||||
|
||||
std::set<double> frames(xform_frames);
|
||||
frames.insert(shape_frames.begin(), shape_frames.end());
|
||||
|
||||
/* Export all frames. */
|
||||
|
||||
std::set<double>::const_iterator begin = frames.begin();
|
||||
std::set<double>::const_iterator end = frames.end();
|
||||
|
||||
const float size = static_cast<float>(frames.size());
|
||||
size_t i = 0;
|
||||
|
||||
for (; begin != end; ++begin) {
|
||||
progress = (++i / size);
|
||||
|
||||
if (G.is_break) {
|
||||
was_canceled = true;
|
||||
break;
|
||||
}
|
||||
|
||||
double f = *begin;
|
||||
setCurrentFrame(bmain, f);
|
||||
|
||||
if (shape_frames.count(f) != 0) {
|
||||
for (int i = 0, e = m_shapes.size(); i != e; ++i) {
|
||||
m_shapes[i]->write();
|
||||
}
|
||||
}
|
||||
|
||||
if (xform_frames.count(f) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::map<std::string, AbcTransformWriter *>::iterator xit, xe;
|
||||
for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) {
|
||||
xit->second->write();
|
||||
}
|
||||
|
||||
/* Save the archive 's bounding box. */
|
||||
Imath::Box3d bounds;
|
||||
|
||||
for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) {
|
||||
Imath::Box3d box = xit->second->bounds();
|
||||
bounds.extendBy(box);
|
||||
}
|
||||
|
||||
archive_bounds_prop.set(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
void AbcExporter::createTransformWritersHierarchy(EvaluationContext *eval_ctx)
|
||||
{
|
||||
Base *base = static_cast<Base *>(m_scene->base.first);
|
||||
|
||||
while (base) {
|
||||
Object *ob = base->object;
|
||||
|
||||
if (export_object(&m_settings, ob)) {
|
||||
switch(ob->type) {
|
||||
case OB_LAMP:
|
||||
case OB_LATTICE:
|
||||
case OB_MBALL:
|
||||
case OB_SPEAKER:
|
||||
/* We do not export transforms for objects of these classes. */
|
||||
break;
|
||||
|
||||
default:
|
||||
exploreTransform(eval_ctx, ob, ob->parent, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
base = base->next;
|
||||
}
|
||||
}
|
||||
|
||||
void AbcExporter::createTransformWritersFlat()
|
||||
{
|
||||
Base *base = static_cast<Base *>(m_scene->base.first);
|
||||
|
||||
while (base) {
|
||||
Object *ob = base->object;
|
||||
|
||||
if (export_object(&m_settings, ob) && object_is_shape(ob)) {
|
||||
std::string name = get_id_name(ob);
|
||||
m_xforms[name] = new AbcTransformWriter(ob, m_archive.getTop(), 0, m_trans_sampling_index, m_settings);
|
||||
}
|
||||
|
||||
base = base->next;
|
||||
}
|
||||
}
|
||||
|
||||
void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent)
|
||||
{
|
||||
createTransformWriter(ob, parent, dupliObParent);
|
||||
|
||||
ListBase *lb = object_duplilist(eval_ctx, m_scene, ob);
|
||||
|
||||
if (lb) {
|
||||
DupliObject *link = static_cast<DupliObject *>(lb->first);
|
||||
Object *dupli_ob = NULL;
|
||||
Object *dupli_parent = NULL;
|
||||
|
||||
while (link) {
|
||||
if (link->type == OB_DUPLIGROUP) {
|
||||
dupli_ob = link->ob;
|
||||
dupli_parent = (dupli_ob->parent) ? dupli_ob->parent : ob;
|
||||
|
||||
exploreTransform(eval_ctx, dupli_ob, dupli_parent, ob);
|
||||
}
|
||||
|
||||
link = link->next;
|
||||
}
|
||||
}
|
||||
|
||||
free_object_duplilist(lb);
|
||||
}
|
||||
|
||||
void AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupliObParent)
|
||||
{
|
||||
const std::string name = get_object_dag_path_name(ob, dupliObParent);
|
||||
|
||||
/* check if we have already created a transform writer for this object */
|
||||
if (m_xforms.find(name) != m_xforms.end()){
|
||||
std::cerr << "xform " << name << " already exists\n";
|
||||
return;
|
||||
}
|
||||
|
||||
AbcTransformWriter *parent_xform = NULL;
|
||||
|
||||
if (parent) {
|
||||
const std::string parentname = get_object_dag_path_name(parent, dupliObParent);
|
||||
parent_xform = getXForm(parentname);
|
||||
|
||||
if (!parent_xform) {
|
||||
if (parent->parent) {
|
||||
createTransformWriter(parent, parent->parent, dupliObParent);
|
||||
}
|
||||
else {
|
||||
createTransformWriter(parent, dupliObParent, dupliObParent);
|
||||
}
|
||||
|
||||
parent_xform = getXForm(parentname);
|
||||
}
|
||||
}
|
||||
|
||||
if (parent_xform) {
|
||||
m_xforms[name] = new AbcTransformWriter(ob, parent_xform->alembicXform(), parent_xform, m_trans_sampling_index, m_settings);
|
||||
m_xforms[name]->setParent(parent);
|
||||
}
|
||||
else {
|
||||
m_xforms[name] = new AbcTransformWriter(ob, m_archive.getTop(), NULL, m_trans_sampling_index, m_settings);
|
||||
}
|
||||
}
|
||||
|
||||
void AbcExporter::createShapeWriters(EvaluationContext *eval_ctx)
|
||||
{
|
||||
Base *base = static_cast<Base *>(m_scene->base.first);
|
||||
|
||||
while (base) {
|
||||
Object *ob = base->object;
|
||||
exploreObject(eval_ctx, ob, NULL);
|
||||
|
||||
base = base->next;
|
||||
}
|
||||
}
|
||||
|
||||
void AbcExporter::exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent)
|
||||
{
|
||||
ListBase *lb = object_duplilist(eval_ctx, m_scene, ob);
|
||||
|
||||
createShapeWriter(ob, dupliObParent);
|
||||
|
||||
if (lb) {
|
||||
DupliObject *dupliob = static_cast<DupliObject *>(lb->first);
|
||||
|
||||
while (dupliob) {
|
||||
if (dupliob->type == OB_DUPLIGROUP) {
|
||||
exploreObject(eval_ctx, dupliob->ob, ob);
|
||||
}
|
||||
|
||||
dupliob = dupliob->next;
|
||||
}
|
||||
}
|
||||
|
||||
free_object_duplilist(lb);
|
||||
}
|
||||
|
||||
void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent)
|
||||
{
|
||||
if (!object_is_shape(ob)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!export_object(&m_settings, ob)) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string name;
|
||||
|
||||
if (m_settings.flatten_hierarchy) {
|
||||
name = get_id_name(ob);
|
||||
}
|
||||
else {
|
||||
name = get_object_dag_path_name(ob, dupliObParent);
|
||||
}
|
||||
|
||||
AbcTransformWriter *xform = getXForm(name);
|
||||
|
||||
if (!xform) {
|
||||
std::cerr << __func__ << ": xform " << name << " is NULL\n";
|
||||
return;
|
||||
}
|
||||
|
||||
ParticleSystem *psys = static_cast<ParticleSystem *>(ob->particlesystem.first);
|
||||
|
||||
for (; psys; psys = psys->next) {
|
||||
if (!psys_check_enabled(ob, psys, G.is_rendering) || !psys->part) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (psys->part->type == PART_HAIR) {
|
||||
m_settings.export_child_hairs = true;
|
||||
m_shapes.push_back(new AbcHairWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys));
|
||||
}
|
||||
else if (psys->part->type == PART_EMITTER) {
|
||||
m_shapes.push_back(new AbcPointsWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys));
|
||||
}
|
||||
}
|
||||
|
||||
switch(ob->type) {
|
||||
case OB_MESH:
|
||||
{
|
||||
Mesh *me = static_cast<Mesh *>(ob->data);
|
||||
|
||||
if (!me || me->totvert == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_shapes.push_back(new AbcMeshWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
|
||||
break;
|
||||
}
|
||||
case OB_SURF:
|
||||
{
|
||||
Curve *cu = static_cast<Curve *>(ob->data);
|
||||
|
||||
if (!cu) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_shapes.push_back(new AbcNurbsWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
|
||||
break;
|
||||
}
|
||||
case OB_CURVE:
|
||||
{
|
||||
Curve *cu = static_cast<Curve *>(ob->data);
|
||||
|
||||
if (!cu) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_shapes.push_back(new AbcCurveWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
|
||||
break;
|
||||
}
|
||||
case OB_CAMERA:
|
||||
{
|
||||
Camera *cam = static_cast<Camera *>(ob->data);
|
||||
|
||||
if (cam->type == CAM_PERSP) {
|
||||
m_shapes.push_back(new AbcCameraWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AbcTransformWriter *AbcExporter::getXForm(const std::string &name)
|
||||
{
|
||||
std::map<std::string, AbcTransformWriter *>::iterator it = m_xforms.find(name);
|
||||
|
||||
if (it == m_xforms.end()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void AbcExporter::setCurrentFrame(Main *bmain, double t)
|
||||
{
|
||||
m_scene->r.cfra = std::floor(t);
|
||||
m_scene->r.subframe = t - m_scene->r.cfra;
|
||||
BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, m_scene, m_scene->lay);
|
||||
}
|
112
source/blender/alembic/intern/abc_exporter.h
Normal file
112
source/blender/alembic/intern/abc_exporter.h
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __ABC_EXPORTER_H__
|
||||
#define __ABC_EXPORTER_H__
|
||||
|
||||
#include <Alembic/Abc/All.h>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
class AbcObjectWriter;
|
||||
class AbcTransformWriter;
|
||||
|
||||
struct EvaluationContext;
|
||||
struct Main;
|
||||
struct Object;
|
||||
struct Scene;
|
||||
|
||||
struct ExportSettings {
|
||||
ExportSettings();
|
||||
|
||||
Scene *scene;
|
||||
|
||||
bool selected_only;
|
||||
bool visible_layers_only;
|
||||
bool renderable_only;
|
||||
|
||||
double frame_start, frame_end;
|
||||
double frame_step_xform;
|
||||
double frame_step_shape;
|
||||
double shutter_open;
|
||||
double shutter_close;
|
||||
float global_scale;
|
||||
|
||||
bool flatten_hierarchy;
|
||||
|
||||
bool export_normals;
|
||||
bool export_uvs;
|
||||
bool export_vcols;
|
||||
bool export_face_sets;
|
||||
bool export_vweigths;
|
||||
|
||||
bool apply_subdiv;
|
||||
bool use_subdiv_schema;
|
||||
bool export_child_hairs;
|
||||
bool export_ogawa;
|
||||
bool pack_uv;
|
||||
|
||||
bool do_convert_axis;
|
||||
float convert_matrix[3][3];
|
||||
};
|
||||
|
||||
class AbcExporter {
|
||||
ExportSettings &m_settings;
|
||||
|
||||
const char *m_filename;
|
||||
|
||||
Alembic::Abc::OArchive m_archive;
|
||||
unsigned int m_trans_sampling_index, m_shape_sampling_index;
|
||||
|
||||
Scene *m_scene;
|
||||
|
||||
std::map<std::string, AbcTransformWriter *> m_xforms;
|
||||
std::vector<AbcObjectWriter *> m_shapes;
|
||||
|
||||
public:
|
||||
AbcExporter(Scene *scene, const char *filename, ExportSettings &settings);
|
||||
~AbcExporter();
|
||||
|
||||
void operator()(Main *bmain, float &progress, bool &was_canceled);
|
||||
|
||||
private:
|
||||
void getShutterSamples(double step, bool time_relative, std::vector<double> &samples);
|
||||
|
||||
Alembic::Abc::TimeSamplingPtr createTimeSampling(double step);
|
||||
|
||||
void getFrameSet(double step, std::set<double> &frames);
|
||||
|
||||
void createTransformWritersHierarchy(EvaluationContext *eval_ctx);
|
||||
void createTransformWritersFlat();
|
||||
void createTransformWriter(Object *ob, Object *parent, Object *dupliObParent);
|
||||
void exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent = NULL);
|
||||
void exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent);
|
||||
void createShapeWriters(EvaluationContext *eval_ctx);
|
||||
void createShapeWriter(Object *ob, Object *dupliObParent);
|
||||
|
||||
AbcTransformWriter *getXForm(const std::string &name);
|
||||
|
||||
void setCurrentFrame(Main *bmain, double t);
|
||||
};
|
||||
|
||||
#endif /* __ABC_EXPORTER_H__ */
|
290
source/blender/alembic/intern/abc_hair.cc
Normal file
290
source/blender/alembic/intern/abc_hair.cc
Normal file
@ -0,0 +1,290 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "abc_hair.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include "abc_transform.h"
|
||||
#include "abc_util.h"
|
||||
|
||||
extern "C" {
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_modifier_types.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_geom.h"
|
||||
|
||||
#include "BKE_DerivedMesh.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_particle.h"
|
||||
}
|
||||
|
||||
using Alembic::Abc::P3fArraySamplePtr;
|
||||
|
||||
using Alembic::AbcGeom::OCurves;
|
||||
using Alembic::AbcGeom::OCurvesSchema;
|
||||
using Alembic::AbcGeom::ON3fGeomParam;
|
||||
using Alembic::AbcGeom::OV2fGeomParam;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcHairWriter::AbcHairWriter(Scene *scene,
|
||||
Object *ob,
|
||||
AbcTransformWriter *parent,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings,
|
||||
ParticleSystem *psys)
|
||||
: AbcObjectWriter(scene, ob, time_sampling, settings, parent)
|
||||
{
|
||||
m_psys = psys;
|
||||
|
||||
OCurves curves(parent->alembicXform(), m_name, m_time_sampling);
|
||||
m_schema = curves.getSchema();
|
||||
}
|
||||
|
||||
void AbcHairWriter::do_write()
|
||||
{
|
||||
if (!m_psys) {
|
||||
return;
|
||||
}
|
||||
|
||||
ParticleSystemModifierData *psmd = psys_get_modifier(m_object, m_psys);
|
||||
|
||||
if (!psmd->dm_final) {
|
||||
return;
|
||||
}
|
||||
|
||||
DerivedMesh *dm = mesh_create_derived_view(m_scene, m_object, CD_MASK_MESH);
|
||||
DM_ensure_tessface(dm);
|
||||
DM_update_tessface_data(dm);
|
||||
|
||||
std::vector<Imath::V3f> verts;
|
||||
std::vector<int32_t> hvertices;
|
||||
std::vector<Imath::V2f> uv_values;
|
||||
std::vector<Imath::V3f> norm_values;
|
||||
|
||||
if (m_psys->pathcache) {
|
||||
ParticleSettings *part = m_psys->part;
|
||||
|
||||
write_hair_sample(dm, part, verts, norm_values, uv_values, hvertices);
|
||||
|
||||
if (m_settings.export_child_hairs && m_psys->childcache) {
|
||||
write_hair_child_sample(dm, part, verts, norm_values, uv_values, hvertices);
|
||||
}
|
||||
}
|
||||
|
||||
dm->release(dm);
|
||||
|
||||
Alembic::Abc::P3fArraySample iPos(verts);
|
||||
m_sample = OCurvesSchema::Sample(iPos, hvertices);
|
||||
m_sample.setBasis(Alembic::AbcGeom::kNoBasis);
|
||||
m_sample.setType(Alembic::AbcGeom::kLinear);
|
||||
m_sample.setWrap(Alembic::AbcGeom::kNonPeriodic);
|
||||
|
||||
if (!uv_values.empty()) {
|
||||
OV2fGeomParam::Sample uv_smp;
|
||||
uv_smp.setVals(uv_values);
|
||||
m_sample.setUVs(uv_smp);
|
||||
}
|
||||
|
||||
if (!norm_values.empty()) {
|
||||
ON3fGeomParam::Sample norm_smp;
|
||||
norm_smp.setVals(norm_values);
|
||||
m_sample.setNormals(norm_smp);
|
||||
}
|
||||
|
||||
m_sample.setSelfBounds(bounds());
|
||||
m_schema.set(m_sample);
|
||||
}
|
||||
|
||||
void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
|
||||
ParticleSettings *part,
|
||||
std::vector<Imath::V3f> &verts,
|
||||
std::vector<Imath::V3f> &norm_values,
|
||||
std::vector<Imath::V2f> &uv_values,
|
||||
std::vector<int32_t> &hvertices)
|
||||
{
|
||||
/* Get untransformed vertices, there's a xform under the hair. */
|
||||
float inv_mat[4][4];
|
||||
invert_m4_m4_safe(inv_mat, m_object->obmat);
|
||||
|
||||
MTFace *mtface = static_cast<MTFace *>(CustomData_get_layer(&dm->faceData, CD_MTFACE));
|
||||
MFace *mface = dm->getTessFaceArray(dm);
|
||||
MVert *mverts = dm->getVertArray(dm);
|
||||
|
||||
if (!mtface || !mface) {
|
||||
std::fprintf(stderr, "Warning, no UV set found for underlying geometry.\n");
|
||||
}
|
||||
|
||||
ParticleData * pa = m_psys->particles;
|
||||
int k;
|
||||
|
||||
ParticleCacheKey **cache = m_psys->pathcache;
|
||||
ParticleCacheKey *path;
|
||||
float normal[3];
|
||||
Imath::V3f tmp_nor;
|
||||
|
||||
for (int p = 0; p < m_psys->totpart; ++p, ++pa) {
|
||||
/* underlying info for faces-only emission */
|
||||
path = cache[p];
|
||||
|
||||
if (part->from == PART_FROM_FACE && mtface) {
|
||||
const int num = pa->num_dmcache >= 0 ? pa->num_dmcache : pa->num;
|
||||
|
||||
if (num < dm->getNumTessFaces(dm)) {
|
||||
MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, num, CD_MFACE));
|
||||
MTFace *tface = mtface + num;
|
||||
|
||||
if (mface) {
|
||||
float r_uv[2], mapfw[4], vec[3];
|
||||
|
||||
psys_interpolate_uvs(tface, face->v4, pa->fuv, r_uv);
|
||||
uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1]));
|
||||
|
||||
psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, normal, NULL, NULL, NULL, NULL);
|
||||
|
||||
copy_zup_yup(tmp_nor.getValue(), normal);
|
||||
norm_values.push_back(tmp_nor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::fprintf(stderr, "Particle to faces overflow (%d/%d)\n", num, dm->getNumTessFaces(dm));
|
||||
}
|
||||
}
|
||||
else if (part->from == PART_FROM_VERT && mtface) {
|
||||
/* vertex id */
|
||||
const int num = (pa->num_dmcache >= 0) ? pa->num_dmcache : pa->num;
|
||||
|
||||
/* iterate over all faces to find a corresponding underlying UV */
|
||||
for (int n = 0; n < dm->getNumTessFaces(dm); ++n) {
|
||||
MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, n, CD_MFACE));
|
||||
MTFace *tface = mtface + n;
|
||||
unsigned int vtx[4];
|
||||
vtx[0] = face->v1;
|
||||
vtx[1] = face->v2;
|
||||
vtx[2] = face->v3;
|
||||
vtx[3] = face->v4;
|
||||
bool found = false;
|
||||
|
||||
for (int o = 0; o < 4; ++o) {
|
||||
if (o > 2 && vtx[o] == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (vtx[o] == num) {
|
||||
uv_values.push_back(Imath::V2f(tface->uv[o][0], tface->uv[o][1]));
|
||||
|
||||
MVert *mv = mverts + vtx[o];
|
||||
|
||||
normal_short_to_float_v3(normal, mv->no);
|
||||
copy_zup_yup(tmp_nor.getValue(), normal);
|
||||
norm_values.push_back(tmp_nor);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int steps = path->segments + 1;
|
||||
hvertices.push_back(steps);
|
||||
|
||||
for (k = 0; k < steps; ++k) {
|
||||
float vert[3];
|
||||
copy_v3_v3(vert, path->co);
|
||||
mul_m4_v3(inv_mat, vert);
|
||||
|
||||
/* Convert Z-up to Y-up. */
|
||||
verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1]));
|
||||
|
||||
++path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AbcHairWriter::write_hair_child_sample(DerivedMesh *dm,
|
||||
ParticleSettings *part,
|
||||
std::vector<Imath::V3f> &verts,
|
||||
std::vector<Imath::V3f> &norm_values,
|
||||
std::vector<Imath::V2f> &uv_values,
|
||||
std::vector<int32_t> &hvertices)
|
||||
{
|
||||
/* Get untransformed vertices, there's a xform under the hair. */
|
||||
float inv_mat[4][4];
|
||||
invert_m4_m4_safe(inv_mat, m_object->obmat);
|
||||
|
||||
MTFace *mtface = static_cast<MTFace *>(CustomData_get_layer(&dm->faceData, CD_MTFACE));
|
||||
MFace *mface = dm->getTessFaceArray(dm);
|
||||
MVert *mverts = dm->getVertArray(dm);
|
||||
|
||||
if (!mtface || !mface) {
|
||||
std::fprintf(stderr, "Warning, no UV set found for underlying geometry.\n");
|
||||
}
|
||||
|
||||
ParticleCacheKey **cache = m_psys->childcache;
|
||||
ParticleCacheKey *path;
|
||||
|
||||
ChildParticle *pc = m_psys->child;
|
||||
|
||||
for (int p = 0; p < m_psys->totchild; ++p, ++pc) {
|
||||
path = cache[p];
|
||||
|
||||
if (part->from == PART_FROM_FACE) {
|
||||
const int num = pc->num;
|
||||
|
||||
MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, num, CD_MFACE));
|
||||
MTFace *tface = mtface + num;
|
||||
|
||||
if (mface && mtface) {
|
||||
float r_uv[2], tmpnor[3], mapfw[4], vec[3];
|
||||
|
||||
psys_interpolate_uvs(tface, face->v4, pc->fuv, r_uv);
|
||||
uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1]));
|
||||
|
||||
psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, tmpnor, NULL, NULL, NULL, NULL);
|
||||
|
||||
/* Convert Z-up to Y-up. */
|
||||
norm_values.push_back(Imath::V3f(tmpnor[0], tmpnor[2], -tmpnor[1]));
|
||||
}
|
||||
}
|
||||
|
||||
int steps = path->segments + 1;
|
||||
hvertices.push_back(steps);
|
||||
|
||||
for (int k = 0; k < steps; ++k) {
|
||||
float vert[3];
|
||||
copy_v3_v3(vert, path->co);
|
||||
mul_m4_v3(inv_mat, vert);
|
||||
|
||||
/* Convert Z-up to Y-up. */
|
||||
verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1]));
|
||||
|
||||
++path;
|
||||
}
|
||||
}
|
||||
}
|
66
source/blender/alembic/intern/abc_hair.h
Normal file
66
source/blender/alembic/intern/abc_hair.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __ABC_HAIR_H__
|
||||
#define __ABC_HAIR_H__
|
||||
|
||||
#include "abc_object.h"
|
||||
|
||||
struct DerivedMesh;
|
||||
struct ParticleSettings;
|
||||
struct ParticleSystem;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcHairWriter : public AbcObjectWriter {
|
||||
ParticleSystem *m_psys;
|
||||
|
||||
Alembic::AbcGeom::OCurvesSchema m_schema;
|
||||
Alembic::AbcGeom::OCurvesSchema::Sample m_sample;
|
||||
|
||||
public:
|
||||
AbcHairWriter(Scene *scene,
|
||||
Object *ob,
|
||||
AbcTransformWriter *parent,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings,
|
||||
ParticleSystem *psys);
|
||||
|
||||
private:
|
||||
virtual void do_write();
|
||||
|
||||
void write_hair_sample(DerivedMesh *dm,
|
||||
ParticleSettings *part,
|
||||
std::vector<Imath::V3f> &verts,
|
||||
std::vector<Imath::V3f> &norm_values,
|
||||
std::vector<Imath::V2f> &uv_values,
|
||||
std::vector<int32_t> &hvertices);
|
||||
|
||||
void write_hair_child_sample(DerivedMesh *dm,
|
||||
ParticleSettings *part,
|
||||
std::vector<Imath::V3f> &verts,
|
||||
std::vector<Imath::V3f> &norm_values,
|
||||
std::vector<Imath::V2f> &uv_values,
|
||||
std::vector<int32_t> &hvertices);
|
||||
};
|
||||
|
||||
#endif /* __ABC_HAIR_H__ */
|
1213
source/blender/alembic/intern/abc_mesh.cc
Normal file
1213
source/blender/alembic/intern/abc_mesh.cc
Normal file
File diff suppressed because it is too large
Load Diff
152
source/blender/alembic/intern/abc_mesh.h
Normal file
152
source/blender/alembic/intern/abc_mesh.h
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __ABC_MESH_H__
|
||||
#define __ABC_MESH_H__
|
||||
|
||||
#include "abc_customdata.h"
|
||||
#include "abc_object.h"
|
||||
|
||||
struct DerivedMesh;
|
||||
struct Mesh;
|
||||
struct ModifierData;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcMeshWriter : public AbcObjectWriter {
|
||||
Alembic::AbcGeom::OPolyMeshSchema m_mesh_schema;
|
||||
Alembic::AbcGeom::OPolyMeshSchema::Sample m_mesh_sample;
|
||||
|
||||
Alembic::AbcGeom::OSubDSchema m_subdiv_schema;
|
||||
Alembic::AbcGeom::OSubDSchema::Sample m_subdiv_sample;
|
||||
|
||||
bool m_has_per_face_materials;
|
||||
Alembic::AbcGeom::OFaceSet m_face_set;
|
||||
Alembic::Abc::OArrayProperty m_mat_indices;
|
||||
|
||||
bool m_is_animated;
|
||||
ModifierData *m_subsurf_mod;
|
||||
|
||||
CDStreamConfig m_custom_data_config;
|
||||
|
||||
bool m_is_liquid;
|
||||
bool m_is_subd;
|
||||
|
||||
public:
|
||||
AbcMeshWriter(Scene *scene,
|
||||
Object *ob,
|
||||
AbcTransformWriter *parent,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings);
|
||||
|
||||
~AbcMeshWriter();
|
||||
|
||||
private:
|
||||
virtual void do_write();
|
||||
|
||||
bool isAnimated() const;
|
||||
|
||||
void writeMesh(DerivedMesh *dm);
|
||||
void writeSubD(DerivedMesh *dm);
|
||||
|
||||
void getMeshInfo(DerivedMesh *dm, std::vector<float> &points,
|
||||
std::vector<int32_t> &facePoints,
|
||||
std::vector<int32_t> &faceCounts,
|
||||
std::vector<int32_t> &creaseIndices,
|
||||
std::vector<int32_t> &creaseLengths,
|
||||
std::vector<float> &creaseSharpness);
|
||||
|
||||
DerivedMesh *getFinalMesh();
|
||||
void freeMesh(DerivedMesh *dm);
|
||||
|
||||
void getMaterialIndices(DerivedMesh *dm, std::vector<int32_t> &indices);
|
||||
|
||||
void writeArbGeoParams(DerivedMesh *dm);
|
||||
void getGeoGroups(DerivedMesh *dm, std::map<std::string, std::vector<int32_t> > &geoGroups);
|
||||
|
||||
/* fluid surfaces support */
|
||||
void getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels);
|
||||
|
||||
template <typename Schema>
|
||||
void writeCommonData(DerivedMesh *dm, Schema &schema);
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcMeshReader : public AbcObjectReader {
|
||||
Alembic::AbcGeom::IPolyMeshSchema m_schema;
|
||||
|
||||
CDStreamConfig m_mesh_data;
|
||||
|
||||
public:
|
||||
AbcMeshReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
|
||||
|
||||
bool valid() const;
|
||||
|
||||
void readObjectData(Main *bmain, float time);
|
||||
|
||||
private:
|
||||
void readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start,
|
||||
const Alembic::AbcGeom::ISampleSelector &sample_sel);
|
||||
};
|
||||
|
||||
void read_mesh_sample(ImportSettings *settings,
|
||||
const Alembic::AbcGeom::IPolyMeshSchema &schema,
|
||||
const Alembic::AbcGeom::ISampleSelector &selector,
|
||||
CDStreamConfig &config,
|
||||
bool &do_normals);
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcSubDReader : public AbcObjectReader {
|
||||
Alembic::AbcGeom::ISubDSchema m_schema;
|
||||
|
||||
CDStreamConfig m_mesh_data;
|
||||
|
||||
public:
|
||||
AbcSubDReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
|
||||
|
||||
bool valid() const;
|
||||
|
||||
void readObjectData(Main *bmain, float time);
|
||||
};
|
||||
|
||||
void read_subd_sample(ImportSettings *settings,
|
||||
const Alembic::AbcGeom::ISubDSchema &schema,
|
||||
const Alembic::AbcGeom::ISampleSelector &selector,
|
||||
CDStreamConfig &config);
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
namespace utils {
|
||||
|
||||
void mesh_add_verts(struct Mesh *mesh, size_t len);
|
||||
|
||||
}
|
||||
|
||||
void read_mverts(MVert *mverts,
|
||||
const Alembic::AbcGeom::P3fArraySamplePtr &positions,
|
||||
const Alembic::AbcGeom::N3fArraySamplePtr &normals);
|
||||
|
||||
CDStreamConfig create_config(Mesh *mesh);
|
||||
|
||||
#endif /* __ABC_MESH_H__ */
|
367
source/blender/alembic/intern/abc_nurbs.cc
Normal file
367
source/blender/alembic/intern/abc_nurbs.cc
Normal file
@ -0,0 +1,367 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "abc_nurbs.h"
|
||||
|
||||
#include "abc_transform.h"
|
||||
#include "abc_util.h"
|
||||
|
||||
extern "C" {
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_object.h"
|
||||
}
|
||||
|
||||
using Alembic::AbcGeom::bool_t;
|
||||
using Alembic::AbcGeom::FloatArraySample;
|
||||
using Alembic::AbcGeom::FloatArraySamplePtr;
|
||||
using Alembic::AbcGeom::MetaData;
|
||||
using Alembic::AbcGeom::P3fArraySamplePtr;
|
||||
using Alembic::AbcGeom::kWrapExisting;
|
||||
|
||||
using Alembic::AbcGeom::IBoolProperty;
|
||||
using Alembic::AbcGeom::ICompoundProperty;
|
||||
using Alembic::AbcGeom::INuPatch;
|
||||
using Alembic::AbcGeom::INuPatchSchema;
|
||||
using Alembic::AbcGeom::IObject;
|
||||
using Alembic::AbcGeom::ISampleSelector;
|
||||
|
||||
using Alembic::AbcGeom::OBoolProperty;
|
||||
using Alembic::AbcGeom::OCompoundProperty;
|
||||
using Alembic::AbcGeom::ONuPatch;
|
||||
using Alembic::AbcGeom::ONuPatchSchema;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcNurbsWriter::AbcNurbsWriter(Scene *scene,
|
||||
Object *ob,
|
||||
AbcTransformWriter *parent,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings)
|
||||
: AbcObjectWriter(scene, ob, time_sampling, settings, parent)
|
||||
{
|
||||
m_is_animated = isAnimated();
|
||||
|
||||
/* if the object is static, use the default static time sampling */
|
||||
if (!m_is_animated) {
|
||||
m_time_sampling = 0;
|
||||
}
|
||||
|
||||
Curve *curve = static_cast<Curve *>(m_object->data);
|
||||
size_t numNurbs = BLI_listbase_count(&curve->nurb);
|
||||
|
||||
for (size_t i = 0; i < numNurbs; ++i) {
|
||||
std::stringstream str;
|
||||
str << m_name << '_' << i;
|
||||
|
||||
while (parent->alembicXform().getChildHeader(str.str())) {
|
||||
str << "_";
|
||||
}
|
||||
|
||||
ONuPatch nurbs(parent->alembicXform(), str.str().c_str(), m_time_sampling);
|
||||
m_nurbs_schema.push_back(nurbs.getSchema());
|
||||
}
|
||||
}
|
||||
|
||||
bool AbcNurbsWriter::isAnimated() const
|
||||
{
|
||||
/* check if object has shape keys */
|
||||
Curve *cu = static_cast<Curve *>(m_object->data);
|
||||
return (cu->key != NULL);
|
||||
}
|
||||
|
||||
static void get_knots(std::vector<float> &knots, const int num_knots, float *nu_knots)
|
||||
{
|
||||
if (num_knots <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Add an extra knot at the beggining and end of the array since most apps
|
||||
* require/expect them. */
|
||||
knots.reserve(num_knots + 2);
|
||||
|
||||
knots.push_back(0.0f);
|
||||
|
||||
for (int i = 0; i < num_knots; ++i) {
|
||||
knots.push_back(nu_knots[i]);
|
||||
}
|
||||
|
||||
knots[0] = 2.0f * knots[1] - knots[2];
|
||||
knots.push_back(2.0f * knots[num_knots] - knots[num_knots - 1]);
|
||||
}
|
||||
|
||||
void AbcNurbsWriter::do_write()
|
||||
{
|
||||
/* we have already stored a sample for this object. */
|
||||
if (!m_first_frame && !m_is_animated) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ELEM(m_object->type, OB_SURF, OB_CURVE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Curve *curve = static_cast<Curve *>(m_object->data);
|
||||
ListBase *nulb;
|
||||
|
||||
if (m_object->curve_cache->deformed_nurbs.first != NULL) {
|
||||
nulb = &m_object->curve_cache->deformed_nurbs;
|
||||
}
|
||||
else {
|
||||
nulb = BKE_curve_nurbs_get(curve);
|
||||
}
|
||||
|
||||
size_t count = 0;
|
||||
for (Nurb *nu = static_cast<Nurb *>(nulb->first); nu; nu = nu->next, ++count) {
|
||||
std::vector<float> knotsU;
|
||||
get_knots(knotsU, KNOTSU(nu), nu->knotsu);
|
||||
|
||||
std::vector<float> knotsV;
|
||||
get_knots(knotsV, KNOTSV(nu), nu->knotsv);
|
||||
|
||||
const int size = nu->pntsu * nu->pntsv;
|
||||
std::vector<Imath::V3f> positions(size);
|
||||
std::vector<float> weights(size);
|
||||
|
||||
const BPoint *bp = nu->bp;
|
||||
|
||||
for (int i = 0; i < size; ++i, ++bp) {
|
||||
copy_zup_yup(positions[i].getValue(), bp->vec);
|
||||
weights[i] = bp->vec[3];
|
||||
}
|
||||
|
||||
ONuPatchSchema::Sample sample;
|
||||
sample.setUOrder(nu->orderu + 1);
|
||||
sample.setVOrder(nu->orderv + 1);
|
||||
sample.setPositions(positions);
|
||||
sample.setPositionWeights(weights);
|
||||
sample.setUKnot(FloatArraySample(knotsU));
|
||||
sample.setVKnot(FloatArraySample(knotsV));
|
||||
sample.setNu(nu->pntsu);
|
||||
sample.setNv(nu->pntsv);
|
||||
|
||||
/* TODO(kevin): to accomodate other software we should duplicate control
|
||||
* points to indicate that a NURBS is cyclic. */
|
||||
OCompoundProperty user_props = m_nurbs_schema[count].getUserProperties();
|
||||
|
||||
if ((nu->flagu & CU_NURB_ENDPOINT) != 0) {
|
||||
OBoolProperty prop(user_props, "endpoint_u");
|
||||
prop.set(true);
|
||||
}
|
||||
|
||||
if ((nu->flagv & CU_NURB_ENDPOINT) != 0) {
|
||||
OBoolProperty prop(user_props, "endpoint_v");
|
||||
prop.set(true);
|
||||
}
|
||||
|
||||
if ((nu->flagu & CU_NURB_CYCLIC) != 0) {
|
||||
OBoolProperty prop(user_props, "cyclic_u");
|
||||
prop.set(true);
|
||||
}
|
||||
|
||||
if ((nu->flagv & CU_NURB_CYCLIC) != 0) {
|
||||
OBoolProperty prop(user_props, "cyclic_v");
|
||||
prop.set(true);
|
||||
}
|
||||
|
||||
m_nurbs_schema[count].set(sample);
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcNurbsReader::AbcNurbsReader(const IObject &object, ImportSettings &settings)
|
||||
: AbcObjectReader(object, settings)
|
||||
{
|
||||
getNurbsPatches(m_iobject);
|
||||
get_min_max_time(m_schemas[0].first, m_min_time, m_max_time);
|
||||
}
|
||||
|
||||
bool AbcNurbsReader::valid() const
|
||||
{
|
||||
if (m_schemas.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector< std::pair<INuPatchSchema, IObject> >::const_iterator it;
|
||||
for (it = m_schemas.begin(); it != m_schemas.end(); ++it) {
|
||||
const INuPatchSchema &schema = it->first;
|
||||
|
||||
if (!schema.valid()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool set_knots(const FloatArraySamplePtr &knots, float *&nu_knots)
|
||||
{
|
||||
if (!knots || knots->size() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Skip first and last knots, as they are used for padding. */
|
||||
const size_t num_knots = knots->size() - 2;
|
||||
nu_knots = static_cast<float *>(MEM_callocN(num_knots * sizeof(float), "abc_setsplineknotsu"));
|
||||
|
||||
for (size_t i = 0; i < num_knots; ++i) {
|
||||
nu_knots[i] = (*knots)[i + 1];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AbcNurbsReader::readObjectData(Main *bmain, float time)
|
||||
{
|
||||
Curve *cu = static_cast<Curve *>(BKE_curve_add(bmain, "abc_curve", OB_SURF));
|
||||
cu->actvert = CU_ACT_NONE;
|
||||
|
||||
std::vector< std::pair<INuPatchSchema, IObject> >::iterator it;
|
||||
|
||||
for (it = m_schemas.begin(); it != m_schemas.end(); ++it) {
|
||||
Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "abc_getnurb"));
|
||||
nu->flag = CU_SMOOTH;
|
||||
nu->type = CU_NURBS;
|
||||
nu->resolu = cu->resolu;
|
||||
nu->resolv = cu->resolv;
|
||||
|
||||
const ISampleSelector sample_sel(time);
|
||||
const INuPatchSchema &schema = it->first;
|
||||
const INuPatchSchema::Sample smp = schema.getValue(sample_sel);
|
||||
|
||||
nu->orderu = smp.getUOrder() - 1;
|
||||
nu->orderv = smp.getVOrder() - 1;
|
||||
nu->pntsu = smp.getNumU();
|
||||
nu->pntsv = smp.getNumV();
|
||||
|
||||
/* Read positions and weights. */
|
||||
|
||||
const P3fArraySamplePtr positions = smp.getPositions();
|
||||
const FloatArraySamplePtr weights = smp.getPositionWeights();
|
||||
|
||||
const size_t num_points = positions->size();
|
||||
|
||||
nu->bp = static_cast<BPoint *>(MEM_callocN(num_points * sizeof(BPoint), "abc_setsplinetype"));
|
||||
|
||||
BPoint *bp = nu->bp;
|
||||
float posw_in = 1.0f;
|
||||
|
||||
for (int i = 0; i < num_points; ++i, ++bp) {
|
||||
const Imath::V3f &pos_in = (*positions)[i];
|
||||
|
||||
if (weights) {
|
||||
posw_in = (*weights)[i];
|
||||
}
|
||||
|
||||
copy_yup_zup(bp->vec, pos_in.getValue());
|
||||
bp->vec[3] = posw_in;
|
||||
bp->f1 = SELECT;
|
||||
bp->radius = 1.0f;
|
||||
bp->weight = 1.0f;
|
||||
}
|
||||
|
||||
/* Read knots. */
|
||||
|
||||
if (!set_knots(smp.getUKnot(), nu->knotsu)) {
|
||||
BKE_nurb_knot_calc_u(nu);
|
||||
}
|
||||
|
||||
if (!set_knots(smp.getVKnot(), nu->knotsv)) {
|
||||
BKE_nurb_knot_calc_v(nu);
|
||||
}
|
||||
|
||||
/* Read flags. */
|
||||
|
||||
ICompoundProperty user_props = schema.getUserProperties();
|
||||
|
||||
if (has_property(user_props, "enpoint_u")) {
|
||||
nu->flagu |= CU_NURB_ENDPOINT;
|
||||
}
|
||||
|
||||
if (has_property(user_props, "enpoint_v")) {
|
||||
nu->flagv |= CU_NURB_ENDPOINT;
|
||||
}
|
||||
|
||||
if (has_property(user_props, "cyclic_u")) {
|
||||
nu->flagu |= CU_NURB_CYCLIC;
|
||||
}
|
||||
|
||||
if (has_property(user_props, "cyclic_v")) {
|
||||
nu->flagv |= CU_NURB_CYCLIC;
|
||||
}
|
||||
|
||||
BLI_addtail(BKE_curve_nurbs_get(cu), nu);
|
||||
}
|
||||
|
||||
BLI_strncpy(cu->id.name + 2, m_data_name.c_str(), m_data_name.size() + 1);
|
||||
|
||||
m_object = BKE_object_add_only_object(bmain, OB_SURF, m_object_name.c_str());
|
||||
m_object->data = cu;
|
||||
}
|
||||
|
||||
void AbcNurbsReader::getNurbsPatches(const IObject &obj)
|
||||
{
|
||||
if (!obj.valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int num_children = obj.getNumChildren();
|
||||
|
||||
if (num_children == 0) {
|
||||
INuPatch abc_nurb(obj, kWrapExisting);
|
||||
INuPatchSchema schem = abc_nurb.getSchema();
|
||||
m_schemas.push_back(std::pair<INuPatchSchema, IObject>(schem, obj));
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_children; ++i) {
|
||||
bool ok = true;
|
||||
IObject child(obj, obj.getChildHeader(i).getName());
|
||||
|
||||
if (!m_name.empty() && child.valid() && !begins_with(child.getFullName(), m_name)) {
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (!child.valid()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const MetaData &md = child.getMetaData();
|
||||
|
||||
if (INuPatch::matches(md) && ok) {
|
||||
INuPatch abc_nurb(child, kWrapExisting);
|
||||
INuPatchSchema schem = abc_nurb.getSchema();
|
||||
m_schemas.push_back(std::pair<INuPatchSchema, IObject>(schem, child));
|
||||
}
|
||||
|
||||
getNurbsPatches(child);
|
||||
}
|
||||
}
|
63
source/blender/alembic/intern/abc_nurbs.h
Normal file
63
source/blender/alembic/intern/abc_nurbs.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __ABC_NURBS_H__
|
||||
#define __ABC_NURBS_H__
|
||||
|
||||
#include "abc_object.h"
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcNurbsWriter : public AbcObjectWriter {
|
||||
std::vector<Alembic::AbcGeom::ONuPatchSchema> m_nurbs_schema;
|
||||
bool m_is_animated;
|
||||
|
||||
public:
|
||||
AbcNurbsWriter(Scene *scene,
|
||||
Object *ob,
|
||||
AbcTransformWriter *parent,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings);
|
||||
|
||||
private:
|
||||
virtual void do_write();
|
||||
|
||||
bool isAnimated() const;
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcNurbsReader : public AbcObjectReader {
|
||||
std::vector< std::pair<Alembic::AbcGeom::INuPatchSchema, Alembic::Abc::IObject> > m_schemas;
|
||||
|
||||
public:
|
||||
AbcNurbsReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
|
||||
|
||||
bool valid() const;
|
||||
|
||||
void readObjectData(Main *bmain, float time);
|
||||
|
||||
private:
|
||||
void getNurbsPatches(const Alembic::Abc::IObject &obj);
|
||||
};
|
||||
|
||||
#endif /* __ABC_NURBS_H__ */
|
238
source/blender/alembic/intern/abc_object.cc
Normal file
238
source/blender/alembic/intern/abc_object.cc
Normal file
@ -0,0 +1,238 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "abc_object.h"
|
||||
|
||||
#include "abc_util.h"
|
||||
|
||||
extern "C" {
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_space_types.h" /* for FILE_MAX */
|
||||
|
||||
#include "BKE_constraint.h"
|
||||
#include "BKE_depsgraph.h"
|
||||
#include "BKE_idprop.h"
|
||||
#include "BKE_library.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_string.h"
|
||||
}
|
||||
|
||||
using Alembic::AbcGeom::IObject;
|
||||
using Alembic::AbcGeom::IXform;
|
||||
using Alembic::AbcGeom::IXformSchema;
|
||||
|
||||
using Alembic::AbcGeom::OCompoundProperty;
|
||||
using Alembic::AbcGeom::ODoubleArrayProperty;
|
||||
using Alembic::AbcGeom::ODoubleProperty;
|
||||
using Alembic::AbcGeom::OFloatArrayProperty;
|
||||
using Alembic::AbcGeom::OFloatProperty;
|
||||
using Alembic::AbcGeom::OInt32ArrayProperty;
|
||||
using Alembic::AbcGeom::OInt32Property;
|
||||
using Alembic::AbcGeom::OStringArrayProperty;
|
||||
using Alembic::AbcGeom::OStringProperty;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcObjectWriter::AbcObjectWriter(Scene *scene,
|
||||
Object *ob,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings,
|
||||
AbcObjectWriter *parent)
|
||||
: m_object(ob)
|
||||
, m_settings(settings)
|
||||
, m_scene(scene)
|
||||
, m_time_sampling(time_sampling)
|
||||
, m_first_frame(true)
|
||||
{
|
||||
m_name = get_id_name(m_object) + "Shape";
|
||||
|
||||
if (parent) {
|
||||
parent->addChild(this);
|
||||
}
|
||||
}
|
||||
|
||||
AbcObjectWriter::~AbcObjectWriter()
|
||||
{}
|
||||
|
||||
void AbcObjectWriter::addChild(AbcObjectWriter *child)
|
||||
{
|
||||
m_children.push_back(child);
|
||||
}
|
||||
|
||||
Imath::Box3d AbcObjectWriter::bounds()
|
||||
{
|
||||
BoundBox *bb = BKE_object_boundbox_get(this->m_object);
|
||||
|
||||
if (!bb) {
|
||||
if (this->m_object->type != OB_CAMERA) {
|
||||
std::cerr << "Boundbox is null!\n";
|
||||
}
|
||||
|
||||
return Imath::Box3d();
|
||||
}
|
||||
|
||||
/* Convert Z-up to Y-up. */
|
||||
this->m_bounds.min.x = bb->vec[0][0];
|
||||
this->m_bounds.min.y = bb->vec[0][2];
|
||||
this->m_bounds.min.z = -bb->vec[0][1];
|
||||
|
||||
this->m_bounds.max.x = bb->vec[6][0];
|
||||
this->m_bounds.max.y = bb->vec[6][2];
|
||||
this->m_bounds.max.z = -bb->vec[6][1];
|
||||
|
||||
return this->m_bounds;
|
||||
}
|
||||
|
||||
void AbcObjectWriter::write()
|
||||
{
|
||||
do_write();
|
||||
m_first_frame = false;
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings)
|
||||
: m_name("")
|
||||
, m_object_name("")
|
||||
, m_data_name("")
|
||||
, m_object(NULL)
|
||||
, m_iobject(object)
|
||||
, m_settings(&settings)
|
||||
, m_min_time(std::numeric_limits<chrono_t>::max())
|
||||
, m_max_time(std::numeric_limits<chrono_t>::min())
|
||||
{
|
||||
m_name = object.getFullName();
|
||||
std::vector<std::string> parts;
|
||||
split(m_name, '/', parts);
|
||||
|
||||
if (parts.size() >= 2) {
|
||||
m_object_name = parts[parts.size() - 2];
|
||||
m_data_name = parts[parts.size() - 1];
|
||||
}
|
||||
else {
|
||||
m_object_name = m_data_name = parts[parts.size() - 1];
|
||||
}
|
||||
}
|
||||
|
||||
AbcObjectReader::~AbcObjectReader()
|
||||
{}
|
||||
|
||||
const IObject &AbcObjectReader::iobject() const
|
||||
{
|
||||
return m_iobject;
|
||||
}
|
||||
|
||||
Object *AbcObjectReader::object() const
|
||||
{
|
||||
return m_object;
|
||||
}
|
||||
|
||||
void AbcObjectReader::readObjectMatrix(const float time)
|
||||
{
|
||||
IXform ixform;
|
||||
bool has_alembic_parent = false;
|
||||
|
||||
/* Check that we have an empty object (locator, bone head/tail...). */
|
||||
if (IXform::matches(m_iobject.getMetaData())) {
|
||||
ixform = IXform(m_iobject, Alembic::AbcGeom::kWrapExisting);
|
||||
|
||||
/* See comment below. */
|
||||
has_alembic_parent = m_iobject.getParent().getParent().valid();
|
||||
}
|
||||
/* Check that we have an object with actual data. */
|
||||
else if (IXform::matches(m_iobject.getParent().getMetaData())) {
|
||||
ixform = IXform(m_iobject.getParent(), Alembic::AbcGeom::kWrapExisting);
|
||||
|
||||
/* This is a bit hackish, but we need to make sure that extra
|
||||
* transformations added to the matrix (rotation/scale) are only applied
|
||||
* to root objects. The way objects and their hierarchy are created will
|
||||
* need to be revisited at some point but for now this seems to do the
|
||||
* trick.
|
||||
*
|
||||
* Explanation of the trick:
|
||||
* The first getParent() will return this object's transformation matrix.
|
||||
* The second getParent() will get the parent of the transform, but this
|
||||
* might be the archive root ('/') which is valid, so we go passed it to
|
||||
* make sure that there is no parent.
|
||||
*/
|
||||
has_alembic_parent = m_iobject.getParent().getParent().getParent().valid();
|
||||
}
|
||||
/* Should not happen. */
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
const IXformSchema &schema(ixform.getSchema());
|
||||
|
||||
if (!schema.valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Alembic::AbcGeom::ISampleSelector sample_sel(time);
|
||||
Alembic::AbcGeom::XformSample xs;
|
||||
schema.get(xs, sample_sel);
|
||||
|
||||
create_input_transform(sample_sel, ixform, m_object, m_object->obmat, m_settings->scale, has_alembic_parent);
|
||||
|
||||
invert_m4_m4(m_object->imat, m_object->obmat);
|
||||
|
||||
BKE_object_apply_mat4(m_object, m_object->obmat, false, false);
|
||||
|
||||
if (!schema.isConstant()) {
|
||||
bConstraint *con = BKE_constraint_add_for_object(m_object, NULL, CONSTRAINT_TYPE_TRANSFORM_CACHE);
|
||||
bTransformCacheConstraint *data = static_cast<bTransformCacheConstraint *>(con->data);
|
||||
BLI_strncpy(data->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
|
||||
|
||||
data->cache_file = m_settings->cache_file;
|
||||
id_us_plus(&data->cache_file->id);
|
||||
}
|
||||
}
|
||||
|
||||
void AbcObjectReader::addCacheModifier() const
|
||||
{
|
||||
ModifierData *md = modifier_new(eModifierType_MeshSequenceCache);
|
||||
BLI_addtail(&m_object->modifiers, md);
|
||||
|
||||
MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
|
||||
|
||||
mcmd->cache_file = m_settings->cache_file;
|
||||
id_us_plus(&mcmd->cache_file->id);
|
||||
|
||||
BLI_strncpy(mcmd->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
|
||||
}
|
||||
|
||||
chrono_t AbcObjectReader::minTime() const
|
||||
{
|
||||
return m_min_time;
|
||||
}
|
||||
|
||||
chrono_t AbcObjectReader::maxTime() const
|
||||
{
|
||||
return m_max_time;
|
||||
}
|
169
source/blender/alembic/intern/abc_object.h
Normal file
169
source/blender/alembic/intern/abc_object.h
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __ABC_OBJECT_H__
|
||||
#define __ABC_OBJECT_H__
|
||||
|
||||
#include <Alembic/Abc/All.h>
|
||||
#include <Alembic/AbcGeom/All.h>
|
||||
|
||||
#include "abc_exporter.h"
|
||||
|
||||
extern "C" {
|
||||
#include "DNA_ID.h"
|
||||
}
|
||||
|
||||
class AbcTransformWriter;
|
||||
|
||||
struct Main;
|
||||
struct Object;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcObjectWriter {
|
||||
protected:
|
||||
Object *m_object;
|
||||
ExportSettings &m_settings;
|
||||
|
||||
Scene *m_scene;
|
||||
uint32_t m_time_sampling;
|
||||
|
||||
Imath::Box3d m_bounds;
|
||||
std::vector<AbcObjectWriter *> m_children;
|
||||
|
||||
std::vector< std::pair<std::string, IDProperty *> > m_props;
|
||||
|
||||
bool m_first_frame;
|
||||
std::string m_name;
|
||||
|
||||
public:
|
||||
AbcObjectWriter(Scene *scene,
|
||||
Object *ob,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings,
|
||||
AbcObjectWriter *parent = NULL);
|
||||
|
||||
virtual ~AbcObjectWriter();
|
||||
|
||||
void addChild(AbcObjectWriter *child);
|
||||
|
||||
virtual Imath::Box3d bounds();
|
||||
|
||||
void write();
|
||||
|
||||
private:
|
||||
virtual void do_write() = 0;
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class CacheFile;
|
||||
|
||||
struct ImportSettings {
|
||||
bool do_convert_mat;
|
||||
float conversion_mat[4][4];
|
||||
|
||||
int from_up;
|
||||
int from_forward;
|
||||
float scale;
|
||||
bool is_sequence;
|
||||
bool set_frame_range;
|
||||
|
||||
/* Length and frame offset of file sequences. */
|
||||
int sequence_len;
|
||||
int offset;
|
||||
|
||||
/* From MeshSeqCacheModifierData.read_flag */
|
||||
int read_flag;
|
||||
|
||||
bool validate_meshes;
|
||||
|
||||
CacheFile *cache_file;
|
||||
|
||||
ImportSettings()
|
||||
: do_convert_mat(false)
|
||||
, from_up(0)
|
||||
, from_forward(0)
|
||||
, scale(1.0f)
|
||||
, is_sequence(false)
|
||||
, set_frame_range(false)
|
||||
, sequence_len(1)
|
||||
, offset(0)
|
||||
, read_flag(0)
|
||||
, validate_meshes(false)
|
||||
, cache_file(NULL)
|
||||
{}
|
||||
};
|
||||
|
||||
template <typename Schema>
|
||||
static bool has_animations(Schema &schema, ImportSettings *settings)
|
||||
{
|
||||
if (settings->is_sequence) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!schema.isConstant()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
using Alembic::AbcCoreAbstract::chrono_t;
|
||||
|
||||
class AbcObjectReader {
|
||||
protected:
|
||||
std::string m_name;
|
||||
std::string m_object_name;
|
||||
std::string m_data_name;
|
||||
Object *m_object;
|
||||
Alembic::Abc::IObject m_iobject;
|
||||
|
||||
ImportSettings *m_settings;
|
||||
|
||||
chrono_t m_min_time;
|
||||
chrono_t m_max_time;
|
||||
|
||||
public:
|
||||
explicit AbcObjectReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
|
||||
|
||||
virtual ~AbcObjectReader();
|
||||
|
||||
const Alembic::Abc::IObject &iobject() const;
|
||||
|
||||
Object *object() const;
|
||||
|
||||
virtual bool valid() const = 0;
|
||||
|
||||
virtual void readObjectData(Main *bmain, float time) = 0;
|
||||
|
||||
void readObjectMatrix(const float time);
|
||||
|
||||
void addCacheModifier() const;
|
||||
|
||||
chrono_t minTime() const;
|
||||
chrono_t maxTime() const;
|
||||
};
|
||||
|
||||
#endif /* __ABC_OBJECT_H__ */
|
198
source/blender/alembic/intern/abc_points.cc
Normal file
198
source/blender/alembic/intern/abc_points.cc
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Kévin Dietrich.
|
||||
* All rights reserved.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*
|
||||
*/
|
||||
|
||||
#include "abc_points.h"
|
||||
|
||||
#include "abc_mesh.h"
|
||||
#include "abc_transform.h"
|
||||
#include "abc_util.h"
|
||||
|
||||
extern "C" {
|
||||
#include "DNA_mesh_types.h"
|
||||
|
||||
#include "BKE_lattice.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_particle.h"
|
||||
#include "BKE_scene.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
}
|
||||
|
||||
using Alembic::AbcGeom::kVertexScope;
|
||||
using Alembic::AbcGeom::kWrapExisting;
|
||||
using Alembic::AbcGeom::P3fArraySamplePtr;
|
||||
using Alembic::AbcGeom::N3fArraySamplePtr;
|
||||
|
||||
using Alembic::AbcGeom::ICompoundProperty;
|
||||
using Alembic::AbcGeom::IN3fArrayProperty;
|
||||
using Alembic::AbcGeom::IPoints;
|
||||
using Alembic::AbcGeom::IPointsSchema;
|
||||
using Alembic::AbcGeom::ISampleSelector;
|
||||
|
||||
using Alembic::AbcGeom::OPoints;
|
||||
using Alembic::AbcGeom::OPointsSchema;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcPointsWriter::AbcPointsWriter(Scene *scene,
|
||||
Object *ob,
|
||||
AbcTransformWriter *parent,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings,
|
||||
ParticleSystem *psys)
|
||||
: AbcObjectWriter(scene, ob, time_sampling, settings, parent)
|
||||
{
|
||||
m_psys = psys;
|
||||
|
||||
OPoints points(parent->alembicXform(), m_name, m_time_sampling);
|
||||
m_schema = points.getSchema();
|
||||
}
|
||||
|
||||
void AbcPointsWriter::do_write()
|
||||
{
|
||||
if (!m_psys) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Imath::V3f> points;
|
||||
std::vector<Imath::V3f> velocities;
|
||||
std::vector<float> widths;
|
||||
std::vector<uint64_t> ids;
|
||||
|
||||
ParticleKey state;
|
||||
|
||||
ParticleSimulationData sim;
|
||||
sim.scene = m_scene;
|
||||
sim.ob = m_object;
|
||||
sim.psys = m_psys;
|
||||
|
||||
m_psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
|
||||
|
||||
uint64_t index = 0;
|
||||
for (int p = 0; p < m_psys->totpart; p++) {
|
||||
float pos[3], vel[3];
|
||||
|
||||
if (m_psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
state.time = BKE_scene_frame_get(m_scene);
|
||||
|
||||
if (psys_get_particle_state(&sim, p, &state, 0) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* location */
|
||||
mul_v3_m4v3(pos, m_object->imat, state.co);
|
||||
|
||||
/* velocity */
|
||||
sub_v3_v3v3(vel, state.co, m_psys->particles[p].prev_state.co);
|
||||
|
||||
/* Convert Z-up to Y-up. */
|
||||
points.push_back(Imath::V3f(pos[0], pos[2], -pos[1]));
|
||||
velocities.push_back(Imath::V3f(vel[0], vel[2], -vel[1]));
|
||||
widths.push_back(m_psys->particles[p].size);
|
||||
ids.push_back(index++);
|
||||
}
|
||||
|
||||
if (m_psys->lattice_deform_data) {
|
||||
end_latt_deform(m_psys->lattice_deform_data);
|
||||
m_psys->lattice_deform_data = NULL;
|
||||
}
|
||||
|
||||
Alembic::Abc::P3fArraySample psample(points);
|
||||
Alembic::Abc::UInt64ArraySample idsample(ids);
|
||||
Alembic::Abc::V3fArraySample vsample(velocities);
|
||||
Alembic::Abc::FloatArraySample wsample_array(widths);
|
||||
Alembic::AbcGeom::OFloatGeomParam::Sample wsample(wsample_array, kVertexScope);
|
||||
|
||||
m_sample = OPointsSchema::Sample(psample, idsample, vsample, wsample);
|
||||
m_sample.setSelfBounds(bounds());
|
||||
|
||||
m_schema.set(m_sample);
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcPointsReader::AbcPointsReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
|
||||
: AbcObjectReader(object, settings)
|
||||
{
|
||||
IPoints ipoints(m_iobject, kWrapExisting);
|
||||
m_schema = ipoints.getSchema();
|
||||
get_min_max_time(m_schema, m_min_time, m_max_time);
|
||||
}
|
||||
|
||||
bool AbcPointsReader::valid() const
|
||||
{
|
||||
return m_schema.valid();
|
||||
}
|
||||
|
||||
void AbcPointsReader::readObjectData(Main *bmain, float time)
|
||||
{
|
||||
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
|
||||
|
||||
const ISampleSelector sample_sel(time);
|
||||
m_sample = m_schema.getValue(sample_sel);
|
||||
|
||||
const P3fArraySamplePtr &positions = m_sample.getPositions();
|
||||
utils::mesh_add_verts(mesh, positions->size());
|
||||
|
||||
CDStreamConfig config = create_config(mesh);
|
||||
read_points_sample(m_schema, sample_sel, config, time);
|
||||
|
||||
if (m_settings->validate_meshes) {
|
||||
BKE_mesh_validate(mesh, false, false);
|
||||
}
|
||||
|
||||
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
|
||||
m_object->data = mesh;
|
||||
|
||||
if (has_animations(m_schema, m_settings)) {
|
||||
addCacheModifier();
|
||||
}
|
||||
}
|
||||
|
||||
void read_points_sample(const IPointsSchema &schema,
|
||||
const ISampleSelector &selector,
|
||||
CDStreamConfig &config,
|
||||
float time)
|
||||
{
|
||||
Alembic::AbcGeom::IPointsSchema::Sample sample = schema.getValue(selector);
|
||||
|
||||
const P3fArraySamplePtr &positions = sample.getPositions();
|
||||
|
||||
ICompoundProperty prop = schema.getArbGeomParams();
|
||||
N3fArraySamplePtr vnormals;
|
||||
|
||||
if (has_property(prop, "N")) {
|
||||
const IN3fArrayProperty &normals_prop = IN3fArrayProperty(prop, "N", time);
|
||||
|
||||
if (normals_prop) {
|
||||
vnormals = normals_prop.getValue(selector);
|
||||
}
|
||||
}
|
||||
|
||||
read_mverts(config.mvert, positions, vnormals);
|
||||
}
|
70
source/blender/alembic/intern/abc_points.h
Normal file
70
source/blender/alembic/intern/abc_points.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Kévin Dietrich.
|
||||
* All rights reserved.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ABC_POINTS_H__
|
||||
#define __ABC_POINTS_H__
|
||||
|
||||
#include "abc_object.h"
|
||||
#include "abc_customdata.h"
|
||||
|
||||
class ParticleSystem;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcPointsWriter : public AbcObjectWriter {
|
||||
Alembic::AbcGeom::OPointsSchema m_schema;
|
||||
Alembic::AbcGeom::OPointsSchema::Sample m_sample;
|
||||
ParticleSystem *m_psys;
|
||||
|
||||
public:
|
||||
AbcPointsWriter(Scene *scene,
|
||||
Object *ob,
|
||||
AbcTransformWriter *parent,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings,
|
||||
ParticleSystem *psys);
|
||||
|
||||
void do_write();
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcPointsReader : public AbcObjectReader {
|
||||
Alembic::AbcGeom::IPointsSchema m_schema;
|
||||
Alembic::AbcGeom::IPointsSchema::Sample m_sample;
|
||||
|
||||
public:
|
||||
AbcPointsReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
|
||||
|
||||
bool valid() const;
|
||||
|
||||
void readObjectData(Main *bmain, float time);
|
||||
};
|
||||
|
||||
void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema,
|
||||
const Alembic::AbcGeom::ISampleSelector &selector,
|
||||
CDStreamConfig &config,
|
||||
float time);
|
||||
|
||||
#endif /* __ABC_POINTS_H__ */
|
152
source/blender/alembic/intern/abc_transform.cc
Normal file
152
source/blender/alembic/intern/abc_transform.cc
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "abc_transform.h"
|
||||
|
||||
#include <OpenEXR/ImathBoxAlgo.h>
|
||||
|
||||
#include "abc_util.h"
|
||||
|
||||
extern "C" {
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
|
||||
#include "BKE_object.h"
|
||||
}
|
||||
|
||||
using Alembic::AbcGeom::OObject;
|
||||
using Alembic::AbcGeom::OXform;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
static bool has_parent_camera(Object *ob)
|
||||
{
|
||||
if (!ob->parent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Object *parent = ob->parent;
|
||||
|
||||
if (parent->type == OB_CAMERA) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return has_parent_camera(parent);
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcTransformWriter::AbcTransformWriter(Object *ob,
|
||||
const OObject &abc_parent,
|
||||
AbcTransformWriter *parent,
|
||||
unsigned int time_sampling,
|
||||
ExportSettings &settings)
|
||||
: AbcObjectWriter(NULL, ob, time_sampling, settings, parent)
|
||||
{
|
||||
m_is_animated = hasAnimation(m_object);
|
||||
m_parent = NULL;
|
||||
|
||||
if (!m_is_animated) {
|
||||
time_sampling = 0;
|
||||
}
|
||||
|
||||
m_xform = OXform(abc_parent, get_id_name(m_object), time_sampling);
|
||||
m_schema = m_xform.getSchema();
|
||||
}
|
||||
|
||||
void AbcTransformWriter::do_write()
|
||||
{
|
||||
if (m_first_frame) {
|
||||
m_visibility = Alembic::AbcGeom::CreateVisibilityProperty(m_xform, m_xform.getSchema().getTimeSampling());
|
||||
}
|
||||
|
||||
m_visibility.set(!(m_object->restrictflag & OB_RESTRICT_VIEW));
|
||||
|
||||
if (!m_first_frame && !m_is_animated) {
|
||||
return;
|
||||
}
|
||||
|
||||
float mat[4][4];
|
||||
create_transform_matrix(m_object, mat);
|
||||
|
||||
/* Only apply rotation to root camera, parenting will propagate it. */
|
||||
if (m_object->type == OB_CAMERA && !has_parent_camera(m_object)) {
|
||||
float rot_mat[4][4];
|
||||
unit_m4(rot_mat);
|
||||
rotate_m4(rot_mat, 'X', -M_PI_2);
|
||||
mul_m4_m4m4(mat, mat, rot_mat);
|
||||
}
|
||||
|
||||
if (!m_object->parent) {
|
||||
/* Only apply scaling to root objects, parenting will propagate it. */
|
||||
float scale_mat[4][4];
|
||||
scale_m4_fl(scale_mat, m_settings.global_scale);
|
||||
mul_m4_m4m4(mat, mat, scale_mat);
|
||||
mul_v3_fl(mat[3], m_settings.global_scale);
|
||||
}
|
||||
|
||||
m_matrix = convert_matrix(mat);
|
||||
|
||||
m_sample.setMatrix(m_matrix);
|
||||
m_schema.set(m_sample);
|
||||
}
|
||||
|
||||
Imath::Box3d AbcTransformWriter::bounds()
|
||||
{
|
||||
Imath::Box3d bounds;
|
||||
|
||||
for (int i = 0; i < m_children.size(); ++i) {
|
||||
Imath::Box3d box(m_children[i]->bounds());
|
||||
bounds.extendBy(box);
|
||||
}
|
||||
|
||||
return Imath::transform(bounds, m_matrix);
|
||||
}
|
||||
|
||||
bool AbcTransformWriter::hasAnimation(Object */*ob*/) const
|
||||
{
|
||||
/* TODO(kevin): implement this. */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcEmptyReader::AbcEmptyReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
|
||||
: AbcObjectReader(object, settings)
|
||||
{
|
||||
Alembic::AbcGeom::IXform xform(object, Alembic::AbcGeom::kWrapExisting);
|
||||
m_schema = xform.getSchema();
|
||||
|
||||
get_min_max_time(m_schema, m_min_time, m_max_time);
|
||||
}
|
||||
|
||||
bool AbcEmptyReader::valid() const
|
||||
{
|
||||
return m_schema.valid();
|
||||
}
|
||||
|
||||
void AbcEmptyReader::readObjectData(Main *bmain, float /*time*/)
|
||||
{
|
||||
m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_object_name.c_str());
|
||||
m_object->data = NULL;
|
||||
}
|
73
source/blender/alembic/intern/abc_transform.h
Normal file
73
source/blender/alembic/intern/abc_transform.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __ABC_TRANSFORM_H__
|
||||
#define __ABC_TRANSFORM_H__
|
||||
|
||||
#include "abc_object.h"
|
||||
|
||||
#include <Alembic/AbcGeom/All.h>
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcTransformWriter : public AbcObjectWriter {
|
||||
Alembic::AbcGeom::OXform m_xform;
|
||||
Alembic::AbcGeom::OXformSchema m_schema;
|
||||
Alembic::AbcGeom::XformSample m_sample;
|
||||
Alembic::AbcGeom::OVisibilityProperty m_visibility;
|
||||
Alembic::Abc::M44d m_matrix;
|
||||
|
||||
bool m_is_animated;
|
||||
Object *m_parent;
|
||||
bool m_visible;
|
||||
|
||||
public:
|
||||
AbcTransformWriter(Object *ob,
|
||||
const Alembic::AbcGeom::OObject &abc_parent,
|
||||
AbcTransformWriter *parent,
|
||||
unsigned int time_sampling,
|
||||
ExportSettings &settings);
|
||||
|
||||
Alembic::AbcGeom::OXform &alembicXform() { return m_xform;}
|
||||
virtual Imath::Box3d bounds();
|
||||
void setParent(Object *p) { m_parent = p; }
|
||||
|
||||
private:
|
||||
virtual void do_write();
|
||||
|
||||
bool hasAnimation(Object *ob) const;
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcEmptyReader : public AbcObjectReader {
|
||||
Alembic::AbcGeom::IXformSchema m_schema;
|
||||
|
||||
public:
|
||||
AbcEmptyReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
|
||||
|
||||
bool valid() const;
|
||||
|
||||
void readObjectData(Main *bmain, float time);
|
||||
};
|
||||
|
||||
#endif /* __ABC_TRANSFORM_H__ */
|
437
source/blender/alembic/intern/abc_util.cc
Normal file
437
source/blender/alembic/intern/abc_util.cc
Normal file
@ -0,0 +1,437 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "abc_util.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
extern "C" {
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
}
|
||||
|
||||
std::string get_id_name(Object *ob)
|
||||
{
|
||||
if (!ob) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return get_id_name(&ob->id);
|
||||
}
|
||||
|
||||
std::string get_id_name(ID *id)
|
||||
{
|
||||
std::string name(id->name + 2);
|
||||
std::replace(name.begin(), name.end(), ' ', '_');
|
||||
std::replace(name.begin(), name.end(), '.', '_');
|
||||
std::replace(name.begin(), name.end(), ':', '_');
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string get_object_dag_path_name(Object *ob, Object *dupli_parent)
|
||||
{
|
||||
std::string name = get_id_name(ob);
|
||||
|
||||
Object *p = ob->parent;
|
||||
|
||||
while (p) {
|
||||
name = get_id_name(p) + "/" + name;
|
||||
p = p->parent;
|
||||
}
|
||||
|
||||
if (dupli_parent && (ob != dupli_parent)) {
|
||||
name = get_id_name(dupli_parent) + "/" + name;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
bool object_selected(Object *ob)
|
||||
{
|
||||
return ob->flag & SELECT;
|
||||
}
|
||||
|
||||
bool parent_selected(Object *ob)
|
||||
{
|
||||
if (object_selected(ob)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool do_export = false;
|
||||
|
||||
Object *parent = ob->parent;
|
||||
|
||||
while (parent != NULL) {
|
||||
if (object_selected(parent)) {
|
||||
do_export = true;
|
||||
break;
|
||||
}
|
||||
|
||||
parent = parent->parent;
|
||||
}
|
||||
|
||||
return do_export;
|
||||
}
|
||||
|
||||
Imath::M44d convert_matrix(float mat[4][4])
|
||||
{
|
||||
Imath::M44d m;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
m[i][j] = mat[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
void split(const std::string &s, const char delim, std::vector<std::string> &tokens)
|
||||
{
|
||||
tokens.clear();
|
||||
|
||||
std::stringstream ss(s);
|
||||
std::string item;
|
||||
|
||||
while (std::getline(ss, item, delim)) {
|
||||
if (!item.empty()) {
|
||||
tokens.push_back(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a rotation matrix for each axis from euler angles.
|
||||
* Euler angles are swaped to change coordinate system. */
|
||||
static void create_rotation_matrix(
|
||||
float rot_x_mat[3][3], float rot_y_mat[3][3],
|
||||
float rot_z_mat[3][3], const float euler[3], const bool to_yup)
|
||||
{
|
||||
const float rx = euler[0];
|
||||
const float ry = (to_yup) ? euler[2] : -euler[2];
|
||||
const float rz = (to_yup) ? -euler[1] : euler[1];
|
||||
|
||||
unit_m3(rot_x_mat);
|
||||
unit_m3(rot_y_mat);
|
||||
unit_m3(rot_z_mat);
|
||||
|
||||
rot_x_mat[1][1] = cos(rx);
|
||||
rot_x_mat[2][1] = -sin(rx);
|
||||
rot_x_mat[1][2] = sin(rx);
|
||||
rot_x_mat[2][2] = cos(rx);
|
||||
|
||||
rot_y_mat[2][2] = cos(ry);
|
||||
rot_y_mat[0][2] = -sin(ry);
|
||||
rot_y_mat[2][0] = sin(ry);
|
||||
rot_y_mat[0][0] = cos(ry);
|
||||
|
||||
rot_z_mat[0][0] = cos(rz);
|
||||
rot_z_mat[1][0] = -sin(rz);
|
||||
rot_z_mat[0][1] = sin(rz);
|
||||
rot_z_mat[1][1] = cos(rz);
|
||||
}
|
||||
|
||||
/* Recompute transform matrix of object in new coordinate system
|
||||
* (from Y-Up to Z-Up). */
|
||||
void create_transform_matrix(float r_mat[4][4])
|
||||
{
|
||||
float rot_mat[3][3], rot[3][3], scale_mat[4][4], invmat[4][4], transform_mat[4][4];
|
||||
float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3];
|
||||
float loc[3], scale[3], euler[3];
|
||||
|
||||
zero_v3(loc);
|
||||
zero_v3(scale);
|
||||
zero_v3(euler);
|
||||
unit_m3(rot);
|
||||
unit_m3(rot_mat);
|
||||
unit_m4(scale_mat);
|
||||
unit_m4(transform_mat);
|
||||
unit_m4(invmat);
|
||||
|
||||
/* Compute rotation matrix. */
|
||||
|
||||
/* Extract location, rotation, and scale from matrix. */
|
||||
mat4_to_loc_rot_size(loc, rot, scale, r_mat);
|
||||
|
||||
/* Get euler angles from rotation matrix. */
|
||||
mat3_to_eulO(euler, ROT_MODE_XYZ, rot);
|
||||
|
||||
/* Create X, Y, Z rotation matrices from euler angles. */
|
||||
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, false);
|
||||
|
||||
/* Concatenate rotation matrices. */
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
|
||||
|
||||
/* Add rotation matrix to transformation matrix. */
|
||||
copy_m4_m3(transform_mat, rot_mat);
|
||||
|
||||
/* Add translation to transformation matrix. */
|
||||
copy_yup_zup(transform_mat[3], loc);
|
||||
|
||||
/* Create scale matrix. */
|
||||
scale_mat[0][0] = scale[0];
|
||||
scale_mat[1][1] = scale[2];
|
||||
scale_mat[2][2] = scale[1];
|
||||
|
||||
/* Add scale to transformation matrix. */
|
||||
mul_m4_m4m4(transform_mat, transform_mat, scale_mat);
|
||||
|
||||
copy_m4_m4(r_mat, transform_mat);
|
||||
}
|
||||
|
||||
void create_input_transform(const Alembic::AbcGeom::ISampleSelector &sample_sel,
|
||||
const Alembic::AbcGeom::IXform &ixform, Object *ob,
|
||||
float r_mat[4][4], float scale, bool has_alembic_parent)
|
||||
{
|
||||
|
||||
const Alembic::AbcGeom::IXformSchema &ixform_schema = ixform.getSchema();
|
||||
Alembic::AbcGeom::XformSample xs;
|
||||
ixform_schema.get(xs, sample_sel);
|
||||
const Imath::M44d &xform = xs.getMatrix();
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
r_mat[i][j] = xform[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
if (ob->type == OB_CAMERA) {
|
||||
float cam_to_yup[4][4];
|
||||
unit_m4(cam_to_yup);
|
||||
rotate_m4(cam_to_yup, 'X', M_PI_2);
|
||||
mul_m4_m4m4(r_mat, r_mat, cam_to_yup);
|
||||
}
|
||||
|
||||
create_transform_matrix(r_mat);
|
||||
|
||||
if (ob->parent) {
|
||||
mul_m4_m4m4(r_mat, ob->parent->obmat, r_mat);
|
||||
}
|
||||
/* TODO(kevin) */
|
||||
else if (!has_alembic_parent) {
|
||||
/* Only apply scaling to root objects, parenting will propagate it. */
|
||||
float scale_mat[4][4];
|
||||
scale_m4_fl(scale_mat, scale);
|
||||
mul_m4_m4m4(r_mat, r_mat, scale_mat);
|
||||
mul_v3_fl(r_mat[3], scale);
|
||||
}
|
||||
}
|
||||
|
||||
/* Recompute transform matrix of object in new coordinate system (from Z-Up to Y-Up). */
|
||||
void create_transform_matrix(Object *obj, float transform_mat[4][4])
|
||||
{
|
||||
float rot_mat[3][3], rot[3][3], scale_mat[4][4], invmat[4][4], mat[4][4];
|
||||
float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3];
|
||||
float loc[3], scale[3], euler[3];
|
||||
|
||||
zero_v3(loc);
|
||||
zero_v3(scale);
|
||||
zero_v3(euler);
|
||||
unit_m3(rot);
|
||||
unit_m3(rot_mat);
|
||||
unit_m4(scale_mat);
|
||||
unit_m4(transform_mat);
|
||||
unit_m4(invmat);
|
||||
unit_m4(mat);
|
||||
|
||||
/* get local matrix. */
|
||||
if (obj->parent) {
|
||||
invert_m4_m4(invmat, obj->parent->obmat);
|
||||
mul_m4_m4m4(mat, invmat, obj->obmat);
|
||||
}
|
||||
else {
|
||||
copy_m4_m4(mat, obj->obmat);
|
||||
}
|
||||
|
||||
/* Compute rotation matrix. */
|
||||
switch (obj->rotmode) {
|
||||
case ROT_MODE_AXISANGLE:
|
||||
{
|
||||
/* Get euler angles from axis angle rotation. */
|
||||
axis_angle_to_eulO(euler, ROT_MODE_XYZ, obj->rotAxis, obj->rotAngle);
|
||||
|
||||
/* Create X, Y, Z rotation matrices from euler angles. */
|
||||
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
|
||||
|
||||
/* Concatenate rotation matrices. */
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
|
||||
|
||||
/* Extract location and scale from matrix. */
|
||||
mat4_to_loc_rot_size(loc, rot, scale, mat);
|
||||
|
||||
break;
|
||||
}
|
||||
case ROT_MODE_QUAT:
|
||||
{
|
||||
float q[4];
|
||||
copy_v4_v4(q, obj->quat);
|
||||
|
||||
/* Swap axis. */
|
||||
q[2] = obj->quat[3];
|
||||
q[3] = -obj->quat[2];
|
||||
|
||||
/* Compute rotation matrix from quaternion. */
|
||||
quat_to_mat3(rot_mat, q);
|
||||
|
||||
/* Extract location and scale from matrix. */
|
||||
mat4_to_loc_rot_size(loc, rot, scale, mat);
|
||||
|
||||
break;
|
||||
}
|
||||
case ROT_MODE_XYZ:
|
||||
{
|
||||
/* Extract location, rotation, and scale form matrix. */
|
||||
mat4_to_loc_rot_size(loc, rot, scale, mat);
|
||||
|
||||
/* Get euler angles from rotation matrix. */
|
||||
mat3_to_eulO(euler, ROT_MODE_XYZ, rot);
|
||||
|
||||
/* Create X, Y, Z rotation matrices from euler angles. */
|
||||
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
|
||||
|
||||
/* Concatenate rotation matrices. */
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
|
||||
|
||||
break;
|
||||
}
|
||||
case ROT_MODE_XZY:
|
||||
{
|
||||
/* Extract location, rotation, and scale form matrix. */
|
||||
mat4_to_loc_rot_size(loc, rot, scale, mat);
|
||||
|
||||
/* Get euler angles from rotation matrix. */
|
||||
mat3_to_eulO(euler, ROT_MODE_XZY, rot);
|
||||
|
||||
/* Create X, Y, Z rotation matrices from euler angles. */
|
||||
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
|
||||
|
||||
/* Concatenate rotation matrices. */
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
|
||||
|
||||
break;
|
||||
}
|
||||
case ROT_MODE_YXZ:
|
||||
{
|
||||
/* Extract location, rotation, and scale form matrix. */
|
||||
mat4_to_loc_rot_size(loc, rot, scale, mat);
|
||||
|
||||
/* Get euler angles from rotation matrix. */
|
||||
mat3_to_eulO(euler, ROT_MODE_YXZ, rot);
|
||||
|
||||
/* Create X, Y, Z rotation matrices from euler angles. */
|
||||
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
|
||||
|
||||
/* Concatenate rotation matrices. */
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
|
||||
|
||||
break;
|
||||
}
|
||||
case ROT_MODE_YZX:
|
||||
{
|
||||
/* Extract location, rotation, and scale form matrix. */
|
||||
mat4_to_loc_rot_size(loc, rot, scale, mat);
|
||||
|
||||
/* Get euler angles from rotation matrix. */
|
||||
mat3_to_eulO(euler, ROT_MODE_YZX, rot);
|
||||
|
||||
/* Create X, Y, Z rotation matrices from euler angles. */
|
||||
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
|
||||
|
||||
/* Concatenate rotation matrices. */
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
|
||||
|
||||
break;
|
||||
}
|
||||
case ROT_MODE_ZXY:
|
||||
{
|
||||
/* Extract location, rotation, and scale form matrix. */
|
||||
mat4_to_loc_rot_size(loc, rot, scale, mat);
|
||||
|
||||
/* Get euler angles from rotation matrix. */
|
||||
mat3_to_eulO(euler, ROT_MODE_ZXY, rot);
|
||||
|
||||
/* Create X, Y, Z rotation matrices from euler angles. */
|
||||
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
|
||||
|
||||
/* Concatenate rotation matrices. */
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
|
||||
|
||||
break;
|
||||
}
|
||||
case ROT_MODE_ZYX:
|
||||
{
|
||||
/* Extract location, rotation, and scale form matrix. */
|
||||
mat4_to_loc_rot_size(loc, rot, scale, mat);
|
||||
|
||||
/* Get euler angles from rotation matrix. */
|
||||
mat3_to_eulO(euler, ROT_MODE_ZYX, rot);
|
||||
|
||||
/* Create X, Y, Z rotation matrices from euler angles. */
|
||||
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
|
||||
|
||||
/* Concatenate rotation matrices. */
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add rotation matrix to transformation matrix. */
|
||||
copy_m4_m3(transform_mat, rot_mat);
|
||||
|
||||
/* Add translation to transformation matrix. */
|
||||
copy_zup_yup(transform_mat[3], loc);
|
||||
|
||||
/* Create scale matrix. */
|
||||
scale_mat[0][0] = scale[0];
|
||||
scale_mat[1][1] = scale[2];
|
||||
scale_mat[2][2] = scale[1];
|
||||
|
||||
/* Add scale to transformation matrix. */
|
||||
mul_m4_m4m4(transform_mat, transform_mat, scale_mat);
|
||||
}
|
||||
|
||||
bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name)
|
||||
{
|
||||
if (!prop.valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return prop.getPropertyHeader(name) != NULL;
|
||||
}
|
125
source/blender/alembic/intern/abc_util.h
Normal file
125
source/blender/alembic/intern/abc_util.h
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __ABC_UTIL_H__
|
||||
#define __ABC_UTIL_H__
|
||||
|
||||
#include <Alembic/Abc/All.h>
|
||||
#include <Alembic/AbcGeom/All.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define ABC_INLINE static __forceinline
|
||||
#else
|
||||
# define ABC_INLINE static inline
|
||||
#endif
|
||||
|
||||
using Alembic::Abc::chrono_t;
|
||||
|
||||
class ImportSettings;
|
||||
|
||||
struct ID;
|
||||
struct Object;
|
||||
|
||||
std::string get_id_name(ID *id);
|
||||
std::string get_id_name(Object *ob);
|
||||
std::string get_object_dag_path_name(Object *ob, Object *dupli_parent);
|
||||
|
||||
bool object_selected(Object *ob);
|
||||
bool parent_selected(Object *ob);
|
||||
|
||||
Imath::M44d convert_matrix(float mat[4][4]);
|
||||
void create_transform_matrix(float r_mat[4][4]);
|
||||
void create_transform_matrix(Object *obj, float transform_mat[4][4]);
|
||||
|
||||
void split(const std::string &s, const char delim, std::vector<std::string> &tokens);
|
||||
|
||||
template<class TContainer>
|
||||
bool begins_with(const TContainer &input, const TContainer &match)
|
||||
{
|
||||
return input.size() >= match.size()
|
||||
&& std::equal(match.begin(), match.end(), input.begin());
|
||||
}
|
||||
|
||||
void create_input_transform(const Alembic::AbcGeom::ISampleSelector &sample_sel,
|
||||
const Alembic::AbcGeom::IXform &ixform, Object *ob,
|
||||
float r_mat[4][4], float scale, bool has_alembic_parent = false);
|
||||
|
||||
template <typename Schema>
|
||||
void get_min_max_time(const Schema &schema, chrono_t &min, chrono_t &max)
|
||||
{
|
||||
const Alembic::Abc::TimeSamplingPtr &time_samp = schema.getTimeSampling();
|
||||
|
||||
if (!schema.isConstant()) {
|
||||
const size_t num_samps = schema.getNumSamples();
|
||||
|
||||
if (num_samps > 0) {
|
||||
const chrono_t min_time = time_samp->getSampleTime(0);
|
||||
min = std::min(min, min_time);
|
||||
|
||||
const chrono_t max_time = time_samp->getSampleTime(num_samps - 1);
|
||||
max = std::max(max, max_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name);
|
||||
|
||||
/* ************************** */
|
||||
|
||||
/* TODO(kevin): for now keeping these transformations hardcoded to make sure
|
||||
* everything works properly, and also because Alembic is almost exclusively
|
||||
* used in Y-up software, but eventually they'll be set by the user in the UI
|
||||
* like other importers/exporters do, to support other axis. */
|
||||
|
||||
/* Copy from Y-up to Z-up. */
|
||||
|
||||
ABC_INLINE void copy_yup_zup(float zup[3], const float yup[3])
|
||||
{
|
||||
zup[0] = yup[0];
|
||||
zup[1] = -yup[2];
|
||||
zup[2] = yup[1];
|
||||
}
|
||||
|
||||
ABC_INLINE void copy_yup_zup(short zup[3], const short yup[3])
|
||||
{
|
||||
zup[0] = yup[0];
|
||||
zup[1] = -yup[2];
|
||||
zup[2] = yup[1];
|
||||
}
|
||||
|
||||
/* Copy from Z-up to Y-up. */
|
||||
|
||||
ABC_INLINE void copy_zup_yup(float yup[3], const float zup[3])
|
||||
{
|
||||
yup[0] = zup[0];
|
||||
yup[1] = zup[2];
|
||||
yup[2] = -zup[1];
|
||||
}
|
||||
|
||||
ABC_INLINE void copy_zup_yup(short yup[3], const short zup[3])
|
||||
{
|
||||
yup[0] = zup[0];
|
||||
yup[1] = zup[2];
|
||||
yup[2] = -zup[1];
|
||||
}
|
||||
|
||||
#endif /* __ABC_UTIL_H__ */
|
1136
source/blender/alembic/intern/alembic_capi.cc
Normal file
1136
source/blender/alembic/intern/alembic_capi.cc
Normal file
File diff suppressed because it is too large
Load Diff
67
source/blender/blenkernel/BKE_cachefile.h
Normal file
67
source/blender/blenkernel/BKE_cachefile.h
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributor(s): Kevin Dietrich.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __BKE_CACHEFILE_H__
|
||||
#define __BKE_CACHEFILE_H__
|
||||
|
||||
/** \file BKE_cachefile.h
|
||||
* \ingroup bke
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct CacheFile;
|
||||
struct Main;
|
||||
struct Scene;
|
||||
|
||||
void *BKE_cachefile_add(struct Main *bmain, const char *name);
|
||||
|
||||
void BKE_cachefile_init(struct CacheFile *cache_file);
|
||||
|
||||
void BKE_cachefile_free(struct CacheFile *cache_file);
|
||||
|
||||
struct CacheFile *BKE_cachefile_copy(struct Main *bmain, struct CacheFile *cache_file);
|
||||
|
||||
void BKE_cachefile_make_local(struct Main *bmain, struct CacheFile *cache_file, const bool lib_local);
|
||||
|
||||
void BKE_cachefile_reload(const struct Main *bmain, struct CacheFile *cache_file);
|
||||
|
||||
void BKE_cachefile_ensure_handle(const struct Main *bmain, struct CacheFile *cache_file);
|
||||
|
||||
void BKE_cachefile_update_frame(struct Main *bmain, struct Scene *scene, float ctime, const float fps);
|
||||
|
||||
bool BKE_cachefile_filepath_get(
|
||||
const struct Main *bmain, const struct CacheFile *cache_file, float frame,
|
||||
char r_filename[1024]);
|
||||
|
||||
float BKE_cachefile_time_offset(struct CacheFile *cache_file, const float time, const float fps);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __BKE_CACHEFILE_H__ */
|
@ -39,6 +39,7 @@ extern "C" {
|
||||
|
||||
struct ARegion;
|
||||
struct bScreen;
|
||||
struct CacheFile;
|
||||
struct ListBase;
|
||||
struct Main;
|
||||
struct Object;
|
||||
@ -271,6 +272,8 @@ struct Text *CTX_data_edit_text(const bContext *C);
|
||||
struct MovieClip *CTX_data_edit_movieclip(const bContext *C);
|
||||
struct Mask *CTX_data_edit_mask(const bContext *C);
|
||||
|
||||
struct CacheFile *CTX_data_edit_cachefile(const bContext *C);
|
||||
|
||||
int CTX_data_selected_nodes(const bContext *C, ListBase *list);
|
||||
|
||||
struct EditBone *CTX_data_active_bone(const bContext *C);
|
||||
|
@ -94,7 +94,7 @@ void id_clear_lib_data_ex(struct Main *bmain, struct ID *id, const bool id_in_ma
|
||||
|
||||
struct ListBase *which_libbase(struct Main *mainlib, short type);
|
||||
|
||||
#define MAX_LIBARRAY 34
|
||||
#define MAX_LIBARRAY 35
|
||||
int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
|
||||
|
||||
/* Main API */
|
||||
|
@ -102,6 +102,7 @@ typedef struct Main {
|
||||
ListBase movieclip;
|
||||
ListBase mask;
|
||||
ListBase linestyle;
|
||||
ListBase cachefiles;
|
||||
|
||||
char id_tag_update[256];
|
||||
|
||||
|
@ -81,6 +81,7 @@ set(SRC
|
||||
intern/brush.c
|
||||
intern/bullet.c
|
||||
intern/bvhutils.c
|
||||
intern/cachefile.c
|
||||
intern/camera.c
|
||||
intern/cdderivedmesh.c
|
||||
intern/cloth.c
|
||||
@ -207,6 +208,7 @@ set(SRC
|
||||
BKE_brush.h
|
||||
BKE_bullet.h
|
||||
BKE_bvhutils.h
|
||||
BKE_cachefile.h
|
||||
BKE_camera.h
|
||||
BKE_ccg.h
|
||||
BKE_cdderivedmesh.h
|
||||
@ -500,6 +502,13 @@ if(WITH_FREESTYLE)
|
||||
add_definitions(-DWITH_FREESTYLE)
|
||||
endif()
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
list(APPEND INC
|
||||
../alembic
|
||||
)
|
||||
add_definitions(-DWITH_ALEMBIC)
|
||||
endif()
|
||||
|
||||
if(WITH_OPENSUBDIV)
|
||||
add_definitions(-DWITH_OPENSUBDIV)
|
||||
list(APPEND INC_SYS
|
||||
|
@ -97,6 +97,7 @@ bool id_type_can_have_animdata(const short id_type)
|
||||
case ID_MC:
|
||||
case ID_MSK:
|
||||
case ID_GD:
|
||||
case ID_CF:
|
||||
return true;
|
||||
|
||||
/* no AnimData */
|
||||
@ -1160,6 +1161,9 @@ void BKE_animdata_main_cb(Main *mainptr, ID_AnimData_Edit_Callback func, void *u
|
||||
|
||||
/* grease pencil */
|
||||
ANIMDATA_IDS_CB(mainptr->gpencil.first);
|
||||
|
||||
/* cache files */
|
||||
ANIMDATA_IDS_CB(mainptr->cachefiles.first);
|
||||
}
|
||||
|
||||
/* Fix all RNA-Paths throughout the database (directly access the Global.main version)
|
||||
@ -1250,6 +1254,9 @@ void BKE_animdata_fix_paths_rename_all(ID *ref_id, const char *prefix, const cha
|
||||
|
||||
/* grease pencil */
|
||||
RENAMEFIX_ANIM_IDS(mainptr->gpencil.first);
|
||||
|
||||
/* cache files */
|
||||
RENAMEFIX_ANIM_IDS(mainptr->cachefiles.first);
|
||||
|
||||
/* scenes */
|
||||
RENAMEFIX_ANIM_NODETREE_IDS(mainptr->scene.first, Scene);
|
||||
@ -2873,6 +2880,9 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
|
||||
|
||||
/* grease pencil */
|
||||
EVAL_ANIM_IDS(main->gpencil.first, ADT_RECALC_ANIM);
|
||||
|
||||
/* cache files */
|
||||
EVAL_ANIM_IDS(main->cachefiles.first, ADT_RECALC_ANIM);
|
||||
|
||||
/* objects */
|
||||
/* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_brush_types.h"
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_image_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
@ -653,6 +654,12 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
|
||||
rewrite_path_fixed(clip->name, visit_cb, absbase, bpath_user_data);
|
||||
break;
|
||||
}
|
||||
case ID_CF:
|
||||
{
|
||||
CacheFile *cache_file = (CacheFile *)id;
|
||||
rewrite_path_fixed(cache_file->filepath, visit_cb, absbase, bpath_user_data);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* Nothing to do for other IDs that don't contain file paths. */
|
||||
break;
|
||||
|
173
source/blender/blenkernel/intern/cachefile.c
Normal file
173
source/blender/blenkernel/intern/cachefile.c
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributor(s): Kevin Dietrich.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/blenkernel/intern/cachefile.c
|
||||
* \ingroup bke
|
||||
*/
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BLI_fileops.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_path_util.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_animsys.h"
|
||||
#include "BKE_cachefile.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_library.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_scene.h"
|
||||
|
||||
#ifdef WITH_ALEMBIC
|
||||
# include "ABC_alembic.h"
|
||||
#endif
|
||||
|
||||
void *BKE_cachefile_add(Main *bmain, const char *name)
|
||||
{
|
||||
CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, name);
|
||||
|
||||
BKE_cachefile_init(cache_file);
|
||||
|
||||
return cache_file;
|
||||
}
|
||||
|
||||
void BKE_cachefile_init(CacheFile *cache_file)
|
||||
{
|
||||
cache_file->handle = NULL;
|
||||
cache_file->filepath[0] = '\0';
|
||||
cache_file->override_frame = false;
|
||||
cache_file->frame = 0.0f;
|
||||
cache_file->is_sequence = false;
|
||||
cache_file->scale = 1.0f;
|
||||
}
|
||||
|
||||
/** Free (or release) any data used by this cachefile (does not free the cachefile itself). */
|
||||
void BKE_cachefile_free(CacheFile *cache_file)
|
||||
{
|
||||
BKE_animdata_free((ID *)cache_file, false);
|
||||
|
||||
#ifdef WITH_ALEMBIC
|
||||
ABC_free_handle(cache_file->handle);
|
||||
#endif
|
||||
|
||||
BLI_freelistN(&cache_file->object_paths);
|
||||
}
|
||||
|
||||
CacheFile *BKE_cachefile_copy(Main *bmain, CacheFile *cache_file)
|
||||
{
|
||||
CacheFile *new_cache_file = BKE_libblock_copy(bmain, &cache_file->id);
|
||||
new_cache_file->handle = NULL;
|
||||
|
||||
BLI_listbase_clear(&cache_file->object_paths);
|
||||
|
||||
BKE_id_copy_ensure_local(bmain, &cache_file->id, &new_cache_file->id);
|
||||
|
||||
return new_cache_file;
|
||||
}
|
||||
|
||||
void BKE_cachefile_make_local(Main *bmain, CacheFile *cache_file, const bool lib_local)
|
||||
{
|
||||
BKE_id_make_local_generic(bmain, &cache_file->id, true, lib_local);
|
||||
}
|
||||
|
||||
void BKE_cachefile_reload(const Main *bmain, CacheFile *cache_file)
|
||||
{
|
||||
char filepath[FILE_MAX];
|
||||
|
||||
BLI_strncpy(filepath, cache_file->filepath, sizeof(filepath));
|
||||
BLI_path_abs(filepath, ID_BLEND_PATH(bmain, &cache_file->id));
|
||||
|
||||
#ifdef WITH_ALEMBIC
|
||||
if (cache_file->handle) {
|
||||
ABC_free_handle(cache_file->handle);
|
||||
}
|
||||
|
||||
cache_file->handle = ABC_create_handle(filepath, &cache_file->object_paths);
|
||||
#endif
|
||||
}
|
||||
|
||||
void BKE_cachefile_ensure_handle(const Main *bmain, CacheFile *cache_file)
|
||||
{
|
||||
if (cache_file->handle == NULL) {
|
||||
BKE_cachefile_reload(bmain, cache_file);
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_cachefile_update_frame(Main *bmain, Scene *scene, const float ctime, const float fps)
|
||||
{
|
||||
CacheFile *cache_file;
|
||||
char filename[FILE_MAX];
|
||||
|
||||
for (cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) {
|
||||
/* Execute drivers only, as animation has already been done. */
|
||||
BKE_animsys_evaluate_animdata(scene, &cache_file->id, cache_file->adt, ctime, ADT_RECALC_DRIVERS);
|
||||
|
||||
if (!cache_file->is_sequence) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const float time = BKE_cachefile_time_offset(cache_file, ctime, fps);
|
||||
|
||||
if (BKE_cachefile_filepath_get(bmain, cache_file, time, filename)) {
|
||||
#ifdef WITH_ALEMBIC
|
||||
ABC_free_handle(cache_file->handle);
|
||||
cache_file->handle = ABC_create_handle(filename, NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BKE_cachefile_filepath_get(
|
||||
const Main *bmain, const CacheFile *cache_file, float frame,
|
||||
char r_filepath[FILE_MAX])
|
||||
{
|
||||
BLI_strncpy(r_filepath, cache_file->filepath, FILE_MAX);
|
||||
BLI_path_abs(r_filepath, ID_BLEND_PATH(bmain, &cache_file->id));
|
||||
|
||||
int fframe;
|
||||
int frame_len;
|
||||
|
||||
if (cache_file->is_sequence && BLI_path_frame_get(r_filepath, &fframe, &frame_len)) {
|
||||
char ext[32];
|
||||
BLI_path_frame_strip(r_filepath, true, ext);
|
||||
BLI_path_frame(r_filepath, frame, frame_len);
|
||||
BLI_ensure_extension(r_filepath, FILE_MAX, ext);
|
||||
|
||||
/* TODO(kevin): store sequence range? */
|
||||
return BLI_exists(r_filepath);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float BKE_cachefile_time_offset(CacheFile *cache_file, const float time, const float fps)
|
||||
{
|
||||
const float frame = (cache_file->override_frame ? cache_file->frame : time);
|
||||
return cache_file->is_sequence ? frame : frame / fps;
|
||||
}
|
@ -3402,7 +3402,7 @@ void CDDM_calc_edges(DerivedMesh *dm)
|
||||
BLI_edgehashIterator_getKey(ehi, &med->v1, &med->v2);
|
||||
j = GET_INT_FROM_POINTER(BLI_edgehashIterator_getValue(ehi));
|
||||
|
||||
if (j == 0) {
|
||||
if (j == 0 || !eindex) {
|
||||
med->flag = ME_EDGEDRAW | ME_EDGERENDER;
|
||||
*index = ORIGINDEX_NONE;
|
||||
}
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
@ -63,6 +64,7 @@
|
||||
#include "BKE_anim.h" /* for the curve calculation part */
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_bvhutils.h"
|
||||
#include "BKE_cachefile.h"
|
||||
#include "BKE_camera.h"
|
||||
#include "BKE_constraint.h"
|
||||
#include "BKE_curve.h"
|
||||
@ -86,6 +88,10 @@
|
||||
# include "BPY_extern.h"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_ALEMBIC
|
||||
# include "ABC_alembic.h"
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* Useful macros for testing various common flag combinations */
|
||||
|
||||
@ -4333,6 +4339,73 @@ static bConstraintTypeInfo CTI_OBJECTSOLVER = {
|
||||
objectsolver_evaluate /* evaluate */
|
||||
};
|
||||
|
||||
/* ----------- Transform Cache ------------- */
|
||||
|
||||
static void transformcache_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
|
||||
{
|
||||
bTransformCacheConstraint *data = con->data;
|
||||
func(con, (ID **)&data->cache_file, false, userdata);
|
||||
}
|
||||
|
||||
static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
|
||||
{
|
||||
#ifdef WITH_ALEMBIC
|
||||
bTransformCacheConstraint *data = con->data;
|
||||
Scene *scene = cob->scene;
|
||||
|
||||
const float frame = BKE_scene_frame_get(scene);
|
||||
const float time = BKE_cachefile_time_offset(data->cache_file, frame, FPS);
|
||||
|
||||
CacheFile *cache_file = data->cache_file;
|
||||
|
||||
BKE_cachefile_ensure_handle(G.main, cache_file);
|
||||
|
||||
ABC_get_transform(cache_file->handle, cob->ob, data->object_path,
|
||||
cob->matrix, time, cache_file->scale);
|
||||
#else
|
||||
UNUSED_VARS(con, cob);
|
||||
#endif
|
||||
|
||||
UNUSED_VARS(targets);
|
||||
}
|
||||
|
||||
static void transformcache_copy(bConstraint *con, bConstraint *srccon)
|
||||
{
|
||||
bTransformCacheConstraint *src = srccon->data;
|
||||
bTransformCacheConstraint *dst = con->data;
|
||||
|
||||
BLI_strncpy(dst->object_path, src->object_path, sizeof(dst->object_path));
|
||||
dst->cache_file = src->cache_file;
|
||||
|
||||
if (dst->cache_file) {
|
||||
id_us_plus(&dst->cache_file->id);
|
||||
}
|
||||
}
|
||||
|
||||
static void transformcache_free(bConstraint *con)
|
||||
{
|
||||
bTransformCacheConstraint *data = con->data;
|
||||
|
||||
if (data->cache_file) {
|
||||
id_us_min(&data->cache_file->id);
|
||||
}
|
||||
}
|
||||
|
||||
static bConstraintTypeInfo CTI_TRANSFORM_CACHE = {
|
||||
CONSTRAINT_TYPE_TRANSFORM_CACHE, /* type */
|
||||
sizeof(bTransformCacheConstraint), /* size */
|
||||
"Transform Cache", /* name */
|
||||
"bTransformCacheConstraint", /* struct name */
|
||||
transformcache_free, /* free data */
|
||||
transformcache_id_looper, /* id looper */
|
||||
transformcache_copy, /* copy data */
|
||||
NULL, /* new data */
|
||||
NULL, /* get constraint targets */
|
||||
NULL, /* flush constraint targets */
|
||||
NULL, /* get target matrix */
|
||||
transformcache_evaluate /* evaluate */
|
||||
};
|
||||
|
||||
/* ************************* Constraints Type-Info *************************** */
|
||||
/* All of the constraints api functions use bConstraintTypeInfo structs to carry out
|
||||
* and operations that involve constraint specific code.
|
||||
@ -4374,6 +4447,7 @@ static void constraints_init_typeinfo(void)
|
||||
constraintsTypeInfo[26] = &CTI_FOLLOWTRACK; /* Follow Track Constraint */
|
||||
constraintsTypeInfo[27] = &CTI_CAMERASOLVER; /* Camera Solver Constraint */
|
||||
constraintsTypeInfo[28] = &CTI_OBJECTSOLVER; /* Object Solver Constraint */
|
||||
constraintsTypeInfo[29] = &CTI_TRANSFORM_CACHE; /* Transform Cache Constraint */
|
||||
}
|
||||
|
||||
/* This function should be used for getting the appropriate type-info when only
|
||||
|
@ -1067,6 +1067,11 @@ struct EditBone *CTX_data_active_bone(const bContext *C)
|
||||
return ctx_data_pointer_get(C, "active_bone");
|
||||
}
|
||||
|
||||
struct CacheFile *CTX_data_edit_cachefile(const bContext *C)
|
||||
{
|
||||
return ctx_data_pointer_get(C, "edit_cachefile");
|
||||
}
|
||||
|
||||
int CTX_data_selected_bones(const bContext *C, ListBase *list)
|
||||
{
|
||||
return ctx_data_collection_get(C, "selected_bones", list);
|
||||
|
@ -46,6 +46,7 @@
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_group_types.h"
|
||||
#include "DNA_lamp_types.h"
|
||||
#include "DNA_lattice_types.h"
|
||||
@ -2173,7 +2174,12 @@ static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob)
|
||||
|
||||
if (cti) {
|
||||
/* special case for camera tracking -- it doesn't use targets to define relations */
|
||||
if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) {
|
||||
if (ELEM(cti->type,
|
||||
CONSTRAINT_TYPE_FOLLOWTRACK,
|
||||
CONSTRAINT_TYPE_CAMERASOLVER,
|
||||
CONSTRAINT_TYPE_OBJECTSOLVER,
|
||||
CONSTRAINT_TYPE_TRANSFORM_CACHE))
|
||||
{
|
||||
ob->recalc |= OB_RECALC_OB;
|
||||
}
|
||||
else if (cti->get_constraint_targets) {
|
||||
@ -3001,6 +3007,33 @@ void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag)
|
||||
/* BLI_assert(!"invalid flag for this 'idtype'"); */
|
||||
}
|
||||
}
|
||||
else if (GS(id->name) == ID_CF) {
|
||||
for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
|
||||
ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
|
||||
|
||||
if (md) {
|
||||
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
|
||||
|
||||
if (mcmd->cache_file && (&mcmd->cache_file->id == id)) {
|
||||
ob->recalc |= OB_RECALC_DATA;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for (bConstraint *con = ob->constraints.first; con; con = con->next) {
|
||||
if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bTransformCacheConstraint *data = con->data;
|
||||
|
||||
if (data->cache_file && (&data->cache_file->id == id)) {
|
||||
ob->recalc |= OB_RECALC_DATA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DAG_id_tag_update(ID *id, short flag)
|
||||
|
@ -60,6 +60,7 @@ static IDType idtypes[] = {
|
||||
{ ID_AR, "Armature", "armatures", BLT_I18NCONTEXT_ID_ARMATURE, IDTYPE_FLAGS_ISLINKABLE },
|
||||
{ ID_BR, "Brush", "brushes", BLT_I18NCONTEXT_ID_BRUSH, IDTYPE_FLAGS_ISLINKABLE },
|
||||
{ ID_CA, "Camera", "cameras", BLT_I18NCONTEXT_ID_CAMERA, IDTYPE_FLAGS_ISLINKABLE },
|
||||
{ ID_CF, "CacheFile", "cache_files", BLT_I18NCONTEXT_ID_CACHEFILE, IDTYPE_FLAGS_ISLINKABLE },
|
||||
{ ID_CU, "Curve", "curves", BLT_I18NCONTEXT_ID_CURVE, IDTYPE_FLAGS_ISLINKABLE },
|
||||
{ ID_GD, "GPencil", "grease_pencil", BLT_I18NCONTEXT_ID_GPENCIL, IDTYPE_FLAGS_ISLINKABLE }, /* rename gpencil */
|
||||
{ ID_GR, "Group", "groups", BLT_I18NCONTEXT_ID_GROUP, IDTYPE_FLAGS_ISLINKABLE },
|
||||
@ -184,6 +185,7 @@ int BKE_idcode_to_idfilter(const short idcode)
|
||||
CASE_IDFILTER(AR);
|
||||
CASE_IDFILTER(BR);
|
||||
CASE_IDFILTER(CA);
|
||||
CASE_IDFILTER(CF);
|
||||
CASE_IDFILTER(CU);
|
||||
CASE_IDFILTER(GD);
|
||||
CASE_IDFILTER(GR);
|
||||
@ -227,6 +229,7 @@ short BKE_idcode_from_idfilter(const int idfilter)
|
||||
CASE_IDFILTER(AR);
|
||||
CASE_IDFILTER(BR);
|
||||
CASE_IDFILTER(CA);
|
||||
CASE_IDFILTER(CF);
|
||||
CASE_IDFILTER(CU);
|
||||
CASE_IDFILTER(GD);
|
||||
CASE_IDFILTER(GR);
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_brush_types.h"
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_group_types.h"
|
||||
#include "DNA_gpencil_types.h"
|
||||
@ -56,6 +57,7 @@
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meta_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_movieclip_types.h"
|
||||
#include "DNA_mask_types.h"
|
||||
#include "DNA_node_types.h"
|
||||
@ -81,6 +83,7 @@
|
||||
#include "BKE_bpath.h"
|
||||
#include "BKE_brush.h"
|
||||
#include "BKE_camera.h"
|
||||
#include "BKE_cachefile.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_depsgraph.h"
|
||||
@ -425,6 +428,9 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local)
|
||||
case ID_PC:
|
||||
if (!test) BKE_paint_curve_make_local(bmain, (PaintCurve *)id, lib_local);
|
||||
return true;
|
||||
case ID_CF:
|
||||
if (!test) BKE_cachefile_make_local(bmain, (CacheFile *)id, lib_local);
|
||||
return true;
|
||||
case ID_SCR:
|
||||
case ID_LI:
|
||||
case ID_KE:
|
||||
@ -529,6 +535,9 @@ bool id_copy(Main *bmain, ID *id, ID **newid, bool test)
|
||||
case ID_PC:
|
||||
if (!test) *newid = (ID *)BKE_paint_curve_copy(bmain, (PaintCurve *)id);
|
||||
return true;
|
||||
case ID_CF:
|
||||
if (!test) *newid = (ID *)BKE_cachefile_copy(bmain, (CacheFile *)id);
|
||||
return true;
|
||||
case ID_SCE:
|
||||
case ID_LI:
|
||||
case ID_SCR:
|
||||
@ -641,6 +650,8 @@ ListBase *which_libbase(Main *mainlib, short type)
|
||||
return &(mainlib->palettes);
|
||||
case ID_PC:
|
||||
return &(mainlib->paintcurves);
|
||||
case ID_CF:
|
||||
return &(mainlib->cachefiles);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -764,6 +775,7 @@ int set_listbasepointers(Main *main, ListBase **lb)
|
||||
|
||||
lb[a++] = &(main->armature);
|
||||
|
||||
lb[a++] = &(main->cachefiles);
|
||||
lb[a++] = &(main->mesh);
|
||||
lb[a++] = &(main->curve);
|
||||
lb[a++] = &(main->mball);
|
||||
@ -915,6 +927,9 @@ void *BKE_libblock_alloc_notest(short type)
|
||||
case ID_PC:
|
||||
id = MEM_callocN(sizeof(PaintCurve), "Paint Curve");
|
||||
break;
|
||||
case ID_CF:
|
||||
id = MEM_callocN(sizeof(CacheFile), "Cache File");
|
||||
break;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
@ -1041,6 +1056,9 @@ void BKE_libblock_init_empty(ID *id)
|
||||
case ID_LS:
|
||||
BKE_linestyle_init((FreestyleLineStyle *)id);
|
||||
break;
|
||||
case ID_CF:
|
||||
BKE_cachefile_init((CacheFile *)id);
|
||||
break;
|
||||
case ID_KE:
|
||||
/* Shapekeys are a complex topic too - they depend on their 'user' data type...
|
||||
* They are not linkable, though, so it should never reach here anyway. */
|
||||
@ -1228,6 +1246,7 @@ void BKE_main_free(Main *mainvar)
|
||||
case 31: BKE_libblock_free_ex(mainvar, id, false); break;
|
||||
case 32: BKE_libblock_free_ex(mainvar, id, false); break;
|
||||
case 33: BKE_libblock_free_ex(mainvar, id, false); break;
|
||||
case 34: BKE_libblock_free_ex(mainvar, id, false); break;
|
||||
default:
|
||||
BLI_assert(0);
|
||||
break;
|
||||
|
@ -854,6 +854,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
|
||||
case ID_WM:
|
||||
case ID_PAL:
|
||||
case ID_PC:
|
||||
case ID_CF:
|
||||
break;
|
||||
|
||||
/* Deprecated. */
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_brush_types.h"
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_group_types.h"
|
||||
#include "DNA_gpencil_types.h"
|
||||
#include "DNA_ipo_types.h"
|
||||
@ -69,6 +70,7 @@
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_brush.h"
|
||||
#include "BKE_camera.h"
|
||||
#include "BKE_cachefile.h"
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_depsgraph.h"
|
||||
#include "BKE_fcurve.h"
|
||||
@ -812,6 +814,9 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user)
|
||||
case ID_PC:
|
||||
BKE_paint_curve_free((PaintCurve *)id);
|
||||
break;
|
||||
case ID_CF:
|
||||
BKE_cachefile_free((CacheFile *)id);
|
||||
break;
|
||||
}
|
||||
|
||||
/* avoid notifying on removed data */
|
||||
|
@ -65,6 +65,7 @@
|
||||
#include "BKE_animsys.h"
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_cachefile.h"
|
||||
#include "BKE_colortools.h"
|
||||
#include "BKE_depsgraph.h"
|
||||
#include "BKE_editmesh.h"
|
||||
@ -1926,6 +1927,9 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
|
||||
|
||||
BKE_mask_evaluate_all_masks(bmain, ctime, true);
|
||||
|
||||
/* Update animated cache files for modifiers. */
|
||||
BKE_cachefile_update_frame(bmain, sce, ctime, (((double)sce->r.frs_sec) / (double)sce->r.frs_sec_base));
|
||||
|
||||
#ifdef POSE_ANIMATION_WORKAROUND
|
||||
scene_armature_depsgraph_workaround(bmain);
|
||||
#endif
|
||||
|
@ -77,6 +77,13 @@ if(WITH_CODEC_FFMPEG)
|
||||
add_definitions(-DWITH_FFMPEG)
|
||||
endif()
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
list(APPEND INC
|
||||
../alembic
|
||||
)
|
||||
add_definitions(-DWITH_ALEMBIC)
|
||||
endif()
|
||||
|
||||
blender_add_lib(bf_blenloader "${SRC}" "${INC}" "${INC_SYS}")
|
||||
|
||||
# needed so writefile.c can use dna_type_offsets.h
|
||||
|
@ -59,6 +59,7 @@
|
||||
#include "DNA_actuator_types.h"
|
||||
#include "DNA_brush_types.h"
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_cloth_types.h"
|
||||
#include "DNA_controller_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
@ -114,6 +115,7 @@
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_brush.h"
|
||||
#include "BKE_cachefile.h"
|
||||
#include "BKE_cloth.h"
|
||||
#include "BKE_constraint.h"
|
||||
#include "BKE_context.h"
|
||||
@ -2691,6 +2693,36 @@ static void direct_link_animdata(FileData *fd, AnimData *adt)
|
||||
adt->actstrip = newdataadr(fd, adt->actstrip);
|
||||
}
|
||||
|
||||
/* ************ READ CACHEFILES *************** */
|
||||
|
||||
static void lib_link_cachefiles(FileData *fd, Main *bmain)
|
||||
{
|
||||
CacheFile *cache_file;
|
||||
|
||||
/* only link ID pointers */
|
||||
for (cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) {
|
||||
if (cache_file->id.tag & LIB_TAG_NEED_LINK) {
|
||||
cache_file->id.tag &= ~LIB_TAG_NEED_LINK;
|
||||
}
|
||||
|
||||
BLI_listbase_clear(&cache_file->object_paths);
|
||||
cache_file->handle = NULL;
|
||||
|
||||
if (cache_file->adt) {
|
||||
lib_link_animdata(fd, &cache_file->id, cache_file->adt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void direct_link_cachefile(FileData *fd, CacheFile *cache_file)
|
||||
{
|
||||
cache_file->handle = NULL;
|
||||
|
||||
/* relink animdata */
|
||||
cache_file->adt = newdataadr(fd, cache_file->adt);
|
||||
direct_link_animdata(fd, cache_file->adt);
|
||||
}
|
||||
|
||||
/* ************ READ MOTION PATHS *************** */
|
||||
|
||||
/* direct data for cache */
|
||||
@ -7912,6 +7944,7 @@ static const char *dataname(short id_code)
|
||||
case ID_MC: return "Data from MC";
|
||||
case ID_MSK: return "Data from MSK";
|
||||
case ID_LS: return "Data from LS";
|
||||
case ID_CF: return "Data from CF";
|
||||
}
|
||||
return "Data from Lib Block";
|
||||
|
||||
@ -8163,6 +8196,9 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
|
||||
case ID_PC:
|
||||
direct_link_paint_curve(fd, (PaintCurve *)id);
|
||||
break;
|
||||
case ID_CF:
|
||||
direct_link_cachefile(fd, (CacheFile *)id);
|
||||
break;
|
||||
}
|
||||
|
||||
oldnewmap_free_unused(fd->datamap);
|
||||
@ -8356,6 +8392,7 @@ static void lib_link_all(FileData *fd, Main *main)
|
||||
lib_link_mask(fd, main);
|
||||
lib_link_linestyle(fd, main);
|
||||
lib_link_gpencil(fd, main);
|
||||
lib_link_cachefiles(fd, main);
|
||||
|
||||
lib_link_mesh(fd, main); /* as last: tpage images with users at zero */
|
||||
|
||||
@ -9462,6 +9499,13 @@ static void expand_camera(FileData *fd, Main *mainvar, Camera *ca)
|
||||
expand_animdata(fd, mainvar, ca->adt);
|
||||
}
|
||||
|
||||
static void expand_cachefile(FileData *fd, Main *mainvar, CacheFile *cache_file)
|
||||
{
|
||||
if (cache_file->adt) {
|
||||
expand_animdata(fd, mainvar, cache_file->adt);
|
||||
}
|
||||
}
|
||||
|
||||
static void expand_speaker(FileData *fd, Main *mainvar, Speaker *spk)
|
||||
{
|
||||
expand_doit(fd, mainvar, spk->sound);
|
||||
@ -9657,6 +9701,9 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
|
||||
case ID_GD:
|
||||
expand_gpencil(fd, mainvar, (bGPdata *)id);
|
||||
break;
|
||||
case ID_CF:
|
||||
expand_cachefile(fd, mainvar, (CacheFile *)id);
|
||||
break;
|
||||
}
|
||||
|
||||
do_it = true;
|
||||
|
@ -107,6 +107,7 @@
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_actuator_types.h"
|
||||
#include "DNA_brush_types.h"
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_cloth_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
@ -3882,6 +3883,21 @@ static void write_linestyles(WriteData *wd, ListBase *idbase)
|
||||
}
|
||||
}
|
||||
|
||||
static void write_cachefiles(WriteData *wd, ListBase *idbase)
|
||||
{
|
||||
CacheFile *cache_file;
|
||||
|
||||
for (cache_file = idbase->first; cache_file; cache_file = cache_file->id.next) {
|
||||
if (cache_file->id.us > 0 || wd->current) {
|
||||
writestruct(wd, ID_CF, CacheFile, 1, cache_file);
|
||||
|
||||
if (cache_file->adt) {
|
||||
write_animdata(wd, cache_file->adt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Keep it last of write_foodata functions. */
|
||||
static void write_libraries(WriteData *wd, Main *main)
|
||||
{
|
||||
@ -4079,6 +4095,7 @@ static bool write_file_handle(
|
||||
write_paintcurves(wd, &mainvar->paintcurves);
|
||||
write_gpencils(wd, &mainvar->gpencil);
|
||||
write_linestyles(wd, &mainvar->linestyle);
|
||||
write_cachefiles(wd, &mainvar->cachefiles);
|
||||
write_libraries(wd, mainvar->next);
|
||||
|
||||
/* So changes above don't cause a 'DNA1' to be detected as changed on undo. */
|
||||
|
@ -120,6 +120,7 @@ bool BLT_lang_is_ime_supported(void);
|
||||
#define BLT_I18NCONTEXT_ID_ARMATURE "Armature"
|
||||
#define BLT_I18NCONTEXT_ID_BRUSH "Brush"
|
||||
#define BLT_I18NCONTEXT_ID_CAMERA "Camera"
|
||||
#define BLT_I18NCONTEXT_ID_CACHEFILE "CacheFile"
|
||||
#define BLT_I18NCONTEXT_ID_CURVE "Curve"
|
||||
#define BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE "FreestyleLineStyle"
|
||||
#define BLT_I18NCONTEXT_ID_GPENCIL "GPencil"
|
||||
@ -171,6 +172,7 @@ typedef struct {
|
||||
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_ARMATURE, "id_armature"), \
|
||||
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_BRUSH, "id_brush"), \
|
||||
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_CAMERA, "id_camera"), \
|
||||
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_CACHEFILE, "id_cachefile"), \
|
||||
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_CURVE, "id_curve"), \
|
||||
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE, "id_fs_linestyle"), \
|
||||
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_GPENCIL, "id_gpencil"), \
|
||||
|
@ -79,6 +79,7 @@ void DEG_scene_graph_free(struct Scene *scene);
|
||||
*/
|
||||
struct DepsNodeHandle;
|
||||
|
||||
struct CacheFile;
|
||||
struct Object;
|
||||
|
||||
typedef enum eDepsSceneComponentType {
|
||||
@ -100,11 +101,13 @@ typedef enum eDepsObjectComponentType {
|
||||
|
||||
DEG_OB_COMP_EVAL_PARTICLES, /* Particle Systems Component */
|
||||
DEG_OB_COMP_SHADING, /* Material Shading Component */
|
||||
DEG_OB_COMP_CACHE, /* Cache Component */
|
||||
} eDepsObjectComponentType;
|
||||
|
||||
void DEG_add_scene_relation(struct DepsNodeHandle *node, struct Scene *scene, eDepsSceneComponentType component, const char *description);
|
||||
void DEG_add_object_relation(struct DepsNodeHandle *node, struct Object *ob, eDepsObjectComponentType component, const char *description);
|
||||
void DEG_add_bone_relation(struct DepsNodeHandle *handle, struct Object *ob, const char *bone_name, eDepsObjectComponentType component, const char *description);
|
||||
void DEG_add_object_cache_relation(struct DepsNodeHandle *handle, struct CacheFile *cache_file, eDepsObjectComponentType component, const char *description);
|
||||
|
||||
/* TODO(sergey): Remove once all geometry update is granular. */
|
||||
void DEG_add_special_eval_flag(struct Depsgraph *graph, struct ID *id, short flag);
|
||||
|
@ -46,6 +46,7 @@ extern "C" {
|
||||
#include "DNA_action_types.h"
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_curve_types.h"
|
||||
@ -339,6 +340,14 @@ void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene)
|
||||
if (scene->gpd) {
|
||||
build_gpencil(scene->gpd);
|
||||
}
|
||||
|
||||
/* cache files */
|
||||
for (CacheFile *cachefile = static_cast<CacheFile *>(bmain->cachefiles.first);
|
||||
cachefile;
|
||||
cachefile = static_cast<CacheFile *>(cachefile->id.next))
|
||||
{
|
||||
build_cachefile(cachefile);
|
||||
}
|
||||
}
|
||||
|
||||
void DepsgraphNodeBuilder::build_group(Scene *scene,
|
||||
@ -1259,4 +1268,18 @@ void DepsgraphNodeBuilder::build_gpencil(bGPdata *gpd)
|
||||
build_animdata(gpd_id);
|
||||
}
|
||||
|
||||
void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file)
|
||||
{
|
||||
ID *cache_file_id = &cache_file->id;
|
||||
|
||||
add_component_node(cache_file_id, DEPSNODE_TYPE_CACHE);
|
||||
|
||||
add_operation_node(cache_file_id, DEPSNODE_TYPE_CACHE,
|
||||
DEPSOP_TYPE_EXEC, NULL,
|
||||
DEG_OPCODE_PLACEHOLDER, "Cache File Update");
|
||||
|
||||
add_id_node(cache_file_id);
|
||||
build_animdata(cache_file_id);
|
||||
}
|
||||
|
||||
} // namespace DEG
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "intern/depsgraph_types.h"
|
||||
|
||||
struct Base;
|
||||
struct CacheFile;
|
||||
struct bGPdata;
|
||||
struct ListBase;
|
||||
struct GHash;
|
||||
@ -144,6 +145,7 @@ struct DepsgraphNodeBuilder {
|
||||
void build_world(World *world);
|
||||
void build_compositor(Scene *scene);
|
||||
void build_gpencil(bGPdata *gpd);
|
||||
void build_cachefile(CacheFile *cache_file);
|
||||
|
||||
protected:
|
||||
Main *m_bmain;
|
||||
|
@ -47,6 +47,7 @@ extern "C" {
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_effect_types.h"
|
||||
@ -599,6 +600,18 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode
|
||||
TimeSourceKey time_src_key;
|
||||
add_relation(time_src_key, constraint_op_key, DEPSREL_TYPE_TIME, "[TimeSrc -> Animation]");
|
||||
}
|
||||
else if (cti->type == CONSTRAINT_TYPE_TRANSFORM_CACHE) {
|
||||
/* TODO(kevin): This is more a TimeSource -> CacheFile -> Constraint dependency chain. */
|
||||
TimeSourceKey time_src_key;
|
||||
add_relation(time_src_key, constraint_op_key, DEPSREL_TYPE_TIME, "[TimeSrc -> Animation]");
|
||||
|
||||
bTransformCacheConstraint *data = (bTransformCacheConstraint *)con->data;
|
||||
|
||||
if (data->cache_file) {
|
||||
ComponentKey cache_key(&data->cache_file->id, DEPSNODE_TYPE_CACHE);
|
||||
add_relation(cache_key, constraint_op_key, DEPSREL_TYPE_CACHE, cti->name);
|
||||
}
|
||||
}
|
||||
else if (cti->get_constraint_targets) {
|
||||
ListBase targets = {NULL, NULL};
|
||||
cti->get_constraint_targets(con, &targets);
|
||||
|
@ -90,6 +90,7 @@ static const int deg_debug_node_type_color_map[][2] = {
|
||||
{DEPSNODE_TYPE_GEOMETRY, 8},
|
||||
{DEPSNODE_TYPE_SEQUENCER, 9},
|
||||
{DEPSNODE_TYPE_SHADING, 10},
|
||||
{DEPSNODE_TYPE_CACHE, 11},
|
||||
{-1, 0}
|
||||
};
|
||||
#endif
|
||||
@ -401,6 +402,7 @@ static void deg_debug_graphviz_node(const DebugContext &ctx,
|
||||
case DEPSNODE_TYPE_EVAL_POSE:
|
||||
case DEPSNODE_TYPE_BONE:
|
||||
case DEPSNODE_TYPE_SHADING:
|
||||
case DEPSNODE_TYPE_CACHE:
|
||||
case DEPSNODE_TYPE_EVAL_PARTICLES:
|
||||
{
|
||||
ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
extern "C" {
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
@ -89,6 +90,7 @@ static DEG::eDepsNode_Type deg_build_object_component_type(
|
||||
case DEG_OB_COMP_BONE: return DEG::DEPSNODE_TYPE_BONE;
|
||||
case DEG_OB_COMP_EVAL_PARTICLES: return DEG::DEPSNODE_TYPE_EVAL_PARTICLES;
|
||||
case DEG_OB_COMP_SHADING: return DEG::DEPSNODE_TYPE_SHADING;
|
||||
case DEG_OB_COMP_CACHE: return DEG::DEPSNODE_TYPE_CACHE;
|
||||
}
|
||||
return DEG::DEPSNODE_TYPE_UNDEFINED;
|
||||
}
|
||||
@ -126,6 +128,20 @@ void DEG_add_object_relation(DepsNodeHandle *handle,
|
||||
description);
|
||||
}
|
||||
|
||||
void DEG_add_object_cache_relation(DepsNodeHandle *handle,
|
||||
CacheFile *cache_file,
|
||||
eDepsObjectComponentType component,
|
||||
const char *description)
|
||||
{
|
||||
DEG::eDepsNode_Type type = deg_build_object_component_type(component);
|
||||
DEG::ComponentKey comp_key(&cache_file->id, type);
|
||||
DEG::DepsNodeHandle *deg_handle = get_handle(handle);
|
||||
deg_handle->builder->add_node_handle_relation(comp_key,
|
||||
deg_handle,
|
||||
DEG::DEPSREL_TYPE_CACHE,
|
||||
description);
|
||||
}
|
||||
|
||||
void DEG_add_bone_relation(DepsNodeHandle *handle,
|
||||
Object *ob,
|
||||
const char *bone_name,
|
||||
|
@ -133,6 +133,8 @@ typedef enum eDepsNode_Type {
|
||||
DEPSNODE_TYPE_EVAL_PARTICLES = 23,
|
||||
/* Material Shading Component */
|
||||
DEPSNODE_TYPE_SHADING = 24,
|
||||
/* Cache Component */
|
||||
DEPSNODE_TYPE_CACHE = 25,
|
||||
} eDepsNode_Type;
|
||||
|
||||
/* Identifiers for common operations (as an enum). */
|
||||
@ -330,6 +332,9 @@ typedef enum eDepsRelation_Type {
|
||||
|
||||
/* relationship is used to trigger editor/screen updates */
|
||||
DEPSREL_TYPE_UPDATE_UI,
|
||||
|
||||
/* cache dependency */
|
||||
DEPSREL_TYPE_CACHE,
|
||||
} eDepsRelation_Type;
|
||||
|
||||
} // namespace DEG
|
||||
|
@ -366,6 +366,11 @@ static DepsNodeFactoryImpl<ParticlesComponentDepsNode> DNTI_EVAL_PARTICLES;
|
||||
DEG_DEPSNODE_DEFINE(ShadingComponentDepsNode, DEPSNODE_TYPE_SHADING, "Shading Component");
|
||||
static DepsNodeFactoryImpl<ShadingComponentDepsNode> DNTI_SHADING;
|
||||
|
||||
/* Cache Component Defines ============================ */
|
||||
|
||||
DEG_DEPSNODE_DEFINE(CacheComponentDepsNode, DEPSNODE_TYPE_CACHE, "Cache Component");
|
||||
static DepsNodeFactoryImpl<CacheComponentDepsNode> DNTI_CACHE;
|
||||
|
||||
|
||||
/* Node Types Register =================================== */
|
||||
|
||||
@ -383,6 +388,8 @@ void deg_register_component_depsnodes()
|
||||
|
||||
deg_register_node_typeinfo(&DNTI_EVAL_PARTICLES);
|
||||
deg_register_node_typeinfo(&DNTI_SHADING);
|
||||
|
||||
deg_register_node_typeinfo(&DNTI_CACHE);
|
||||
}
|
||||
|
||||
} // namespace DEG
|
||||
|
@ -209,6 +209,10 @@ struct ShadingComponentDepsNode : public ComponentDepsNode {
|
||||
DEG_DEPSNODE_DECLARE;
|
||||
};
|
||||
|
||||
struct CacheComponentDepsNode : public ComponentDepsNode {
|
||||
DEG_DEPSNODE_DECLARE;
|
||||
};
|
||||
|
||||
|
||||
void deg_register_component_depsnodes();
|
||||
|
||||
|
@ -40,6 +40,7 @@
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_particle_types.h"
|
||||
@ -1577,6 +1578,88 @@ static bAnimChannelType ACF_DSTEX =
|
||||
|
||||
/* Camera Expander ------------------------------------------- */
|
||||
|
||||
// TODO: just get this from RNA?
|
||||
static int acf_dscachefile_icon(bAnimListElem *ale)
|
||||
{
|
||||
UNUSED_VARS(ale);
|
||||
return ICON_FILE;
|
||||
}
|
||||
|
||||
/* get the appropriate flag(s) for the setting when it is valid */
|
||||
static int acf_dscachefile_setting_flag(bAnimContext *ac, eAnimChannel_Settings setting, bool *neg)
|
||||
{
|
||||
/* clear extra return data first */
|
||||
*neg = false;
|
||||
|
||||
switch (setting) {
|
||||
case ACHANNEL_SETTING_EXPAND: /* expanded */
|
||||
return CACHEFILE_DS_EXPAND;
|
||||
|
||||
case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */
|
||||
return ADT_NLA_EVAL_OFF;
|
||||
|
||||
case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */
|
||||
*neg = true;
|
||||
return ADT_CURVES_NOT_VISIBLE;
|
||||
|
||||
case ACHANNEL_SETTING_SELECT: /* selected */
|
||||
return ADT_UI_SELECTED;
|
||||
|
||||
default: /* unsupported */
|
||||
return 0;
|
||||
}
|
||||
|
||||
UNUSED_VARS(ac);
|
||||
}
|
||||
|
||||
/* get pointer to the setting */
|
||||
static void *acf_dscachefile_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type)
|
||||
{
|
||||
CacheFile *cache_file = (CacheFile *)ale->data;
|
||||
|
||||
/* clear extra return data first */
|
||||
*type = 0;
|
||||
|
||||
switch (setting) {
|
||||
case ACHANNEL_SETTING_EXPAND: /* expanded */
|
||||
return GET_ACF_FLAG_PTR(cache_file->flag, type);
|
||||
|
||||
case ACHANNEL_SETTING_SELECT: /* selected */
|
||||
case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */
|
||||
case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */
|
||||
if (cache_file->adt) {
|
||||
return GET_ACF_FLAG_PTR(cache_file->adt->flag, type);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
default: /* unsupported */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* CacheFile expander type define. */
|
||||
static bAnimChannelType ACF_DSCACHEFILE =
|
||||
{
|
||||
"Cache File Expander", /* type name */
|
||||
ACHANNEL_ROLE_EXPANDER, /* role */
|
||||
|
||||
acf_generic_dataexpand_color, /* backdrop color */
|
||||
acf_generic_dataexpand_backdrop, /* backdrop */
|
||||
acf_generic_indention_1, /* indent level */
|
||||
acf_generic_basic_offset, /* offset */
|
||||
|
||||
acf_generic_idblock_name, /* name */
|
||||
acf_generic_idfill_name_prop, /* name prop */
|
||||
acf_dscachefile_icon, /* icon */
|
||||
|
||||
acf_generic_dataexpand_setting_valid, /* has setting */
|
||||
acf_dscachefile_setting_flag, /* flag for setting */
|
||||
acf_dscachefile_setting_ptr /* pointer for setting */
|
||||
};
|
||||
|
||||
/* Camera Expander ------------------------------------------- */
|
||||
|
||||
// TODO: just get this from RNA?
|
||||
static int acf_dscam_icon(bAnimListElem *UNUSED(ale))
|
||||
{
|
||||
@ -3388,6 +3471,7 @@ static void ANIM_init_channel_typeinfo_data(void)
|
||||
animchannelTypeInfo[type++] = &ACF_DSMAT; /* Material Channel */
|
||||
animchannelTypeInfo[type++] = &ACF_DSLAM; /* Lamp Channel */
|
||||
animchannelTypeInfo[type++] = &ACF_DSCAM; /* Camera Channel */
|
||||
animchannelTypeInfo[type++] = &ACF_DSCACHEFILE; /* CacheFile Channel */
|
||||
animchannelTypeInfo[type++] = &ACF_DSCUR; /* Curve Channel */
|
||||
animchannelTypeInfo[type++] = &ACF_DSSKEY; /* ShapeKey Channel */
|
||||
animchannelTypeInfo[type++] = &ACF_DSWOR; /* World Channel */
|
||||
|
@ -120,6 +120,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
|
||||
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
|
||||
case ANIMTYPE_DSLAM:
|
||||
case ANIMTYPE_DSCAM:
|
||||
case ANIMTYPE_DSCACHEFILE:
|
||||
case ANIMTYPE_DSCUR:
|
||||
case ANIMTYPE_DSSKEY:
|
||||
case ANIMTYPE_DSWOR:
|
||||
@ -175,6 +176,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
|
||||
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
|
||||
case ANIMTYPE_DSLAM:
|
||||
case ANIMTYPE_DSCAM:
|
||||
case ANIMTYPE_DSCACHEFILE:
|
||||
case ANIMTYPE_DSCUR:
|
||||
case ANIMTYPE_DSSKEY:
|
||||
case ANIMTYPE_DSWOR:
|
||||
@ -275,6 +277,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
|
||||
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
|
||||
case ANIMTYPE_DSLAM:
|
||||
case ANIMTYPE_DSCAM:
|
||||
case ANIMTYPE_DSCACHEFILE:
|
||||
case ANIMTYPE_DSCUR:
|
||||
case ANIMTYPE_DSSKEY:
|
||||
case ANIMTYPE_DSWOR:
|
||||
@ -370,6 +373,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
|
||||
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
|
||||
case ANIMTYPE_DSLAM:
|
||||
case ANIMTYPE_DSCAM:
|
||||
case ANIMTYPE_DSCACHEFILE:
|
||||
case ANIMTYPE_DSCUR:
|
||||
case ANIMTYPE_DSSKEY:
|
||||
case ANIMTYPE_DSWOR:
|
||||
@ -2716,6 +2720,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
|
||||
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
|
||||
case ANIMTYPE_DSLAM:
|
||||
case ANIMTYPE_DSCAM:
|
||||
case ANIMTYPE_DSCACHEFILE:
|
||||
case ANIMTYPE_DSCUR:
|
||||
case ANIMTYPE_DSSKEY:
|
||||
case ANIMTYPE_DSWOR:
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_lamp_types.h"
|
||||
#include "DNA_lattice_types.h"
|
||||
#include "DNA_linestyle_types.h"
|
||||
@ -199,6 +200,16 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction)
|
||||
|
||||
ac->mode = saction->mode;
|
||||
return true;
|
||||
|
||||
case SACTCONT_CACHEFILE: /* Cache File */ /* XXX review how this mode is handled... */
|
||||
/* update scene-pointer (no need to check for pinning yet, as not implemented) */
|
||||
saction->ads.source = (ID *)ac->scene;
|
||||
|
||||
ac->datatype = ANIMCONT_CHANNEL;
|
||||
ac->data = &saction->ads;
|
||||
|
||||
ac->mode = saction->mode;
|
||||
return true;
|
||||
|
||||
case SACTCONT_MASK: /* Mask */ /* XXX review how this mode is handled... */
|
||||
{
|
||||
@ -660,6 +671,19 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne
|
||||
ale->adt = BKE_animdata_from_id(data);
|
||||
break;
|
||||
}
|
||||
case ANIMTYPE_DSCACHEFILE:
|
||||
{
|
||||
CacheFile *cache_file = (CacheFile *)data;
|
||||
AnimData *adt = cache_file->adt;
|
||||
|
||||
ale->flag = FILTER_CACHEFILE_OBJD(cache_file);
|
||||
|
||||
ale->key_data = (adt) ? adt->action : NULL;
|
||||
ale->datatype = ALE_ACT;
|
||||
|
||||
ale->adt = BKE_animdata_from_id(data);
|
||||
break;
|
||||
}
|
||||
case ANIMTYPE_DSCUR:
|
||||
{
|
||||
Curve *cu = (Curve *)data;
|
||||
@ -1751,6 +1775,42 @@ static size_t animdata_filter_ds_gpencil(bAnimContext *ac, ListBase *anim_data,
|
||||
return items;
|
||||
}
|
||||
|
||||
/* Helper for Cache File data integrated with main DopeSheet */
|
||||
static size_t animdata_filter_ds_cachefile(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, CacheFile *cache_file, int filter_mode)
|
||||
{
|
||||
ListBase tmp_data = {NULL, NULL};
|
||||
size_t tmp_items = 0;
|
||||
size_t items = 0;
|
||||
|
||||
/* add relevant animation channels for Cache File */
|
||||
BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_CACHEFILE_OBJD(cache_file))
|
||||
{
|
||||
/* add animation channels */
|
||||
tmp_items += animfilter_block_data(ac, &tmp_data, ads, &cache_file->id, filter_mode);
|
||||
}
|
||||
END_ANIMFILTER_SUBCHANNELS;
|
||||
|
||||
/* did we find anything? */
|
||||
if (tmp_items) {
|
||||
/* include data-expand widget first */
|
||||
if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
|
||||
/* check if filtering by active status */
|
||||
// XXX: active check here needs checking
|
||||
if (ANIMCHANNEL_ACTIVEOK(cache_file)) {
|
||||
ANIMCHANNEL_NEW_CHANNEL(cache_file, ANIMTYPE_DSCACHEFILE, cache_file);
|
||||
}
|
||||
}
|
||||
|
||||
/* now add the list of collected channels */
|
||||
BLI_movelisttolist(anim_data, &tmp_data);
|
||||
BLI_assert(BLI_listbase_is_empty(&tmp_data));
|
||||
items += tmp_items;
|
||||
}
|
||||
|
||||
/* return the number of items added to the list */
|
||||
return items;
|
||||
}
|
||||
|
||||
/* Helper for Mask Editing - mask layers */
|
||||
static size_t animdata_filter_mask_data(ListBase *anim_data, Mask *mask, const int filter_mode)
|
||||
{
|
||||
@ -2839,6 +2899,12 @@ static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, b
|
||||
filter_mode |= ANIMFILTER_SELEDIT;
|
||||
}
|
||||
|
||||
/* Cache files level animations (frame duration and such). */
|
||||
CacheFile *cache_file = G.main->cachefiles.first;
|
||||
for (; cache_file; cache_file = cache_file->id.next) {
|
||||
items += animdata_filter_ds_cachefile(ac, anim_data, ads, cache_file, filter_mode);
|
||||
}
|
||||
|
||||
/* scene-linked animation - e.g. world, compositing nodes, scene anim (including sequencer currently) */
|
||||
items += animdata_filter_dopesheet_scene(ac, anim_data, ads, scene, filter_mode);
|
||||
|
||||
@ -2950,7 +3016,11 @@ static size_t animdata_filter_animchan(bAnimContext *ac, ListBase *anim_data, bD
|
||||
case ANIMTYPE_OBJECT:
|
||||
items += animdata_filter_dopesheet_ob(ac, anim_data, ads, channel->data, filter_mode);
|
||||
break;
|
||||
|
||||
|
||||
case ANIMTYPE_DSCACHEFILE:
|
||||
items += animdata_filter_ds_cachefile(ac, anim_data, ads, channel->data, filter_mode);
|
||||
break;
|
||||
|
||||
case ANIMTYPE_ANIMDATA:
|
||||
items += animfilter_block_data(ac, anim_data, ads, channel->id, filter_mode);
|
||||
break;
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_gpencil_types.h"
|
||||
@ -965,6 +966,37 @@ void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, DLRBT_Tree *bl
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
}
|
||||
|
||||
void cachefile_to_keylist(bDopeSheet *ads, CacheFile *cache_file, DLRBT_Tree *keys, DLRBT_Tree *blocks)
|
||||
{
|
||||
if (cache_file == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* create a dummy wrapper data to work with */
|
||||
bAnimListElem dummychan = {NULL};
|
||||
dummychan.type = ANIMTYPE_DSCACHEFILE;
|
||||
dummychan.data = cache_file;
|
||||
dummychan.id = &cache_file->id;
|
||||
dummychan.adt = cache_file->adt;
|
||||
|
||||
bAnimContext ac = {NULL};
|
||||
ac.ads = ads;
|
||||
ac.data = &dummychan;
|
||||
ac.datatype = ANIMCONT_CHANNEL;
|
||||
|
||||
/* get F-Curves to take keyframes from */
|
||||
ListBase anim_data = { NULL, NULL };
|
||||
int filter = ANIMFILTER_DATA_VISIBLE; // curves only
|
||||
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
|
||||
|
||||
/* loop through each F-Curve, grabbing the keyframes */
|
||||
for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) {
|
||||
fcurve_to_keylist(ale->adt, ale->data, keys, blocks);
|
||||
}
|
||||
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
}
|
||||
|
||||
void fcurve_to_keylist(AnimData *adt, FCurve *fcu, DLRBT_Tree *keys, DLRBT_Tree *blocks)
|
||||
{
|
||||
BezTriple *bezt;
|
||||
|
@ -156,6 +156,7 @@ typedef enum eAnim_ChannelType {
|
||||
ANIMTYPE_DSMAT,
|
||||
ANIMTYPE_DSLAM,
|
||||
ANIMTYPE_DSCAM,
|
||||
ANIMTYPE_DSCACHEFILE,
|
||||
ANIMTYPE_DSCUR,
|
||||
ANIMTYPE_DSSKEY,
|
||||
ANIMTYPE_DSWOR,
|
||||
@ -275,6 +276,7 @@ typedef enum eAnimFilter_Flags {
|
||||
#define FILTER_MAT_OBJD(ma) (CHECK_TYPE_INLINE(ma, Material *), ((ma->flag & MA_DS_EXPAND)))
|
||||
#define FILTER_LAM_OBJD(la) (CHECK_TYPE_INLINE(la, Lamp *), ((la->flag & LA_DS_EXPAND)))
|
||||
#define FILTER_CAM_OBJD(ca) (CHECK_TYPE_INLINE(ca, Camera *), ((ca->flag & CAM_DS_EXPAND)))
|
||||
#define FILTER_CACHEFILE_OBJD(cf) (CHECK_TYPE_INLINE(cf, CacheFile *), ((cf->flag & CACHEFILE_DS_EXPAND)))
|
||||
#define FILTER_CUR_OBJD(cu) (CHECK_TYPE_INLINE(cu, Curve *), ((cu->flag & CU_DS_EXPAND)))
|
||||
#define FILTER_PART_OBJD(part) (CHECK_TYPE_INLINE(part, ParticleSettings *), ((part->flag & PART_DS_EXPAND)))
|
||||
#define FILTER_MBALL_OBJD(mb) (CHECK_TYPE_INLINE(mb, MetaBall *), ((mb->flag2 & MB_DS_EXPAND)))
|
||||
|
@ -34,6 +34,7 @@
|
||||
|
||||
struct bAnimContext;
|
||||
struct AnimData;
|
||||
struct CacheFile;
|
||||
struct FCurve;
|
||||
struct bDopeSheet;
|
||||
struct bAction;
|
||||
@ -141,6 +142,8 @@ void agroup_to_keylist(struct AnimData *adt, struct bActionGroup *agrp, struct D
|
||||
void action_to_keylist(struct AnimData *adt, struct bAction *act, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
|
||||
/* Object */
|
||||
void ob_to_keylist(struct bDopeSheet *ads, struct Object *ob, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
|
||||
/* Cache File */
|
||||
void cachefile_to_keylist(struct bDopeSheet *ads, struct CacheFile *cache_file, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
|
||||
/* Scene */
|
||||
void scene_to_keylist(struct bDopeSheet *ads, struct Scene *sce, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
|
||||
/* DopeSheet Summary */
|
||||
|
@ -945,6 +945,7 @@ void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C);
|
||||
void uiTemplateKeymapItemProperties(uiLayout *layout, struct PointerRNA *ptr);
|
||||
void uiTemplateComponentMenu(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name);
|
||||
void uiTemplateNodeSocket(uiLayout *layout, struct bContext *C, float *color);
|
||||
void uiTemplateCacheFile(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname);
|
||||
|
||||
/* Default UIList class name, keep in sync with its declaration in bl_ui/__init__.py */
|
||||
#define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list"
|
||||
|
@ -1541,6 +1541,8 @@ int UI_idcode_icon_get(const int idcode)
|
||||
return ICON_BRUSH_DATA;
|
||||
case ID_CA:
|
||||
return ICON_CAMERA_DATA;
|
||||
case ID_CF:
|
||||
return ICON_FILE;
|
||||
case ID_CU:
|
||||
return ICON_CURVE_DATA;
|
||||
case ID_GD:
|
||||
|
@ -32,6 +32,7 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_node_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
@ -368,6 +369,7 @@ static const char *template_id_browse_tip(StructRNA *type)
|
||||
case ID_MSK: return N_("Browse Mask to be linked");
|
||||
case ID_PAL: return N_("Browse Palette Data to be linked");
|
||||
case ID_PC: return N_("Browse Paint Curve Data to be linked");
|
||||
case ID_CF: return N_("Browse Cache Files to be linked");
|
||||
}
|
||||
}
|
||||
return N_("Browse ID data to be linked");
|
||||
@ -3848,3 +3850,73 @@ void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float *color)
|
||||
|
||||
UI_block_align_end(block);
|
||||
}
|
||||
|
||||
/********************************* Cache File *********************************/
|
||||
|
||||
void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname)
|
||||
{
|
||||
if (!ptr->data) {
|
||||
return;
|
||||
}
|
||||
|
||||
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
|
||||
|
||||
if (!prop) {
|
||||
printf("%s: property not found: %s.%s\n",
|
||||
__func__, RNA_struct_identifier(ptr->type), propname);
|
||||
return;
|
||||
}
|
||||
|
||||
if (RNA_property_type(prop) != PROP_POINTER) {
|
||||
printf("%s: expected pointer property for %s.%s\n",
|
||||
__func__, RNA_struct_identifier(ptr->type), propname);
|
||||
return;
|
||||
}
|
||||
|
||||
PointerRNA fileptr = RNA_property_pointer_get(ptr, prop);
|
||||
CacheFile *file = fileptr.data;
|
||||
|
||||
uiLayoutSetContextPointer(layout, "edit_cachefile", &fileptr);
|
||||
|
||||
uiTemplateID(layout, C, ptr, propname, NULL, "CACHEFILE_OT_open", NULL);
|
||||
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
uiLayout *row = uiLayoutRow(layout, false);
|
||||
uiBlock *block = uiLayoutGetBlock(row);
|
||||
uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("File Path:"), 0, 19, 145, 19, NULL, 0, 0, 0, 0, "");
|
||||
|
||||
row = uiLayoutRow(layout, false);
|
||||
uiLayout *split = uiLayoutSplit(row, 0.0f, false);
|
||||
row = uiLayoutRow(split, true);
|
||||
|
||||
uiItemR(row, &fileptr, "filepath", 0, "", ICON_NONE);
|
||||
uiItemO(row, "", ICON_FILE_REFRESH, "cachefile.reload");
|
||||
|
||||
row = uiLayoutRow(layout, false);
|
||||
uiItemR(row, &fileptr, "is_sequence", 0, "Is Sequence", ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(layout, false);
|
||||
uiItemR(row, &fileptr, "override_frame", 0, "Override Frame", ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(layout, false);
|
||||
uiLayoutSetEnabled(row, RNA_boolean_get(&fileptr, "override_frame"));
|
||||
uiItemR(row, &fileptr, "frame", 0, "Frame", ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(layout, false);
|
||||
uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(layout, false);
|
||||
uiItemR(row, &fileptr, "scale", 0, "Scale", ICON_NONE);
|
||||
|
||||
/* TODO: unused for now, so no need to expose. */
|
||||
#if 0
|
||||
row = uiLayoutRow(layout, false);
|
||||
uiItemR(row, &fileptr, "forward_axis", 0, "Forward Axis", ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(layout, false);
|
||||
uiItemR(row, &fileptr, "up_axis", 0, "Up Axis", ICON_NONE);
|
||||
#endif
|
||||
}
|
||||
|
@ -28,6 +28,8 @@ set(INC
|
||||
../../makesrna
|
||||
../../windowmanager
|
||||
../../collada
|
||||
../../alembic
|
||||
../../../../intern/guardedalloc
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
@ -35,9 +37,13 @@ set(INC_SYS
|
||||
)
|
||||
|
||||
set(SRC
|
||||
io_alembic.c
|
||||
io_cache.c
|
||||
io_collada.c
|
||||
io_ops.c
|
||||
|
||||
io_alembic.h
|
||||
io_cache.h
|
||||
io_collada.h
|
||||
io_ops.h
|
||||
)
|
||||
@ -46,6 +52,14 @@ if(WITH_OPENCOLLADA)
|
||||
add_definitions(-DWITH_COLLADA)
|
||||
endif()
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
add_definitions(-DWITH_ALEMBIC)
|
||||
|
||||
if(WITH_ALEMBIC_HDF5)
|
||||
add_definitions(-DWITH_ALEMBIC_HDF5)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_INTERNATIONAL)
|
||||
add_definitions(-DWITH_INTERNATIONAL)
|
||||
endif()
|
||||
|
458
source/blender/editors/io/io_alembic.c
Normal file
458
source/blender/editors/io/io_alembic.c
Normal file
@ -0,0 +1,458 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef WITH_ALEMBIC
|
||||
|
||||
/* needed for directory lookup */
|
||||
#ifndef WIN32
|
||||
# include <dirent.h>
|
||||
#else
|
||||
# include "BLI_winstuff.h"
|
||||
#endif
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_vector.h"
|
||||
#include "BLI_path_util.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_define.h"
|
||||
#include "RNA_enum_types.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
#include "UI_resources.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "io_alembic.h"
|
||||
|
||||
#include "ABC_alembic.h"
|
||||
|
||||
static int wm_alembic_export_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
|
||||
char filepath[FILE_MAX];
|
||||
BLI_strncpy(filepath, G.main->name, sizeof(filepath));
|
||||
BLI_replace_extension(filepath, sizeof(filepath), ".abc");
|
||||
RNA_string_set(op->ptr, "filepath", filepath);
|
||||
}
|
||||
|
||||
WM_event_add_fileselect(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
|
||||
UNUSED_VARS(event);
|
||||
}
|
||||
|
||||
static int wm_alembic_export_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No filename given");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
char filename[FILE_MAX];
|
||||
RNA_string_get(op->ptr, "filepath", filename);
|
||||
|
||||
const struct AlembicExportParams params = {
|
||||
.frame_start = RNA_int_get(op->ptr, "start"),
|
||||
.frame_end = RNA_int_get(op->ptr, "end"),
|
||||
|
||||
.frame_step_xform = 1.0 / (double)RNA_int_get(op->ptr, "xsamples"),
|
||||
.frame_step_shape = 1.0 / (double)RNA_int_get(op->ptr, "gsamples"),
|
||||
|
||||
.shutter_open = RNA_float_get(op->ptr, "sh_open"),
|
||||
.shutter_close = RNA_float_get(op->ptr, "sh_close"),
|
||||
|
||||
.selected_only = RNA_boolean_get(op->ptr, "selected"),
|
||||
.uvs = RNA_boolean_get(op->ptr, "uvs"),
|
||||
.normals = RNA_boolean_get(op->ptr, "normals"),
|
||||
.vcolors = RNA_boolean_get(op->ptr, "vcolors"),
|
||||
.apply_subdiv = RNA_boolean_get(op->ptr, "apply_subdiv"),
|
||||
.flatten_hierarchy = RNA_boolean_get(op->ptr, "flatten"),
|
||||
.visible_layers_only = RNA_boolean_get(op->ptr, "visible_layers_only"),
|
||||
.renderable_only = RNA_boolean_get(op->ptr, "renderable_only"),
|
||||
.face_sets = RNA_boolean_get(op->ptr, "face_sets"),
|
||||
.use_subdiv_schema = RNA_boolean_get(op->ptr, "subdiv_schema"),
|
||||
.compression_type = RNA_enum_get(op->ptr, "compression_type"),
|
||||
.packuv = RNA_boolean_get(op->ptr, "packuv"),
|
||||
|
||||
.global_scale = RNA_float_get(op->ptr, "global_scale"),
|
||||
};
|
||||
|
||||
ABC_export(CTX_data_scene(C), C, filename, ¶ms);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr)
|
||||
{
|
||||
uiLayout *box = uiLayoutBox(layout);
|
||||
uiLayout *row;
|
||||
|
||||
#ifdef WITH_ALEMBIC_HDF5
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemL(row, IFACE_("Archive Options:"), ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "compression_type", 0, NULL, ICON_NONE);
|
||||
#endif
|
||||
|
||||
box = uiLayoutBox(layout);
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "global_scale", 0, NULL, ICON_NONE);
|
||||
|
||||
/* Scene Options */
|
||||
box = uiLayoutBox(layout);
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemL(row, IFACE_("Scene Options:"), ICON_SCENE_DATA);
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "start", 0, NULL, ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "end", 0, NULL, ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "xsamples", 0, NULL, ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "gsamples", 0, NULL, ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "sh_open", 0, NULL, ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "sh_close", 0, NULL, ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "selected", 0, NULL, ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "renderable_only", 0, NULL, ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "visible_layers_only", 0, NULL, ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "flatten", 0, NULL, ICON_NONE);
|
||||
|
||||
/* Object Data */
|
||||
box = uiLayoutBox(layout);
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemL(row, IFACE_("Object Options:"), ICON_OBJECT_DATA);
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "uvs", 0, NULL, ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "packuv", 0, NULL, ICON_NONE);
|
||||
uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "uvs"));
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "normals", 0, NULL, ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "vcolors", 0, NULL, ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "face_sets", 0, NULL, ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "subdiv_schema", 0, NULL, ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "apply_subdiv", 0, NULL, ICON_NONE);
|
||||
}
|
||||
|
||||
static void wm_alembic_export_draw(bContext *UNUSED(C), wmOperator *op)
|
||||
{
|
||||
PointerRNA ptr;
|
||||
|
||||
RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
|
||||
ui_alembic_export_settings(op->layout, &ptr);
|
||||
}
|
||||
|
||||
void WM_OT_alembic_export(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Export Alembic Archive";
|
||||
ot->idname = "WM_OT_alembic_export";
|
||||
|
||||
ot->invoke = wm_alembic_export_invoke;
|
||||
ot->exec = wm_alembic_export_exec;
|
||||
ot->poll = WM_operator_winactive;
|
||||
ot->ui = wm_alembic_export_draw;
|
||||
|
||||
WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
|
||||
FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH,
|
||||
FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
|
||||
|
||||
RNA_def_int(ot->srna, "start", 1, INT_MIN, INT_MAX,
|
||||
"Start Frame", "Start Frame", INT_MIN, INT_MAX);
|
||||
|
||||
RNA_def_int(ot->srna, "end", 1, INT_MIN, INT_MAX,
|
||||
"End Frame", "End Frame", INT_MIN, INT_MAX);
|
||||
|
||||
RNA_def_int(ot->srna, "xsamples", 1, 1, 128,
|
||||
"Transform Samples", "Number of times per frame transformations are sampled", 1, 128);
|
||||
|
||||
RNA_def_int(ot->srna, "gsamples", 1, 1, 128,
|
||||
"Geometry Samples", "Number of times per frame object datas are sampled", 1, 128);
|
||||
|
||||
RNA_def_float(ot->srna, "sh_open", 0.0f, -1.0f, 1.0f,
|
||||
"Shutter Open", "Time at which the shutter is open", -1.0f, 1.0f);
|
||||
|
||||
RNA_def_float(ot->srna, "sh_close", 1.0f, -1.0f, 1.0f,
|
||||
"Shutter Close", "Time at which the shutter is closed", -1.0f, 1.0f);
|
||||
|
||||
RNA_def_boolean(ot->srna, "selected", 0,
|
||||
"Selected Objects Only", "Export only selected objects");
|
||||
|
||||
RNA_def_boolean(ot->srna, "renderable_only", 1,
|
||||
"Renderable Objects Only",
|
||||
"Export only objects marked renderable in the outliner");
|
||||
|
||||
RNA_def_boolean(ot->srna, "visible_layers_only", 0,
|
||||
"Visible Layers Only", "Export only objects in visible layers");
|
||||
|
||||
RNA_def_boolean(ot->srna, "flatten", 0,
|
||||
"Flatten Hierarchy",
|
||||
"Do not preserve objects' parent/children relationship");
|
||||
|
||||
RNA_def_boolean(ot->srna, "uvs", 1, "UVs", "Export UVs");
|
||||
|
||||
RNA_def_boolean(ot->srna, "packuv", 1, "Pack UV Islands",
|
||||
"Export UVs with packed island");
|
||||
|
||||
RNA_def_boolean(ot->srna, "normals", 1, "Normals", "Export normals");
|
||||
|
||||
RNA_def_boolean(ot->srna, "vcolors", 0, "Vertex colors", "Export vertex colors");
|
||||
|
||||
RNA_def_boolean(ot->srna, "face_sets", 0, "Face Sets", "Export per face shading group assignments");
|
||||
|
||||
RNA_def_boolean(ot->srna, "subdiv_schema", 0,
|
||||
"Use Subdivision Schema",
|
||||
"Export meshes using Alembic's subdivision schema");
|
||||
|
||||
RNA_def_boolean(ot->srna, "apply_subdiv", 0,
|
||||
"Apply Subsurf", "Export subdivision surfaces as meshes");
|
||||
|
||||
RNA_def_enum(ot->srna, "compression_type", rna_enum_abc_compression_items,
|
||||
ABC_ARCHIVE_OGAWA, "Compression", "");
|
||||
|
||||
RNA_def_float(ot->srna, "global_scale", 1.0f, 0.0001f, 1000.0f, "Scale",
|
||||
"Value by which to enlarge or shrink the objects with respect to the world's origin",
|
||||
0.0001f, 1000.0f);
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
/* TODO(kevin): check on de-duplicating all this with code in image_ops.c */
|
||||
|
||||
typedef struct CacheFrame {
|
||||
struct CacheFrame *next, *prev;
|
||||
int framenr;
|
||||
} CacheFrame;
|
||||
|
||||
static int cmp_frame(const void *a, const void *b)
|
||||
{
|
||||
const CacheFrame *frame_a = a;
|
||||
const CacheFrame *frame_b = b;
|
||||
|
||||
if (frame_a->framenr < frame_b->framenr) return -1;
|
||||
if (frame_a->framenr > frame_b->framenr) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_sequence_len(char *filename, int *ofs)
|
||||
{
|
||||
int frame;
|
||||
int numdigit;
|
||||
|
||||
if (!BLI_path_frame_get(filename, &frame, &numdigit)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
char path[FILE_MAX];
|
||||
BLI_split_dir_part(filename, path, FILE_MAX);
|
||||
|
||||
DIR *dir = opendir(path);
|
||||
|
||||
const char *ext = ".abc";
|
||||
const char *basename = BLI_path_basename(filename);
|
||||
const int len = strlen(basename) - (numdigit + strlen(ext));
|
||||
|
||||
ListBase frames;
|
||||
BLI_listbase_clear(&frames);
|
||||
|
||||
struct dirent *fname;
|
||||
while ((fname = readdir(dir)) != NULL) {
|
||||
/* do we have the right extension? */
|
||||
if (!strstr(fname->d_name, ext)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!STREQLEN(basename, fname->d_name, len)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CacheFrame *cache_frame = MEM_callocN(sizeof(CacheFrame), "abc_frame");
|
||||
|
||||
BLI_path_frame_get(fname->d_name, &cache_frame->framenr, &numdigit);
|
||||
|
||||
BLI_addtail(&frames, cache_frame);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
BLI_listbase_sort(&frames, cmp_frame);
|
||||
|
||||
CacheFrame *cache_frame = frames.first;
|
||||
|
||||
if (cache_frame) {
|
||||
int frame_curr = cache_frame->framenr;
|
||||
(*ofs) = frame_curr;
|
||||
|
||||
while (cache_frame && (cache_frame->framenr == frame_curr)) {
|
||||
++frame_curr;
|
||||
cache_frame = cache_frame->next;
|
||||
}
|
||||
|
||||
BLI_freelistN(&frames);
|
||||
|
||||
return frame_curr - (*ofs);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
static void ui_alembic_import_settings(uiLayout *layout, PointerRNA *imfptr)
|
||||
{
|
||||
uiLayout *box = uiLayoutBox(layout);
|
||||
uiLayout *row = uiLayoutRow(box, false);
|
||||
uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "scale", 0, NULL, ICON_NONE);
|
||||
|
||||
box = uiLayoutBox(layout);
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemL(row, IFACE_("Options:"), ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "set_frame_range", 0, NULL, ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "is_sequence", 0, NULL, ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(box, false);
|
||||
uiItemR(row, imfptr, "validate_meshes", 0, NULL, ICON_NONE);
|
||||
}
|
||||
|
||||
static void wm_alembic_import_draw(bContext *UNUSED(C), wmOperator *op)
|
||||
{
|
||||
PointerRNA ptr;
|
||||
|
||||
RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
|
||||
ui_alembic_import_settings(op->layout, &ptr);
|
||||
}
|
||||
|
||||
static int wm_alembic_import_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No filename given");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
char filename[FILE_MAX];
|
||||
RNA_string_get(op->ptr, "filepath", filename);
|
||||
|
||||
const float scale = RNA_float_get(op->ptr, "scale");
|
||||
const bool is_sequence = RNA_boolean_get(op->ptr, "is_sequence");
|
||||
const bool set_frame_range = RNA_boolean_get(op->ptr, "set_frame_range");
|
||||
const bool validate_meshes = RNA_boolean_get(op->ptr, "validate_meshes");
|
||||
|
||||
int offset = 0;
|
||||
int sequence_len = 1;
|
||||
|
||||
if (is_sequence) {
|
||||
sequence_len = get_sequence_len(filename, &offset);
|
||||
}
|
||||
|
||||
ABC_import(C, filename, scale, is_sequence, set_frame_range, sequence_len, offset, validate_meshes);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void WM_OT_alembic_import(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Import Alembic Archive";
|
||||
ot->idname = "WM_OT_alembic_import";
|
||||
|
||||
ot->invoke = WM_operator_filesel;
|
||||
ot->exec = wm_alembic_import_exec;
|
||||
ot->poll = WM_operator_winactive;
|
||||
ot->ui = wm_alembic_import_draw;
|
||||
|
||||
WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
|
||||
FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH,
|
||||
FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
|
||||
|
||||
RNA_def_float(ot->srna, "scale", 1.0f, 0.0001f, 1000.0f, "Scale",
|
||||
"Value by which to enlarge or shrink the objects with respect to the world's origin",
|
||||
0.0001f, 1000.0f);
|
||||
|
||||
RNA_def_boolean(ot->srna, "set_frame_range", true,
|
||||
"Set Frame Range",
|
||||
"If checked, update scene's start and end frame to match those of the Alembic archive");
|
||||
|
||||
RNA_def_boolean(ot->srna, "validate_meshes", 0,
|
||||
"Validate Meshes", "Check imported mesh objects for invalid data (slow)");
|
||||
|
||||
RNA_def_boolean(ot->srna, "is_sequence", false, "Is Sequence",
|
||||
"Set to true if the cache is split into separate files");
|
||||
}
|
||||
|
||||
#endif
|
37
source/blender/editors/io/io_alembic.h
Normal file
37
source/blender/editors/io/io_alembic.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __IO_ALEMBIC_H__
|
||||
#define __IO_ALEMBIC_H__
|
||||
|
||||
/** \file blender/editors/io/io_alembic.h
|
||||
* \ingroup editor/io
|
||||
*/
|
||||
|
||||
struct wmOperatorType;
|
||||
|
||||
void WM_OT_alembic_export(struct wmOperatorType *ot);
|
||||
void WM_OT_alembic_import(struct wmOperatorType *ot);
|
||||
|
||||
#endif /* __IO_ALEMBIC_H__ */
|
162
source/blender/editors/io/io_cache.c
Normal file
162
source/blender/editors/io/io_cache.c
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_path_util.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BKE_cachefile.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_library.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "io_cache.h"
|
||||
|
||||
static void cachefile_init(bContext *C, wmOperator *op)
|
||||
{
|
||||
PropertyPointerRNA *pprop;
|
||||
|
||||
op->customdata = pprop = MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA");
|
||||
UI_context_active_but_prop_get_templateID(C, &pprop->ptr, &pprop->prop);
|
||||
}
|
||||
|
||||
static int cachefile_open_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
|
||||
char filepath[FILE_MAX];
|
||||
BLI_strncpy(filepath, G.main->name, sizeof(filepath));
|
||||
BLI_replace_extension(filepath, sizeof(filepath), ".abc");
|
||||
RNA_string_set(op->ptr, "filepath", filepath);
|
||||
}
|
||||
|
||||
cachefile_init(C, op);
|
||||
|
||||
WM_event_add_fileselect(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
|
||||
UNUSED_VARS(event);
|
||||
}
|
||||
|
||||
static void open_cancel(bContext *UNUSED(C), wmOperator *op)
|
||||
{
|
||||
MEM_freeN(op->customdata);
|
||||
op->customdata = NULL;
|
||||
}
|
||||
|
||||
static int cachefile_open_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No filename given");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
char filename[FILE_MAX];
|
||||
RNA_string_get(op->ptr, "filepath", filename);
|
||||
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
||||
CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, BLI_path_basename(filename));
|
||||
BLI_strncpy(cache_file->filepath, filename, FILE_MAX);
|
||||
BKE_cachefile_reload(bmain, cache_file);
|
||||
|
||||
/* hook into UI */
|
||||
PropertyPointerRNA *pprop = op->customdata;
|
||||
|
||||
if (pprop->prop) {
|
||||
/* when creating new ID blocks, use is already 1, but RNA
|
||||
* pointer se also increases user, so this compensates it */
|
||||
id_us_min(&cache_file->id);
|
||||
|
||||
PointerRNA idptr;
|
||||
RNA_id_pointer_create(&cache_file->id, &idptr);
|
||||
RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr);
|
||||
RNA_property_update(C, &pprop->ptr, pprop->prop);
|
||||
}
|
||||
|
||||
MEM_freeN(op->customdata);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void CACHEFILE_OT_open(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Open Cache File";
|
||||
ot->idname = "CACHEFILE_OT_open";
|
||||
|
||||
ot->invoke = cachefile_open_invoke;
|
||||
ot->exec = cachefile_open_exec;
|
||||
ot->cancel = open_cancel;
|
||||
|
||||
WM_operator_properties_filesel(ot, FILE_TYPE_ALEMBIC | FILE_TYPE_FOLDER,
|
||||
FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH,
|
||||
FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
|
||||
}
|
||||
|
||||
/* ***************************** Reload Operator **************************** */
|
||||
|
||||
static int cachefile_reload_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
CacheFile *cache_file = CTX_data_edit_cachefile(C);
|
||||
|
||||
if (!cache_file) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
||||
BLI_listbase_clear(&cache_file->object_paths);
|
||||
BKE_cachefile_reload(bmain, cache_file);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
|
||||
UNUSED_VARS(op);
|
||||
}
|
||||
|
||||
void CACHEFILE_OT_reload(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Refresh Archive";
|
||||
ot->description = "Update objects paths list with new data from the archive";
|
||||
ot->idname = "CACHEFILE_OT_reload";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = cachefile_reload_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
37
source/blender/editors/io/io_cache.h
Normal file
37
source/blender/editors/io/io_cache.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __IO_CACHE_H__
|
||||
#define __IO_CACHE_H__
|
||||
|
||||
/** \file blender/editors/io/io_cache.h
|
||||
* \ingroup editor/io
|
||||
*/
|
||||
|
||||
struct wmOperatorType;
|
||||
|
||||
void CACHEFILE_OT_open(struct wmOperatorType *ot);
|
||||
void CACHEFILE_OT_reload(struct wmOperatorType *ot);
|
||||
|
||||
#endif /* __IO_CACHE_H__ */
|
@ -30,11 +30,18 @@
|
||||
|
||||
#include "io_ops.h" /* own include */
|
||||
|
||||
#include "WM_api.h"
|
||||
|
||||
#ifdef WITH_COLLADA
|
||||
# include "io_collada.h"
|
||||
# include "WM_api.h"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_ALEMBIC
|
||||
# include "io_alembic.h"
|
||||
#endif
|
||||
|
||||
#include "io_cache.h"
|
||||
|
||||
void ED_operatortypes_io(void)
|
||||
{
|
||||
#ifdef WITH_COLLADA
|
||||
@ -42,4 +49,11 @@ void ED_operatortypes_io(void)
|
||||
WM_operatortype_append(WM_OT_collada_export);
|
||||
WM_operatortype_append(WM_OT_collada_import);
|
||||
#endif
|
||||
#ifdef WITH_ALEMBIC
|
||||
WM_operatortype_append(WM_OT_alembic_import);
|
||||
WM_operatortype_append(WM_OT_alembic_export);
|
||||
#endif
|
||||
|
||||
WM_operatortype_append(CACHEFILE_OT_open);
|
||||
WM_operatortype_append(CACHEFILE_OT_reload);
|
||||
}
|
||||
|
@ -416,6 +416,13 @@ static void test_constraint(Object *owner, bPoseChannel *pchan, bConstraint *con
|
||||
if ((data->flag & CAMERASOLVER_ACTIVECLIP) == 0 && (data->clip == NULL))
|
||||
con->flag |= CONSTRAINT_DISABLE;
|
||||
}
|
||||
else if (con->type == CONSTRAINT_TYPE_TRANSFORM_CACHE) {
|
||||
bTransformCacheConstraint *data = con->data;
|
||||
|
||||
if ((data->cache_file == NULL) || (data->object_path[0] == '\0')) {
|
||||
con->flag |= CONSTRAINT_DISABLE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check targets for constraints */
|
||||
if (check_targets && cti && cti->get_constraint_targets) {
|
||||
|
@ -920,6 +920,8 @@ static int filelist_geticon_ex(
|
||||
return ICON_FILE_BLANK;
|
||||
else if (typeflag & FILE_TYPE_COLLADA)
|
||||
return ICON_FILE_BLANK;
|
||||
else if (typeflag & FILE_TYPE_ALEMBIC)
|
||||
return ICON_FILE_BLANK;
|
||||
else if (typeflag & FILE_TYPE_TEXT)
|
||||
return ICON_FILE_TEXT;
|
||||
else if (typeflag & FILE_TYPE_BLENDERLIB) {
|
||||
@ -1952,6 +1954,9 @@ int ED_path_extension_type(const char *path)
|
||||
else if (BLI_testextensie(path, ".dae")) {
|
||||
return FILE_TYPE_COLLADA;
|
||||
}
|
||||
else if (BLI_testextensie(path, ".abc")) {
|
||||
return FILE_TYPE_ALEMBIC;
|
||||
}
|
||||
else if (BLI_testextensie_array(path, imb_ext_image) ||
|
||||
(G.have_quicktime && BLI_testextensie_array(path, imb_ext_image_qt)))
|
||||
{
|
||||
@ -2004,6 +2009,8 @@ int ED_file_extension_icon(const char *path)
|
||||
return ICON_FILE_BLANK;
|
||||
case FILE_TYPE_COLLADA:
|
||||
return ICON_FILE_BLANK;
|
||||
case FILE_TYPE_ALEMBIC:
|
||||
return ICON_FILE_BLANK;
|
||||
case FILE_TYPE_TEXT:
|
||||
return ICON_FILE_TEXT;
|
||||
default:
|
||||
|
@ -185,6 +185,8 @@ short ED_fileselect_set_params(SpaceFile *sfile)
|
||||
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BTX : 0;
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "filter_collada")))
|
||||
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_COLLADA : 0;
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "filter_alembic")))
|
||||
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_ALEMBIC : 0;
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "filter_glob"))) {
|
||||
/* Protection against pyscripts not setting proper size limit... */
|
||||
char *tmp = RNA_property_string_get_alloc(
|
||||
@ -213,7 +215,7 @@ short ED_fileselect_set_params(SpaceFile *sfile)
|
||||
FILTER_ID_GR | FILTER_ID_IM | FILTER_ID_LA | FILTER_ID_LS | FILTER_ID_LT | FILTER_ID_MA |
|
||||
FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME | FILTER_ID_MSK | FILTER_ID_NT | FILTER_ID_OB |
|
||||
FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | FILTER_ID_SPK | FILTER_ID_SO |
|
||||
FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO;
|
||||
FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | FILTER_ID_CF;
|
||||
|
||||
if (U.uiflag & USER_HIDE_DOT) {
|
||||
params->flag |= FILE_HIDE_DOT;
|
||||
|
@ -131,6 +131,7 @@ bool nla_panel_context(const bContext *C, PointerRNA *adt_ptr, PointerRNA *nlt_p
|
||||
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
|
||||
case ANIMTYPE_DSLAM:
|
||||
case ANIMTYPE_DSCAM:
|
||||
case ANIMTYPE_DSCACHEFILE:
|
||||
case ANIMTYPE_DSCUR:
|
||||
case ANIMTYPE_DSSKEY:
|
||||
case ANIMTYPE_DSWOR:
|
||||
|
@ -170,6 +170,7 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe
|
||||
case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
|
||||
case ANIMTYPE_DSLAM:
|
||||
case ANIMTYPE_DSCAM:
|
||||
case ANIMTYPE_DSCACHEFILE:
|
||||
case ANIMTYPE_DSCUR:
|
||||
case ANIMTYPE_DSSKEY:
|
||||
case ANIMTYPE_DSWOR:
|
||||
|
@ -1173,6 +1173,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
|
||||
UI_icon_draw(x, y, ICON_MOD_TRIANGULATE); break;
|
||||
case eModifierType_MeshCache:
|
||||
UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */
|
||||
case eModifierType_MeshSequenceCache:
|
||||
UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */
|
||||
case eModifierType_Wireframe:
|
||||
UI_icon_draw(x, y, ICON_MOD_WIREFRAME); break;
|
||||
case eModifierType_LaplacianDeform:
|
||||
|
@ -62,7 +62,7 @@ typedef struct TreeElement {
|
||||
#define TREESTORE_ID_TYPE(_id) \
|
||||
(ELEM(GS((_id)->name), ID_SCE, ID_LI, ID_OB, ID_ME, ID_CU, ID_MB, ID_NT, ID_MA, ID_TE, ID_IM, ID_LT, ID_LA, ID_CA) || \
|
||||
ELEM(GS((_id)->name), ID_KE, ID_WO, ID_SPK, ID_GR, ID_AR, ID_AC, ID_BR, ID_PA, ID_GD, ID_LS) || \
|
||||
ELEM(GS((_id)->name), ID_SCR, ID_WM, ID_TXT, ID_VF, ID_SO)) /* Only in 'blendfile' mode ... :/ */
|
||||
ELEM(GS((_id)->name), ID_SCR, ID_WM, ID_TXT, ID_VF, ID_SO, ID_CF)) /* Only in 'blendfile' mode ... :/ */
|
||||
|
||||
/* TreeElement->flag */
|
||||
#define TE_ACTIVE 1
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_gpencil_types.h"
|
||||
#include "DNA_group_types.h"
|
||||
#include "DNA_key_types.h"
|
||||
@ -746,6 +747,16 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor
|
||||
outliner_add_element(soops, &te->subtree, ca, te, TSE_ANIM_DATA, 0);
|
||||
break;
|
||||
}
|
||||
case ID_CF:
|
||||
{
|
||||
CacheFile *cache_file = (CacheFile *)id;
|
||||
|
||||
if (outliner_animdata_test(cache_file->adt)) {
|
||||
outliner_add_element(soops, &te->subtree, cache_file, te, TSE_ANIM_DATA, 0);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ID_LA:
|
||||
{
|
||||
Lamp *la = (Lamp *)id;
|
||||
|
@ -32,7 +32,10 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_gpencil_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
@ -42,7 +45,10 @@
|
||||
#include "BLI_dlrbTree.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_constraint.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_screen.h"
|
||||
#include "BKE_pointcache.h"
|
||||
|
||||
@ -320,6 +326,9 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel)
|
||||
case ID_GD:
|
||||
gpencil_to_keylist(&ads, (bGPdata *)id, &keys);
|
||||
break;
|
||||
case ID_CF:
|
||||
cachefile_to_keylist(&ads, (CacheFile *)id, &keys, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
/* build linked-list for searching */
|
||||
@ -344,6 +353,56 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel)
|
||||
BLI_dlrbTree_free(&keys);
|
||||
}
|
||||
|
||||
static void time_draw_caches_keyframes(Main *bmain, Scene *scene, View2D *v2d, bool onlysel)
|
||||
{
|
||||
CacheFile *cache_file;
|
||||
|
||||
for (cache_file = bmain->cachefiles.first;
|
||||
cache_file;
|
||||
cache_file = cache_file->id.next)
|
||||
{
|
||||
cache_file->draw_flag &= ~CACHEFILE_KEYFRAME_DRAWN;
|
||||
}
|
||||
|
||||
for (Base *base = scene->base.first; base; base = base->next) {
|
||||
Object *ob = base->object;
|
||||
|
||||
ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
|
||||
|
||||
if (md) {
|
||||
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
|
||||
|
||||
cache_file = mcmd->cache_file;
|
||||
|
||||
if (!cache_file || (cache_file->draw_flag & CACHEFILE_KEYFRAME_DRAWN) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN;
|
||||
|
||||
time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel);
|
||||
}
|
||||
|
||||
for (bConstraint *con = ob->constraints.first; con; con = con->next) {
|
||||
if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bTransformCacheConstraint *data = con->data;
|
||||
|
||||
cache_file = data->cache_file;
|
||||
|
||||
if (!cache_file || (cache_file->draw_flag & CACHEFILE_KEYFRAME_DRAWN) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN;
|
||||
|
||||
time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* draw keyframe lines for timeline */
|
||||
static void time_draw_keyframes(const bContext *C, ARegion *ar)
|
||||
{
|
||||
@ -354,7 +413,11 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar)
|
||||
|
||||
/* set this for all keyframe lines once and for all */
|
||||
glLineWidth(1.0);
|
||||
|
||||
|
||||
/* draw cache files keyframes (if available) */
|
||||
UI_ThemeColor(TH_TIME_KEYFRAME);
|
||||
time_draw_caches_keyframes(CTX_data_main(C), scene, v2d, onlysel);
|
||||
|
||||
/* draw grease pencil keyframes (if available) */
|
||||
UI_ThemeColor(TH_TIME_GP_KEYFRAME);
|
||||
if (scene->gpd) {
|
||||
|
@ -247,6 +247,7 @@ typedef enum ID_Type {
|
||||
ID_LS = MAKE_ID2('L', 'S'), /* FreestyleLineStyle */
|
||||
ID_PAL = MAKE_ID2('P', 'L'), /* Palette */
|
||||
ID_PC = MAKE_ID2('P', 'C'), /* PaintCurve */
|
||||
ID_CF = MAKE_ID2('C', 'F'), /* CacheFile */
|
||||
} ID_Type;
|
||||
|
||||
/* Only used as 'placeholder' in .blend files for directly linked datablocks. */
|
||||
@ -377,6 +378,7 @@ enum {
|
||||
FILTER_ID_VF = (1 << 25),
|
||||
FILTER_ID_WO = (1 << 26),
|
||||
FILTER_ID_PA = (1 << 27),
|
||||
FILTER_ID_CF = (1 << 28),
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -694,7 +694,9 @@ typedef enum eAnimEdit_Context {
|
||||
/* dopesheet (default) */
|
||||
SACTCONT_DOPESHEET = 3,
|
||||
/* mask */
|
||||
SACTCONT_MASK = 4
|
||||
SACTCONT_MASK = 4,
|
||||
/* cache file */
|
||||
SACTCONT_CACHEFILE = 5,
|
||||
} eAnimEdit_Context;
|
||||
|
||||
/* SpaceAction AutoSnap Settings (also used by other Animation Editors) */
|
||||
|
84
source/blender/makesdna/DNA_cachefile_types.h
Normal file
84
source/blender/makesdna/DNA_cachefile_types.h
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributor(s): Kevin Dietrich.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file DNA_cachefile_types.h
|
||||
* \ingroup DNA
|
||||
*/
|
||||
|
||||
#ifndef __DNA_CACHEFILE_TYPES_H__
|
||||
#define __DNA_CACHEFILE_TYPES_H__
|
||||
|
||||
#include "DNA_ID.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* CacheFile::flag */
|
||||
enum {
|
||||
CACHEFILE_DS_EXPAND = (1 << 0),
|
||||
};
|
||||
|
||||
/* CacheFile::draw_flag */
|
||||
enum {
|
||||
CACHEFILE_KEYFRAME_DRAWN = (1 << 0),
|
||||
};
|
||||
|
||||
typedef struct AlembicObjectPath {
|
||||
struct AlembicObjectPath *next, *prev;
|
||||
|
||||
char path[1024]; /* 1024 = FILE_MAX, might use PATH_MAX in the future. */
|
||||
} AlembicObjectPath;
|
||||
|
||||
typedef struct CacheFile {
|
||||
ID id;
|
||||
struct AnimData *adt;
|
||||
|
||||
struct AbcArchiveHandle *handle;
|
||||
|
||||
/* Paths of the objects inside of the Alembic archive referenced by this
|
||||
* CacheFile. */
|
||||
ListBase object_paths;
|
||||
|
||||
char filepath[1024]; /* 1024 = FILE_MAX */
|
||||
|
||||
char is_sequence;
|
||||
char forward_axis;
|
||||
char up_axis;
|
||||
char override_frame;
|
||||
|
||||
float scale;
|
||||
float frame; /* The frame/time to lookup in the cache file. */
|
||||
|
||||
short flag; /* Animation flag. */
|
||||
short draw_flag;
|
||||
} CacheFile;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __DNA_CACHEFILE_TYPES_H__ */
|
@ -458,6 +458,12 @@ typedef struct bObjectSolverConstraint {
|
||||
struct Object *camera;
|
||||
} bObjectSolverConstraint;
|
||||
|
||||
/* Transform matrix cache constraint */
|
||||
typedef struct bTransformCacheConstraint {
|
||||
struct CacheFile *cache_file;
|
||||
char object_path[1024]; /* FILE_MAX */
|
||||
} bTransformCacheConstraint;
|
||||
|
||||
/* ------------------------------------------ */
|
||||
|
||||
/* bConstraint->type
|
||||
@ -494,6 +500,7 @@ typedef enum eBConstraint_Types {
|
||||
CONSTRAINT_TYPE_FOLLOWTRACK = 26, /* Follow Track Constraint */
|
||||
CONSTRAINT_TYPE_CAMERASOLVER = 27, /* Camera Solver Constraint */
|
||||
CONSTRAINT_TYPE_OBJECTSOLVER = 28, /* Object Solver Constraint */
|
||||
CONSTRAINT_TYPE_TRANSFORM_CACHE = 29, /* Transform Cache Constraint */
|
||||
|
||||
/* NOTE: no constraints are allowed to be added after this */
|
||||
NUM_CONSTRAINT_TYPES
|
||||
|
@ -85,6 +85,7 @@ typedef enum ModifierType {
|
||||
eModifierType_DataTransfer = 49,
|
||||
eModifierType_NormalEdit = 50,
|
||||
eModifierType_CorrectiveSmooth = 51,
|
||||
eModifierType_MeshSequenceCache = 52,
|
||||
NUM_MODIFIER_TYPES
|
||||
} ModifierType;
|
||||
|
||||
@ -1541,4 +1542,25 @@ enum {
|
||||
MOD_NORMALEDIT_MIX_MUL = 3,
|
||||
};
|
||||
|
||||
typedef struct MeshSeqCacheModifierData {
|
||||
ModifierData modifier;
|
||||
|
||||
struct CacheFile *cache_file;
|
||||
char object_path[1024]; /* 1024 = FILE_MAX */
|
||||
|
||||
char read_flag;
|
||||
char pad[7];
|
||||
} MeshSeqCacheModifierData;
|
||||
|
||||
/* MeshSeqCacheModifierData.read_flag */
|
||||
enum {
|
||||
MOD_MESHSEQ_READ_VERT = (1 << 0),
|
||||
MOD_MESHSEQ_READ_POLY = (1 << 1),
|
||||
MOD_MESHSEQ_READ_UV = (1 << 2),
|
||||
MOD_MESHSEQ_READ_COLOR = (1 << 3),
|
||||
};
|
||||
|
||||
#define MOD_MESHSEQ_READ_ALL \
|
||||
(MOD_MESHSEQ_READ_VERT | MOD_MESHSEQ_READ_POLY | MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)
|
||||
|
||||
#endif /* __DNA_MODIFIER_TYPES_H__ */
|
||||
|
@ -738,6 +738,7 @@ typedef enum eFileSel_File_Types {
|
||||
FILE_TYPE_COLLADA = (1 << 13),
|
||||
FILE_TYPE_OPERATOR = (1 << 14), /* from filter_glob operator property */
|
||||
FILE_TYPE_APPLICATIONBUNDLE = (1 << 15),
|
||||
FILE_TYPE_ALEMBIC = (1 << 16),
|
||||
|
||||
FILE_TYPE_DIR = (1 << 30), /* An FS directory (i.e. S_ISDIR on its path is true). */
|
||||
FILE_TYPE_BLENDERLIB = (1 << 31),
|
||||
|
@ -129,6 +129,7 @@ static const char *includefiles[] = {
|
||||
"DNA_rigidbody_types.h",
|
||||
"DNA_freestyle_types.h",
|
||||
"DNA_linestyle_types.h",
|
||||
"DNA_cachefile_types.h",
|
||||
/* see comment above before editing! */
|
||||
|
||||
/* empty string to indicate end of includefiles */
|
||||
@ -1340,4 +1341,5 @@ int main(int argc, char **argv)
|
||||
#include "DNA_rigidbody_types.h"
|
||||
#include "DNA_freestyle_types.h"
|
||||
#include "DNA_linestyle_types.h"
|
||||
#include "DNA_cachefile_types.h"
|
||||
/* end of list */
|
||||
|
@ -95,6 +95,8 @@ extern StructRNA RNA_Brush;
|
||||
extern StructRNA RNA_BrushTextureSlot;
|
||||
extern StructRNA RNA_BuildModifier;
|
||||
extern StructRNA RNA_MeshCacheModifier;
|
||||
extern StructRNA RNA_MeshSequenceCacheModifier;
|
||||
extern StructRNA RNA_CacheFile;
|
||||
extern StructRNA RNA_Camera;
|
||||
extern StructRNA RNA_CastModifier;
|
||||
extern StructRNA RNA_ChildOfConstraint;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user