IO: Remove Collada import/export
Removes Collada import/export (has been deprecated since 4.2). Pull Request: https://projects.blender.org/blender/blender/pulls/139337
This commit is contained in:
parent
65fe5f4b0f
commit
5ad6d42c83
@ -476,8 +476,6 @@ option(WITH_FRIBIDI "Enable features relying on fribidi" OFF)
|
||||
option(WITH_HARFBUZZ "Enable features relying on harfbuzz" OFF)
|
||||
|
||||
# 3D format support
|
||||
# Disable opencollada when we don't have precompiled libs
|
||||
option(WITH_OPENCOLLADA "Enable OpenCollada Support (http://www.opencollada.org)" ON)
|
||||
option(WITH_IO_WAVEFRONT_OBJ "Enable Wavefront-OBJ 3D file format support (*.obj)" ON)
|
||||
option(WITH_IO_PLY "Enable PLY 3D file format support (*.ply)" ON)
|
||||
option(WITH_IO_STL "Enable STL 3D file format support (*.stl)" ON)
|
||||
@ -2779,7 +2777,6 @@ if(FIRST_RUN)
|
||||
info_cfg_option(WITH_INPUT_IME)
|
||||
info_cfg_option(WITH_INTERNATIONAL)
|
||||
info_cfg_option(WITH_MANIFOLD)
|
||||
info_cfg_option(WITH_OPENCOLLADA)
|
||||
info_cfg_option(WITH_OPENCOLORIO)
|
||||
info_cfg_option(WITH_OPENIMAGEDENOISE)
|
||||
info_cfg_option(WITH_OPENSUBDIV)
|
||||
|
@ -58,7 +58,6 @@ include(cmake/epoxy.cmake)
|
||||
include(cmake/alembic.cmake)
|
||||
include(cmake/opensubdiv.cmake)
|
||||
include(cmake/sdl.cmake)
|
||||
include(cmake/opencollada.cmake)
|
||||
if(UNIX)
|
||||
include(cmake/nasm.cmake)
|
||||
endif()
|
||||
|
@ -89,7 +89,6 @@ download_source(EPOXY)
|
||||
download_source(ALEMBIC)
|
||||
download_source(OPENSUBDIV)
|
||||
download_source(SDL)
|
||||
download_source(OPENCOLLADA)
|
||||
download_source(OPENCOLORIO)
|
||||
download_source(MINIZIPNG)
|
||||
download_source(LLVM)
|
||||
|
@ -1,83 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2002-2022 Blender Authors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
if(UNIX)
|
||||
set(OPENCOLLADA_EXTRA_ARGS
|
||||
-DLIBXML2_INCLUDE_DIR=${LIBDIR}/xml2/include/libxml2
|
||||
-DLIBXML2_LIBRARIES=${LIBDIR}/xml2/lib/libxml2.a)
|
||||
|
||||
# WARNING: the patch contains mixed UNIX and DOS line endings
|
||||
# as does the OPENCOLLADA package, if this can be corrected upstream that would be better.
|
||||
# For now use `sed` to force UNIX line endings so the patch applies.
|
||||
# Needed as neither ignoring white-space or applying as a binary resolve this problem.
|
||||
if(APPLE)
|
||||
set(_dos2unix dos2unix)
|
||||
else()
|
||||
set(_dos2unix sed -i "s/\\r//")
|
||||
endif()
|
||||
set(PATCH_MAYBE_DOS2UNIX_CMD
|
||||
${_dos2unix}
|
||||
${BUILD_DIR}/opencollada/src/external_opencollada/CMakeLists.txt
|
||||
${BUILD_DIR}/opencollada/src/external_opencollada/Externals/LibXML/CMakeLists.txt
|
||||
)
|
||||
else()
|
||||
set(OPENCOLLADA_EXTRA_ARGS
|
||||
-DCMAKE_DEBUG_POSTFIX=_d
|
||||
-DLIBXML2_INCLUDE_DIR=${LIBDIR}/xml2/include/libxml2
|
||||
)
|
||||
if(BUILD_MODE STREQUAL Release)
|
||||
list(APPEND OPENCOLLADA_EXTRA_ARGS -DLIBXML2_LIBRARIES=${LIBDIR}/xml2/lib/libxml2s.lib)
|
||||
else()
|
||||
list(APPEND OPENCOLLADA_EXTRA_ARGS -DLIBXML2_LIBRARIES=${LIBDIR}/xml2/lib/libxml2sd.lib)
|
||||
endif()
|
||||
set(PATCH_MAYBE_DOS2UNIX_CMD)
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(external_opencollada
|
||||
URL file://${PACKAGE_DIR}/${OPENCOLLADA_FILE}
|
||||
DOWNLOAD_DIR ${DOWNLOAD_DIR}
|
||||
URL_HASH ${OPENCOLLADA_HASH_TYPE}=${OPENCOLLADA_HASH}
|
||||
PREFIX ${BUILD_DIR}/opencollada
|
||||
|
||||
PATCH_COMMAND
|
||||
${PATCH_MAYBE_DOS2UNIX_CMD}
|
||||
|
||||
CMAKE_ARGS
|
||||
-DCMAKE_INSTALL_PREFIX=${LIBDIR}/opencollada
|
||||
${DEFAULT_CMAKE_FLAGS}
|
||||
${OPENCOLLADA_EXTRA_ARGS}
|
||||
|
||||
INSTALL_DIR ${LIBDIR}/opencollada
|
||||
)
|
||||
|
||||
unset(PATCH_MAYBE_DOS2UNIX_CMD)
|
||||
|
||||
add_dependencies(
|
||||
external_opencollada
|
||||
external_xml2
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
if(BUILD_MODE STREQUAL Release)
|
||||
ExternalProject_Add_Step(external_opencollada after_install
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
${LIBDIR}/opencollada/
|
||||
${HARVEST_TARGET}/opencollada/
|
||||
|
||||
DEPENDEES install
|
||||
)
|
||||
endif()
|
||||
if(BUILD_MODE STREQUAL Debug)
|
||||
ExternalProject_Add_Step(external_opencollada after_install
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
${LIBDIR}/opencollada/lib
|
||||
${HARVEST_TARGET}/opencollada/lib
|
||||
|
||||
DEPENDEES install
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
harvest(external_opencollada opencollada/include/opencollada opencollada/include "*.h")
|
||||
harvest(external_opencollada opencollada/lib/opencollada opencollada/lib "*.a")
|
||||
endif()
|
@ -232,14 +232,6 @@ set(SDL_HOMEPAGE https://www.libsdl.org)
|
||||
set(SDL_LICENSE SPDX:Zlib)
|
||||
set(SDL_COPYRIGHT "Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>")
|
||||
|
||||
set(OPENCOLLADA_VERSION dfc341ab0b3b23ee307ab8660c0213e64da1eac6)
|
||||
set(OPENCOLLADA_URI https://github.com/aras-p/OpenCOLLADA/archive/${OPENCOLLADA_VERSION}.tar.gz)
|
||||
set(OPENCOLLADA_HASH 2120c8c02aab840e81cb87e625a608f7)
|
||||
set(OPENCOLLADA_HASH_TYPE MD5)
|
||||
set(OPENCOLLADA_FILE opencollada-${OPENCOLLADA_VERSION}.tar.gz)
|
||||
set(OPENCOLLADA_LICENSE SPDX:MIT)
|
||||
set(OPENCOLLADA_COPYRIGHT "Copyright (c) 2008-2009 NetAllied Systems GmbH")
|
||||
|
||||
set(OPENCOLORIO_VERSION 2.4.1)
|
||||
set(OPENCOLORIO_URI https://github.com/AcademySoftwareFoundation/OpenColorIO/archive/v${OPENCOLORIO_VERSION}.tar.gz)
|
||||
set(OPENCOLORIO_HASH a11368ef8f001837f29b7dd18dbd2290)
|
||||
|
@ -40,7 +40,7 @@ endif()
|
||||
|
||||
if(UNIX)
|
||||
if(APPLE)
|
||||
harvest(external_xml2 xml2/lib opencollada/lib "*.a")
|
||||
harvest(external_xml2 xml2/lib xml2/lib "*.a")
|
||||
else()
|
||||
harvest(external_xml2 xml2/include xml2/include "*.h")
|
||||
harvest(external_xml2 xml2/lib xml2/lib "*.a")
|
||||
|
@ -50,7 +50,6 @@ graph[autosize = false, size = "25.7,8.3!", resolution = 300];
|
||||
external_numpy -- external_python_site_packages;
|
||||
external_ocloc -- external_igc;
|
||||
external_ocloc -- external_gmmlib;
|
||||
external_opencollada -- external_xml2;
|
||||
external_opencolorio -- external_yamlcpp;
|
||||
external_opencolorio -- external_expat;
|
||||
external_opencolorio -- external_imath;
|
||||
|
@ -799,14 +799,6 @@ PACKAGES_ALL = (
|
||||
DISTRO_ID_ARCH: "usd", # No official package, in AUR only currently.
|
||||
},
|
||||
),
|
||||
Package(name="OpenCollada Library", is_mandatory=False,
|
||||
version="1.6.68", version_short="1.6", version_min="1.6.68", version_mex="1.7",
|
||||
distro_package_names={DISTRO_ID_DEBIAN: "opencollada-dev", # Useless, very old!
|
||||
DISTRO_ID_FEDORA: "openCOLLADA-devel",
|
||||
DISTRO_ID_SUSE: "libopenCOLLADA-devel",
|
||||
DISTRO_ID_ARCH: "opencollada",
|
||||
},
|
||||
),
|
||||
Package(name="Embree Library", is_mandatory=False,
|
||||
version="4.3.3", version_short="4.3", version_min="4.3", version_mex="5.0",
|
||||
sub_packages=(),
|
||||
|
@ -1,2 +0,0 @@
|
||||
# Files contains mixed line endings, patch needs to preserve them to apply.
|
||||
opencollada.diff binary
|
@ -1,142 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2011 Blender Authors
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
# - Find OpenCOLLADA library
|
||||
# Find the native OpenCOLLADA includes and library
|
||||
# This module defines
|
||||
# OPENCOLLADA_INCLUDE_DIRS, where to find COLLADABaseUtils/ and
|
||||
# COLLADAFramework/, Set when OPENCOLLADA_INCLUDE_DIR is found.
|
||||
# OPENCOLLADA_LIBRARIES, libraries to link against to use OpenCOLLADA.
|
||||
# OPENCOLLADA_ROOT_DIR, The base directory to search for OpenCOLLADA.
|
||||
# This can also be an environment variable.
|
||||
# OPENCOLLADA_FOUND, If false, do not try to use OpenCOLLADA.
|
||||
|
||||
# note about include paths, there are 2 ways includes are set
|
||||
#
|
||||
# Where '/usr/include/opencollada' is the root dir:
|
||||
# /usr/include/opencollada/COLLADABaseUtils/COLLADABUPlatform.h
|
||||
#
|
||||
# Where '/opt/opencollada' is the base dir:
|
||||
# /opt/opencollada/COLLADABaseUtils/include/COLLADABUPlatform.h
|
||||
|
||||
# If `OPENCOLLADA_ROOT_DIR` was defined in the environment, use it.
|
||||
if(DEFINED OPENCOLLADA_ROOT_DIR)
|
||||
# Pass.
|
||||
elseif(DEFINED ENV{OPENCOLLADA_ROOT_DIR})
|
||||
set(OPENCOLLADA_ROOT_DIR $ENV{OPENCOLLADA_ROOT_DIR})
|
||||
else()
|
||||
set(OPENCOLLADA_ROOT_DIR "")
|
||||
endif()
|
||||
|
||||
set(_opencollada_FIND_INCLUDES
|
||||
COLLADAStreamWriter
|
||||
COLLADABaseUtils
|
||||
COLLADAFramework
|
||||
COLLADASaxFrameworkLoader
|
||||
GeneratedSaxParser
|
||||
)
|
||||
|
||||
set(_opencollada_FIND_COMPONENTS
|
||||
OpenCOLLADAStreamWriter
|
||||
OpenCOLLADASaxFrameworkLoader
|
||||
OpenCOLLADAFramework
|
||||
OpenCOLLADABaseUtils
|
||||
GeneratedSaxParser
|
||||
MathMLSolver
|
||||
)
|
||||
|
||||
# Fedora openCOLLADA package links these statically
|
||||
# note that order is important here or it won't link
|
||||
set(_opencollada_FIND_STATIC_COMPONENTS
|
||||
buffer
|
||||
ftoa
|
||||
UTF
|
||||
)
|
||||
|
||||
set(_opencollada_SEARCH_DIRS
|
||||
${OPENCOLLADA_ROOT_DIR}
|
||||
/opt/lib/opencollada
|
||||
)
|
||||
|
||||
set(_opencollada_INCLUDES)
|
||||
foreach(COMPONENT ${_opencollada_FIND_INCLUDES})
|
||||
string(TOUPPER ${COMPONENT} UPPERCOMPONENT)
|
||||
|
||||
# need to use this even thouh we are looking for a dir
|
||||
find_file(OPENCOLLADA_${UPPERCOMPONENT}_INCLUDE_DIR
|
||||
NAMES
|
||||
${COMPONENT}/include
|
||||
${COMPONENT}
|
||||
# Ubuntu ppa needs this.
|
||||
# Alternative would be to suffix all members of search path
|
||||
# but this is less trouble, just looks strange.
|
||||
include/opencollada/${COMPONENT}
|
||||
include/${COMPONENT}/include
|
||||
include/${COMPONENT}
|
||||
HINTS
|
||||
${_opencollada_SEARCH_DIRS}
|
||||
)
|
||||
mark_as_advanced(OPENCOLLADA_${UPPERCOMPONENT}_INCLUDE_DIR)
|
||||
list(APPEND _opencollada_INCLUDES "${OPENCOLLADA_${UPPERCOMPONENT}_INCLUDE_DIR}")
|
||||
endforeach()
|
||||
|
||||
|
||||
set(_opencollada_LIBRARIES)
|
||||
foreach(COMPONENT ${_opencollada_FIND_COMPONENTS})
|
||||
string(TOUPPER ${COMPONENT} UPPERCOMPONENT)
|
||||
|
||||
find_library(OPENCOLLADA_${UPPERCOMPONENT}_LIBRARY
|
||||
NAMES
|
||||
${COMPONENT}
|
||||
HINTS
|
||||
${_opencollada_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
lib64 lib
|
||||
# Ubuntu ppa needs this.
|
||||
lib64/opencollada lib/opencollada
|
||||
)
|
||||
mark_as_advanced(OPENCOLLADA_${UPPERCOMPONENT}_LIBRARY)
|
||||
list(APPEND _opencollada_LIBRARIES "${OPENCOLLADA_${UPPERCOMPONENT}_LIBRARY}")
|
||||
endforeach()
|
||||
|
||||
foreach(COMPONENT ${_opencollada_FIND_STATIC_COMPONENTS})
|
||||
string(TOUPPER ${COMPONENT} UPPERCOMPONENT)
|
||||
|
||||
find_library(OPENCOLLADA_${UPPERCOMPONENT}_LIBRARY
|
||||
NAMES
|
||||
${COMPONENT}
|
||||
HINTS
|
||||
${_opencollada_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
lib64 lib
|
||||
# Ubuntu ppa needs this.
|
||||
lib64/opencollada lib/opencollada
|
||||
)
|
||||
mark_as_advanced(OPENCOLLADA_${UPPERCOMPONENT}_LIBRARY)
|
||||
if(OPENCOLLADA_${UPPERCOMPONENT}_LIBRARY)
|
||||
list(APPEND _opencollada_LIBRARIES "${OPENCOLLADA_${UPPERCOMPONENT}_LIBRARY}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set OPENCOLLADA_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(OpenCOLLADA DEFAULT_MSG
|
||||
_opencollada_LIBRARIES _opencollada_INCLUDES)
|
||||
|
||||
|
||||
if(OPENCOLLADA_FOUND)
|
||||
set(OPENCOLLADA_LIBRARIES ${_opencollada_LIBRARIES})
|
||||
set(OPENCOLLADA_INCLUDE_DIRS ${_opencollada_INCLUDES})
|
||||
endif()
|
||||
|
||||
unset(COMPONENT)
|
||||
unset(UPPERCOMPONENT)
|
||||
unset(_opencollada_FIND_COMPONENTS)
|
||||
unset(_opencollada_FIND_INCLUDES)
|
||||
unset(_opencollada_FIND_STATIC_COMPONENTS)
|
||||
unset(_opencollada_INCLUDES)
|
||||
unset(_opencollada_LIBRARIES)
|
||||
unset(_opencollada_SEARCH_DIRS)
|
@ -42,7 +42,6 @@ set(WITH_MOD_REMESH ON CACHE BOOL "" FORCE)
|
||||
set(WITH_UV_SLIM ON CACHE BOOL "" FORCE)
|
||||
set(WITH_NANOVDB ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENAL ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENCOLLADA ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENCOLORIO ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENIMAGEDENOISE ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENSUBDIV ON CACHE BOOL "" FORCE)
|
||||
|
@ -50,7 +50,6 @@ set(WITH_MOD_REMESH OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_UV_SLIM OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_NANOVDB OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENAL OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENCOLLADA OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENCOLORIO OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENIMAGEDENOISE OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENSUBDIV OFF CACHE BOOL "" FORCE)
|
||||
|
@ -46,7 +46,6 @@ set(WITH_MOD_REMESH ON CACHE BOOL "" FORCE)
|
||||
set(WITH_UV_SLIM ON CACHE BOOL "" FORCE)
|
||||
set(WITH_NANOVDB ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENAL ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENCOLLADA ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENCOLORIO ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENIMAGEDENOISE ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENSUBDIV ON CACHE BOOL "" FORCE)
|
||||
|
@ -25,7 +25,7 @@ endfunction()
|
||||
# ------------------------------------------------------------------------
|
||||
# Find system provided libraries.
|
||||
|
||||
# Find system ZLIB, not the pre-compiled one supplied with OpenCollada.
|
||||
# Find system ZLIB
|
||||
set(ZLIB_ROOT /usr)
|
||||
find_package(ZLIB REQUIRED)
|
||||
find_package(BZip2 REQUIRED)
|
||||
@ -214,12 +214,6 @@ if(WITH_JACK)
|
||||
string(APPEND PLATFORM_LINKFLAGS " -F/Library/Frameworks -weak_framework jackmp")
|
||||
endif()
|
||||
|
||||
if(WITH_OPENCOLLADA)
|
||||
find_package(OpenCOLLADA)
|
||||
find_library(XML2_LIBRARIES NAMES xml2 HINTS ${LIBDIR}/opencollada/lib)
|
||||
print_found_status("XML2" "${XML2_LIBRARIES}")
|
||||
endif()
|
||||
|
||||
if(WITH_SDL)
|
||||
find_package(SDL2)
|
||||
set(SDL_INCLUDE_DIR ${SDL2_INCLUDE_DIRS})
|
||||
|
@ -87,9 +87,7 @@ if(DEFINED LIBDIR)
|
||||
# not need to be ever discovered for the Blender linking.
|
||||
list(REMOVE_ITEM LIB_SUBDIRS ${LIBDIR}/dpcpp)
|
||||
|
||||
# NOTE: Make sure "proper" compiled zlib comes first before the one
|
||||
# which is a part of OpenCollada. They have different ABI, and we
|
||||
# do need to use the official one.
|
||||
# NOTE: Make sure "proper" compiled zlib comes first
|
||||
set(CMAKE_PREFIX_PATH ${LIBDIR}/zlib ${LIB_SUBDIRS})
|
||||
|
||||
include(platform_old_libs_update)
|
||||
@ -333,15 +331,6 @@ if(WITH_FFTW3)
|
||||
set_and_warn_library_found("fftw3" FFTW3_FOUND WITH_FFTW3)
|
||||
endif()
|
||||
|
||||
if(WITH_OPENCOLLADA)
|
||||
find_package_wrapper(OpenCOLLADA)
|
||||
if(OPENCOLLADA_FOUND)
|
||||
find_package_wrapper(XML2)
|
||||
else()
|
||||
set_and_warn_library_found("OpenCollada" OPENCOLLADA_FOUND WITH_OPENCOLLADA)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_MEM_JEMALLOC)
|
||||
find_package_wrapper(JeMalloc)
|
||||
set_and_warn_library_found("JeMalloc" JEMALLOC_FOUND WITH_MEM_JEMALLOC)
|
||||
@ -541,13 +530,6 @@ if(WITH_LLVM)
|
||||
find_package_wrapper(Clang)
|
||||
set_and_warn_library_found("Clang" CLANG_FOUND WITH_CLANG)
|
||||
endif()
|
||||
|
||||
# Symbol conflicts with same UTF library used by OpenCollada
|
||||
if(DEFINED LIBDIR)
|
||||
if(WITH_OPENCOLLADA AND (${LLVM_VERSION} VERSION_LESS "4.0.0"))
|
||||
list(REMOVE_ITEM OPENCOLLADA_LIBRARIES ${OPENCOLLADA_UTF_LIBRARY})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@ -500,45 +500,6 @@ if(WITH_IMAGE_WEBP)
|
||||
set(WEBP_FOUND ON)
|
||||
endif()
|
||||
|
||||
if(WITH_OPENCOLLADA)
|
||||
set(OPENCOLLADA ${LIBDIR}/opencollada)
|
||||
|
||||
set(OPENCOLLADA_INCLUDE_DIRS
|
||||
${OPENCOLLADA}/include/opencollada/COLLADAStreamWriter
|
||||
${OPENCOLLADA}/include/opencollada/COLLADABaseUtils
|
||||
${OPENCOLLADA}/include/opencollada/COLLADAFramework
|
||||
${OPENCOLLADA}/include/opencollada/COLLADASaxFrameworkLoader
|
||||
${OPENCOLLADA}/include/opencollada/GeneratedSaxParser
|
||||
)
|
||||
|
||||
set(OPENCOLLADA_LIBRARIES
|
||||
optimized ${OPENCOLLADA}/lib/opencollada/OpenCOLLADASaxFrameworkLoader.lib
|
||||
optimized ${OPENCOLLADA}/lib/opencollada/OpenCOLLADAFramework.lib
|
||||
optimized ${OPENCOLLADA}/lib/opencollada/OpenCOLLADABaseUtils.lib
|
||||
optimized ${OPENCOLLADA}/lib/opencollada/OpenCOLLADAStreamWriter.lib
|
||||
optimized ${OPENCOLLADA}/lib/opencollada/MathMLSolver.lib
|
||||
optimized ${OPENCOLLADA}/lib/opencollada/GeneratedSaxParser.lib
|
||||
optimized ${OPENCOLLADA}/lib/opencollada/buffer.lib
|
||||
optimized ${OPENCOLLADA}/lib/opencollada/ftoa.lib
|
||||
|
||||
debug ${OPENCOLLADA}/lib/opencollada/OpenCOLLADASaxFrameworkLoader_d.lib
|
||||
debug ${OPENCOLLADA}/lib/opencollada/OpenCOLLADAFramework_d.lib
|
||||
debug ${OPENCOLLADA}/lib/opencollada/OpenCOLLADABaseUtils_d.lib
|
||||
debug ${OPENCOLLADA}/lib/opencollada/OpenCOLLADAStreamWriter_d.lib
|
||||
debug ${OPENCOLLADA}/lib/opencollada/MathMLSolver_d.lib
|
||||
debug ${OPENCOLLADA}/lib/opencollada/GeneratedSaxParser_d.lib
|
||||
debug ${OPENCOLLADA}/lib/opencollada/buffer_d.lib
|
||||
debug ${OPENCOLLADA}/lib/opencollada/ftoa_d.lib
|
||||
)
|
||||
if(EXISTS ${LIBDIR}/xml2/lib/libxml2s.lib) # 3.4 libraries
|
||||
list(APPEND OPENCOLLADA_LIBRARIES ${LIBDIR}/xml2/lib/libxml2s.lib)
|
||||
else()
|
||||
list(APPEND OPENCOLLADA_LIBRARIES ${OPENCOLLADA}/lib/opencollada/xml.lib)
|
||||
endif()
|
||||
|
||||
list(APPEND OPENCOLLADA_LIBRARIES ${OPENCOLLADA}/lib/opencollada/UTF.lib)
|
||||
endif()
|
||||
|
||||
if(WITH_CODEC_FFMPEG)
|
||||
set(FFMPEG_INCLUDE_DIRS
|
||||
${LIBDIR}/ffmpeg/include
|
||||
|
@ -288,10 +288,6 @@
|
||||
/** \defgroup externformats External Formats
|
||||
* \ingroup blender */
|
||||
|
||||
/** \defgroup collada COLLADA
|
||||
* \ingroup externformats
|
||||
*/
|
||||
|
||||
/** \defgroup avi AVI
|
||||
* \ingroup externformats
|
||||
*/
|
||||
|
@ -3101,7 +3101,6 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
| [Mesa](https://www.mesa3d.org/) | 23.3.0 | `Copyright (C) 1999-2007 Brian Paul All Rights Reserved.` |
|
||||
| [Ocloc](https://github.com/intel/compute-runtime) | 24.45.31740 | `Copyright (C) 2018-2023 Intel Corporation` |
|
||||
| [oneAPI Level Zero](https://github.com/oneapi-src/level-zero) | 1.19.2 | `Copyright (C) 2019-2024 Intel Corporation` |
|
||||
| Opencollada | dfc341ab0b3 | `Copyright (c) 2008-2009 NetAllied Systems GmbH` |
|
||||
| [Pugixml](https://pugixml.org/) | 1.10 | `Copyright (c) 2006-2020 Arseny Kapoulkine` |
|
||||
| [QuadriFlow](https://github.com/hjwdzh/QuadriFlow) | 27a6867 | `Copyright (c) 2018 Jingwei Huang, Yichao Zhou, Matthias Niessner, Jonathan Shewchuk and Leonidas Guibas. All rights reserved.` |
|
||||
| [RenderDoc](https://github.com/baldurk/renderdoc/) | d47e79ae079 | `Copyright (c) 2015-2024 Baldur Karlsson; Copyright (c) 2014 Crytek` |
|
||||
|
@ -511,7 +511,6 @@ class SpellChecker:
|
||||
"clearcoat",
|
||||
"codec", "codecs",
|
||||
"codepoint",
|
||||
"collada",
|
||||
"colorspace",
|
||||
"compositing",
|
||||
"crossfade",
|
||||
|
@ -1,17 +0,0 @@
|
||||
import bpy
|
||||
op = bpy.context.active_operator
|
||||
|
||||
op.apply_modifiers = True
|
||||
op.export_mesh_type = 0
|
||||
op.export_mesh_type_selection = 'view'
|
||||
op.selected = True
|
||||
op.include_children = False
|
||||
op.include_armatures = True
|
||||
op.include_shapekeys = False
|
||||
op.deform_bones_only = True
|
||||
op.active_uv_only = True
|
||||
op.use_texture_copies = True
|
||||
op.triangulate = True
|
||||
op.use_object_instantiation = False
|
||||
op.sort_by_name = True
|
||||
op.open_sim = True
|
@ -1,17 +0,0 @@
|
||||
import bpy
|
||||
op = bpy.context.active_operator
|
||||
|
||||
op.apply_modifiers = True
|
||||
op.export_mesh_type = 0
|
||||
op.export_mesh_type_selection = 'view'
|
||||
op.selected = True
|
||||
op.include_children = False
|
||||
op.include_armatures = False
|
||||
op.include_shapekeys = False
|
||||
op.deform_bones_only = False
|
||||
op.active_uv_only = True
|
||||
op.use_texture_copies = True
|
||||
op.triangulate = True
|
||||
op.use_object_instantiation = False
|
||||
op.sort_by_name = True
|
||||
op.open_sim = False
|
@ -891,8 +891,6 @@ class WM_OT_operator_presets_cleanup(Operator):
|
||||
operators = [
|
||||
"WM_OT_alembic_export",
|
||||
"WM_OT_alembic_import",
|
||||
"WM_OT_collada_export",
|
||||
"WM_OT_collada_import",
|
||||
"WM_OT_obj_export",
|
||||
"WM_OT_obj_import",
|
||||
"WM_OT_ply_export",
|
||||
|
@ -373,8 +373,6 @@ class TOPBAR_MT_file_import(Menu):
|
||||
|
||||
if bpy.app.build_options.io_fbx:
|
||||
self.layout.operator("wm.fbx_import", text="FBX (.fbx) (experimental)")
|
||||
if bpy.app.build_options.collada:
|
||||
self.layout.operator("wm.collada_import", text="Collada (.dae) (Legacy)")
|
||||
|
||||
|
||||
class TOPBAR_MT_file_export(Menu):
|
||||
@ -403,8 +401,6 @@ class TOPBAR_MT_file_export(Menu):
|
||||
self.layout.operator("wm.ply_export", text="Stanford PLY (.ply)")
|
||||
if bpy.app.build_options.io_stl:
|
||||
self.layout.operator("wm.stl_export", text="STL (.stl)")
|
||||
if bpy.app.build_options.collada:
|
||||
self.layout.operator("wm.collada_export", text="Collada (.dae) (Legacy)")
|
||||
|
||||
|
||||
class TOPBAR_MT_file_external_data(Menu):
|
||||
|
@ -269,7 +269,7 @@ enum {
|
||||
G_DEBUG_DEPSGRAPH_TIME | G_DEBUG_DEPSGRAPH_UID),
|
||||
G_DEBUG_SIMDATA = (1 << 15), /* sim debug data display */
|
||||
G_DEBUG_GPU = (1 << 16), /* gpu debug */
|
||||
G_DEBUG_IO = (1 << 17), /* IO Debugging (for Collada, ...). */
|
||||
G_DEBUG_IO = (1 << 17), /* IO Debugging. */
|
||||
G_DEBUG_GPU_FORCE_WORKAROUNDS = (1 << 18), /* Force GPU workarounds bypassing detection. */
|
||||
G_DEBUG_GPU_FORCE_VULKAN_LOCAL_READ = (1 << 19), /* Force GPU dynamic rendering local read. */
|
||||
G_DEBUG_GPU_COMPILE_SHADERS = (1 << 20), /* Compile all statically defined shaders. . */
|
||||
|
@ -5,7 +5,6 @@
|
||||
set(INC
|
||||
../include
|
||||
../../io/alembic
|
||||
../../io/collada
|
||||
../../io/common
|
||||
../../io/fbx
|
||||
../../io/grease_pencil
|
||||
@ -24,7 +23,6 @@ set(INC_SYS
|
||||
set(SRC
|
||||
io_alembic.cc
|
||||
io_cache.cc
|
||||
io_collada.cc
|
||||
io_drop_import_file.cc
|
||||
io_fbx_ops.cc
|
||||
io_grease_pencil.cc
|
||||
@ -37,7 +35,6 @@ set(SRC
|
||||
|
||||
io_alembic.hh
|
||||
io_cache.hh
|
||||
io_collada.hh
|
||||
io_drop_import_file.hh
|
||||
io_fbx_ops.hh
|
||||
io_grease_pencil.hh
|
||||
@ -62,13 +59,6 @@ set(LIB
|
||||
PRIVATE bf::windowmanager
|
||||
)
|
||||
|
||||
if(WITH_OPENCOLLADA)
|
||||
list(APPEND LIB
|
||||
bf_io_collada
|
||||
)
|
||||
add_definitions(-DWITH_COLLADA)
|
||||
endif()
|
||||
|
||||
if(WITH_IO_WAVEFRONT_OBJ)
|
||||
list(APPEND LIB
|
||||
bf_io_wavefront_obj
|
||||
|
@ -1,884 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2008 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
#ifdef WITH_COLLADA
|
||||
# include "DNA_space_types.h"
|
||||
|
||||
# include "BLT_translation.hh"
|
||||
|
||||
# include "BLI_fileops.h"
|
||||
# include "BLI_path_utils.hh"
|
||||
# include "BLI_string.h"
|
||||
|
||||
# include "BKE_context.hh"
|
||||
# include "BKE_file_handler.hh"
|
||||
# include "BKE_report.hh"
|
||||
|
||||
# include "DEG_depsgraph.hh"
|
||||
|
||||
# include "ED_fileselect.hh"
|
||||
# include "ED_object.hh"
|
||||
# include "ED_outliner.hh"
|
||||
|
||||
# include "RNA_access.hh"
|
||||
# include "RNA_define.hh"
|
||||
|
||||
# include "UI_interface.hh"
|
||||
# include "UI_resources.hh"
|
||||
|
||||
# include "WM_api.hh"
|
||||
# include "WM_types.hh"
|
||||
|
||||
# include "collada.h"
|
||||
|
||||
# include "io_collada.hh"
|
||||
# include "io_utils.hh"
|
||||
|
||||
static wmOperatorStatus wm_collada_export_invoke(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent * /*event*/)
|
||||
{
|
||||
ED_fileselect_ensure_default_filepath(C, op, ".dae");
|
||||
|
||||
WM_event_add_fileselect(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static wmOperatorStatus wm_collada_export_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
char filepath[FILE_MAX];
|
||||
int apply_modifiers;
|
||||
int global_forward;
|
||||
int global_up;
|
||||
int apply_global_orientation;
|
||||
int export_mesh_type;
|
||||
int selected;
|
||||
int include_children;
|
||||
int include_armatures;
|
||||
int include_shapekeys;
|
||||
int deform_bones_only;
|
||||
|
||||
int include_animations;
|
||||
int include_all_actions;
|
||||
int sampling_rate;
|
||||
int keep_smooth_curves;
|
||||
int keep_keyframes;
|
||||
int keep_flat_curves;
|
||||
|
||||
int export_animation_type;
|
||||
int use_texture_copies;
|
||||
int active_uv_only;
|
||||
|
||||
int triangulate;
|
||||
int use_object_instantiation;
|
||||
int use_blender_profile;
|
||||
int sort_by_name;
|
||||
int export_object_transformation_type;
|
||||
int export_animation_transformation_type;
|
||||
|
||||
int open_sim;
|
||||
int limit_precision;
|
||||
int keep_bind_info;
|
||||
|
||||
int export_count;
|
||||
int sample_animations;
|
||||
|
||||
if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No filepath given");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
RNA_string_get(op->ptr, "filepath", filepath);
|
||||
BLI_path_extension_ensure(filepath, sizeof(filepath), ".dae");
|
||||
|
||||
/* Avoid File write exceptions in Collada */
|
||||
if (!BLI_exists(filepath)) {
|
||||
BLI_file_ensure_parent_dir_exists(filepath);
|
||||
if (!BLI_file_touch(filepath)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Can't create export file");
|
||||
fprintf(stdout, "Collada export: Can not create: %s\n", filepath);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
}
|
||||
else if (!BLI_file_is_writable(filepath)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Can't overwrite export file");
|
||||
fprintf(stdout, "Collada export: Can not modify: %s\n", filepath);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* Now the exporter can create and write the export file */
|
||||
|
||||
/* Options panel */
|
||||
apply_modifiers = RNA_boolean_get(op->ptr, "apply_modifiers");
|
||||
export_mesh_type = RNA_enum_get(op->ptr, "export_mesh_type_selection");
|
||||
global_forward = RNA_enum_get(op->ptr, "export_global_forward_selection");
|
||||
global_up = RNA_enum_get(op->ptr, "export_global_up_selection");
|
||||
apply_global_orientation = RNA_boolean_get(op->ptr, "apply_global_orientation");
|
||||
|
||||
selected = RNA_boolean_get(op->ptr, "selected");
|
||||
include_children = RNA_boolean_get(op->ptr, "include_children");
|
||||
include_armatures = RNA_boolean_get(op->ptr, "include_armatures");
|
||||
include_shapekeys = RNA_boolean_get(op->ptr, "include_shapekeys");
|
||||
|
||||
include_animations = RNA_boolean_get(op->ptr, "include_animations");
|
||||
include_all_actions = RNA_boolean_get(op->ptr, "include_all_actions");
|
||||
export_animation_type = RNA_enum_get(op->ptr, "export_animation_type_selection");
|
||||
sample_animations = (export_animation_type == BC_ANIMATION_EXPORT_SAMPLES);
|
||||
sampling_rate = (sample_animations) ? RNA_int_get(op->ptr, "sampling_rate") : 0;
|
||||
keep_smooth_curves = RNA_boolean_get(op->ptr, "keep_smooth_curves");
|
||||
keep_keyframes = RNA_boolean_get(op->ptr, "keep_keyframes");
|
||||
keep_flat_curves = RNA_boolean_get(op->ptr, "keep_flat_curves");
|
||||
|
||||
deform_bones_only = RNA_boolean_get(op->ptr, "deform_bones_only");
|
||||
|
||||
use_texture_copies = RNA_boolean_get(op->ptr, "use_texture_copies");
|
||||
active_uv_only = RNA_boolean_get(op->ptr, "active_uv_only");
|
||||
|
||||
triangulate = RNA_boolean_get(op->ptr, "triangulate");
|
||||
use_object_instantiation = RNA_boolean_get(op->ptr, "use_object_instantiation");
|
||||
use_blender_profile = RNA_boolean_get(op->ptr, "use_blender_profile");
|
||||
sort_by_name = RNA_boolean_get(op->ptr, "sort_by_name");
|
||||
|
||||
export_object_transformation_type = RNA_enum_get(op->ptr,
|
||||
"export_object_transformation_type_selection");
|
||||
export_animation_transformation_type = RNA_enum_get(
|
||||
op->ptr, "export_animation_transformation_type_selection");
|
||||
|
||||
open_sim = RNA_boolean_get(op->ptr, "open_sim");
|
||||
limit_precision = RNA_boolean_get(op->ptr, "limit_precision");
|
||||
keep_bind_info = RNA_boolean_get(op->ptr, "keep_bind_info");
|
||||
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
||||
/* get editmode results */
|
||||
blender::ed::object::editmode_load(bmain, CTX_data_edit_object(C));
|
||||
|
||||
// Scene *scene = CTX_data_scene(C);
|
||||
|
||||
ExportSettings export_settings{};
|
||||
|
||||
export_settings.filepath = filepath;
|
||||
|
||||
export_settings.apply_modifiers = apply_modifiers != 0;
|
||||
export_settings.global_forward = BC_global_forward_axis(global_forward);
|
||||
export_settings.global_up = BC_global_up_axis(global_up);
|
||||
export_settings.apply_global_orientation = apply_global_orientation != 0;
|
||||
|
||||
export_settings.export_mesh_type = BC_export_mesh_type(export_mesh_type);
|
||||
export_settings.selected = selected != 0;
|
||||
export_settings.include_children = include_children != 0;
|
||||
export_settings.include_armatures = include_armatures != 0;
|
||||
export_settings.include_shapekeys = include_shapekeys != 0;
|
||||
export_settings.deform_bones_only = deform_bones_only != 0;
|
||||
export_settings.include_animations = include_animations != 0;
|
||||
export_settings.include_all_actions = include_all_actions != 0;
|
||||
export_settings.sampling_rate = sampling_rate;
|
||||
export_settings.keep_keyframes = keep_keyframes != 0 || sampling_rate < 1;
|
||||
export_settings.keep_flat_curves = keep_flat_curves != 0;
|
||||
|
||||
export_settings.active_uv_only = active_uv_only != 0;
|
||||
export_settings.export_animation_type = BC_export_animation_type(export_animation_type);
|
||||
export_settings.use_texture_copies = use_texture_copies != 0;
|
||||
|
||||
export_settings.triangulate = triangulate != 0;
|
||||
export_settings.use_object_instantiation = use_object_instantiation != 0;
|
||||
export_settings.use_blender_profile = use_blender_profile != 0;
|
||||
export_settings.sort_by_name = sort_by_name != 0;
|
||||
export_settings.object_transformation_type = BC_export_transformation_type(
|
||||
export_object_transformation_type);
|
||||
export_settings.animation_transformation_type = BC_export_transformation_type(
|
||||
export_animation_transformation_type);
|
||||
export_settings.keep_smooth_curves = keep_smooth_curves != 0;
|
||||
|
||||
if (export_animation_type != BC_ANIMATION_EXPORT_SAMPLES) {
|
||||
/* When curves are exported then we can not export as matrix. */
|
||||
export_settings.animation_transformation_type = BC_TRANSFORMATION_TYPE_DECOMPOSED;
|
||||
}
|
||||
|
||||
if (export_settings.animation_transformation_type != BC_TRANSFORMATION_TYPE_DECOMPOSED) {
|
||||
/* Can not export smooth curves when Matrix export is enabled. */
|
||||
export_settings.keep_smooth_curves = false;
|
||||
}
|
||||
|
||||
if (include_animations) {
|
||||
export_settings.object_transformation_type = export_settings.animation_transformation_type;
|
||||
}
|
||||
|
||||
export_settings.open_sim = open_sim != 0;
|
||||
export_settings.limit_precision = limit_precision != 0;
|
||||
export_settings.keep_bind_info = keep_bind_info != 0;
|
||||
|
||||
export_count = collada_export(C, &export_settings);
|
||||
|
||||
if (export_count == 0) {
|
||||
BKE_report(op->reports, RPT_WARNING, "No objects selected -- Created empty export file");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
if (export_count < 0) {
|
||||
BKE_report(op->reports, RPT_WARNING, "Error during export (see Console)");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
char buff[100];
|
||||
SNPRINTF(buff, "Exported %d Objects", export_count);
|
||||
BKE_report(op->reports, RPT_INFO, buff);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
|
||||
{
|
||||
uiLayout *box, *row, *col, *sub;
|
||||
bool include_animations = RNA_boolean_get(imfptr, "include_animations");
|
||||
int ui_section = RNA_enum_get(imfptr, "prop_bc_export_ui_section");
|
||||
|
||||
BC_export_animation_type animation_type = BC_export_animation_type(
|
||||
RNA_enum_get(imfptr, "export_animation_type_selection"));
|
||||
|
||||
BC_export_transformation_type animation_transformation_type = BC_export_transformation_type(
|
||||
RNA_enum_get(imfptr, "export_animation_transformation_type_selection"));
|
||||
|
||||
bool sampling = animation_type == BC_ANIMATION_EXPORT_SAMPLES;
|
||||
|
||||
/* Export Options: */
|
||||
row = &layout->row(false);
|
||||
row->prop(imfptr, "prop_bc_export_ui_section", UI_ITEM_R_EXPAND, std::nullopt, ICON_NONE);
|
||||
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
uiLayoutSetPropDecorate(layout, false);
|
||||
|
||||
if (ui_section == BC_UI_SECTION_MAIN) {
|
||||
/* Export data options. */
|
||||
box = &layout->box();
|
||||
col = &box->column(false);
|
||||
col->prop(imfptr, "selected", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
sub = &col->column(false);
|
||||
uiLayoutSetEnabled(sub, RNA_boolean_get(imfptr, "selected"));
|
||||
sub->prop(imfptr, "include_children", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
sub->prop(imfptr, "include_armatures", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
sub->prop(imfptr, "include_shapekeys", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
|
||||
box = &layout->box();
|
||||
row = &box->row(false);
|
||||
row->label(IFACE_("Global Orientation"), ICON_ORIENTATION_GLOBAL);
|
||||
|
||||
box->prop(imfptr, "apply_global_orientation", UI_ITEM_NONE, IFACE_("Apply"), ICON_NONE);
|
||||
box->prop(imfptr,
|
||||
"export_global_forward_selection",
|
||||
UI_ITEM_NONE,
|
||||
IFACE_("Forward Axis"),
|
||||
ICON_NONE);
|
||||
box->prop(imfptr, "export_global_up_selection", UI_ITEM_NONE, IFACE_("Up Axis"), ICON_NONE);
|
||||
|
||||
/* Texture options */
|
||||
box = &layout->box();
|
||||
box->label(IFACE_("Texture Options"), ICON_TEXTURE_DATA);
|
||||
|
||||
col = &box->column(false);
|
||||
col->prop(imfptr, "use_texture_copies", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
row = &col->row(true, IFACE_("UV"));
|
||||
row->prop(imfptr, "active_uv_only", UI_ITEM_NONE, IFACE_("Only Selected Map"), ICON_NONE);
|
||||
}
|
||||
else if (ui_section == BC_UI_SECTION_GEOMETRY) {
|
||||
box = &layout->box();
|
||||
box->label(IFACE_("Export Data Options"), ICON_MESH_DATA);
|
||||
|
||||
col = &box->column(false);
|
||||
|
||||
col->prop(imfptr, "triangulate", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
|
||||
row = &col->row(true, IFACE_("Apply Modifiers"));
|
||||
row->prop(imfptr, "apply_modifiers", UI_ITEM_NONE, "", ICON_NONE);
|
||||
sub = &row->column(false);
|
||||
uiLayoutSetActive(sub, RNA_boolean_get(imfptr, "apply_modifiers"));
|
||||
sub->prop(imfptr, "export_mesh_type_selection", UI_ITEM_NONE, "", ICON_NONE);
|
||||
|
||||
if (RNA_boolean_get(imfptr, "include_animations")) {
|
||||
col->prop(imfptr,
|
||||
"export_animation_transformation_type_selection",
|
||||
UI_ITEM_NONE,
|
||||
std::nullopt,
|
||||
ICON_NONE);
|
||||
}
|
||||
else {
|
||||
col->prop(imfptr,
|
||||
"export_object_transformation_type_selection",
|
||||
UI_ITEM_NONE,
|
||||
std::nullopt,
|
||||
ICON_NONE);
|
||||
}
|
||||
}
|
||||
else if (ui_section == BC_UI_SECTION_ARMATURE) {
|
||||
/* Armature options */
|
||||
box = &layout->box();
|
||||
box->label(IFACE_("Armature Options"), ICON_ARMATURE_DATA);
|
||||
|
||||
col = &box->column(false);
|
||||
col->prop(imfptr, "deform_bones_only", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col->prop(imfptr, "open_sim", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
}
|
||||
else if (ui_section == BC_UI_SECTION_ANIMATION) {
|
||||
/* Animation options. */
|
||||
box = &layout->box();
|
||||
box->prop(imfptr, "include_animations", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
|
||||
col = &box->column(false);
|
||||
row = &col->row(false);
|
||||
uiLayoutSetActive(row, include_animations);
|
||||
row->prop(
|
||||
imfptr, "export_animation_type_selection", UI_ITEM_R_EXPAND, std::nullopt, ICON_NONE);
|
||||
|
||||
uiLayoutSetActive(row, include_animations && animation_type == BC_ANIMATION_EXPORT_SAMPLES);
|
||||
if (RNA_boolean_get(imfptr, "include_animations")) {
|
||||
box->prop(imfptr,
|
||||
"export_animation_transformation_type_selection",
|
||||
UI_ITEM_NONE,
|
||||
std::nullopt,
|
||||
ICON_NONE);
|
||||
}
|
||||
else {
|
||||
box->prop(imfptr,
|
||||
"export_object_transformation_type_selection",
|
||||
UI_ITEM_NONE,
|
||||
std::nullopt,
|
||||
ICON_NONE);
|
||||
}
|
||||
|
||||
row = &col->column(false);
|
||||
uiLayoutSetActive(row,
|
||||
include_animations &&
|
||||
(animation_transformation_type == BC_TRANSFORMATION_TYPE_DECOMPOSED ||
|
||||
animation_type == BC_ANIMATION_EXPORT_KEYS));
|
||||
row->prop(imfptr, "keep_smooth_curves", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
|
||||
sub = &col->column(false);
|
||||
uiLayoutSetActive(sub, sampling && include_animations);
|
||||
sub->prop(imfptr, "sampling_rate", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
sub->prop(imfptr, "keep_keyframes", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
|
||||
sub = &col->column(false);
|
||||
uiLayoutSetActive(sub, include_animations);
|
||||
sub->prop(imfptr, "keep_flat_curves", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
sub->prop(imfptr, "include_all_actions", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
}
|
||||
else if (ui_section == BC_UI_SECTION_COLLADA) {
|
||||
/* Collada options: */
|
||||
box = &layout->box();
|
||||
row = &box->row(false);
|
||||
row->label(IFACE_("Collada Options"), ICON_MODIFIER);
|
||||
|
||||
col = &box->column(false);
|
||||
col->prop(imfptr, "use_object_instantiation", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col->prop(imfptr, "use_blender_profile", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col->prop(imfptr, "sort_by_name", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col->prop(imfptr, "keep_bind_info", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col->prop(imfptr, "limit_precision", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_collada_export_draw(bContext * /*C*/, wmOperator *op)
|
||||
{
|
||||
uiCollada_exportSettings(op->layout, op->ptr);
|
||||
}
|
||||
|
||||
static bool wm_collada_export_check(bContext * /*C*/, wmOperator *op)
|
||||
{
|
||||
char filepath[FILE_MAX];
|
||||
RNA_string_get(op->ptr, "filepath", filepath);
|
||||
|
||||
if (!BLI_path_extension_check(filepath, ".dae")) {
|
||||
BLI_path_extension_ensure(filepath, FILE_MAX, ".dae");
|
||||
RNA_string_set(op->ptr, "filepath", filepath);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void WM_OT_collada_export(wmOperatorType *ot)
|
||||
{
|
||||
static const EnumPropertyItem prop_bc_export_mesh_type[] = {
|
||||
{BC_MESH_TYPE_VIEW, "view", 0, "Viewport", "Apply modifier's viewport settings"},
|
||||
{BC_MESH_TYPE_RENDER, "render", 0, "Render", "Apply modifier's render settings"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem prop_bc_export_global_forward[] = {
|
||||
{BC_GLOBAL_FORWARD_X, "X", 0, "X", "Global Forward is positive X Axis"},
|
||||
{BC_GLOBAL_FORWARD_Y, "Y", 0, "Y", "Global Forward is positive Y Axis"},
|
||||
{BC_GLOBAL_FORWARD_Z, "Z", 0, "Z", "Global Forward is positive Z Axis"},
|
||||
{BC_GLOBAL_FORWARD_MINUS_X, "-X", 0, "-X", "Global Forward is negative X Axis"},
|
||||
{BC_GLOBAL_FORWARD_MINUS_Y, "-Y", 0, "-Y", "Global Forward is negative Y Axis"},
|
||||
{BC_GLOBAL_FORWARD_MINUS_Z, "-Z", 0, "-Z", "Global Forward is negative Z Axis"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem prop_bc_export_global_up[] = {
|
||||
{BC_GLOBAL_UP_X, "X", 0, "X", "Global UP is positive X Axis"},
|
||||
{BC_GLOBAL_UP_Y, "Y", 0, "Y", "Global UP is positive Y Axis"},
|
||||
{BC_GLOBAL_UP_Z, "Z", 0, "Z", "Global UP is positive Z Axis"},
|
||||
{BC_GLOBAL_UP_MINUS_X, "-X", 0, "-X", "Global UP is negative X Axis"},
|
||||
{BC_GLOBAL_UP_MINUS_Y, "-Y", 0, "-Y", "Global UP is negative Y Axis"},
|
||||
{BC_GLOBAL_UP_MINUS_Z, "-Z", 0, "-Z", "Global UP is negative Z Axis"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem prop_bc_export_transformation_type[] = {
|
||||
{BC_TRANSFORMATION_TYPE_MATRIX,
|
||||
"matrix",
|
||||
0,
|
||||
"Matrix",
|
||||
"Use <matrix> representation for exported transformations"},
|
||||
{BC_TRANSFORMATION_TYPE_DECOMPOSED,
|
||||
"decomposed",
|
||||
0,
|
||||
"Decomposed",
|
||||
"Use <rotate>, <translate> and <scale> representation for exported transformations"},
|
||||
{0, nullptr, 0, nullptr, nullptr}};
|
||||
|
||||
static const EnumPropertyItem prop_bc_export_animation_type[] = {
|
||||
{BC_ANIMATION_EXPORT_SAMPLES,
|
||||
"sample",
|
||||
0,
|
||||
"Samples",
|
||||
"Export Sampled points guided by sampling rate"},
|
||||
{BC_ANIMATION_EXPORT_KEYS,
|
||||
"keys",
|
||||
0,
|
||||
"Curves",
|
||||
"Export Curves (note: guided by curve keys)"},
|
||||
{0, nullptr, 0, nullptr, nullptr}};
|
||||
|
||||
static const EnumPropertyItem prop_bc_export_ui_section[] = {
|
||||
{BC_UI_SECTION_MAIN, "main", 0, "Main", "Data export section"},
|
||||
{BC_UI_SECTION_GEOMETRY, "geometry", 0, "Geom", "Geometry export section"},
|
||||
{BC_UI_SECTION_ARMATURE, "armature", 0, "Arm", "Armature export section"},
|
||||
{BC_UI_SECTION_ANIMATION, "animation", 0, "Anim", "Animation export section"},
|
||||
{BC_UI_SECTION_COLLADA, "collada", 0, "Extra", "Collada export section"},
|
||||
{0, nullptr, 0, nullptr, nullptr}};
|
||||
|
||||
ot->name = "Export COLLADA (Legacy)";
|
||||
ot->description = "Save a Collada file (Deprecated)";
|
||||
ot->idname = "WM_OT_collada_export";
|
||||
|
||||
ot->invoke = wm_collada_export_invoke;
|
||||
ot->exec = wm_collada_export_exec;
|
||||
ot->poll = WM_operator_winactive;
|
||||
ot->check = wm_collada_export_check;
|
||||
|
||||
ot->flag = OPTYPE_PRESET;
|
||||
|
||||
ot->ui = wm_collada_export_draw;
|
||||
|
||||
WM_operator_properties_filesel(ot,
|
||||
FILE_TYPE_FOLDER | FILE_TYPE_COLLADA,
|
||||
FILE_BLENDER,
|
||||
FILE_SAVE,
|
||||
WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
|
||||
FILE_DEFAULTDISPLAY,
|
||||
FILE_SORT_DEFAULT);
|
||||
|
||||
PropertyRNA *prop = RNA_def_string(ot->srna, "filter_glob", "*.dae", 0, "", "");
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
|
||||
RNA_def_enum(ot->srna,
|
||||
"prop_bc_export_ui_section",
|
||||
prop_bc_export_ui_section,
|
||||
0,
|
||||
"Export Section",
|
||||
"Only for User Interface organization");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"apply_modifiers",
|
||||
false,
|
||||
"Apply Modifiers",
|
||||
"Apply modifiers to exported mesh (non destructive)");
|
||||
|
||||
RNA_def_int(ot->srna,
|
||||
"export_mesh_type",
|
||||
0,
|
||||
INT_MIN,
|
||||
INT_MAX,
|
||||
"Resolution",
|
||||
"Modifier resolution for export",
|
||||
INT_MIN,
|
||||
INT_MAX);
|
||||
|
||||
RNA_def_enum(ot->srna,
|
||||
"export_mesh_type_selection",
|
||||
prop_bc_export_mesh_type,
|
||||
0,
|
||||
"Resolution",
|
||||
"Modifier resolution for export");
|
||||
|
||||
RNA_def_enum(ot->srna,
|
||||
"export_global_forward_selection",
|
||||
prop_bc_export_global_forward,
|
||||
BC_DEFAULT_FORWARD,
|
||||
"Global Forward Axis",
|
||||
"Global Forward axis for export");
|
||||
|
||||
RNA_def_enum(ot->srna,
|
||||
"export_global_up_selection",
|
||||
prop_bc_export_global_up,
|
||||
BC_DEFAULT_UP,
|
||||
"Global Up Axis",
|
||||
"Global Up axis for export");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"apply_global_orientation",
|
||||
false,
|
||||
"Apply Global Orientation",
|
||||
"Rotate all root objects to match the global orientation settings "
|
||||
"otherwise set the global orientation per Collada asset");
|
||||
|
||||
RNA_def_boolean(ot->srna, "selected", false, "Selection Only", "Export only selected elements");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"include_children",
|
||||
false,
|
||||
"Include Children",
|
||||
"Export all children of selected objects (even if not selected)");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"include_armatures",
|
||||
false,
|
||||
"Include Armatures",
|
||||
"Export related armatures (even if not selected)");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"include_shapekeys",
|
||||
false,
|
||||
"Include Shape Keys",
|
||||
"Export all Shape Keys from Mesh Objects");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"deform_bones_only",
|
||||
false,
|
||||
"Deform Bones Only",
|
||||
"Only export deforming bones with armatures");
|
||||
|
||||
RNA_def_boolean(
|
||||
ot->srna,
|
||||
"include_animations",
|
||||
true,
|
||||
"Include Animations",
|
||||
"Export animations if available (exporting animations will enforce the decomposition of "
|
||||
"node transforms into <translation> <rotation> and <scale> components)");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"include_all_actions",
|
||||
true,
|
||||
"Include all Actions",
|
||||
"Export also unassigned actions (this allows you to export entire animation "
|
||||
"libraries for your character(s))");
|
||||
|
||||
RNA_def_enum(ot->srna,
|
||||
"export_animation_type_selection",
|
||||
prop_bc_export_animation_type,
|
||||
0,
|
||||
"Key Type",
|
||||
"Type for exported animations (use sample keys or Curve keys)");
|
||||
|
||||
RNA_def_int(ot->srna,
|
||||
"sampling_rate",
|
||||
1,
|
||||
1,
|
||||
INT_MAX,
|
||||
"Sampling Rate",
|
||||
"The distance between 2 keyframes (1 to key every frame)",
|
||||
1,
|
||||
INT_MAX);
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"keep_smooth_curves",
|
||||
false,
|
||||
"Keep Smooth curves",
|
||||
"Export also the curve handles (if available) (this does only work when the "
|
||||
"inverse parent matrix "
|
||||
"is the unity matrix, otherwise you may end up with odd results)");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"keep_keyframes",
|
||||
false,
|
||||
"Keep Keyframes",
|
||||
"Use existing keyframes as additional sample points (this helps when you want "
|
||||
"to keep manual tweaks)");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"keep_flat_curves",
|
||||
false,
|
||||
"All Keyed Curves",
|
||||
"Export also curves which have only one key or are totally flat");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"active_uv_only",
|
||||
false,
|
||||
"Only Selected UV Map",
|
||||
"Export only the selected UV Map");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"use_texture_copies",
|
||||
true,
|
||||
"Copy",
|
||||
"Copy textures to same folder where the .dae file is exported");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"triangulate",
|
||||
true,
|
||||
"Triangulate",
|
||||
"Export polygons (quads and n-gons) as triangles");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"use_object_instantiation",
|
||||
true,
|
||||
"Use Object Instances",
|
||||
"Instantiate multiple Objects from same Data");
|
||||
|
||||
RNA_def_boolean(
|
||||
ot->srna,
|
||||
"use_blender_profile",
|
||||
true,
|
||||
"Use Blender Profile",
|
||||
"Export additional Blender specific information (for material, shaders, bones, etc.)");
|
||||
|
||||
RNA_def_boolean(
|
||||
ot->srna, "sort_by_name", false, "Sort by Object name", "Sort exported data by Object name");
|
||||
|
||||
RNA_def_int(ot->srna,
|
||||
"export_object_transformation_type",
|
||||
0,
|
||||
INT_MIN,
|
||||
INT_MAX,
|
||||
"Transform",
|
||||
"Object Transformation type for translation, scale and rotation",
|
||||
INT_MIN,
|
||||
INT_MAX);
|
||||
|
||||
RNA_def_enum(ot->srna,
|
||||
"export_object_transformation_type_selection",
|
||||
prop_bc_export_transformation_type,
|
||||
0,
|
||||
"Transform",
|
||||
"Object Transformation type for translation, scale and rotation");
|
||||
|
||||
RNA_def_int(ot->srna,
|
||||
"export_animation_transformation_type",
|
||||
0,
|
||||
INT_MIN,
|
||||
INT_MAX,
|
||||
"Transform",
|
||||
"Transformation type for translation, scale and rotation. "
|
||||
"Note: The Animation transformation type in the Anim Tab "
|
||||
"is always equal to the Object transformation type in the Geom tab",
|
||||
INT_MIN,
|
||||
INT_MAX);
|
||||
|
||||
RNA_def_enum(ot->srna,
|
||||
"export_animation_transformation_type_selection",
|
||||
prop_bc_export_transformation_type,
|
||||
0,
|
||||
"Transform",
|
||||
"Transformation type for translation, scale and rotation. "
|
||||
"Note: The Animation transformation type in the Anim Tab "
|
||||
"is always equal to the Object transformation type in the Geom tab");
|
||||
|
||||
RNA_def_boolean(
|
||||
ot->srna,
|
||||
"open_sim",
|
||||
false,
|
||||
"Export to SL/OpenSim",
|
||||
"Compatibility mode for Second Life, OpenSimulator and other compatible online worlds");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"limit_precision",
|
||||
false,
|
||||
"Limit Precision",
|
||||
"Reduce the precision of the exported data to 6 digits");
|
||||
|
||||
RNA_def_boolean(
|
||||
ot->srna,
|
||||
"keep_bind_info",
|
||||
false,
|
||||
"Keep Bind Info",
|
||||
"Store Bindpose information in custom bone properties for later use during Collada export");
|
||||
}
|
||||
|
||||
static wmOperatorStatus wm_collada_import_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
char filepath[FILE_MAX];
|
||||
int import_units;
|
||||
int find_chains;
|
||||
int auto_connect;
|
||||
int fix_orientation;
|
||||
int min_chain_length;
|
||||
|
||||
int keep_bind_info;
|
||||
int custom_normals;
|
||||
ImportSettings import_settings{};
|
||||
|
||||
if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No filepath given");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* Options panel */
|
||||
import_units = RNA_boolean_get(op->ptr, "import_units");
|
||||
custom_normals = RNA_boolean_get(op->ptr, "custom_normals");
|
||||
find_chains = RNA_boolean_get(op->ptr, "find_chains");
|
||||
auto_connect = RNA_boolean_get(op->ptr, "auto_connect");
|
||||
fix_orientation = RNA_boolean_get(op->ptr, "fix_orientation");
|
||||
|
||||
keep_bind_info = RNA_boolean_get(op->ptr, "keep_bind_info");
|
||||
|
||||
min_chain_length = RNA_int_get(op->ptr, "min_chain_length");
|
||||
|
||||
RNA_string_get(op->ptr, "filepath", filepath);
|
||||
|
||||
import_settings.filepath = filepath;
|
||||
import_settings.import_units = import_units != 0;
|
||||
import_settings.custom_normals = custom_normals != 0;
|
||||
import_settings.auto_connect = auto_connect != 0;
|
||||
import_settings.find_chains = find_chains != 0;
|
||||
import_settings.fix_orientation = fix_orientation != 0;
|
||||
import_settings.min_chain_length = min_chain_length;
|
||||
import_settings.keep_bind_info = keep_bind_info != 0;
|
||||
|
||||
if (collada_import(C, &import_settings)) {
|
||||
DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_BASE_FLAGS);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
|
||||
ED_outliner_select_sync_from_object_tag(C);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
BKE_report(op->reports, RPT_ERROR, "Parsing errors in Document (see Blender Console)");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
static void wm_collada_import_settings(uiLayout *layout, PointerRNA *imfptr)
|
||||
{
|
||||
uiLayout *box, *col;
|
||||
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
uiLayoutSetPropDecorate(layout, false);
|
||||
|
||||
/* Import Options: */
|
||||
box = &layout->box();
|
||||
box->label(IFACE_("Import Data Options"), ICON_MESH_DATA);
|
||||
|
||||
box->prop(imfptr, "import_units", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
box->prop(imfptr, "custom_normals", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
|
||||
box = &layout->box();
|
||||
box->label(IFACE_("Armature Options"), ICON_ARMATURE_DATA);
|
||||
|
||||
col = &box->column(false);
|
||||
col->prop(imfptr, "fix_orientation", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col->prop(imfptr, "find_chains", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col->prop(imfptr, "auto_connect", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col->prop(imfptr, "min_chain_length", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
|
||||
box = &layout->box();
|
||||
|
||||
box->prop(imfptr, "keep_bind_info", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
}
|
||||
|
||||
static void wm_collada_import_draw(bContext * /*C*/, wmOperator *op)
|
||||
{
|
||||
wm_collada_import_settings(op->layout, op->ptr);
|
||||
}
|
||||
|
||||
void WM_OT_collada_import(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Import COLLADA (Legacy)";
|
||||
ot->description = "Load a Collada file (Deprecated)";
|
||||
ot->idname = "WM_OT_collada_import";
|
||||
ot->flag = OPTYPE_UNDO | OPTYPE_PRESET;
|
||||
|
||||
ot->invoke = blender::ed::io::filesel_drop_import_invoke;
|
||||
ot->exec = wm_collada_import_exec;
|
||||
ot->poll = WM_operator_winactive;
|
||||
|
||||
ot->ui = wm_collada_import_draw;
|
||||
|
||||
WM_operator_properties_filesel(ot,
|
||||
FILE_TYPE_FOLDER | FILE_TYPE_COLLADA,
|
||||
FILE_BLENDER,
|
||||
FILE_OPENFILE,
|
||||
WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
|
||||
FILE_DEFAULTDISPLAY,
|
||||
FILE_SORT_DEFAULT);
|
||||
|
||||
PropertyRNA *prop = RNA_def_string(ot->srna, "filter_glob", "*.dae", 0, "", "");
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"import_units",
|
||||
false,
|
||||
"Import Units",
|
||||
"If disabled match import to Blender's current Unit settings, "
|
||||
"otherwise use the settings from the Imported scene");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"custom_normals",
|
||||
true,
|
||||
"Custom Normals",
|
||||
"Import custom normals, if available (otherwise Blender will compute them)");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"fix_orientation",
|
||||
false,
|
||||
"Fix Leaf Bones",
|
||||
"Fix Orientation of Leaf Bones (Collada does only support Joints)");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"find_chains",
|
||||
false,
|
||||
"Find Bone Chains",
|
||||
"Find best matching Bone Chains and ensure bones in chain are connected");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"auto_connect",
|
||||
false,
|
||||
"Auto Connect",
|
||||
"Set use_connect for parent bones which have exactly one child bone");
|
||||
|
||||
RNA_def_int(ot->srna,
|
||||
"min_chain_length",
|
||||
0,
|
||||
0,
|
||||
INT_MAX,
|
||||
"Minimum Chain Length",
|
||||
"When searching Bone Chains disregard chains of length below this value",
|
||||
0,
|
||||
INT_MAX);
|
||||
|
||||
RNA_def_boolean(
|
||||
ot->srna,
|
||||
"keep_bind_info",
|
||||
false,
|
||||
"Keep Bind Info",
|
||||
"Store Bindpose information in custom bone properties for later use during Collada export");
|
||||
}
|
||||
|
||||
namespace blender::ed::io {
|
||||
void collada_file_handler_add()
|
||||
{
|
||||
auto fh = std::make_unique<blender::bke::FileHandlerType>();
|
||||
STRNCPY(fh->idname, "IO_FH_collada");
|
||||
STRNCPY(fh->import_operator, "WM_OT_collada_import");
|
||||
STRNCPY(fh->label, "Collada");
|
||||
STRNCPY(fh->file_extensions_str, ".dae");
|
||||
fh->poll_drop = poll_file_object_drop;
|
||||
bke::file_handler_add(std::move(fh));
|
||||
}
|
||||
} // namespace blender::ed::io
|
||||
|
||||
#endif
|
@ -1,18 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2007 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup editor/io
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct wmOperatorType;
|
||||
|
||||
void WM_OT_collada_export(wmOperatorType *ot);
|
||||
void WM_OT_collada_import(wmOperatorType *ot);
|
||||
|
||||
namespace blender::ed::io {
|
||||
void collada_file_handler_add();
|
||||
}
|
@ -2,18 +2,10 @@
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include "io_ops.hh" /* own include */
|
||||
|
||||
#include "WM_api.hh"
|
||||
|
||||
#ifdef WITH_COLLADA
|
||||
# include "io_collada.hh"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_ALEMBIC
|
||||
# include "io_alembic.hh"
|
||||
#endif
|
||||
@ -87,12 +79,6 @@ void ED_operatortypes_io()
|
||||
/* ed::io::fbx_file_handler_add(); TODO: add once not experimental */
|
||||
#endif
|
||||
|
||||
#ifdef WITH_COLLADA
|
||||
WM_operatortype_append(WM_OT_collada_export);
|
||||
WM_operatortype_append(WM_OT_collada_import);
|
||||
ed::io::collada_file_handler_add();
|
||||
#endif
|
||||
|
||||
WM_operatortype_append(WM_OT_drop_import_file);
|
||||
ED_dropbox_drop_import_file();
|
||||
}
|
||||
|
@ -1303,9 +1303,6 @@ static int filelist_geticon_file_type_ex(const FileList *filelist,
|
||||
if (typeflag & FILE_TYPE_BTX) {
|
||||
return ICON_FILE_BLANK;
|
||||
}
|
||||
if (typeflag & FILE_TYPE_COLLADA) {
|
||||
return ICON_FILE_3D;
|
||||
}
|
||||
if (typeflag & FILE_TYPE_ALEMBIC) {
|
||||
return ICON_FILE_3D;
|
||||
}
|
||||
@ -2796,9 +2793,6 @@ int ED_path_extension_type(const char *path)
|
||||
if (BLI_path_extension_check(path, ".btx")) {
|
||||
return FILE_TYPE_BTX;
|
||||
}
|
||||
if (BLI_path_extension_check(path, ".dae")) {
|
||||
return FILE_TYPE_COLLADA;
|
||||
}
|
||||
if (BLI_path_extension_check(path, ".abc")) {
|
||||
return FILE_TYPE_ALEMBIC;
|
||||
}
|
||||
@ -2855,7 +2849,6 @@ int ED_file_extension_icon(const char *path)
|
||||
return ICON_FILE_FONT;
|
||||
case FILE_TYPE_BTX:
|
||||
return ICON_FILE_BLANK;
|
||||
case FILE_TYPE_COLLADA:
|
||||
case FILE_TYPE_ALEMBIC:
|
||||
case FILE_TYPE_OBJECT_IO:
|
||||
return ICON_FILE_3D;
|
||||
|
@ -263,9 +263,6 @@ static FileSelectParams *fileselect_ensure_updated_file_params(SpaceFile *sfile)
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "filter_btx"))) {
|
||||
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_BTX) : 0;
|
||||
}
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "filter_collada"))) {
|
||||
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_COLLADA) : 0;
|
||||
}
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "filter_alembic"))) {
|
||||
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? int(FILE_TYPE_ALEMBIC) : 0;
|
||||
}
|
||||
|
@ -30,10 +30,6 @@ if(WITH_ALEMBIC)
|
||||
add_subdirectory(alembic)
|
||||
endif()
|
||||
|
||||
if(WITH_OPENCOLLADA)
|
||||
add_subdirectory(collada)
|
||||
endif()
|
||||
|
||||
if(WITH_USD)
|
||||
add_subdirectory(usd)
|
||||
endif()
|
||||
|
@ -1,36 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2018-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "AnimationClipExporter.h"
|
||||
|
||||
void AnimationClipExporter::exportAnimationClips(Scene *sce)
|
||||
{
|
||||
openLibrary();
|
||||
std::map<std::string, COLLADASW::ColladaAnimationClip *> clips;
|
||||
|
||||
std::vector<std::vector<std::string>>::iterator anim_meta_entry;
|
||||
for (anim_meta_entry = anim_meta.begin(); anim_meta_entry != anim_meta.end(); ++anim_meta_entry)
|
||||
{
|
||||
std::vector<std::string> entry = *anim_meta_entry;
|
||||
std::string action_id = entry[0];
|
||||
std::string action_name = entry[1];
|
||||
|
||||
std::map<std::string, COLLADASW::ColladaAnimationClip *>::iterator it = clips.find(
|
||||
action_name);
|
||||
if (it == clips.end()) {
|
||||
COLLADASW::ColladaAnimationClip *clip = new COLLADASW::ColladaAnimationClip(action_name);
|
||||
clips[action_name] = clip;
|
||||
}
|
||||
COLLADASW::ColladaAnimationClip *clip = clips[action_name];
|
||||
clip->setInstancedAnimation(action_id);
|
||||
}
|
||||
|
||||
std::map<std::string, COLLADASW::ColladaAnimationClip *>::iterator clips_it;
|
||||
for (clips_it = clips.begin(); clips_it != clips.end(); clips_it++) {
|
||||
COLLADASW::ColladaAnimationClip *clip = (COLLADASW::ColladaAnimationClip *)clips_it->second;
|
||||
addAnimationClip(*clip);
|
||||
}
|
||||
|
||||
closeLibrary();
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "COLLADASWLibraryAnimationClips.h"
|
||||
#include "DEG_depsgraph.hh"
|
||||
#include "ExportSettings.h"
|
||||
|
||||
class AnimationClipExporter : COLLADASW::LibraryAnimationClips {
|
||||
private:
|
||||
Depsgraph *depsgraph;
|
||||
Scene *scene = nullptr;
|
||||
COLLADASW::StreamWriter *sw;
|
||||
BCExportSettings &export_settings;
|
||||
std::vector<std::vector<std::string>> anim_meta;
|
||||
|
||||
public:
|
||||
AnimationClipExporter(Depsgraph *depsgraph,
|
||||
COLLADASW::StreamWriter *sw,
|
||||
BCExportSettings &export_settings,
|
||||
std::vector<std::vector<std::string>> anim_meta)
|
||||
: COLLADASW::LibraryAnimationClips(sw),
|
||||
depsgraph(depsgraph),
|
||||
sw(sw),
|
||||
export_settings(export_settings),
|
||||
anim_meta(anim_meta)
|
||||
{
|
||||
}
|
||||
|
||||
void exportAnimationClips(Scene *sce);
|
||||
};
|
@ -1,830 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2009-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include "AnimationExporter.h"
|
||||
#include "BCAnimationSampler.h"
|
||||
#include "collada_utils.h"
|
||||
|
||||
#include "BKE_material.hh"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
std::string EMPTY_STRING;
|
||||
|
||||
std::string AnimationExporter::get_axis_name(std::string channel_type, int id)
|
||||
{
|
||||
|
||||
static std::map<std::string, std::vector<std::string>> BC_COLLADA_AXIS_FROM_TYPE = {
|
||||
{"color", {"R", "G", "B"}},
|
||||
{"specular_color", {"R", "G", "B"}},
|
||||
{"diffuse_color", {"R", "G", "B"}},
|
||||
{"alpha", {"R", "G", "B"}},
|
||||
{"scale", {"X", "Y", "Z"}},
|
||||
{"location", {"X", "Y", "Z"}},
|
||||
{"rotation_euler", {"X", "Y", "Z"}}};
|
||||
|
||||
std::map<std::string, std::vector<std::string>>::const_iterator it;
|
||||
|
||||
it = BC_COLLADA_AXIS_FROM_TYPE.find(channel_type);
|
||||
if (it == BC_COLLADA_AXIS_FROM_TYPE.end()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const std::vector<std::string> &subchannel = it->second;
|
||||
if (id >= subchannel.size()) {
|
||||
return "";
|
||||
}
|
||||
return subchannel[id];
|
||||
}
|
||||
|
||||
bool AnimationExporter::open_animation_container(bool has_container, Object *ob)
|
||||
{
|
||||
if (!has_container) {
|
||||
char anim_id[200];
|
||||
SNPRINTF(anim_id, "action_container-%s", translate_id(id_name(ob)).c_str());
|
||||
openAnimation(anim_id, encode_xml(id_name(ob)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AnimationExporter::openAnimationWithClip(std::string action_id, std::string action_name)
|
||||
{
|
||||
std::vector<std::string> anim_meta_entry;
|
||||
anim_meta_entry.push_back(translate_id(action_id));
|
||||
anim_meta_entry.push_back(action_name);
|
||||
anim_meta.push_back(anim_meta_entry);
|
||||
|
||||
openAnimation(translate_id(action_id), action_name);
|
||||
}
|
||||
|
||||
void AnimationExporter::close_animation_container(bool has_container)
|
||||
{
|
||||
if (has_container) {
|
||||
closeAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
bool AnimationExporter::exportAnimations()
|
||||
{
|
||||
Scene *sce = export_settings.get_scene();
|
||||
|
||||
LinkNode *export_set = this->export_settings.get_export_set();
|
||||
bool has_anim_data = bc_has_animations(sce, export_set);
|
||||
int animation_count = 0;
|
||||
if (has_anim_data) {
|
||||
|
||||
BCObjectSet animated_subset;
|
||||
BCAnimationSampler::get_animated_from_export_set(animated_subset, *export_set);
|
||||
animation_count = animated_subset.size();
|
||||
BCAnimationSampler animation_sampler(export_settings, animated_subset);
|
||||
|
||||
try {
|
||||
animation_sampler.sample_scene(export_settings, /*keyframe_at_end = */ true);
|
||||
|
||||
openLibrary();
|
||||
|
||||
BCObjectSet::iterator it;
|
||||
for (it = animated_subset.begin(); it != animated_subset.end(); ++it) {
|
||||
Object *ob = *it;
|
||||
exportAnimation(ob, animation_sampler);
|
||||
}
|
||||
}
|
||||
catch (std::invalid_argument &iae) {
|
||||
fprintf(stderr, "Animation export interrupted");
|
||||
fprintf(stderr, "Exception was: %s", iae.what());
|
||||
}
|
||||
|
||||
closeLibrary();
|
||||
|
||||
#if 0
|
||||
/* TODO: If all actions shall be exported, we need to call the
|
||||
* AnimationClipExporter which will figure out which actions
|
||||
* need to be exported for which objects
|
||||
*/
|
||||
if (this->export_settings->include_all_actions) {
|
||||
AnimationClipExporter ace(eval_ctx, sw, export_settings, anim_meta);
|
||||
ace.exportAnimationClips(sce);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return animation_count;
|
||||
}
|
||||
|
||||
void AnimationExporter::exportAnimation(Object *ob, BCAnimationSampler &sampler)
|
||||
{
|
||||
bool container_is_open = false;
|
||||
|
||||
/* Transform animations (trans, rot, scale). */
|
||||
container_is_open = open_animation_container(container_is_open, ob);
|
||||
|
||||
/* Now take care of the Object Animations
|
||||
* NOTE: For Armatures the skeletal animation has already been exported (see above)
|
||||
* However Armatures also can have Object animation.
|
||||
*/
|
||||
bool export_as_matrix = this->export_settings.get_animation_transformation_type() ==
|
||||
BC_TRANSFORMATION_TYPE_MATRIX;
|
||||
|
||||
if (export_as_matrix) {
|
||||
/* export all transform_curves as one single matrix animation */
|
||||
export_matrix_animation(ob, sampler);
|
||||
}
|
||||
|
||||
export_curve_animation_set(ob, sampler, export_as_matrix);
|
||||
|
||||
if (ob->type == OB_ARMATURE && export_as_matrix) {
|
||||
|
||||
#ifdef WITH_MORPH_ANIMATION
|
||||
/* TODO: This needs to be handled by extra profiles, postponed for now */
|
||||
export_morph_animation(ob);
|
||||
#endif
|
||||
|
||||
/* Export skeletal animation (if any) */
|
||||
bArmature *arm = (bArmature *)ob->data;
|
||||
LISTBASE_FOREACH (Bone *, root_bone, &arm->bonebase) {
|
||||
export_bone_animations_recursive(ob, root_bone, sampler);
|
||||
}
|
||||
}
|
||||
|
||||
close_animation_container(container_is_open);
|
||||
}
|
||||
|
||||
void AnimationExporter::export_curve_animation_set(Object *ob,
|
||||
BCAnimationSampler &sampler,
|
||||
bool export_as_matrix)
|
||||
{
|
||||
BCAnimationCurveMap *curves = sampler.get_curves(ob);
|
||||
bool keep_flat_curves = this->export_settings.get_keep_flat_curves();
|
||||
|
||||
BCAnimationCurveMap::iterator it;
|
||||
for (it = curves->begin(); it != curves->end(); ++it) {
|
||||
BCAnimationCurve &curve = *it->second;
|
||||
std::string channel_type = curve.get_channel_type();
|
||||
if (channel_type == "rotation_quaternion") {
|
||||
/* Can not export Quaternion animation in Collada as far as i know)
|
||||
* Maybe automatically convert to euler rotation?
|
||||
* Discard for now. */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (export_as_matrix && curve.is_transform_curve()) {
|
||||
/* All Transform curves will be exported within a single matrix animation,
|
||||
* see export_matrix_animation()
|
||||
* No need to export the curves here again.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!keep_flat_curves && !curve.is_animated()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BCAnimationCurve *mcurve = get_modified_export_curve(ob, curve, *curves);
|
||||
if (mcurve) {
|
||||
export_curve_animation(ob, *mcurve);
|
||||
delete mcurve;
|
||||
}
|
||||
else {
|
||||
export_curve_animation(ob, curve);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationExporter::export_matrix_animation(Object *ob, BCAnimationSampler &sampler)
|
||||
{
|
||||
bool keep_flat_curves = this->export_settings.get_keep_flat_curves();
|
||||
|
||||
std::vector<float> frames;
|
||||
sampler.get_object_frames(frames, ob);
|
||||
if (!frames.empty()) {
|
||||
BCMatrixSampleMap samples;
|
||||
bool is_animated = sampler.get_object_samples(samples, ob);
|
||||
if (keep_flat_curves || is_animated) {
|
||||
bAction *action = bc_getSceneObjectAction(ob);
|
||||
std::string name = encode_xml(id_name(ob));
|
||||
std::string action_name = (action == nullptr) ? name + "-action" : id_name(action);
|
||||
std::string channel_type = "transform";
|
||||
std::string axis;
|
||||
std::string id = bc_get_action_id(action_name, name, channel_type, axis);
|
||||
|
||||
std::string target = translate_id(name) + '/' + channel_type;
|
||||
|
||||
BC_global_rotation_type global_rotation_type = get_global_rotation_type(ob);
|
||||
export_collada_matrix_animation(
|
||||
id, name, target, frames, samples, global_rotation_type, ob->parentinv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BC_global_rotation_type AnimationExporter::get_global_rotation_type(Object *ob)
|
||||
{
|
||||
bool is_export_root = this->export_settings.is_export_root(ob);
|
||||
if (!is_export_root) {
|
||||
return BC_NO_ROTATION;
|
||||
}
|
||||
|
||||
bool apply_global_rotation = this->export_settings.get_apply_global_orientation();
|
||||
|
||||
return (apply_global_rotation) ? BC_DATA_ROTATION : BC_OBJECT_ROTATION;
|
||||
}
|
||||
|
||||
void AnimationExporter::export_bone_animations_recursive(Object *ob,
|
||||
Bone *bone,
|
||||
BCAnimationSampler &sampler)
|
||||
{
|
||||
bool keep_flat_curves = this->export_settings.get_keep_flat_curves();
|
||||
|
||||
std::vector<float> frames;
|
||||
sampler.get_bone_frames(frames, ob, bone);
|
||||
|
||||
if (!frames.empty()) {
|
||||
BCMatrixSampleMap samples;
|
||||
bool is_animated = sampler.get_bone_samples(samples, ob, bone);
|
||||
if (keep_flat_curves || is_animated) {
|
||||
export_bone_animation(ob, bone, frames, samples);
|
||||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (Bone *, child, &bone->childbase) {
|
||||
export_bone_animations_recursive(ob, child, sampler);
|
||||
}
|
||||
}
|
||||
|
||||
BCAnimationCurve *AnimationExporter::get_modified_export_curve(Object *ob,
|
||||
BCAnimationCurve &curve,
|
||||
BCAnimationCurveMap &curves)
|
||||
{
|
||||
std::string channel_type = curve.get_channel_type();
|
||||
BCAnimationCurve *mcurve = nullptr;
|
||||
if (channel_type == "lens") {
|
||||
|
||||
/* Create an xfov curve */
|
||||
|
||||
BCCurveKey key(BC_ANIMATION_TYPE_CAMERA, "xfov", 0);
|
||||
mcurve = new BCAnimationCurve(key, ob);
|
||||
|
||||
/* now tricky part: transform the fcurve */
|
||||
BCValueMap lens_values;
|
||||
curve.get_value_map(lens_values);
|
||||
|
||||
BCAnimationCurve *sensor_curve = nullptr;
|
||||
BCCurveKey sensor_key(BC_ANIMATION_TYPE_CAMERA, "sensor_width", 0);
|
||||
BCAnimationCurveMap::iterator cit = curves.find(sensor_key);
|
||||
if (cit != curves.end()) {
|
||||
sensor_curve = cit->second;
|
||||
}
|
||||
|
||||
BCValueMap::const_iterator vit;
|
||||
for (vit = lens_values.begin(); vit != lens_values.end(); ++vit) {
|
||||
int frame = vit->first;
|
||||
float lens_value = vit->second;
|
||||
|
||||
float sensor_value;
|
||||
if (sensor_curve) {
|
||||
sensor_value = sensor_curve->get_value(frame);
|
||||
}
|
||||
else {
|
||||
sensor_value = ((Camera *)ob->data)->sensor_x;
|
||||
}
|
||||
float value = RAD2DEGF(focallength_to_fov(lens_value, sensor_value));
|
||||
mcurve->add_value(value, frame);
|
||||
}
|
||||
/* to reset the handles */
|
||||
mcurve->clean_handles();
|
||||
}
|
||||
return mcurve;
|
||||
}
|
||||
|
||||
void AnimationExporter::export_curve_animation(Object *ob, BCAnimationCurve &curve)
|
||||
{
|
||||
std::string channel_target = curve.get_channel_target();
|
||||
|
||||
/*
|
||||
* Some curves can not be exported as is and need some conversion
|
||||
* For more information see implementation of get_modified_export_curve()
|
||||
* NOTE: if mcurve is not null then it must be deleted at end of this method;
|
||||
*/
|
||||
|
||||
int channel_index = curve.get_channel_index();
|
||||
/* RGB or XYZ or "" */
|
||||
std::string channel_type = curve.get_channel_type();
|
||||
std::string axis = get_axis_name(channel_type, channel_index);
|
||||
|
||||
std::string action_name;
|
||||
bAction *action = bc_getSceneObjectAction(ob);
|
||||
action_name = (action) ? id_name(action) : "constraint_anim";
|
||||
|
||||
const std::string curve_name = encode_xml(curve.get_animation_name(ob));
|
||||
std::string id = bc_get_action_id(action_name, curve_name, channel_target, axis, ".");
|
||||
|
||||
std::string collada_target = translate_id(curve_name);
|
||||
|
||||
if (curve.is_of_animation_type(BC_ANIMATION_TYPE_MATERIAL)) {
|
||||
int material_index = curve.get_subindex();
|
||||
Material *ma = BKE_object_material_get(ob, material_index + 1);
|
||||
if (ma) {
|
||||
collada_target = translate_id(id_name(ma)) + "-effect/common/" +
|
||||
get_collada_sid(curve, axis);
|
||||
}
|
||||
}
|
||||
else {
|
||||
collada_target += "/" + get_collada_sid(curve, axis);
|
||||
}
|
||||
|
||||
BC_global_rotation_type global_rotation_type = get_global_rotation_type(ob);
|
||||
export_collada_curve_animation(
|
||||
id, curve_name, collada_target, axis, curve, global_rotation_type);
|
||||
}
|
||||
|
||||
void AnimationExporter::export_bone_animation(Object *ob,
|
||||
Bone *bone,
|
||||
BCFrames &frames,
|
||||
BCMatrixSampleMap &samples)
|
||||
{
|
||||
bAction *action = bc_getSceneObjectAction(ob);
|
||||
std::string bone_name(bone->name);
|
||||
std::string name = encode_xml(id_name(ob));
|
||||
std::string id = bc_get_action_id(id_name(action), name, bone_name, "pose_matrix");
|
||||
std::string target = translate_id(id_name(ob) + "_" + bone_name) + "/transform";
|
||||
|
||||
BC_global_rotation_type global_rotation_type = get_global_rotation_type(ob);
|
||||
export_collada_matrix_animation(
|
||||
id, name, target, frames, samples, global_rotation_type, ob->parentinv);
|
||||
}
|
||||
|
||||
bool AnimationExporter::is_bone_deform_group(Bone *bone)
|
||||
{
|
||||
bool is_def;
|
||||
/* Check if current bone is deform */
|
||||
if ((bone->flag & BONE_NO_DEFORM) == 0) {
|
||||
return true;
|
||||
}
|
||||
/* Check child bones */
|
||||
|
||||
LISTBASE_FOREACH (Bone *, child, &bone->childbase) {
|
||||
/* loop through all the children until deform bone is found, and then return */
|
||||
is_def = is_bone_deform_group(child);
|
||||
if (is_def) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* no deform bone found in children also */
|
||||
return false;
|
||||
}
|
||||
|
||||
void AnimationExporter::export_collada_curve_animation(
|
||||
std::string id,
|
||||
std::string name,
|
||||
std::string collada_target,
|
||||
std::string axis,
|
||||
BCAnimationCurve &curve,
|
||||
BC_global_rotation_type global_rotation_type)
|
||||
{
|
||||
BCFrames frames;
|
||||
BCValues values;
|
||||
curve.get_frames(frames);
|
||||
curve.get_values(values);
|
||||
|
||||
fprintf(
|
||||
stdout, "Export animation curve %s (%d control points)\n", id.c_str(), int(frames.size()));
|
||||
openAnimation(id, name);
|
||||
BC_animation_source_type source_type = curve.is_rotation_curve() ? BC_SOURCE_TYPE_ANGLE :
|
||||
BC_SOURCE_TYPE_VALUE;
|
||||
|
||||
std::string input_id = collada_source_from_values(
|
||||
BC_SOURCE_TYPE_TIMEFRAME, COLLADASW::InputSemantic::INPUT, frames, id, axis);
|
||||
std::string output_id = collada_source_from_values(
|
||||
source_type, COLLADASW::InputSemantic::OUTPUT, values, id, axis);
|
||||
|
||||
bool has_tangents = false;
|
||||
std::string interpolation_id;
|
||||
if (this->export_settings.get_keep_smooth_curves()) {
|
||||
interpolation_id = collada_interpolation_source(curve, id, axis, &has_tangents);
|
||||
}
|
||||
else {
|
||||
interpolation_id = collada_linear_interpolation_source(frames.size(), id);
|
||||
}
|
||||
|
||||
std::string intangent_id;
|
||||
std::string outtangent_id;
|
||||
if (has_tangents) {
|
||||
intangent_id = collada_tangent_from_curve(
|
||||
COLLADASW::InputSemantic::IN_TANGENT, curve, id, axis);
|
||||
outtangent_id = collada_tangent_from_curve(
|
||||
COLLADASW::InputSemantic::OUT_TANGENT, curve, id, axis);
|
||||
}
|
||||
|
||||
std::string sampler_id = std::string(id) + SAMPLER_ID_SUFFIX;
|
||||
|
||||
COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
|
||||
|
||||
sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(EMPTY_STRING, input_id));
|
||||
sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(EMPTY_STRING, output_id));
|
||||
sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION,
|
||||
COLLADABU::URI(EMPTY_STRING, interpolation_id));
|
||||
|
||||
if (has_tangents) {
|
||||
sampler.addInput(COLLADASW::InputSemantic::IN_TANGENT,
|
||||
COLLADABU::URI(EMPTY_STRING, intangent_id));
|
||||
sampler.addInput(COLLADASW::InputSemantic::OUT_TANGENT,
|
||||
COLLADABU::URI(EMPTY_STRING, outtangent_id));
|
||||
}
|
||||
|
||||
addSampler(sampler);
|
||||
addChannel(COLLADABU::URI(EMPTY_STRING, sampler_id), collada_target);
|
||||
|
||||
closeAnimation();
|
||||
}
|
||||
|
||||
void AnimationExporter::export_collada_matrix_animation(
|
||||
std::string id,
|
||||
std::string name,
|
||||
std::string target,
|
||||
BCFrames &frames,
|
||||
BCMatrixSampleMap &samples,
|
||||
BC_global_rotation_type global_rotation_type,
|
||||
Matrix &parentinv)
|
||||
{
|
||||
fprintf(
|
||||
stdout, "Export animation matrix %s (%d control points)\n", id.c_str(), int(frames.size()));
|
||||
|
||||
openAnimationWithClip(id, name);
|
||||
|
||||
std::string input_id = collada_source_from_values(
|
||||
BC_SOURCE_TYPE_TIMEFRAME, COLLADASW::InputSemantic::INPUT, frames, id, "");
|
||||
std::string output_id = collada_source_from_values(samples, id, global_rotation_type, parentinv);
|
||||
std::string interpolation_id = collada_linear_interpolation_source(frames.size(), id);
|
||||
|
||||
std::string sampler_id = std::string(id) + SAMPLER_ID_SUFFIX;
|
||||
COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
|
||||
|
||||
sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(EMPTY_STRING, input_id));
|
||||
sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(EMPTY_STRING, output_id));
|
||||
sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION,
|
||||
COLLADABU::URI(EMPTY_STRING, interpolation_id));
|
||||
|
||||
/* Matrix animation has no tangents */
|
||||
|
||||
addSampler(sampler);
|
||||
addChannel(COLLADABU::URI(EMPTY_STRING, sampler_id), target);
|
||||
|
||||
closeAnimation();
|
||||
}
|
||||
|
||||
std::string AnimationExporter::get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic)
|
||||
{
|
||||
switch (semantic) {
|
||||
case COLLADASW::InputSemantic::INPUT:
|
||||
return INPUT_SOURCE_ID_SUFFIX;
|
||||
case COLLADASW::InputSemantic::OUTPUT:
|
||||
return OUTPUT_SOURCE_ID_SUFFIX;
|
||||
case COLLADASW::InputSemantic::INTERPOLATION:
|
||||
return INTERPOLATION_SOURCE_ID_SUFFIX;
|
||||
case COLLADASW::InputSemantic::IN_TANGENT:
|
||||
return INTANGENT_SOURCE_ID_SUFFIX;
|
||||
case COLLADASW::InputSemantic::OUT_TANGENT:
|
||||
return OUTTANGENT_SOURCE_ID_SUFFIX;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNameList ¶m,
|
||||
COLLADASW::InputSemantic::Semantics semantic,
|
||||
bool is_rot,
|
||||
const std::string axis,
|
||||
bool transform)
|
||||
{
|
||||
switch (semantic) {
|
||||
case COLLADASW::InputSemantic::INPUT:
|
||||
param.emplace_back("TIME");
|
||||
break;
|
||||
case COLLADASW::InputSemantic::OUTPUT:
|
||||
if (is_rot) {
|
||||
param.emplace_back("ANGLE");
|
||||
}
|
||||
else {
|
||||
if (!axis.empty()) {
|
||||
param.push_back(axis);
|
||||
}
|
||||
else if (transform) {
|
||||
param.emplace_back("TRANSFORM");
|
||||
}
|
||||
else {
|
||||
/* assumes if axis isn't specified all axes are added */
|
||||
param.emplace_back("X");
|
||||
param.emplace_back("Y");
|
||||
param.emplace_back("Z");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case COLLADASW::InputSemantic::IN_TANGENT:
|
||||
case COLLADASW::InputSemantic::OUT_TANGENT:
|
||||
param.emplace_back("X");
|
||||
param.emplace_back("Y");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string AnimationExporter::collada_tangent_from_curve(
|
||||
COLLADASW::InputSemantic::Semantics semantic,
|
||||
BCAnimationCurve &curve,
|
||||
const std::string &anim_id,
|
||||
std::string axis_name)
|
||||
{
|
||||
Scene *scene = this->export_settings.get_scene();
|
||||
|
||||
std::string channel = curve.get_channel_target();
|
||||
|
||||
const std::string source_id = anim_id + get_semantic_suffix(semantic);
|
||||
|
||||
bool is_angle = (bc_startswith(channel, "rotation") || channel == "spot_size");
|
||||
|
||||
COLLADASW::FloatSourceF source(mSW);
|
||||
source.setId(source_id);
|
||||
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
|
||||
source.setAccessorCount(curve.sample_count());
|
||||
source.setAccessorStride(2);
|
||||
|
||||
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
||||
add_source_parameters(param, semantic, is_angle, axis_name, false);
|
||||
|
||||
source.prepareToAppendValues();
|
||||
|
||||
const FCurve *fcu = curve.get_fcurve();
|
||||
int tangent = (semantic == COLLADASW::InputSemantic::IN_TANGENT) ? 0 : 2;
|
||||
|
||||
for (int i = 0; i < fcu->totvert; i++) {
|
||||
BezTriple &bezt = fcu->bezt[i];
|
||||
|
||||
float sampled_time = bezt.vec[tangent][0];
|
||||
float sampled_val = bezt.vec[tangent][1];
|
||||
|
||||
if (is_angle) {
|
||||
sampled_val = RAD2DEGF(sampled_val);
|
||||
}
|
||||
|
||||
source.appendValues(FRA2TIME(sampled_time));
|
||||
source.appendValues(sampled_val);
|
||||
}
|
||||
source.finish();
|
||||
return source_id;
|
||||
}
|
||||
|
||||
std::string AnimationExporter::collada_source_from_values(
|
||||
BC_animation_source_type source_type,
|
||||
COLLADASW::InputSemantic::Semantics semantic,
|
||||
std::vector<float> &values,
|
||||
const std::string &anim_id,
|
||||
const std::string axis_name)
|
||||
{
|
||||
BlenderContext &blender_context = this->export_settings.get_blender_context();
|
||||
Scene *scene = blender_context.get_scene();
|
||||
/* T can be float, int or double */
|
||||
|
||||
int stride = 1;
|
||||
int entry_count = values.size() / stride;
|
||||
std::string source_id = anim_id + get_semantic_suffix(semantic);
|
||||
|
||||
COLLADASW::FloatSourceF source(mSW);
|
||||
source.setId(source_id);
|
||||
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
|
||||
source.setAccessorCount(entry_count);
|
||||
source.setAccessorStride(stride);
|
||||
|
||||
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
||||
add_source_parameters(param, semantic, source_type == BC_SOURCE_TYPE_ANGLE, axis_name, false);
|
||||
|
||||
source.prepareToAppendValues();
|
||||
|
||||
for (int i = 0; i < entry_count; i++) {
|
||||
float val = values[i];
|
||||
switch (source_type) {
|
||||
case BC_SOURCE_TYPE_TIMEFRAME:
|
||||
val = FRA2TIME(val);
|
||||
break;
|
||||
case BC_SOURCE_TYPE_ANGLE:
|
||||
val = RAD2DEGF(val);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
source.appendValues(val);
|
||||
}
|
||||
|
||||
source.finish();
|
||||
|
||||
return source_id;
|
||||
}
|
||||
|
||||
std::string AnimationExporter::collada_source_from_values(
|
||||
BCMatrixSampleMap &samples,
|
||||
const std::string &anim_id,
|
||||
BC_global_rotation_type global_rotation_type,
|
||||
Matrix &parentinv)
|
||||
{
|
||||
COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
|
||||
std::string source_id = anim_id + get_semantic_suffix(semantic);
|
||||
|
||||
COLLADASW::Float4x4Source source(mSW);
|
||||
source.setId(source_id);
|
||||
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
|
||||
source.setAccessorCount(samples.size());
|
||||
source.setAccessorStride(16);
|
||||
|
||||
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
||||
add_source_parameters(param, semantic, false, "", true);
|
||||
|
||||
source.prepareToAppendValues();
|
||||
|
||||
BCMatrixSampleMap::iterator it;
|
||||
/* could be made configurable */
|
||||
int precision = this->export_settings.get_limit_precision() ? 6 : -1;
|
||||
for (it = samples.begin(); it != samples.end(); it++) {
|
||||
BCMatrix sample = BCMatrix(*it->second);
|
||||
BCMatrix global_transform = this->export_settings.get_global_transform();
|
||||
DMatrix daemat;
|
||||
if (this->export_settings.get_apply_global_orientation()) {
|
||||
sample.apply_transform(global_transform);
|
||||
}
|
||||
else {
|
||||
sample.add_transform(global_transform);
|
||||
}
|
||||
sample.get_matrix(daemat, true, precision);
|
||||
source.appendValues(daemat);
|
||||
}
|
||||
|
||||
source.finish();
|
||||
return source_id;
|
||||
}
|
||||
|
||||
std::string AnimationExporter::collada_interpolation_source(const BCAnimationCurve &curve,
|
||||
const std::string &anim_id,
|
||||
const std::string axis,
|
||||
bool *has_tangents)
|
||||
{
|
||||
std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
|
||||
|
||||
COLLADASW::NameSource source(mSW);
|
||||
source.setId(source_id);
|
||||
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
|
||||
source.setAccessorCount(curve.sample_count());
|
||||
source.setAccessorStride(1);
|
||||
|
||||
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
||||
param.emplace_back("INTERPOLATION");
|
||||
|
||||
source.prepareToAppendValues();
|
||||
|
||||
*has_tangents = false;
|
||||
|
||||
std::vector<float> frames;
|
||||
curve.get_frames(frames);
|
||||
|
||||
for (uint i = 0; i < curve.sample_count(); i++) {
|
||||
float frame = frames[i];
|
||||
int ipo = curve.get_interpolation_type(frame);
|
||||
if (ipo == BEZT_IPO_BEZ) {
|
||||
source.appendValues(BEZIER_NAME);
|
||||
*has_tangents = true;
|
||||
}
|
||||
else if (ipo == BEZT_IPO_CONST) {
|
||||
source.appendValues(STEP_NAME);
|
||||
}
|
||||
else {
|
||||
/* BEZT_IPO_LIN */
|
||||
source.appendValues(LINEAR_NAME);
|
||||
}
|
||||
}
|
||||
/* unsupported? -- HERMITE, CARDINAL, BSPLINE, NURBS */
|
||||
|
||||
source.finish();
|
||||
|
||||
return source_id;
|
||||
}
|
||||
|
||||
std::string AnimationExporter::collada_linear_interpolation_source(int tot,
|
||||
const std::string &anim_id)
|
||||
{
|
||||
std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
|
||||
|
||||
COLLADASW::NameSource source(mSW);
|
||||
source.setId(source_id);
|
||||
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
|
||||
source.setAccessorCount(tot);
|
||||
source.setAccessorStride(1);
|
||||
|
||||
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
||||
param.emplace_back("INTERPOLATION");
|
||||
|
||||
source.prepareToAppendValues();
|
||||
|
||||
for (int i = 0; i < tot; i++) {
|
||||
source.appendValues(LINEAR_NAME);
|
||||
}
|
||||
|
||||
source.finish();
|
||||
|
||||
return source_id;
|
||||
}
|
||||
|
||||
std::string AnimationExporter::get_collada_name(std::string channel_type) const
|
||||
{
|
||||
/*
|
||||
* Translation table to map FCurve animation types to Collada animation.
|
||||
* TODO: Maybe we can keep the names from the fcurves here instead of
|
||||
* mapping. However this is what i found in the old code. So keep
|
||||
* this map for now.
|
||||
*/
|
||||
static std::map<std::string, std::string> BC_CHANNEL_BLENDER_TO_COLLADA = {
|
||||
{"rotation", "rotation"},
|
||||
{"rotation_euler", "rotation"},
|
||||
{"rotation_quaternion", "rotation"},
|
||||
{"scale", "scale"},
|
||||
{"location", "location"},
|
||||
|
||||
/* Materials */
|
||||
{"specular_color", "specular"},
|
||||
{"diffuse_color", "diffuse"},
|
||||
{"ior", "index_of_refraction"},
|
||||
{"specular_hardness", "specular_hardness"},
|
||||
{"alpha", "alpha"},
|
||||
|
||||
/* Lights */
|
||||
{"color", "color"},
|
||||
{"fall_off_angle", "falloff_angle"},
|
||||
{"spot_size", "falloff_angle"},
|
||||
{"fall_off_exponent", "falloff_exponent"},
|
||||
{"spot_blend", "falloff_exponent"},
|
||||
/* Special blender profile (TODO: make this more elegant). */
|
||||
{"blender/blender_dist", "blender/blender_dist"},
|
||||
/* Special blender profile (TODO: make this more elegant). */
|
||||
{"distance", "blender/blender_dist"},
|
||||
|
||||
/* Cameras */
|
||||
{"lens", "xfov"},
|
||||
{"xfov", "xfov"},
|
||||
{"xmag", "xmag"},
|
||||
{"zfar", "zfar"},
|
||||
{"znear", "znear"},
|
||||
{"ortho_scale", "xmag"},
|
||||
{"clip_end", "zfar"},
|
||||
{"clip_start", "znear"}};
|
||||
|
||||
std::map<std::string, std::string>::iterator name_it = BC_CHANNEL_BLENDER_TO_COLLADA.find(
|
||||
channel_type);
|
||||
if (name_it == BC_CHANNEL_BLENDER_TO_COLLADA.end()) {
|
||||
return "";
|
||||
}
|
||||
std::string tm_name = name_it->second;
|
||||
return tm_name;
|
||||
}
|
||||
|
||||
std::string AnimationExporter::get_collada_sid(const BCAnimationCurve &curve,
|
||||
const std::string axis_name)
|
||||
{
|
||||
std::string channel_type = curve.get_channel_type();
|
||||
std::string tm_name = get_collada_name(channel_type);
|
||||
|
||||
bool is_angle = curve.is_rotation_curve();
|
||||
|
||||
if (!tm_name.empty()) {
|
||||
if (is_angle) {
|
||||
return tm_name + std::string(axis_name) + ".ANGLE";
|
||||
}
|
||||
if (!axis_name.empty()) {
|
||||
return tm_name + "." + std::string(axis_name);
|
||||
}
|
||||
|
||||
return tm_name;
|
||||
}
|
||||
|
||||
return tm_name;
|
||||
}
|
||||
|
||||
#ifdef WITH_MORPH_ANIMATION
|
||||
/* TODO: This function needs to be implemented similar to the material animation export
|
||||
* So we have to update BCSample for this to work. */
|
||||
void AnimationExporter::export_morph_animation(Object *ob, BCAnimationSampler &sampler)
|
||||
{
|
||||
Key *key = BKE_key_from_object(ob);
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (FCurve *fcu : blender::animrig::legacy::fcurves_for_assigned_action(key->adt)) {
|
||||
BC_animation_transform_type tm_type = get_transform_type(fcu->rna_path);
|
||||
|
||||
create_keyframed_animation(ob, fcu, tm_type, true, sampler);
|
||||
}
|
||||
}
|
||||
#endif
|
@ -1,224 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "BCAnimationCurve.h"
|
||||
|
||||
#include "DNA_action_types.h"
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "COLLADASWInputList.h"
|
||||
#include "COLLADASWLibraryAnimations.h"
|
||||
#include "COLLADASWSource.h"
|
||||
|
||||
#include "BCAnimationSampler.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
enum BC_animation_source_type {
|
||||
BC_SOURCE_TYPE_VALUE,
|
||||
BC_SOURCE_TYPE_ANGLE,
|
||||
BC_SOURCE_TYPE_TIMEFRAME,
|
||||
};
|
||||
|
||||
enum BC_global_rotation_type { BC_NO_ROTATION, BC_OBJECT_ROTATION, BC_DATA_ROTATION };
|
||||
|
||||
class AnimationExporter : COLLADASW::LibraryAnimations {
|
||||
private:
|
||||
COLLADASW::StreamWriter *sw;
|
||||
BCExportSettings &export_settings;
|
||||
|
||||
BC_global_rotation_type get_global_rotation_type(Object *ob);
|
||||
|
||||
public:
|
||||
AnimationExporter(COLLADASW::StreamWriter *sw, BCExportSettings &export_settings)
|
||||
: COLLADASW::LibraryAnimations(sw), sw(sw), export_settings(export_settings)
|
||||
{
|
||||
}
|
||||
|
||||
bool exportAnimations();
|
||||
|
||||
/** Called for each exported object. */
|
||||
void operator()(Object *ob);
|
||||
|
||||
protected:
|
||||
void export_object_constraint_animation(Object *ob);
|
||||
|
||||
void export_morph_animation(Object *ob);
|
||||
|
||||
void write_bone_animation_matrix(Object *ob_arm, Bone *bone);
|
||||
|
||||
void write_bone_animation(Object *ob_arm, Bone *bone);
|
||||
|
||||
void sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type);
|
||||
|
||||
void sample_and_write_bone_animation_matrix(Object *ob_arm, Bone *bone);
|
||||
|
||||
void sample_animation(float *v,
|
||||
std::vector<float> &frames,
|
||||
int type,
|
||||
Bone *bone,
|
||||
Object *ob_arm,
|
||||
bPoseChannel *pChan);
|
||||
|
||||
void sample_animation(std::vector<float[4][4]> &mats,
|
||||
std::vector<float> &frames,
|
||||
Bone *bone,
|
||||
Object *ob_arm,
|
||||
bPoseChannel *pChan);
|
||||
|
||||
/* dae_bone_animation -> add_bone_animation
|
||||
* (blend this into dae_bone_animation) */
|
||||
void dae_bone_animation(std::vector<float> &fra,
|
||||
float *v,
|
||||
int tm_type,
|
||||
int axis,
|
||||
std::string ob_name,
|
||||
std::string bone_name);
|
||||
|
||||
void dae_baked_animation(std::vector<float> &fra, Object *ob_arm, Bone *bone);
|
||||
|
||||
void dae_baked_object_animation(std::vector<float> &fra, Object *ob);
|
||||
|
||||
float convert_time(float frame);
|
||||
|
||||
float convert_angle(float angle);
|
||||
|
||||
std::vector<std::vector<std::string>> anim_meta;
|
||||
|
||||
/** Main entry point into Animation export (called for each exported object). */
|
||||
void exportAnimation(Object *ob, BCAnimationSampler &sampler);
|
||||
|
||||
/**
|
||||
* Export all animation FCurves of an Object.
|
||||
*
|
||||
* \note This uses the keyframes as sample points,
|
||||
* and exports "baked keyframes" while keeping the tangent information
|
||||
* of the FCurves intact. This works for simple cases, but breaks
|
||||
* especially when negative scales are involved in the animation.
|
||||
* And when parent inverse matrices are involved (when exporting
|
||||
* object hierarchies)
|
||||
*/
|
||||
void export_curve_animation_set(Object *ob, BCAnimationSampler &sampler, bool export_as_matrix);
|
||||
|
||||
/** Export one single curve. */
|
||||
void export_curve_animation(Object *ob, BCAnimationCurve &curve);
|
||||
|
||||
/** Export animation as matrix data. */
|
||||
void export_matrix_animation(Object *ob, BCAnimationSampler &sampler);
|
||||
|
||||
/** Write bone animations in transform matrix sources (step through the bone hierarchy). */
|
||||
void export_bone_animations_recursive(Object *ob_arm, Bone *bone, BCAnimationSampler &sampler);
|
||||
|
||||
/** Export for one bone. */
|
||||
void export_bone_animation(Object *ob, Bone *bone, BCFrames &frames, BCMatrixSampleMap &samples);
|
||||
|
||||
/** Call to the low level collada exporter. */
|
||||
void export_collada_curve_animation(std::string id,
|
||||
std::string name,
|
||||
std::string target,
|
||||
std::string axis,
|
||||
BCAnimationCurve &curve,
|
||||
BC_global_rotation_type global_rotation_type);
|
||||
|
||||
/** Call to the low level collada exporter. */
|
||||
void export_collada_matrix_animation(std::string id,
|
||||
std::string name,
|
||||
std::string target,
|
||||
BCFrames &frames,
|
||||
BCMatrixSampleMap &samples,
|
||||
BC_global_rotation_type global_rotation_type,
|
||||
Matrix &parentinv);
|
||||
|
||||
/**
|
||||
* In some special cases the exported Curve needs to be replaced
|
||||
* by a modified curve (for collada purposes)
|
||||
* This method checks if a conversion is necessary and if applicable
|
||||
* returns a pointer to the modified BCAnimationCurve.
|
||||
* IMPORTANT: the modified curve must be deleted by the caller when no longer needed
|
||||
* if no conversion is needed this method returns a NULL;
|
||||
*/
|
||||
BCAnimationCurve *get_modified_export_curve(Object *ob,
|
||||
BCAnimationCurve &curve,
|
||||
BCAnimationCurveMap &curves);
|
||||
|
||||
/* Helper functions. */
|
||||
|
||||
void openAnimationWithClip(std::string id, std::string name);
|
||||
bool open_animation_container(bool has_container, Object *ob);
|
||||
void close_animation_container(bool has_container);
|
||||
|
||||
/** Input and Output sources (single valued). */
|
||||
std::string collada_source_from_values(BC_animation_source_type source_type,
|
||||
COLLADASW::InputSemantic::Semantics semantic,
|
||||
std::vector<float> &values,
|
||||
const std::string &anim_id,
|
||||
const std::string axis_name);
|
||||
|
||||
/** Output sources (matrix data). * Create a collada matrix source for a set of samples. */
|
||||
std::string collada_source_from_values(BCMatrixSampleMap &samples,
|
||||
const std::string &anim_id,
|
||||
BC_global_rotation_type global_rotation_type,
|
||||
Matrix &parentinv);
|
||||
|
||||
/** Interpolation sources. */
|
||||
std::string collada_linear_interpolation_source(int tot, const std::string &anim_id);
|
||||
|
||||
/* source ID = animation_name + semantic_suffix */
|
||||
|
||||
std::string get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic);
|
||||
|
||||
void add_source_parameters(COLLADASW::SourceBase::ParameterNameList ¶m,
|
||||
COLLADASW::InputSemantic::Semantics semantic,
|
||||
bool is_rot,
|
||||
const std::string axis,
|
||||
bool transform);
|
||||
|
||||
int get_point_in_curve(BCBezTriple &bezt,
|
||||
COLLADASW::InputSemantic::Semantics semantic,
|
||||
bool is_angle,
|
||||
float *values);
|
||||
int get_point_in_curve(const BCAnimationCurve &curve,
|
||||
float sample_frame,
|
||||
COLLADASW::InputSemantic::Semantics semantic,
|
||||
bool is_angle,
|
||||
float *values);
|
||||
|
||||
std::string collada_tangent_from_curve(COLLADASW::InputSemantic::Semantics semantic,
|
||||
BCAnimationCurve &curve,
|
||||
const std::string &anim_id,
|
||||
const std::string axis_name);
|
||||
|
||||
std::string collada_interpolation_source(const BCAnimationCurve &curve,
|
||||
const std::string &anim_id,
|
||||
std::string axis_name,
|
||||
bool *has_tangents);
|
||||
|
||||
std::string get_axis_name(std::string channel, int id);
|
||||
std::string get_collada_name(std::string channel_type) const;
|
||||
/**
|
||||
* Assign sid of the animated parameter or transform for rotation,
|
||||
* axis name is always appended and the value of append_axis is ignored.
|
||||
*/
|
||||
std::string get_collada_sid(const BCAnimationCurve &curve, const std::string axis_name);
|
||||
|
||||
/* ===================================== */
|
||||
/* Currently unused or not (yet?) needed */
|
||||
/* ===================================== */
|
||||
|
||||
bool is_bone_deform_group(Bone *bone);
|
||||
|
||||
#if 0
|
||||
BC_animation_transform_type _get_transform_type(const std::string path);
|
||||
void get_eul_source_for_quat(std::vector<float> &cache, Object *ob);
|
||||
#endif
|
||||
|
||||
#ifdef WITH_MORPH_ANIMATION
|
||||
void export_morph_animation(Object *ob, BCAnimationSampler &sampler);
|
||||
#endif
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -1,222 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "COLLADAFWAnimation.h"
|
||||
#include "COLLADAFWAnimationCurve.h"
|
||||
#include "COLLADAFWAnimationList.h"
|
||||
#include "COLLADAFWNode.h"
|
||||
#include "COLLADAFWUniqueId.h"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
// #include "ArmatureImporter.h"
|
||||
#include "TransformReader.h"
|
||||
|
||||
#include "collada_internal.h"
|
||||
|
||||
class ArmatureImporter;
|
||||
|
||||
class AnimationImporterBase {
|
||||
public:
|
||||
// virtual void change_eul_to_quat(Object *ob, bAction *act) = 0;
|
||||
};
|
||||
|
||||
class AnimationImporter : private TransformReader, public AnimationImporterBase {
|
||||
private:
|
||||
bContext *mContext;
|
||||
ArmatureImporter *armature_importer;
|
||||
Scene *scene;
|
||||
|
||||
std::map<COLLADAFW::UniqueId, std::vector<FCurve *>> curve_map;
|
||||
std::map<COLLADAFW::UniqueId, TransformReader::Animation> uid_animated_map;
|
||||
// std::map<bActionGroup*, std::vector<FCurve*> > fcurves_actionGroup_map;
|
||||
std::map<COLLADAFW::UniqueId, const COLLADAFW::AnimationList *> animlist_map;
|
||||
std::vector<FCurve *> unused_curves;
|
||||
std::map<COLLADAFW::UniqueId, Object *> joint_objects;
|
||||
|
||||
FCurve *create_fcurve(int array_index, const char *rna_path);
|
||||
|
||||
void add_bezt(FCurve *fcu,
|
||||
float frame,
|
||||
float value,
|
||||
eBezTriple_Interpolation ipo = BEZT_IPO_LIN);
|
||||
|
||||
/**
|
||||
* Create one or several fcurves depending on the number of parameters being animated.
|
||||
*/
|
||||
void animation_to_fcurves(COLLADAFW::AnimationCurve *curve);
|
||||
|
||||
void fcurve_deg_to_rad(FCurve *cu);
|
||||
void fcurve_scale(FCurve *cu, int scale);
|
||||
|
||||
void fcurve_is_used(FCurve *fcu);
|
||||
|
||||
int typeFlag;
|
||||
|
||||
std::string import_from_version;
|
||||
|
||||
enum lightAnim {
|
||||
// INANIMATE = 0,
|
||||
LIGHT_COLOR = 2,
|
||||
LIGHT_FOA = 4,
|
||||
LIGHT_FOE = 8,
|
||||
};
|
||||
|
||||
enum cameraAnim {
|
||||
// INANIMATE = 0,
|
||||
CAMERA_XFOV = 2,
|
||||
CAMERA_XMAG = 4,
|
||||
CAMERA_YFOV = 8,
|
||||
CAMERA_YMAG = 16,
|
||||
CAMERA_ZFAR = 32,
|
||||
CAMERA_ZNEAR = 64,
|
||||
};
|
||||
|
||||
enum matAnim {
|
||||
MATERIAL_SHININESS = 2,
|
||||
MATERIAL_SPEC_COLOR = 4,
|
||||
MATERIAL_DIFF_COLOR = 1 << 3,
|
||||
MATERIAL_TRANSPARENCY = 1 << 4,
|
||||
MATERIAL_IOR = 1 << 5,
|
||||
};
|
||||
|
||||
enum AnimationType {
|
||||
BC_INANIMATE = 0,
|
||||
BC_NODE_TRANSFORM = 1,
|
||||
};
|
||||
|
||||
struct AnimMix {
|
||||
int transform;
|
||||
int light;
|
||||
int camera;
|
||||
int material;
|
||||
int texture;
|
||||
};
|
||||
|
||||
public:
|
||||
AnimationImporter(bContext *C, UnitConverter *conv, ArmatureImporter *arm, Scene *scene)
|
||||
: TransformReader(conv), mContext(C), armature_importer(arm), scene(scene)
|
||||
{
|
||||
}
|
||||
|
||||
~AnimationImporter();
|
||||
|
||||
void set_import_from_version(std::string import_from_version);
|
||||
bool write_animation(const COLLADAFW::Animation *anim);
|
||||
|
||||
/** Called on post-process stage after writeVisualScenes. */
|
||||
bool write_animation_list(const COLLADAFW::AnimationList *animlist);
|
||||
|
||||
/**
|
||||
* \todo refactor read_node_transform to not automatically apply anything,
|
||||
* but rather return the transform matrix, so caller can do with it what is
|
||||
* necessary. Same for \ref get_node_mat
|
||||
*/
|
||||
void read_node_transform(COLLADAFW::Node *node, Object *ob);
|
||||
// virtual void change_eul_to_quat(Object *ob, bAction *act);
|
||||
|
||||
void translate_Animations(COLLADAFW::Node *Node,
|
||||
std::map<COLLADAFW::UniqueId, COLLADAFW::Node *> &root_map,
|
||||
std::multimap<COLLADAFW::UniqueId, Object *> &object_map,
|
||||
std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map,
|
||||
std::map<COLLADAFW::UniqueId, Material *> uid_material_map);
|
||||
|
||||
/**
|
||||
* Check if object is animated by checking if animlist_map
|
||||
* holds the animlist_id of node transforms.
|
||||
*/
|
||||
AnimMix *get_animation_type(
|
||||
const COLLADAFW::Node *node,
|
||||
std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map);
|
||||
|
||||
void apply_matrix_curves(Object *ob,
|
||||
std::vector<FCurve *> &animcurves,
|
||||
COLLADAFW::Node *root,
|
||||
COLLADAFW::Node *node,
|
||||
COLLADAFW::Transformation *tm);
|
||||
|
||||
/**
|
||||
* Creates the rna_paths and array indices of fcurves from animations using transformation and
|
||||
* bound animation class of each animation.
|
||||
*/
|
||||
void Assign_transform_animations(COLLADAFW::Transformation *transform,
|
||||
const COLLADAFW::AnimationList::AnimationBinding *binding,
|
||||
std::vector<FCurve *> *curves,
|
||||
bool is_joint,
|
||||
char *joint_path);
|
||||
|
||||
/**
|
||||
* Creates the rna_paths and array indices of fcurves from animations using color and bound
|
||||
* animation class of each animation.
|
||||
*/
|
||||
void Assign_color_animations(const COLLADAFW::UniqueId &listid,
|
||||
AnimData &adt,
|
||||
const char *anim_type);
|
||||
void Assign_float_animations(const COLLADAFW::UniqueId &listid,
|
||||
AnimData &adt,
|
||||
const char *anim_type);
|
||||
/**
|
||||
* Lens animations must be stored in COLLADA by using FOV,
|
||||
* while blender internally uses focal length.
|
||||
* The imported animation curves must be converted appropriately.
|
||||
*/
|
||||
void Assign_lens_animations(const COLLADAFW::UniqueId &listid,
|
||||
AnimData &adt,
|
||||
double aspect,
|
||||
const Camera *cam,
|
||||
const char *anim_type,
|
||||
int fov_type);
|
||||
|
||||
int setAnimType(const COLLADAFW::Animatable *prop, int type, int addition);
|
||||
|
||||
/** Sets the rna_path and array index to curve. */
|
||||
void modify_fcurve(std::vector<FCurve *> *curves,
|
||||
const char *rna_path,
|
||||
int array_index,
|
||||
int scale = 1);
|
||||
void unused_fcurve(std::vector<FCurve *> *curves);
|
||||
|
||||
void find_frames(std::vector<float> *frames, std::vector<FCurve *> *curves);
|
||||
|
||||
/**
|
||||
* Internal, better make it private
|
||||
* WARNING: evaluates only rotation and only assigns matrix transforms now
|
||||
* prerequisites: animlist_map, curve_map.
|
||||
*/
|
||||
void evaluate_transform_at_frame(float mat[4][4], COLLADAFW::Node *node, float fra);
|
||||
|
||||
/** Return true to indicate that mat contains a sane value. */
|
||||
bool evaluate_animation(COLLADAFW::Transformation *tm,
|
||||
float mat[4][4],
|
||||
float fra,
|
||||
const char *node_id);
|
||||
|
||||
/** Gives a world-space mat of joint at rest position. */
|
||||
void get_joint_rest_mat(float mat[4][4], COLLADAFW::Node *root, COLLADAFW::Node *node);
|
||||
|
||||
/** * Gives a world-space mat, end's mat not included. */
|
||||
bool calc_joint_parent_mat_rest(float mat[4][4],
|
||||
float par[4][4],
|
||||
COLLADAFW::Node *node,
|
||||
COLLADAFW::Node *end);
|
||||
|
||||
float convert_to_focal_length(float in_xfov, int fov_type, float aspect, float sensorx);
|
||||
|
||||
void add_bone_fcurve(Object *ob, COLLADAFW::Node *node, FCurve *fcu);
|
||||
};
|
@ -1,345 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2010-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include "COLLADASWInstanceController.h"
|
||||
|
||||
#include "BKE_armature.hh"
|
||||
|
||||
#include "ED_armature.hh"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
|
||||
#include "ArmatureExporter.h"
|
||||
#include "SceneExporter.h"
|
||||
|
||||
#include "collada_utils.h"
|
||||
|
||||
void ArmatureExporter::add_bone_collections(Object *ob_arm, COLLADASW::Node &node)
|
||||
{
|
||||
bArmature *armature = (bArmature *)ob_arm->data;
|
||||
|
||||
/* Because our importer assumes that "extras" tags have a unique name, it's not possible to
|
||||
* export a `<bonecollection>` element per bone collection. This is why all the names are stored
|
||||
* in one element, newline-separated. */
|
||||
|
||||
std::stringstream collection_stream;
|
||||
std::stringstream visible_stream;
|
||||
for (const BoneCollection *bcoll : armature->collections_span()) {
|
||||
collection_stream << bcoll->name << "\n";
|
||||
|
||||
if (bcoll->flags & BONE_COLLECTION_VISIBLE) {
|
||||
visible_stream << bcoll->name << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
std::string collection_names = collection_stream.str();
|
||||
if (collection_names.length() > 1) {
|
||||
collection_names.pop_back(); /* Pop off the last `\n`. */
|
||||
node.addExtraTechniqueParameter("blender", "collections", collection_names);
|
||||
}
|
||||
|
||||
std::string visible_names = visible_stream.str();
|
||||
if (visible_names.length() > 1) {
|
||||
visible_names.pop_back(); /* Pop off the last `\n`. */
|
||||
node.addExtraTechniqueParameter("blender", "visible_collections", visible_names);
|
||||
}
|
||||
|
||||
if (armature->runtime.active_collection) {
|
||||
node.addExtraTechniqueParameter(
|
||||
"blender", "active_collection", std::string(armature->active_collection_name));
|
||||
}
|
||||
}
|
||||
|
||||
void ArmatureExporter::add_armature_bones(Object *ob_arm,
|
||||
ViewLayer *view_layer,
|
||||
SceneExporter *se,
|
||||
std::vector<Object *> &child_objects)
|
||||
|
||||
{
|
||||
/* write bone nodes */
|
||||
|
||||
bArmature *armature = (bArmature *)ob_arm->data;
|
||||
bool is_edited = armature->edbo != nullptr;
|
||||
|
||||
if (!is_edited) {
|
||||
ED_armature_to_edit(armature);
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (Bone *, bone, &armature->bonebase) {
|
||||
add_bone_node(bone, ob_arm, se, child_objects);
|
||||
}
|
||||
|
||||
if (!is_edited) {
|
||||
ED_armature_edit_free(armature);
|
||||
}
|
||||
}
|
||||
|
||||
void ArmatureExporter::write_bone_URLs(COLLADASW::InstanceController &ins,
|
||||
Object *ob_arm,
|
||||
Bone *bone)
|
||||
{
|
||||
if (bc_is_root_bone(bone, this->export_settings.get_deform_bones_only())) {
|
||||
std::string joint_id = translate_id(id_name(ob_arm) + "_" + bone->name);
|
||||
ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, joint_id));
|
||||
}
|
||||
else {
|
||||
LISTBASE_FOREACH (Bone *, child, &bone->childbase) {
|
||||
write_bone_URLs(ins, ob_arm, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ArmatureExporter::add_instance_controller(Object *ob)
|
||||
{
|
||||
Object *ob_arm = bc_get_assigned_armature(ob);
|
||||
bArmature *arm = (bArmature *)ob_arm->data;
|
||||
|
||||
const std::string &controller_id = get_controller_id(ob_arm, ob);
|
||||
|
||||
COLLADASW::InstanceController ins(mSW);
|
||||
ins.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, controller_id));
|
||||
|
||||
Mesh *mesh = (Mesh *)ob->data;
|
||||
if (mesh->deform_verts().is_empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* write root bone URLs */
|
||||
LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) {
|
||||
write_bone_URLs(ins, ob_arm, bone);
|
||||
}
|
||||
|
||||
InstanceWriter::add_material_bindings(
|
||||
ins.getBindMaterial(), ob, this->export_settings.get_active_uv_only());
|
||||
|
||||
ins.add();
|
||||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void ArmatureExporter::operator()(Object *ob)
|
||||
{
|
||||
Object *ob_arm = bc_get_assigned_armature(ob);
|
||||
}
|
||||
|
||||
bool ArmatureExporter::already_written(Object *ob_arm)
|
||||
{
|
||||
return std::find(written_armatures.begin(), written_armatures.end(), ob_arm) !=
|
||||
written_armatures.end();
|
||||
}
|
||||
|
||||
void ArmatureExporter::wrote(Object *ob_arm)
|
||||
{
|
||||
written_armatures.push_back(ob_arm);
|
||||
}
|
||||
|
||||
void ArmatureExporter::find_objects_using_armature(Object *ob_arm,
|
||||
std::vector<Object *> &objects,
|
||||
Scene *sce)
|
||||
{
|
||||
objects.clear();
|
||||
|
||||
Base *base = (Base *)sce->base.first;
|
||||
while (base) {
|
||||
Object *ob = base->object;
|
||||
|
||||
if (ob->type == OB_MESH && get_assigned_armature(ob) == ob_arm) {
|
||||
objects.push_back(ob);
|
||||
}
|
||||
|
||||
base = base->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void ArmatureExporter::add_bone_node(Bone *bone,
|
||||
Object *ob_arm,
|
||||
SceneExporter *se,
|
||||
std::vector<Object *> &child_objects)
|
||||
{
|
||||
if (can_export(bone)) {
|
||||
std::string node_id = translate_id(id_name(ob_arm) + "_" + bone->name);
|
||||
std::string node_name = std::string(bone->name);
|
||||
std::string node_sid = get_joint_sid(bone);
|
||||
|
||||
COLLADASW::Node node(mSW);
|
||||
|
||||
node.setType(COLLADASW::Node::JOINT);
|
||||
node.setNodeId(node_id);
|
||||
node.setNodeName(node_name);
|
||||
node.setNodeSid(node_sid);
|
||||
|
||||
if (this->export_settings.get_use_blender_profile()) {
|
||||
if (!is_export_root(bone)) {
|
||||
if (bone->flag & BONE_CONNECTED) {
|
||||
node.addExtraTechniqueParameter("blender", "connect", true);
|
||||
}
|
||||
}
|
||||
|
||||
std::string collection_names;
|
||||
LISTBASE_FOREACH (const BoneCollectionReference *, bcoll_ref, &bone->runtime.collections) {
|
||||
collection_names += std::string(bcoll_ref->bcoll->name) + "\n";
|
||||
}
|
||||
if (collection_names.length() > 1) {
|
||||
collection_names.pop_back(); /* Pop off the last `\n`. */
|
||||
node.addExtraTechniqueParameter("blender", "", collection_names, "", "collections");
|
||||
}
|
||||
|
||||
bArmature *armature = (bArmature *)ob_arm->data;
|
||||
EditBone *ebone = bc_get_edit_bone(armature, bone->name);
|
||||
if (ebone && ebone->roll != 0) {
|
||||
node.addExtraTechniqueParameter("blender", "roll", ebone->roll);
|
||||
}
|
||||
if (bc_is_leaf_bone(bone)) {
|
||||
Vector head, tail;
|
||||
const BCMatrix &global_transform = this->export_settings.get_global_transform();
|
||||
if (this->export_settings.get_apply_global_orientation()) {
|
||||
bc_add_global_transform(head, bone->arm_head, global_transform);
|
||||
bc_add_global_transform(tail, bone->arm_tail, global_transform);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(head, bone->arm_head);
|
||||
copy_v3_v3(tail, bone->arm_tail);
|
||||
}
|
||||
node.addExtraTechniqueParameter("blender", "tip_x", tail[0] - head[0]);
|
||||
node.addExtraTechniqueParameter("blender", "tip_y", tail[1] - head[1]);
|
||||
node.addExtraTechniqueParameter("blender", "tip_z", tail[2] - head[2]);
|
||||
}
|
||||
}
|
||||
|
||||
node.start();
|
||||
|
||||
add_bone_transform(ob_arm, bone, node);
|
||||
|
||||
/* Write nodes of child-objects, remove written objects from list. */
|
||||
std::vector<Object *>::iterator iter = child_objects.begin();
|
||||
|
||||
while (iter != child_objects.end()) {
|
||||
Object *ob = *iter;
|
||||
if (ob->partype == PARBONE && STREQ(ob->parsubstr, bone->name)) {
|
||||
float backup_parinv[4][4];
|
||||
copy_m4_m4(backup_parinv, ob->parentinv);
|
||||
|
||||
/* Crude, temporary change to parentinv
|
||||
* so transform gets exported correctly. */
|
||||
|
||||
/* Add bone tail- translation... don't know why
|
||||
* bone parenting is against the tail of a bone
|
||||
* and not its head, seems arbitrary. */
|
||||
ob->parentinv[3][1] += bone->length;
|
||||
|
||||
/* OPEN_SIM_COMPATIBILITY
|
||||
* TODO: when such objects are animated as
|
||||
* single matrix the tweak must be applied
|
||||
* to the result. */
|
||||
if (export_settings.get_open_sim()) {
|
||||
/* Tweak objects parent-inverse to match compatibility. */
|
||||
float temp[4][4];
|
||||
|
||||
copy_m4_m4(temp, bone->arm_mat);
|
||||
temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
|
||||
|
||||
mul_m4_m4m4(ob->parentinv, temp, ob->parentinv);
|
||||
}
|
||||
|
||||
se->writeNode(ob);
|
||||
copy_m4_m4(ob->parentinv, backup_parinv);
|
||||
iter = child_objects.erase(iter);
|
||||
}
|
||||
else {
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (Bone *, child, &bone->childbase) {
|
||||
add_bone_node(child, ob_arm, se, child_objects);
|
||||
}
|
||||
node.end();
|
||||
}
|
||||
else {
|
||||
LISTBASE_FOREACH (Bone *, child, &bone->childbase) {
|
||||
add_bone_node(child, ob_arm, se, child_objects);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ArmatureExporter::is_export_root(Bone *bone)
|
||||
{
|
||||
Bone *entry = bone->parent;
|
||||
while (entry) {
|
||||
if (can_export(entry)) {
|
||||
return false;
|
||||
}
|
||||
entry = entry->parent;
|
||||
}
|
||||
return can_export(bone);
|
||||
}
|
||||
|
||||
void ArmatureExporter::add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node &node)
|
||||
{
|
||||
// bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name);
|
||||
|
||||
float mat[4][4];
|
||||
float bone_rest_mat[4][4]; /* derived from bone->arm_mat */
|
||||
float parent_rest_mat[4][4]; /* derived from bone->parent->arm_mat */
|
||||
|
||||
bool has_restmat = bc_get_property_matrix(bone, "rest_mat", mat);
|
||||
|
||||
if (!has_restmat) {
|
||||
|
||||
/* Have no rest-pose matrix stored, try old style <= Blender 2.78. */
|
||||
|
||||
bc_create_restpose_mat(this->export_settings, bone, bone_rest_mat, bone->arm_mat, true);
|
||||
|
||||
if (is_export_root(bone)) {
|
||||
copy_m4_m4(mat, bone_rest_mat);
|
||||
}
|
||||
else {
|
||||
Matrix parent_inverse;
|
||||
bc_create_restpose_mat(
|
||||
this->export_settings, bone->parent, parent_rest_mat, bone->parent->arm_mat, true);
|
||||
|
||||
invert_m4_m4(parent_inverse, parent_rest_mat);
|
||||
mul_m4_m4m4(mat, parent_inverse, bone_rest_mat);
|
||||
}
|
||||
|
||||
/* OPEN_SIM_COMPATIBILITY */
|
||||
|
||||
if (export_settings.get_open_sim()) {
|
||||
/* Remove rotations vs armature from transform
|
||||
* parent_rest_rot * mat * irest_rot */
|
||||
Matrix workmat;
|
||||
copy_m4_m4(workmat, bone_rest_mat);
|
||||
|
||||
workmat[3][0] = workmat[3][1] = workmat[3][2] = 0.0f;
|
||||
invert_m4(workmat);
|
||||
|
||||
mul_m4_m4m4(mat, mat, workmat);
|
||||
|
||||
if (!is_export_root(bone)) {
|
||||
copy_m4_m4(workmat, parent_rest_mat);
|
||||
workmat[3][0] = workmat[3][1] = workmat[3][2] = 0.0f;
|
||||
|
||||
mul_m4_m4m4(mat, workmat, mat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this->export_settings.get_limit_precision()) {
|
||||
BCMatrix::sanitize(mat, LIMITTED_PRECISION);
|
||||
}
|
||||
|
||||
TransformWriter::add_joint_transform(node, mat, nullptr, this->export_settings, has_restmat);
|
||||
}
|
||||
|
||||
std::string ArmatureExporter::get_controller_id(Object *ob_arm, Object *ob)
|
||||
{
|
||||
return translate_id(id_name(ob_arm)) + "_" + translate_id(id_name(ob)) +
|
||||
SKIN_CONTROLLER_ID_SUFFIX;
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <COLLADASWInputList.h>
|
||||
#include <COLLADASWInstanceController.h>
|
||||
#include <COLLADASWLibraryControllers.h>
|
||||
#include <COLLADASWNode.h>
|
||||
#include <COLLADASWStreamWriter.h>
|
||||
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "InstanceWriter.h"
|
||||
#include "TransformWriter.h"
|
||||
|
||||
#include "ExportSettings.h"
|
||||
|
||||
class SceneExporter;
|
||||
|
||||
/* XXX exporter writes wrong data for shared armatures. A separate
|
||||
* controller should be written for each armature-mesh binding how do
|
||||
* we make controller ids then? */
|
||||
class ArmatureExporter : public COLLADASW::LibraryControllers,
|
||||
protected TransformWriter,
|
||||
protected InstanceWriter {
|
||||
public:
|
||||
/* XXX exporter writes wrong data for shared armatures. A separate
|
||||
* controller should be written for each armature-mesh binding how do
|
||||
* we make controller ids then? */
|
||||
ArmatureExporter(BlenderContext &blender_context,
|
||||
COLLADASW::StreamWriter *sw,
|
||||
BCExportSettings &export_settings)
|
||||
: COLLADASW::LibraryControllers(sw),
|
||||
blender_context(blender_context),
|
||||
export_settings(export_settings)
|
||||
{
|
||||
}
|
||||
|
||||
void add_bone_collections(Object *ob_arm, COLLADASW::Node &node);
|
||||
|
||||
/* write bone nodes */
|
||||
void add_armature_bones(Object *ob_arm,
|
||||
ViewLayer *view_layer,
|
||||
SceneExporter *se,
|
||||
std::vector<Object *> &child_objects);
|
||||
|
||||
bool add_instance_controller(Object *ob);
|
||||
|
||||
private:
|
||||
BlenderContext &blender_context;
|
||||
BCExportSettings &export_settings;
|
||||
|
||||
#if 0
|
||||
std::vector<Object *> written_armatures;
|
||||
|
||||
bool already_written(Object *ob_arm);
|
||||
|
||||
void wrote(Object *ob_arm);
|
||||
|
||||
void find_objects_using_armature(Object *ob_arm, std::vector<Object *> &objects, Scene *sce);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Scene, SceneExporter and the list of child_objects
|
||||
* are required for writing bone parented objects.
|
||||
* \param parent_mat: is armature-space.
|
||||
*/
|
||||
void add_bone_node(Bone *bone,
|
||||
Object *ob_arm,
|
||||
SceneExporter *se,
|
||||
std::vector<Object *> &child_objects);
|
||||
|
||||
bool can_export(Bone *bone)
|
||||
{
|
||||
return !(export_settings.get_deform_bones_only() && bone->flag & BONE_NO_DEFORM);
|
||||
}
|
||||
|
||||
bool is_export_root(Bone *bone);
|
||||
void add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node &node);
|
||||
|
||||
std::string get_controller_id(Object *ob_arm, Object *ob);
|
||||
|
||||
void write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone);
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -1,181 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "COLLADAFWMorphController.h"
|
||||
#include "COLLADAFWNode.h"
|
||||
#include "COLLADAFWUniqueId.h"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_key.hh"
|
||||
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "ED_armature.hh"
|
||||
|
||||
#include "AnimationImporter.h"
|
||||
#include "ExtraTags.h"
|
||||
#include "MeshImporter.h"
|
||||
#include "SkinInfo.h"
|
||||
#include "TransformReader.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "ImportSettings.h"
|
||||
#include "collada_internal.h"
|
||||
#include "collada_utils.h"
|
||||
|
||||
#define UNLIMITED_CHAIN_MAX INT_MAX
|
||||
#define MINIMUM_BONE_LENGTH 0.000001f
|
||||
|
||||
class ArmatureImporter : private TransformReader {
|
||||
private:
|
||||
Main *m_bmain;
|
||||
Scene *scene;
|
||||
ViewLayer *view_layer;
|
||||
UnitConverter *unit_converter;
|
||||
const ImportSettings *import_settings;
|
||||
|
||||
// std::map<int, JointData> joint_index_to_joint_info_map;
|
||||
// std::map<COLLADAFW::UniqueId, int> joint_id_to_joint_index_map;
|
||||
BoneExtensionManager bone_extension_manager;
|
||||
// int bone_direction_row; /* XXX not used */
|
||||
float leaf_bone_length;
|
||||
int totbone;
|
||||
/* XXX not used */
|
||||
// float min_angle; /* minimum angle between bone head-tail and a row of bone matrix */
|
||||
|
||||
#if 0
|
||||
struct ArmatureJoints {
|
||||
Object *ob_arm;
|
||||
std::vector<COLLADAFW::Node *> root_joints;
|
||||
};
|
||||
std::vector<ArmatureJoints> armature_joints;
|
||||
#endif
|
||||
|
||||
Object *empty; /* empty for leaf bones */
|
||||
|
||||
std::map<COLLADAFW::UniqueId, COLLADAFW::UniqueId> geom_uid_by_controller_uid;
|
||||
std::map<COLLADAFW::UniqueId, COLLADAFW::Node *> joint_by_uid; /* contains all joints */
|
||||
std::vector<COLLADAFW::Node *> root_joints;
|
||||
std::vector<COLLADAFW::Node *> finished_joints;
|
||||
std::vector<COLLADAFW::MorphController *> morph_controllers;
|
||||
std::map<COLLADAFW::UniqueId, Object *> joint_parent_map;
|
||||
std::map<COLLADAFW::UniqueId, Object *> unskinned_armature_map;
|
||||
|
||||
MeshImporterBase *mesh_importer;
|
||||
|
||||
/* This is used to store data passed in write_controller_data.
|
||||
* Arrays from COLLADAFW::SkinControllerData lose ownership, so do this class members
|
||||
* so that arrays don't get freed until we free them explicitly. */
|
||||
|
||||
std::map<COLLADAFW::UniqueId, SkinInfo>
|
||||
skin_by_data_uid; /* data UID = skin controller data UID */
|
||||
#if 0
|
||||
JointData *get_joint_data(COLLADAFW::Node *node);
|
||||
#endif
|
||||
|
||||
int create_bone(SkinInfo *skin,
|
||||
COLLADAFW::Node *node,
|
||||
EditBone *parent,
|
||||
int totchild,
|
||||
float parent_mat[4][4],
|
||||
bArmature *arm,
|
||||
std::vector<std::string> &layer_labels);
|
||||
|
||||
BoneExtended &add_bone_extended(EditBone *bone,
|
||||
COLLADAFW::Node *node,
|
||||
int sibcount,
|
||||
std::vector<std::string> &layer_labels,
|
||||
BoneExtensionMap &extended_bones);
|
||||
|
||||
/**
|
||||
* Collada only knows Joints, hence bones at the end of a bone chain
|
||||
* don't have a defined length. This function guesses reasonable
|
||||
* tail locations for the affected bones (nodes which don't have any connected child)
|
||||
* Hint: The extended_bones set gets populated in ArmatureImporter::create_bone
|
||||
*/
|
||||
void fix_leaf_bone_hierarchy(bArmature *armature, Bone *bone, bool fix_orientation);
|
||||
void fix_leaf_bone(bArmature *armature, EditBone *ebone, BoneExtended *be, bool fix_orientation);
|
||||
void fix_parent_connect(bArmature *armature, Bone *bone);
|
||||
void connect_bone_chains(bArmature *armature, Bone *bone, int max_chain_length);
|
||||
|
||||
void set_pose(Object *ob_arm,
|
||||
COLLADAFW::Node *root_node,
|
||||
const char *parentname,
|
||||
float parent_mat[4][4]);
|
||||
|
||||
void set_bone_transformation_type(const COLLADAFW::Node *node, Object *ob_arm);
|
||||
bool node_is_decomposed(const COLLADAFW::Node *node);
|
||||
#if 0
|
||||
void set_leaf_bone_shapes(Object *ob_arm);
|
||||
void set_euler_rotmode();
|
||||
#endif
|
||||
|
||||
Object *get_empty_for_leaves();
|
||||
|
||||
#if 0
|
||||
Object *find_armature(COLLADAFW::Node *node);
|
||||
|
||||
ArmatureJoints &get_armature_joints(Object *ob_arm);
|
||||
#endif
|
||||
|
||||
Object *create_armature_bones(Main *bmain, SkinInfo &skin);
|
||||
void create_armature_bones(Main *bmain, std::vector<Object *> &arm_objs);
|
||||
|
||||
/** TagsMap typedef for uid_tags_map. */
|
||||
using TagsMap = std::map<std::string, ExtraTags *>;
|
||||
TagsMap uid_tags_map;
|
||||
|
||||
public:
|
||||
ArmatureImporter(UnitConverter *conv,
|
||||
MeshImporterBase *mesh,
|
||||
Main *bmain,
|
||||
Scene *sce,
|
||||
ViewLayer *view_layer,
|
||||
const ImportSettings *import_settings);
|
||||
~ArmatureImporter();
|
||||
|
||||
/**
|
||||
* root - if this joint is the top joint in hierarchy, if a joint
|
||||
* is a child of a node (not joint), root should be true since
|
||||
* this is where we build armature bones from
|
||||
*/
|
||||
void add_root_joint(COLLADAFW::Node *node, Object *parent);
|
||||
|
||||
/** Here we add bones to armatures, having armatures previously created in write_controller. */
|
||||
void make_armatures(bContext *C, std::vector<Object *> &objects_to_scale);
|
||||
|
||||
void make_shape_keys(bContext *C);
|
||||
|
||||
#if 0
|
||||
/** Link with meshes, create vertex groups, assign weights. */
|
||||
void link_armature(Object *ob_arm,
|
||||
const COLLADAFW::UniqueId &geom_id,
|
||||
const COLLADAFW::UniqueId &controller_data_id);
|
||||
#endif
|
||||
|
||||
bool write_skin_controller_data(const COLLADAFW::SkinControllerData *data);
|
||||
|
||||
bool write_controller(const COLLADAFW::Controller *controller);
|
||||
|
||||
COLLADAFW::UniqueId *get_geometry_uid(const COLLADAFW::UniqueId &controller_uid);
|
||||
|
||||
Object *get_armature_for_joint(COLLADAFW::Node *node);
|
||||
|
||||
void get_rna_path_for_joint(COLLADAFW::Node *node, char *joint_path, size_t joint_path_maxncpy);
|
||||
|
||||
/** Gives a world-space mat. */
|
||||
bool get_joint_bind_mat(float m[4][4], COLLADAFW::Node *joint);
|
||||
|
||||
void set_tags_map(TagsMap &tags_map);
|
||||
};
|
@ -1,701 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2008 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_light_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BKE_material.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_path.hh"
|
||||
|
||||
#include "ANIM_fcurve.hh"
|
||||
|
||||
#include "BCAnimationCurve.h"
|
||||
|
||||
#include "collada_utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
BCAnimationCurve::BCAnimationCurve()
|
||||
{
|
||||
this->curve_key.set_object_type(BC_ANIMATION_TYPE_OBJECT);
|
||||
this->fcurve = nullptr;
|
||||
this->curve_is_local_copy = false;
|
||||
}
|
||||
|
||||
BCAnimationCurve::BCAnimationCurve(const BCAnimationCurve &other)
|
||||
{
|
||||
this->min = other.min;
|
||||
this->max = other.max;
|
||||
this->fcurve = other.fcurve;
|
||||
this->curve_key = other.curve_key;
|
||||
this->curve_is_local_copy = false;
|
||||
this->id_ptr = other.id_ptr;
|
||||
|
||||
/* The fcurve of the new instance is a copy and can be modified */
|
||||
|
||||
get_edit_fcurve();
|
||||
}
|
||||
|
||||
BCAnimationCurve::BCAnimationCurve(BCCurveKey key, Object *ob, FCurve *fcu)
|
||||
{
|
||||
this->min = 0;
|
||||
this->max = 0;
|
||||
this->curve_key = key;
|
||||
this->fcurve = fcu;
|
||||
this->curve_is_local_copy = false;
|
||||
init_pointer_rna(ob);
|
||||
}
|
||||
|
||||
BCAnimationCurve::BCAnimationCurve(const BCCurveKey &key, Object *ob)
|
||||
{
|
||||
this->curve_key = key;
|
||||
this->fcurve = nullptr;
|
||||
this->curve_is_local_copy = false;
|
||||
init_pointer_rna(ob);
|
||||
}
|
||||
|
||||
void BCAnimationCurve::init_pointer_rna(Object *ob)
|
||||
{
|
||||
switch (this->curve_key.get_animation_type()) {
|
||||
case BC_ANIMATION_TYPE_BONE: {
|
||||
bArmature *arm = (bArmature *)ob->data;
|
||||
id_ptr = RNA_id_pointer_create(&arm->id);
|
||||
break;
|
||||
}
|
||||
case BC_ANIMATION_TYPE_OBJECT: {
|
||||
id_ptr = RNA_id_pointer_create(&ob->id);
|
||||
break;
|
||||
}
|
||||
case BC_ANIMATION_TYPE_MATERIAL: {
|
||||
Material *ma = BKE_object_material_get(ob, curve_key.get_subindex() + 1);
|
||||
id_ptr = RNA_id_pointer_create(&ma->id);
|
||||
break;
|
||||
}
|
||||
case BC_ANIMATION_TYPE_CAMERA: {
|
||||
Camera *camera = (Camera *)ob->data;
|
||||
id_ptr = RNA_id_pointer_create(&camera->id);
|
||||
break;
|
||||
}
|
||||
case BC_ANIMATION_TYPE_LIGHT: {
|
||||
Light *lamp = (Light *)ob->data;
|
||||
id_ptr = RNA_id_pointer_create(&lamp->id);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fprintf(
|
||||
stderr, "BC_animation_curve_type %d not supported", this->curve_key.get_array_index());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BCAnimationCurve::delete_fcurve(FCurve *fcu)
|
||||
{
|
||||
BKE_fcurve_free(fcu);
|
||||
}
|
||||
|
||||
FCurve *BCAnimationCurve::create_fcurve(int array_index, const char *rna_path)
|
||||
{
|
||||
FCurve *fcu = BKE_fcurve_create();
|
||||
fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
|
||||
fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
|
||||
fcu->array_index = array_index;
|
||||
return fcu;
|
||||
}
|
||||
|
||||
void BCAnimationCurve::create_bezt(float frame, float output)
|
||||
{
|
||||
FCurve *fcu = get_edit_fcurve();
|
||||
BezTriple bez;
|
||||
memset(&bez, 0, sizeof(BezTriple));
|
||||
bez.vec[1][0] = frame;
|
||||
bez.vec[1][1] = output;
|
||||
bez.ipo = U.ipo_new; /* use default interpolation mode here... */
|
||||
bez.f1 = bez.f2 = bez.f3 = SELECT;
|
||||
bez.h1 = bez.h2 = HD_AUTO;
|
||||
blender::animrig::insert_bezt_fcurve(fcu, &bez, INSERTKEY_NOFLAGS);
|
||||
BKE_fcurve_handles_recalc(fcu);
|
||||
}
|
||||
|
||||
BCAnimationCurve::~BCAnimationCurve()
|
||||
{
|
||||
if (curve_is_local_copy && fcurve) {
|
||||
// fprintf(stderr, "removed fcurve %s\n", fcurve->rna_path);
|
||||
delete_fcurve(fcurve);
|
||||
this->fcurve = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool BCAnimationCurve::is_of_animation_type(BC_animation_type type) const
|
||||
{
|
||||
return curve_key.get_animation_type() == type;
|
||||
}
|
||||
|
||||
std::string BCAnimationCurve::get_channel_target() const
|
||||
{
|
||||
const std::string path = curve_key.get_path();
|
||||
|
||||
if (bc_startswith(path, "pose.bones")) {
|
||||
return bc_string_after(path, "pose.bones");
|
||||
}
|
||||
return bc_string_after(path, ".");
|
||||
}
|
||||
|
||||
std::string BCAnimationCurve::get_channel_type() const
|
||||
{
|
||||
const std::string channel = get_channel_target();
|
||||
return bc_string_after(channel, ".");
|
||||
}
|
||||
|
||||
std::string BCAnimationCurve::get_channel_posebone() const
|
||||
{
|
||||
const std::string channel = get_channel_target();
|
||||
std::string pose_bone_name = bc_string_before(channel, ".");
|
||||
if (pose_bone_name == channel) {
|
||||
pose_bone_name = "";
|
||||
}
|
||||
else {
|
||||
pose_bone_name = bc_string_after(pose_bone_name, "\"[");
|
||||
pose_bone_name = bc_string_before(pose_bone_name, "]\"");
|
||||
}
|
||||
return pose_bone_name;
|
||||
}
|
||||
|
||||
std::string BCAnimationCurve::get_animation_name(Object *ob) const
|
||||
{
|
||||
std::string name;
|
||||
|
||||
switch (curve_key.get_animation_type()) {
|
||||
case BC_ANIMATION_TYPE_OBJECT: {
|
||||
name = id_name(ob);
|
||||
break;
|
||||
}
|
||||
case BC_ANIMATION_TYPE_BONE: {
|
||||
if (fcurve == nullptr || fcurve->rna_path == nullptr) {
|
||||
name = "";
|
||||
}
|
||||
else {
|
||||
char boneName[MAXBONENAME];
|
||||
if (BLI_str_quoted_substr(fcurve->rna_path, "pose.bones[", boneName, sizeof(boneName))) {
|
||||
name = id_name(ob) + "_" + std::string(boneName);
|
||||
}
|
||||
else {
|
||||
name = "";
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BC_ANIMATION_TYPE_CAMERA: {
|
||||
Camera *camera = (Camera *)ob->data;
|
||||
name = id_name(ob) + "-" + id_name(camera) + "-camera";
|
||||
break;
|
||||
}
|
||||
case BC_ANIMATION_TYPE_LIGHT: {
|
||||
Light *lamp = (Light *)ob->data;
|
||||
name = id_name(ob) + "-" + id_name(lamp) + "-light";
|
||||
break;
|
||||
}
|
||||
case BC_ANIMATION_TYPE_MATERIAL: {
|
||||
Material *ma = BKE_object_material_get(ob, this->curve_key.get_subindex() + 1);
|
||||
name = id_name(ob) + "-" + id_name(ma) + "-material";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
name = "";
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
int BCAnimationCurve::get_channel_index() const
|
||||
{
|
||||
return curve_key.get_array_index();
|
||||
}
|
||||
|
||||
int BCAnimationCurve::get_subindex() const
|
||||
{
|
||||
return curve_key.get_subindex();
|
||||
}
|
||||
|
||||
std::string BCAnimationCurve::get_rna_path() const
|
||||
{
|
||||
return curve_key.get_path();
|
||||
}
|
||||
|
||||
int BCAnimationCurve::sample_count() const
|
||||
{
|
||||
if (fcurve == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return fcurve->totvert;
|
||||
}
|
||||
|
||||
int BCAnimationCurve::closest_index_above(const float sample_frame, const int start_at) const
|
||||
{
|
||||
if (fcurve == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int cframe = fcurve->bezt[start_at].vec[1][0]; /* inaccurate! */
|
||||
|
||||
if (fabs(cframe - sample_frame) < 0.00001) {
|
||||
return start_at;
|
||||
}
|
||||
return (fcurve->totvert > start_at + 1) ? start_at + 1 : start_at;
|
||||
}
|
||||
|
||||
int BCAnimationCurve::closest_index_below(const float sample_frame) const
|
||||
{
|
||||
if (fcurve == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
float lower_frame = sample_frame;
|
||||
float upper_frame = sample_frame;
|
||||
int lower_index = 0;
|
||||
int upper_index = 0;
|
||||
|
||||
for (int fcu_index = 0; fcu_index < fcurve->totvert; fcu_index++) {
|
||||
upper_index = fcu_index;
|
||||
|
||||
const int cframe = fcurve->bezt[fcu_index].vec[1][0]; /* inaccurate! */
|
||||
if (cframe <= sample_frame) {
|
||||
lower_frame = cframe;
|
||||
lower_index = fcu_index;
|
||||
}
|
||||
if (cframe >= sample_frame) {
|
||||
upper_frame = cframe;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (lower_index == upper_index) {
|
||||
return lower_index;
|
||||
}
|
||||
|
||||
const float fraction = float(sample_frame - lower_frame) / (upper_frame - lower_frame);
|
||||
return (fraction < 0.5) ? lower_index : upper_index;
|
||||
}
|
||||
|
||||
int BCAnimationCurve::get_interpolation_type(float sample_frame) const
|
||||
{
|
||||
const int index = closest_index_below(sample_frame);
|
||||
if (index < 0) {
|
||||
return BEZT_IPO_BEZ;
|
||||
}
|
||||
return fcurve->bezt[index].ipo;
|
||||
}
|
||||
|
||||
FCurve *BCAnimationCurve::get_fcurve() const
|
||||
{
|
||||
return fcurve;
|
||||
}
|
||||
|
||||
FCurve *BCAnimationCurve::get_edit_fcurve()
|
||||
{
|
||||
if (!curve_is_local_copy) {
|
||||
const int index = curve_key.get_array_index();
|
||||
const std::string &path = curve_key.get_path();
|
||||
fcurve = create_fcurve(index, path.c_str());
|
||||
|
||||
/* Caution here:
|
||||
* Replacing the pointer here is OK only because the original value
|
||||
* of FCurve was a const pointer into Blender territory. We do not
|
||||
* touch that! We use the local copy to prepare data for export. */
|
||||
|
||||
curve_is_local_copy = true;
|
||||
}
|
||||
return fcurve;
|
||||
}
|
||||
|
||||
void BCAnimationCurve::clean_handles()
|
||||
{
|
||||
using namespace blender::animrig;
|
||||
if (fcurve == nullptr) {
|
||||
fcurve = get_edit_fcurve();
|
||||
}
|
||||
|
||||
const KeyframeSettings settings = get_keyframe_settings(true);
|
||||
|
||||
/* Keep old bezt data for copy). */
|
||||
BezTriple *old_bezts = fcurve->bezt;
|
||||
int totvert = fcurve->totvert;
|
||||
fcurve->bezt = nullptr;
|
||||
fcurve->totvert = 0;
|
||||
|
||||
for (int i = 0; i < totvert; i++) {
|
||||
BezTriple *bezt = &old_bezts[i];
|
||||
float x = bezt->vec[1][0];
|
||||
float y = bezt->vec[1][1];
|
||||
insert_vert_fcurve(fcurve, {x, y}, settings, INSERTKEY_NOFLAGS);
|
||||
BezTriple *lastb = fcurve->bezt + (fcurve->totvert - 1);
|
||||
lastb->f1 = lastb->f2 = lastb->f3 = 0;
|
||||
}
|
||||
|
||||
/* now free the memory used by the old BezTriples */
|
||||
if (old_bezts) {
|
||||
MEM_freeN(old_bezts);
|
||||
}
|
||||
}
|
||||
|
||||
bool BCAnimationCurve::is_transform_curve() const
|
||||
{
|
||||
std::string channel_type = this->get_channel_type();
|
||||
return (is_rotation_curve() || channel_type == "scale" || channel_type == "location");
|
||||
}
|
||||
|
||||
bool BCAnimationCurve::is_rotation_curve() const
|
||||
{
|
||||
std::string channel_type = this->get_channel_type();
|
||||
return ELEM(channel_type, "rotation", "rotation_euler", "rotation_quaternion");
|
||||
}
|
||||
|
||||
float BCAnimationCurve::get_value(const float frame)
|
||||
{
|
||||
if (fcurve) {
|
||||
return evaluate_fcurve(fcurve, frame);
|
||||
}
|
||||
return 0; /* TODO: handle case where neither sample nor fcu exist */
|
||||
}
|
||||
|
||||
void BCAnimationCurve::update_range(float val)
|
||||
{
|
||||
min = std::min(val, min);
|
||||
max = std::max(val, max);
|
||||
}
|
||||
|
||||
void BCAnimationCurve::init_range(float val)
|
||||
{
|
||||
min = max = val;
|
||||
}
|
||||
|
||||
void BCAnimationCurve::adjust_range(const int frame_index)
|
||||
{
|
||||
if (fcurve && fcurve->totvert > 1) {
|
||||
const float eval = evaluate_fcurve(fcurve, frame_index);
|
||||
|
||||
int first_frame = fcurve->bezt[0].vec[1][0];
|
||||
if (first_frame == frame_index) {
|
||||
init_range(eval);
|
||||
}
|
||||
else {
|
||||
update_range(eval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BCAnimationCurve::add_value(const float val, const int frame_index)
|
||||
{
|
||||
using namespace blender::animrig;
|
||||
const KeyframeSettings settings = get_keyframe_settings(true);
|
||||
FCurve *fcu = get_edit_fcurve();
|
||||
fcu->auto_smoothing = U.auto_smoothing_new;
|
||||
insert_vert_fcurve(fcu, {float(frame_index), val}, settings, INSERTKEY_NOFLAGS);
|
||||
|
||||
if (fcu->totvert == 1) {
|
||||
init_range(val);
|
||||
}
|
||||
else {
|
||||
update_range(val);
|
||||
}
|
||||
}
|
||||
|
||||
bool BCAnimationCurve::add_value_from_matrix(const BCSample &sample, const int frame_index)
|
||||
{
|
||||
int array_index = curve_key.get_array_index();
|
||||
|
||||
/* transformation curves are fed directly from the transformation matrix
|
||||
* to resolve parent inverse matrix issues with object hierarchies.
|
||||
* Maybe this can be unified with the
|
||||
*/
|
||||
const std::string channel_target = get_channel_target();
|
||||
float val = 0;
|
||||
/* Pick the value from the sample according to the definition of the FCurve */
|
||||
bool good = sample.get_value(channel_target, array_index, &val);
|
||||
if (good) {
|
||||
add_value(val, frame_index);
|
||||
}
|
||||
return good;
|
||||
}
|
||||
|
||||
bool BCAnimationCurve::add_value_from_rna(const int frame_index)
|
||||
{
|
||||
PointerRNA ptr;
|
||||
PropertyRNA *prop;
|
||||
float value = 0.0f;
|
||||
int array_index = curve_key.get_array_index();
|
||||
const std::string full_path = curve_key.get_full_path();
|
||||
|
||||
/* get property to read from, and get value as appropriate */
|
||||
bool path_resolved = RNA_path_resolve_full(
|
||||
&id_ptr, full_path.c_str(), &ptr, &prop, &array_index);
|
||||
if (!path_resolved && array_index == 0) {
|
||||
const std::string rna_path = curve_key.get_path();
|
||||
path_resolved = RNA_path_resolve_full(&id_ptr, rna_path.c_str(), &ptr, &prop, &array_index);
|
||||
}
|
||||
|
||||
if (path_resolved) {
|
||||
bool is_array = RNA_property_array_check(prop);
|
||||
if (is_array) {
|
||||
/* array */
|
||||
if ((array_index >= 0) && (array_index < RNA_property_array_length(&ptr, prop))) {
|
||||
switch (RNA_property_type(prop)) {
|
||||
case PROP_BOOLEAN:
|
||||
value = float(RNA_property_boolean_get_index(&ptr, prop, array_index));
|
||||
break;
|
||||
case PROP_INT:
|
||||
value = float(RNA_property_int_get_index(&ptr, prop, array_index));
|
||||
break;
|
||||
case PROP_FLOAT:
|
||||
value = RNA_property_float_get_index(&ptr, prop, array_index);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(stderr,
|
||||
"Out of Bounds while reading data for Curve %s\n",
|
||||
curve_key.get_full_path().c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* not an array */
|
||||
switch (RNA_property_type(prop)) {
|
||||
case PROP_BOOLEAN:
|
||||
value = float(RNA_property_boolean_get(&ptr, prop));
|
||||
break;
|
||||
case PROP_INT:
|
||||
value = float(RNA_property_int_get(&ptr, prop));
|
||||
break;
|
||||
case PROP_FLOAT:
|
||||
value = RNA_property_float_get(&ptr, prop);
|
||||
break;
|
||||
case PROP_ENUM:
|
||||
value = float(RNA_property_enum_get(&ptr, prop));
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,
|
||||
"property type %d not supported for Curve %s\n",
|
||||
RNA_property_type(prop),
|
||||
curve_key.get_full_path().c_str());
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* path couldn't be resolved */
|
||||
fprintf(stderr, "Path not recognized for Curve %s\n", curve_key.get_full_path().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
add_value(value, frame_index);
|
||||
return true;
|
||||
}
|
||||
|
||||
void BCAnimationCurve::get_value_map(BCValueMap &value_map)
|
||||
{
|
||||
value_map.clear();
|
||||
if (fcurve == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < fcurve->totvert; i++) {
|
||||
const float frame = fcurve->bezt[i].vec[1][0];
|
||||
const float val = fcurve->bezt[i].vec[1][1];
|
||||
value_map[frame] = val;
|
||||
}
|
||||
}
|
||||
|
||||
void BCAnimationCurve::get_frames(BCFrames &frames) const
|
||||
{
|
||||
frames.clear();
|
||||
if (fcurve) {
|
||||
for (int i = 0; i < fcurve->totvert; i++) {
|
||||
const float val = fcurve->bezt[i].vec[1][0];
|
||||
frames.push_back(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BCAnimationCurve::get_values(BCValues &values) const
|
||||
{
|
||||
values.clear();
|
||||
if (fcurve) {
|
||||
for (int i = 0; i < fcurve->totvert; i++) {
|
||||
const float val = fcurve->bezt[i].vec[1][1];
|
||||
values.push_back(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BCAnimationCurve::is_animated()
|
||||
{
|
||||
static float MIN_DISTANCE = 0.00001;
|
||||
return fabs(max - min) > MIN_DISTANCE;
|
||||
}
|
||||
|
||||
bool BCAnimationCurve::is_keyframe(int frame)
|
||||
{
|
||||
if (this->fcurve == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < fcurve->totvert; i++) {
|
||||
const int cframe = nearbyint(fcurve->bezt[i].vec[1][0]);
|
||||
if (cframe == frame) {
|
||||
return true;
|
||||
}
|
||||
if (cframe > frame) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Needed for adding a BCAnimationCurve into a BCAnimationCurveSet */
|
||||
inline bool operator<(const BCAnimationCurve &lhs, const BCAnimationCurve &rhs)
|
||||
{
|
||||
std::string lhtgt = lhs.get_channel_target();
|
||||
std::string rhtgt = rhs.get_channel_target();
|
||||
if (lhtgt == rhtgt) {
|
||||
const int lha = lhs.get_channel_index();
|
||||
const int rha = rhs.get_channel_index();
|
||||
return lha < rha;
|
||||
}
|
||||
|
||||
return lhtgt < rhtgt;
|
||||
}
|
||||
|
||||
BCCurveKey::BCCurveKey()
|
||||
{
|
||||
this->key_type = BC_ANIMATION_TYPE_OBJECT;
|
||||
this->rna_path = "";
|
||||
this->curve_array_index = 0;
|
||||
this->curve_subindex = -1;
|
||||
}
|
||||
|
||||
BCCurveKey::BCCurveKey(const BC_animation_type type,
|
||||
const std::string path,
|
||||
const int array_index,
|
||||
const int subindex)
|
||||
{
|
||||
this->key_type = type;
|
||||
this->rna_path = path;
|
||||
this->curve_array_index = array_index;
|
||||
this->curve_subindex = subindex;
|
||||
}
|
||||
|
||||
void BCCurveKey::operator=(const BCCurveKey &other)
|
||||
{
|
||||
this->key_type = other.key_type;
|
||||
this->rna_path = other.rna_path;
|
||||
this->curve_array_index = other.curve_array_index;
|
||||
this->curve_subindex = other.curve_subindex;
|
||||
}
|
||||
|
||||
std::string BCCurveKey::get_full_path() const
|
||||
{
|
||||
return this->rna_path + '[' + std::to_string(this->curve_array_index) + ']';
|
||||
}
|
||||
|
||||
std::string BCCurveKey::get_path() const
|
||||
{
|
||||
return this->rna_path;
|
||||
}
|
||||
|
||||
int BCCurveKey::get_array_index() const
|
||||
{
|
||||
return this->curve_array_index;
|
||||
}
|
||||
|
||||
int BCCurveKey::get_subindex() const
|
||||
{
|
||||
return this->curve_subindex;
|
||||
}
|
||||
|
||||
void BCCurveKey::set_object_type(BC_animation_type object_type)
|
||||
{
|
||||
this->key_type = object_type;
|
||||
}
|
||||
|
||||
BC_animation_type BCCurveKey::get_animation_type() const
|
||||
{
|
||||
return this->key_type;
|
||||
}
|
||||
|
||||
bool BCCurveKey::operator<(const BCCurveKey &other) const
|
||||
{
|
||||
/* needed for using this class as key in maps and sets */
|
||||
if (this->key_type != other.key_type) {
|
||||
return this->key_type < other.key_type;
|
||||
}
|
||||
|
||||
if (this->curve_subindex != other.curve_subindex) {
|
||||
return this->curve_subindex < other.curve_subindex;
|
||||
}
|
||||
|
||||
if (this->rna_path != other.rna_path) {
|
||||
return this->rna_path < other.rna_path;
|
||||
}
|
||||
|
||||
return this->curve_array_index < other.curve_array_index;
|
||||
}
|
||||
|
||||
BCBezTriple::BCBezTriple(BezTriple &bezt) : bezt(bezt) {}
|
||||
|
||||
float BCBezTriple::get_frame() const
|
||||
{
|
||||
return bezt.vec[1][0];
|
||||
}
|
||||
|
||||
float BCBezTriple::get_time(Scene *scene) const
|
||||
{
|
||||
return FRA2TIME(bezt.vec[1][0]);
|
||||
}
|
||||
|
||||
float BCBezTriple::get_value() const
|
||||
{
|
||||
return bezt.vec[1][1];
|
||||
}
|
||||
|
||||
float BCBezTriple::get_angle() const
|
||||
{
|
||||
return RAD2DEGF(get_value());
|
||||
}
|
||||
|
||||
void BCBezTriple::get_in_tangent(Scene *scene, float point[2], bool as_angle) const
|
||||
{
|
||||
get_tangent(scene, point, as_angle, 0);
|
||||
}
|
||||
|
||||
void BCBezTriple::get_out_tangent(Scene *scene, float point[2], bool as_angle) const
|
||||
{
|
||||
get_tangent(scene, point, as_angle, 2);
|
||||
}
|
||||
|
||||
void BCBezTriple::get_tangent(Scene *scene, float point[2], bool as_angle, int index) const
|
||||
{
|
||||
point[0] = FRA2TIME(bezt.vec[index][0]);
|
||||
if (bezt.ipo != BEZT_IPO_BEZ) {
|
||||
/* We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain
|
||||
* unused data */
|
||||
point[0] = 0;
|
||||
point[1] = 0;
|
||||
}
|
||||
else if (as_angle) {
|
||||
point[1] = RAD2DEGF(bezt.vec[index][1]);
|
||||
}
|
||||
else {
|
||||
point[1] = bezt.vec[index][1];
|
||||
}
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2008 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "BCSampleData.h"
|
||||
|
||||
#include "BKE_fcurve.hh"
|
||||
|
||||
#include "RNA_types.hh"
|
||||
|
||||
#include "ED_anim_api.hh"
|
||||
|
||||
using TangentPoint = float[2];
|
||||
|
||||
using BCFrameSet = std::set<float>;
|
||||
using BCFrames = std::vector<float>;
|
||||
using BCValues = std::vector<float>;
|
||||
using BCTimes = std::vector<float>;
|
||||
using BCValueMap = std::map<int, float>;
|
||||
|
||||
enum BC_animation_type {
|
||||
BC_ANIMATION_TYPE_OBJECT,
|
||||
BC_ANIMATION_TYPE_BONE,
|
||||
BC_ANIMATION_TYPE_CAMERA,
|
||||
BC_ANIMATION_TYPE_MATERIAL,
|
||||
BC_ANIMATION_TYPE_LIGHT,
|
||||
};
|
||||
|
||||
class BCCurveKey {
|
||||
private:
|
||||
BC_animation_type key_type;
|
||||
std::string rna_path;
|
||||
int curve_array_index;
|
||||
int curve_subindex; /* only needed for materials */
|
||||
|
||||
public:
|
||||
BCCurveKey();
|
||||
BCCurveKey(const BC_animation_type type,
|
||||
const std::string path,
|
||||
int array_index,
|
||||
int subindex = -1);
|
||||
void operator=(const BCCurveKey &other);
|
||||
std::string get_full_path() const;
|
||||
std::string get_path() const;
|
||||
int get_array_index() const;
|
||||
int get_subindex() const;
|
||||
void set_object_type(BC_animation_type object_type);
|
||||
BC_animation_type get_animation_type() const;
|
||||
bool operator<(const BCCurveKey &other) const;
|
||||
};
|
||||
|
||||
class BCBezTriple {
|
||||
public:
|
||||
BezTriple &bezt;
|
||||
|
||||
BCBezTriple(BezTriple &bezt);
|
||||
float get_frame() const;
|
||||
float get_time(Scene *scene) const;
|
||||
float get_value() const;
|
||||
float get_angle() const;
|
||||
void get_in_tangent(Scene *scene, float point[2], bool as_angle) const;
|
||||
void get_out_tangent(Scene *scene, float point[2], bool as_angle) const;
|
||||
void get_tangent(Scene *scene, float point[2], bool as_angle, int index) const;
|
||||
};
|
||||
|
||||
class BCAnimationCurve {
|
||||
private:
|
||||
BCCurveKey curve_key;
|
||||
float min = 0;
|
||||
float max = 0;
|
||||
|
||||
bool curve_is_local_copy = false;
|
||||
FCurve *fcurve;
|
||||
PointerRNA id_ptr;
|
||||
void init_pointer_rna(Object *ob);
|
||||
void delete_fcurve(FCurve *fcu);
|
||||
FCurve *create_fcurve(int array_index, const char *rna_path);
|
||||
void create_bezt(float frame, float output);
|
||||
void update_range(float val);
|
||||
void init_range(float val);
|
||||
|
||||
public:
|
||||
BCAnimationCurve();
|
||||
BCAnimationCurve(const BCAnimationCurve &other);
|
||||
BCAnimationCurve(const BCCurveKey &key, Object *ob);
|
||||
BCAnimationCurve(BCCurveKey key, Object *ob, FCurve *fcu);
|
||||
~BCAnimationCurve();
|
||||
|
||||
bool is_of_animation_type(BC_animation_type type) const;
|
||||
int get_interpolation_type(float sample_frame) const;
|
||||
bool is_animated();
|
||||
bool is_transform_curve() const;
|
||||
bool is_rotation_curve() const;
|
||||
bool is_keyframe(int frame);
|
||||
void adjust_range(int frame);
|
||||
|
||||
std::string get_animation_name(Object *ob) const; /* XXX: this is COLLADA specific. */
|
||||
std::string get_channel_target() const;
|
||||
std::string get_channel_type() const;
|
||||
std::string get_channel_posebone() const; /* returns "" if channel is not a bone channel */
|
||||
|
||||
int get_channel_index() const;
|
||||
int get_subindex() const;
|
||||
std::string get_rna_path() const;
|
||||
FCurve *get_fcurve() const;
|
||||
int sample_count() const;
|
||||
|
||||
float get_value(float frame);
|
||||
void get_values(BCValues &values) const;
|
||||
void get_value_map(BCValueMap &value_map);
|
||||
|
||||
void get_frames(BCFrames &frames) const;
|
||||
|
||||
/* Curve edit functions create a copy of the underlying #FCurve. */
|
||||
FCurve *get_edit_fcurve();
|
||||
bool add_value_from_rna(int frame);
|
||||
bool add_value_from_matrix(const BCSample &sample, int frame);
|
||||
void add_value(float val, int frame);
|
||||
void clean_handles();
|
||||
|
||||
/* experimental stuff */
|
||||
int closest_index_above(float sample_frame, int start_at) const;
|
||||
int closest_index_below(float sample_frame) const;
|
||||
};
|
||||
|
||||
using BCAnimationCurveMap = std::map<BCCurveKey, BCAnimationCurve *>;
|
@ -1,618 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2008 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "BCAnimationCurve.h"
|
||||
#include "BCAnimationSampler.h"
|
||||
#include "BCMath.h"
|
||||
#include "ExportSettings.h"
|
||||
#include "collada_utils.h"
|
||||
|
||||
#include "BKE_action.hh"
|
||||
#include "BKE_constraint.h"
|
||||
#include "BKE_material.hh"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "ED_object.hh"
|
||||
|
||||
#include "ANIM_action_legacy.hh"
|
||||
|
||||
static std::string EMPTY_STRING;
|
||||
static BCAnimationCurveMap BCEmptyAnimationCurves;
|
||||
|
||||
BCAnimationSampler::BCAnimationSampler(BCExportSettings &export_settings, BCObjectSet &object_set)
|
||||
: export_settings(export_settings)
|
||||
{
|
||||
BCObjectSet::iterator it;
|
||||
for (it = object_set.begin(); it != object_set.end(); ++it) {
|
||||
Object *ob = *it;
|
||||
add_object(ob);
|
||||
}
|
||||
}
|
||||
|
||||
BCAnimationSampler::~BCAnimationSampler()
|
||||
{
|
||||
BCAnimationObjectMap::iterator it;
|
||||
for (it = objects.begin(); it != objects.end(); ++it) {
|
||||
BCAnimation *animation = it->second;
|
||||
delete animation;
|
||||
}
|
||||
}
|
||||
|
||||
void BCAnimationSampler::add_object(Object *ob)
|
||||
{
|
||||
BlenderContext blender_context = export_settings.get_blender_context();
|
||||
BCAnimation *animation = new BCAnimation(blender_context.get_context(), ob);
|
||||
objects[ob] = animation;
|
||||
|
||||
initialize_keyframes(animation->frame_set, ob);
|
||||
initialize_curves(animation->curve_map, ob);
|
||||
}
|
||||
|
||||
BCAnimationCurveMap *BCAnimationSampler::get_curves(Object *ob)
|
||||
{
|
||||
BCAnimation &animation = *objects[ob];
|
||||
if (animation.curve_map.empty()) {
|
||||
initialize_curves(animation.curve_map, ob);
|
||||
}
|
||||
return &animation.curve_map;
|
||||
}
|
||||
|
||||
static void get_sample_frames(BCFrameSet &sample_frames,
|
||||
int sampling_rate,
|
||||
bool keyframe_at_end,
|
||||
Scene *scene)
|
||||
{
|
||||
sample_frames.clear();
|
||||
|
||||
if (sampling_rate < 1) {
|
||||
return; /* no sample frames in this case */
|
||||
}
|
||||
|
||||
float sfra = scene->r.sfra;
|
||||
float efra = scene->r.efra;
|
||||
|
||||
int frame_index;
|
||||
for (frame_index = nearbyint(sfra); frame_index < efra; frame_index += sampling_rate) {
|
||||
sample_frames.insert(frame_index);
|
||||
}
|
||||
|
||||
if (frame_index >= efra && keyframe_at_end) {
|
||||
sample_frames.insert(efra);
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_object_keyframe(Object *ob, int frame_index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static void add_keyframes_from(AnimData *adt, BCFrameSet &frameset)
|
||||
{
|
||||
for (FCurve *fcu : blender::animrig::legacy::fcurves_for_assigned_action(adt)) {
|
||||
BezTriple *bezt = fcu->bezt;
|
||||
for (int i = 0; i < fcu->totvert; bezt++, i++) {
|
||||
int frame_index = nearbyint(bezt->vec[1][0]);
|
||||
frameset.insert(frame_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BCAnimationSampler::check_property_is_animated(
|
||||
BCAnimation &animation, float *ref, float *val, std::string data_path, int length)
|
||||
{
|
||||
for (int array_index = 0; array_index < length; array_index++) {
|
||||
if (!bc_in_range(ref[length], val[length], 0.00001)) {
|
||||
BCCurveKey key(BC_ANIMATION_TYPE_OBJECT, data_path, array_index);
|
||||
BCAnimationCurveMap::iterator it = animation.curve_map.find(key);
|
||||
if (it == animation.curve_map.end()) {
|
||||
animation.curve_map[key] = new BCAnimationCurve(key, animation.get_reference());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BCAnimationSampler::update_animation_curves(BCAnimation &animation,
|
||||
BCSample &sample,
|
||||
Object *ob,
|
||||
int frame)
|
||||
{
|
||||
BCAnimationCurveMap::iterator it;
|
||||
for (it = animation.curve_map.begin(); it != animation.curve_map.end(); ++it) {
|
||||
BCAnimationCurve *curve = it->second;
|
||||
if (curve->is_transform_curve()) {
|
||||
curve->add_value_from_matrix(sample, frame);
|
||||
}
|
||||
else {
|
||||
curve->add_value_from_rna(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BCSample &BCAnimationSampler::sample_object(Object *ob, int frame_index, bool for_opensim)
|
||||
{
|
||||
BCSample &ob_sample = sample_data.add(ob, frame_index);
|
||||
#if 0
|
||||
if (export_settings.get_apply_global_orientation()) {
|
||||
const BCMatrix &global_transform = export_settings.get_global_transform();
|
||||
ob_sample.get_matrix(global_transform);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ob->type == OB_ARMATURE) {
|
||||
LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
|
||||
Bone *bone = pchan->bone;
|
||||
Matrix bmat;
|
||||
if (bc_bone_matrix_local_get(ob, bone, bmat, for_opensim)) {
|
||||
|
||||
ob_sample.add_bone_matrix(bone, bmat);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ob_sample;
|
||||
}
|
||||
|
||||
void BCAnimationSampler::sample_scene(BCExportSettings &export_settings, bool keyframe_at_end)
|
||||
{
|
||||
BlenderContext blender_context = export_settings.get_blender_context();
|
||||
int sampling_rate = export_settings.get_sampling_rate();
|
||||
bool for_opensim = export_settings.get_open_sim();
|
||||
bool keep_keyframes = export_settings.get_keep_keyframes();
|
||||
BC_export_animation_type export_animation_type = export_settings.get_export_animation_type();
|
||||
|
||||
Scene *scene = blender_context.get_scene();
|
||||
BCFrameSet scene_sample_frames;
|
||||
get_sample_frames(scene_sample_frames, sampling_rate, keyframe_at_end, scene);
|
||||
|
||||
int startframe = scene->r.sfra;
|
||||
int endframe = scene->r.efra;
|
||||
|
||||
for (int frame_index = startframe; frame_index <= endframe; frame_index++) {
|
||||
/* Loop over all frames and decide for each frame if sampling is necessary */
|
||||
bool is_scene_sample_frame = false;
|
||||
bool needs_update = true;
|
||||
if (scene_sample_frames.find(frame_index) != scene_sample_frames.end()) {
|
||||
bc_update_scene(blender_context, frame_index);
|
||||
needs_update = false;
|
||||
is_scene_sample_frame = true;
|
||||
}
|
||||
|
||||
bool needs_sampling = is_scene_sample_frame || keep_keyframes ||
|
||||
export_animation_type == BC_ANIMATION_EXPORT_KEYS;
|
||||
if (!needs_sampling) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BCAnimationObjectMap::iterator obit;
|
||||
for (obit = objects.begin(); obit != objects.end(); ++obit) {
|
||||
Object *ob = obit->first;
|
||||
BCAnimation *animation = obit->second;
|
||||
BCFrameSet &object_keyframes = animation->frame_set;
|
||||
if (is_scene_sample_frame || object_keyframes.find(frame_index) != object_keyframes.end()) {
|
||||
|
||||
if (needs_update) {
|
||||
bc_update_scene(blender_context, frame_index);
|
||||
needs_update = false;
|
||||
}
|
||||
|
||||
BCSample &sample = sample_object(ob, frame_index, for_opensim);
|
||||
update_animation_curves(*animation, sample, ob, frame_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BCAnimationSampler::is_animated_by_constraint(Object *ob,
|
||||
ListBase *conlist,
|
||||
std::set<Object *> &animated_objects)
|
||||
{
|
||||
LISTBASE_FOREACH (bConstraint *, con, conlist) {
|
||||
ListBase targets = {nullptr, nullptr};
|
||||
|
||||
if (!bc_validateConstraints(con)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (BKE_constraint_targets_get(con, &targets)) {
|
||||
Object *obtar;
|
||||
bool found = false;
|
||||
|
||||
LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
|
||||
obtar = ct->tar;
|
||||
if (obtar) {
|
||||
if (animated_objects.find(obtar) != animated_objects.end()) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
BKE_constraint_targets_flush(con, &targets, true);
|
||||
return found;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BCAnimationSampler::find_depending_animated(std::set<Object *> &animated_objects,
|
||||
std::set<Object *> &candidates)
|
||||
{
|
||||
bool found_more;
|
||||
do {
|
||||
found_more = false;
|
||||
std::set<Object *>::iterator it;
|
||||
for (it = candidates.begin(); it != candidates.end(); ++it) {
|
||||
Object *cob = *it;
|
||||
ListBase *conlist = blender::ed::object::constraint_active_list(cob);
|
||||
if (is_animated_by_constraint(cob, conlist, animated_objects)) {
|
||||
animated_objects.insert(cob);
|
||||
candidates.erase(cob);
|
||||
found_more = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (found_more && !candidates.empty());
|
||||
}
|
||||
|
||||
void BCAnimationSampler::get_animated_from_export_set(std::set<Object *> &animated_objects,
|
||||
LinkNode &export_set)
|
||||
{
|
||||
/* Check if this object is animated. That is: Check if it has its own action, or:
|
||||
*
|
||||
* - Check if it has constraints to other objects.
|
||||
* - at least one of the other objects is animated as well.
|
||||
*/
|
||||
|
||||
animated_objects.clear();
|
||||
std::set<Object *> candidates;
|
||||
|
||||
LinkNode *node;
|
||||
for (node = &export_set; node; node = node->next) {
|
||||
Object *cob = (Object *)node->link;
|
||||
if (bc_has_animations(cob)) {
|
||||
animated_objects.insert(cob);
|
||||
}
|
||||
else {
|
||||
ListBase conlist = cob->constraints;
|
||||
if (conlist.first) {
|
||||
candidates.insert(cob);
|
||||
}
|
||||
}
|
||||
}
|
||||
find_depending_animated(animated_objects, candidates);
|
||||
}
|
||||
|
||||
void BCAnimationSampler::get_object_frames(BCFrames &frames, Object *ob)
|
||||
{
|
||||
sample_data.get_frames(ob, frames);
|
||||
}
|
||||
|
||||
void BCAnimationSampler::get_bone_frames(BCFrames &frames, Object *ob, Bone *bone)
|
||||
{
|
||||
sample_data.get_frames(ob, bone, frames);
|
||||
}
|
||||
|
||||
bool BCAnimationSampler::get_bone_samples(BCMatrixSampleMap &samples, Object *ob, Bone *bone)
|
||||
{
|
||||
sample_data.get_matrices(ob, bone, samples);
|
||||
return bc_is_animated(samples);
|
||||
}
|
||||
|
||||
bool BCAnimationSampler::get_object_samples(BCMatrixSampleMap &samples, Object *ob)
|
||||
{
|
||||
sample_data.get_matrices(ob, samples);
|
||||
return bc_is_animated(samples);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* Add sampled values to #FCurve
|
||||
* If no #FCurve exists, create a temporary #FCurve;
|
||||
* \note The temporary #FCurve will later be removed when the
|
||||
* #BCAnimationSampler is removed (by its destructor).
|
||||
*
|
||||
* \param curve: The curve to which the data is added.
|
||||
* \param matrices: The set of matrix values from where the data is taken.
|
||||
* \param animation_type:
|
||||
* - #BC_ANIMATION_EXPORT_SAMPLES: Use all matrix data.
|
||||
* - #BC_ANIMATION_EXPORT_KEYS: Only take data from matrices for keyframes.
|
||||
*/
|
||||
void BCAnimationSampler::add_value_set(BCAnimationCurve &curve,
|
||||
BCFrameSampleMap &samples,
|
||||
BC_export_animation_type animation_type)
|
||||
{
|
||||
int array_index = curve.get_array_index();
|
||||
const BC_animation_transform_type tm_type = curve.get_transform_type();
|
||||
|
||||
BCFrameSampleMap::iterator it;
|
||||
for (it = samples.begin(); it != samples.end(); ++it) {
|
||||
const int frame_index = nearbyint(it->first);
|
||||
if (animation_type == BC_ANIMATION_EXPORT_SAMPLES || curve.is_keyframe(frame_index)) {
|
||||
|
||||
const BCSample *sample = it->second;
|
||||
float val = 0;
|
||||
|
||||
int subindex = curve.get_subindex();
|
||||
bool good;
|
||||
if (subindex == -1) {
|
||||
good = sample->get_value(tm_type, array_index, &val);
|
||||
}
|
||||
else {
|
||||
good = sample->get_value(tm_type, array_index, &val, subindex);
|
||||
}
|
||||
|
||||
if (good) {
|
||||
curve.add_value(val, frame_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
curve.remove_unused_keyframes();
|
||||
curve.calchandles();
|
||||
}
|
||||
#endif
|
||||
|
||||
void BCAnimationSampler::generate_transform(Object *ob,
|
||||
const BCCurveKey &key,
|
||||
BCAnimationCurveMap &curves)
|
||||
{
|
||||
BCAnimationCurveMap::const_iterator it = curves.find(key);
|
||||
if (it == curves.end()) {
|
||||
curves[key] = new BCAnimationCurve(key, ob);
|
||||
}
|
||||
}
|
||||
|
||||
void BCAnimationSampler::generate_transforms(Object *ob,
|
||||
const std::string prep,
|
||||
const BC_animation_type type,
|
||||
BCAnimationCurveMap &curves)
|
||||
{
|
||||
generate_transform(ob, BCCurveKey(type, prep + "location", 0), curves);
|
||||
generate_transform(ob, BCCurveKey(type, prep + "location", 1), curves);
|
||||
generate_transform(ob, BCCurveKey(type, prep + "location", 2), curves);
|
||||
generate_transform(ob, BCCurveKey(type, prep + "rotation_euler", 0), curves);
|
||||
generate_transform(ob, BCCurveKey(type, prep + "rotation_euler", 1), curves);
|
||||
generate_transform(ob, BCCurveKey(type, prep + "rotation_euler", 2), curves);
|
||||
generate_transform(ob, BCCurveKey(type, prep + "scale", 0), curves);
|
||||
generate_transform(ob, BCCurveKey(type, prep + "scale", 1), curves);
|
||||
generate_transform(ob, BCCurveKey(type, prep + "scale", 2), curves);
|
||||
}
|
||||
|
||||
void BCAnimationSampler::generate_transforms(Object *ob, Bone *bone, BCAnimationCurveMap &curves)
|
||||
{
|
||||
std::string prep = "pose.bones[\"" + std::string(bone->name) + "\"].";
|
||||
generate_transforms(ob, prep, BC_ANIMATION_TYPE_BONE, curves);
|
||||
|
||||
LISTBASE_FOREACH (Bone *, child, &bone->childbase) {
|
||||
generate_transforms(ob, child, curves);
|
||||
}
|
||||
}
|
||||
|
||||
void BCAnimationSampler::initialize_keyframes(BCFrameSet &frameset, Object *ob)
|
||||
{
|
||||
frameset.clear();
|
||||
add_keyframes_from(ob->adt, frameset);
|
||||
add_keyframes_from(bc_getSceneCameraAnimData(ob), frameset);
|
||||
add_keyframes_from(bc_getSceneLightAnimData(ob), frameset);
|
||||
|
||||
for (int a = 0; a < ob->totcol; a++) {
|
||||
Material *ma = BKE_object_material_get(ob, a + 1);
|
||||
add_keyframes_from(bc_getSceneMaterialAnimData(ma), frameset);
|
||||
}
|
||||
}
|
||||
|
||||
void BCAnimationSampler::initialize_curves(BCAnimationCurveMap &curves, Object *ob)
|
||||
{
|
||||
BC_animation_type object_type = BC_ANIMATION_TYPE_OBJECT;
|
||||
|
||||
for (FCurve *fcu : blender::animrig::legacy::fcurves_for_assigned_action(ob->adt)) {
|
||||
object_type = BC_ANIMATION_TYPE_OBJECT;
|
||||
if (ob->type == OB_ARMATURE) {
|
||||
char boneName[MAXBONENAME];
|
||||
if (BLI_str_quoted_substr(fcu->rna_path, "pose.bones[", boneName, sizeof(boneName))) {
|
||||
object_type = BC_ANIMATION_TYPE_BONE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Adding action curves on object */
|
||||
BCCurveKey key(object_type, fcu->rna_path, fcu->array_index);
|
||||
curves[key] = new BCAnimationCurve(key, ob, fcu);
|
||||
}
|
||||
|
||||
/* Add missing curves */
|
||||
object_type = BC_ANIMATION_TYPE_OBJECT;
|
||||
generate_transforms(ob, EMPTY_STRING, object_type, curves);
|
||||
if (ob->type == OB_ARMATURE) {
|
||||
bArmature *arm = (bArmature *)ob->data;
|
||||
LISTBASE_FOREACH (Bone *, root_bone, &arm->bonebase) {
|
||||
generate_transforms(ob, root_bone, curves);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add curves on Object->data actions */
|
||||
AnimData *adt = nullptr;
|
||||
if (ob->type == OB_CAMERA) {
|
||||
adt = bc_getSceneCameraAnimData(ob);
|
||||
object_type = BC_ANIMATION_TYPE_CAMERA;
|
||||
}
|
||||
else if (ob->type == OB_LAMP) {
|
||||
adt = bc_getSceneLightAnimData(ob);
|
||||
object_type = BC_ANIMATION_TYPE_LIGHT;
|
||||
}
|
||||
|
||||
/* Add light action or Camera action */
|
||||
for (FCurve *fcu : blender::animrig::legacy::fcurves_for_assigned_action(adt)) {
|
||||
BCCurveKey key(object_type, fcu->rna_path, fcu->array_index);
|
||||
curves[key] = new BCAnimationCurve(key, ob, fcu);
|
||||
}
|
||||
|
||||
/* Add curves on Object->material actions. */
|
||||
object_type = BC_ANIMATION_TYPE_MATERIAL;
|
||||
for (int a = 0; a < ob->totcol; a++) {
|
||||
/* Export Material parameter animations. */
|
||||
Material *ma = BKE_object_material_get(ob, a + 1);
|
||||
if (ma) {
|
||||
adt = bc_getSceneMaterialAnimData(ma);
|
||||
// isMatAnim = true;
|
||||
for (FCurve *fcu : blender::animrig::legacy::fcurves_for_assigned_action(adt)) {
|
||||
BCCurveKey key(object_type, fcu->rna_path, fcu->array_index, a);
|
||||
curves[key] = new BCAnimationCurve(key, ob, fcu);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================================== */
|
||||
|
||||
BCSample &BCSampleFrame::add(Object *ob)
|
||||
{
|
||||
BCSample *sample = new BCSample(ob);
|
||||
sampleMap[ob] = sample;
|
||||
return *sample;
|
||||
}
|
||||
|
||||
const BCSample *BCSampleFrame::get_sample(Object *ob) const
|
||||
{
|
||||
BCSampleMap::const_iterator it = sampleMap.find(ob);
|
||||
if (it == sampleMap.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
const BCMatrix *BCSampleFrame::get_sample_matrix(Object *ob) const
|
||||
{
|
||||
BCSampleMap::const_iterator it = sampleMap.find(ob);
|
||||
if (it == sampleMap.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
BCSample *sample = it->second;
|
||||
return &sample->get_matrix();
|
||||
}
|
||||
|
||||
const BCMatrix *BCSampleFrame::get_sample_matrix(Object *ob, Bone *bone) const
|
||||
{
|
||||
BCSampleMap::const_iterator it = sampleMap.find(ob);
|
||||
if (it == sampleMap.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BCSample *sample = it->second;
|
||||
const BCMatrix *bc_bone = sample->get_matrix(bone);
|
||||
return bc_bone;
|
||||
}
|
||||
|
||||
bool BCSampleFrame::has_sample_for(Object *ob) const
|
||||
{
|
||||
return sampleMap.find(ob) != sampleMap.end();
|
||||
}
|
||||
|
||||
bool BCSampleFrame::has_sample_for(Object *ob, Bone *bone) const
|
||||
{
|
||||
const BCMatrix *bc_bone = get_sample_matrix(ob, bone);
|
||||
return bc_bone;
|
||||
}
|
||||
|
||||
/* ==================================================================== */
|
||||
|
||||
BCSample &BCSampleFrameContainer::add(Object *ob, int frame_index)
|
||||
{
|
||||
BCSampleFrame &frame = sample_frames[frame_index];
|
||||
return frame.add(ob);
|
||||
}
|
||||
|
||||
/* ====================================================== */
|
||||
/* Below are the getters which we need to export the data */
|
||||
/* ====================================================== */
|
||||
|
||||
BCSampleFrame *BCSampleFrameContainer::get_frame(int frame_index)
|
||||
{
|
||||
BCSampleFrameMap::iterator it = sample_frames.find(frame_index);
|
||||
BCSampleFrame *frame = (it == sample_frames.end()) ? nullptr : &it->second;
|
||||
return frame;
|
||||
}
|
||||
|
||||
int BCSampleFrameContainer::get_frames(std::vector<int> &frames) const
|
||||
{
|
||||
frames.clear(); /* safety; */
|
||||
BCSampleFrameMap::const_iterator it;
|
||||
for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
|
||||
frames.push_back(it->first);
|
||||
}
|
||||
return frames.size();
|
||||
}
|
||||
|
||||
int BCSampleFrameContainer::get_frames(Object *ob, BCFrames &frames) const
|
||||
{
|
||||
frames.clear(); /* safety; */
|
||||
BCSampleFrameMap::const_iterator it;
|
||||
for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
|
||||
const BCSampleFrame &frame = it->second;
|
||||
if (frame.has_sample_for(ob)) {
|
||||
frames.push_back(it->first);
|
||||
}
|
||||
}
|
||||
return frames.size();
|
||||
}
|
||||
|
||||
int BCSampleFrameContainer::get_frames(Object *ob, Bone *bone, BCFrames &frames) const
|
||||
{
|
||||
frames.clear(); /* safety; */
|
||||
BCSampleFrameMap::const_iterator it;
|
||||
for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
|
||||
const BCSampleFrame &frame = it->second;
|
||||
if (frame.has_sample_for(ob, bone)) {
|
||||
frames.push_back(it->first);
|
||||
}
|
||||
}
|
||||
return frames.size();
|
||||
}
|
||||
|
||||
int BCSampleFrameContainer::get_samples(Object *ob, BCFrameSampleMap &samples) const
|
||||
{
|
||||
samples.clear(); /* safety; */
|
||||
BCSampleFrameMap::const_iterator it;
|
||||
for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
|
||||
const BCSampleFrame &frame = it->second;
|
||||
const BCSample *sample = frame.get_sample(ob);
|
||||
if (sample) {
|
||||
samples[it->first] = sample;
|
||||
}
|
||||
}
|
||||
return samples.size();
|
||||
}
|
||||
|
||||
int BCSampleFrameContainer::get_matrices(Object *ob, BCMatrixSampleMap &samples) const
|
||||
{
|
||||
samples.clear(); /* safety; */
|
||||
BCSampleFrameMap::const_iterator it;
|
||||
for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
|
||||
const BCSampleFrame &frame = it->second;
|
||||
const BCMatrix *matrix = frame.get_sample_matrix(ob);
|
||||
if (matrix) {
|
||||
samples[it->first] = matrix;
|
||||
}
|
||||
}
|
||||
return samples.size();
|
||||
}
|
||||
|
||||
int BCSampleFrameContainer::get_matrices(Object *ob, Bone *bone, BCMatrixSampleMap &samples) const
|
||||
{
|
||||
samples.clear(); /* safety; */
|
||||
BCSampleFrameMap::const_iterator it;
|
||||
for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
|
||||
const BCSampleFrame &frame = it->second;
|
||||
const BCMatrix *sample = frame.get_sample_matrix(ob, bone);
|
||||
if (sample) {
|
||||
samples[it->first] = sample;
|
||||
}
|
||||
}
|
||||
return samples.size();
|
||||
}
|
@ -1,186 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BCAnimationCurve.h"
|
||||
#include "BCSampleData.h"
|
||||
#include "collada_utils.h"
|
||||
|
||||
#include "BKE_action.hh"
|
||||
#include "BKE_lib_id.hh"
|
||||
|
||||
/* Collection of animation curves */
|
||||
class BCAnimation {
|
||||
private:
|
||||
Object *reference = nullptr;
|
||||
bContext *mContext;
|
||||
|
||||
public:
|
||||
BCFrameSet frame_set;
|
||||
BCAnimationCurveMap curve_map;
|
||||
|
||||
BCAnimation(bContext *C, Object *ob) : mContext(C)
|
||||
{
|
||||
Main *bmain = CTX_data_main(mContext);
|
||||
reference = (Object *)BKE_id_copy(bmain, &ob->id);
|
||||
id_us_min(&reference->id);
|
||||
}
|
||||
|
||||
~BCAnimation()
|
||||
{
|
||||
BCAnimationCurveMap::iterator it;
|
||||
for (it = curve_map.begin(); it != curve_map.end(); ++it) {
|
||||
delete it->second;
|
||||
}
|
||||
|
||||
if (reference && reference->id.us == 0) {
|
||||
Main *bmain = CTX_data_main(mContext);
|
||||
BKE_id_delete(bmain, &reference->id);
|
||||
}
|
||||
curve_map.clear();
|
||||
}
|
||||
|
||||
Object *get_reference()
|
||||
{
|
||||
return reference;
|
||||
}
|
||||
};
|
||||
|
||||
using BCAnimationObjectMap = std::map<Object *, BCAnimation *>;
|
||||
|
||||
class BCSampleFrame {
|
||||
|
||||
/* Each frame on the timeline that needs to be sampled will have
|
||||
* one BCSampleFrame where we collect sample information about all objects
|
||||
* that need to be sampled for that frame. */
|
||||
|
||||
private:
|
||||
BCSampleMap sampleMap;
|
||||
|
||||
public:
|
||||
~BCSampleFrame()
|
||||
{
|
||||
BCSampleMap::iterator it;
|
||||
for (it = sampleMap.begin(); it != sampleMap.end(); ++it) {
|
||||
BCSample *sample = it->second;
|
||||
delete sample;
|
||||
}
|
||||
sampleMap.clear();
|
||||
}
|
||||
|
||||
BCSample &add(Object *ob);
|
||||
|
||||
/* Following methods return NULL if object is not in the sampleMap. */
|
||||
|
||||
/** Get the matrix for the given key, returns Unity when the key does not exist. */
|
||||
const BCSample *get_sample(Object *ob) const;
|
||||
const BCMatrix *get_sample_matrix(Object *ob) const;
|
||||
/** Get the matrix for the given Bone, returns Unity when the Object is not sampled. */
|
||||
const BCMatrix *get_sample_matrix(Object *ob, Bone *bone) const;
|
||||
|
||||
/** Check if the key is in this BCSampleFrame. */
|
||||
bool has_sample_for(Object *ob) const;
|
||||
/** Check if the Bone is in this BCSampleFrame. */
|
||||
bool has_sample_for(Object *ob, Bone *bone) const;
|
||||
};
|
||||
|
||||
using BCSampleFrameMap = std::map<int, BCSampleFrame>;
|
||||
|
||||
class BCSampleFrameContainer {
|
||||
|
||||
/*
|
||||
* The BCSampleFrameContainer stores a map of BCSampleFrame objects
|
||||
* with the timeline frame as key.
|
||||
*
|
||||
* Some details on the purpose:
|
||||
* An Animation is made of multiple FCurves where each FCurve can
|
||||
* have multiple keyframes. When we want to export the animation we
|
||||
* also can decide whether we want to export the keyframes or a set
|
||||
* of sample frames at equidistant locations (sample period).
|
||||
* In any case we must resample first need to resample it fully
|
||||
* to resolve things like:
|
||||
*
|
||||
* - animations by constraints
|
||||
* - animations by drivers
|
||||
*
|
||||
* For this purpose we need to step through the entire animation and
|
||||
* then sample each frame that contains at least one keyFrame or
|
||||
* sampleFrame. Then for each frame we have to store the transform
|
||||
* information for all exported objects in a BCSampleframe
|
||||
*
|
||||
* The entire set of BCSampleframes is finally collected into
|
||||
* a BCSampleframneContainer
|
||||
*/
|
||||
|
||||
private:
|
||||
BCSampleFrameMap sample_frames;
|
||||
|
||||
public:
|
||||
~BCSampleFrameContainer() = default;
|
||||
|
||||
BCSample &add(Object *ob, int frame_index);
|
||||
/** Return either the #BCSampleFrame or NULL if frame does not exist. */
|
||||
BCSampleFrame *get_frame(int frame_index);
|
||||
|
||||
/** Return a list of all frames that need to be sampled. */
|
||||
int get_frames(std::vector<int> &frames) const;
|
||||
int get_frames(Object *ob, BCFrames &frames) const;
|
||||
int get_frames(Object *ob, Bone *bone, BCFrames &frames) const;
|
||||
|
||||
int get_samples(Object *ob, BCFrameSampleMap &samples) const;
|
||||
int get_matrices(Object *ob, BCMatrixSampleMap &samples) const;
|
||||
int get_matrices(Object *ob, Bone *bone, BCMatrixSampleMap &samples) const;
|
||||
};
|
||||
|
||||
class BCAnimationSampler {
|
||||
private:
|
||||
BCExportSettings &export_settings;
|
||||
BCSampleFrameContainer sample_data;
|
||||
BCAnimationObjectMap objects;
|
||||
|
||||
void generate_transform(Object *ob, const BCCurveKey &key, BCAnimationCurveMap &curves);
|
||||
void generate_transforms(Object *ob,
|
||||
const std::string prep,
|
||||
const BC_animation_type type,
|
||||
BCAnimationCurveMap &curves);
|
||||
void generate_transforms(Object *ob, Bone *bone, BCAnimationCurveMap &curves);
|
||||
|
||||
void initialize_curves(BCAnimationCurveMap &curves, Object *ob);
|
||||
/**
|
||||
* Collect all keyframes from all animation curves related to the object.
|
||||
* The bc_get... functions check for NULL and correct object type.
|
||||
* The #add_keyframes_from() function checks for NULL.
|
||||
*/
|
||||
void initialize_keyframes(BCFrameSet &frameset, Object *ob);
|
||||
BCSample &sample_object(Object *ob, int frame_index, bool for_opensim);
|
||||
void update_animation_curves(BCAnimation &animation,
|
||||
BCSample &sample,
|
||||
Object *ob,
|
||||
int frame_index);
|
||||
void check_property_is_animated(
|
||||
BCAnimation &animation, float *ref, float *val, std::string data_path, int length);
|
||||
|
||||
public:
|
||||
BCAnimationSampler(BCExportSettings &export_settings, BCObjectSet &object_set);
|
||||
~BCAnimationSampler();
|
||||
|
||||
void add_object(Object *ob);
|
||||
|
||||
void sample_scene(BCExportSettings &export_settings, bool keyframe_at_end);
|
||||
|
||||
BCAnimationCurveMap *get_curves(Object *ob);
|
||||
void get_object_frames(BCFrames &frames, Object *ob);
|
||||
bool get_object_samples(BCMatrixSampleMap &samples, Object *ob);
|
||||
void get_bone_frames(BCFrames &frames, Object *ob, Bone *bone);
|
||||
bool get_bone_samples(BCMatrixSampleMap &samples, Object *ob, Bone *bone);
|
||||
|
||||
static void get_animated_from_export_set(std::set<Object *> &animated_objects,
|
||||
LinkNode &export_set);
|
||||
static void find_depending_animated(std::set<Object *> &animated_objects,
|
||||
std::set<Object *> &candidates);
|
||||
static bool is_animated_by_constraint(Object *ob,
|
||||
ListBase *conlist,
|
||||
std::set<Object *> &animated_objects);
|
||||
};
|
@ -1,230 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2008 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BCMath.h"
|
||||
#include "BlenderContext.h"
|
||||
|
||||
#include "BLI_math_matrix.h"
|
||||
|
||||
void BCQuat::rotate_to(Matrix &mat_to)
|
||||
{
|
||||
Quat qd;
|
||||
Matrix matd;
|
||||
Matrix mati;
|
||||
Matrix mat_from;
|
||||
|
||||
quat_to_mat4(mat_from, q);
|
||||
|
||||
/* Calculate the difference matrix matd between mat_from and mat_to */
|
||||
invert_m4_m4(mati, mat_from);
|
||||
mul_m4_m4m4(matd, mati, mat_to);
|
||||
|
||||
mat4_to_quat(qd, matd);
|
||||
|
||||
mul_qt_qtqt(q, qd, q); /* rotate to the final rotation to mat_to */
|
||||
}
|
||||
|
||||
BCMatrix::BCMatrix(const BCMatrix &mat)
|
||||
{
|
||||
set_transform(mat.matrix);
|
||||
}
|
||||
|
||||
BCMatrix::BCMatrix(Matrix &mat)
|
||||
{
|
||||
set_transform(mat);
|
||||
}
|
||||
|
||||
BCMatrix::BCMatrix(Object *ob)
|
||||
{
|
||||
set_transform(ob);
|
||||
}
|
||||
|
||||
BCMatrix::BCMatrix()
|
||||
{
|
||||
unit();
|
||||
}
|
||||
|
||||
BCMatrix::BCMatrix(BC_global_forward_axis global_forward_axis, BC_global_up_axis global_up_axis)
|
||||
{
|
||||
float mrot[3][3];
|
||||
float mat[4][4];
|
||||
mat3_from_axis_conversion(
|
||||
global_forward_axis, global_up_axis, BC_DEFAULT_FORWARD, BC_DEFAULT_UP, mrot);
|
||||
copy_m4_m3(mat, mrot);
|
||||
set_transform(mat);
|
||||
}
|
||||
|
||||
void BCMatrix::add_transform(const Matrix &mat, bool inverted)
|
||||
{
|
||||
add_transform(this->matrix, mat, this->matrix, inverted);
|
||||
}
|
||||
|
||||
void BCMatrix::add_transform(const BCMatrix &mat, bool inverted)
|
||||
{
|
||||
add_transform(this->matrix, mat.matrix, this->matrix, inverted);
|
||||
}
|
||||
|
||||
void BCMatrix::apply_transform(const BCMatrix &mat, bool inverted)
|
||||
{
|
||||
apply_transform(this->matrix, mat.matrix, this->matrix, inverted);
|
||||
}
|
||||
|
||||
void BCMatrix::add_transform(Matrix &to,
|
||||
const Matrix &transform,
|
||||
const Matrix &from,
|
||||
bool inverted)
|
||||
{
|
||||
if (inverted) {
|
||||
Matrix globinv;
|
||||
invert_m4_m4(globinv, transform);
|
||||
add_transform(to, globinv, from, /*inverted=*/false);
|
||||
}
|
||||
else {
|
||||
mul_m4_m4m4(to, transform, from);
|
||||
}
|
||||
}
|
||||
|
||||
void BCMatrix::apply_transform(Matrix &to,
|
||||
const Matrix &transform,
|
||||
const Matrix &from,
|
||||
bool inverse)
|
||||
{
|
||||
Matrix globinv;
|
||||
invert_m4_m4(globinv, transform);
|
||||
if (inverse) {
|
||||
add_transform(to, globinv, from, /*inverted=*/false);
|
||||
}
|
||||
else {
|
||||
mul_m4_m4m4(to, transform, from);
|
||||
mul_m4_m4m4(to, to, globinv);
|
||||
}
|
||||
}
|
||||
|
||||
void BCMatrix::add_inverted_transform(Matrix &to, const Matrix &transform, const Matrix &from)
|
||||
{
|
||||
Matrix workmat;
|
||||
invert_m4_m4(workmat, transform);
|
||||
mul_m4_m4m4(to, workmat, from);
|
||||
}
|
||||
|
||||
void BCMatrix::set_transform(Object *ob)
|
||||
{
|
||||
Matrix lmat;
|
||||
|
||||
BKE_object_matrix_local_get(ob, lmat);
|
||||
copy_m4_m4(matrix, lmat);
|
||||
|
||||
mat4_decompose(this->loc, this->q, this->size, lmat);
|
||||
quat_to_compatible_eul(this->rot, ob->rot, this->q);
|
||||
}
|
||||
|
||||
void BCMatrix::set_transform(Matrix &mat)
|
||||
{
|
||||
copy_m4_m4(matrix, mat);
|
||||
mat4_decompose(this->loc, this->q, this->size, mat);
|
||||
quat_to_eul(this->rot, this->q);
|
||||
}
|
||||
|
||||
void BCMatrix::copy(Matrix &r, Matrix &a)
|
||||
{
|
||||
/* destination comes first: */
|
||||
memcpy(r, a, sizeof(Matrix));
|
||||
}
|
||||
|
||||
void BCMatrix::transpose(Matrix &mat)
|
||||
{
|
||||
transpose_m4(mat);
|
||||
}
|
||||
|
||||
void BCMatrix::sanitize(Matrix &mat, int precision)
|
||||
{
|
||||
for (auto &row : mat) {
|
||||
for (float &cell : row) {
|
||||
double val = double(cell);
|
||||
val = double_round(val, precision);
|
||||
cell = float(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BCMatrix::sanitize(DMatrix &mat, int precision)
|
||||
{
|
||||
for (auto &row : mat) {
|
||||
for (double &cell : row) {
|
||||
cell = double_round(cell, precision);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BCMatrix::unit()
|
||||
{
|
||||
unit_m4(this->matrix);
|
||||
mat4_decompose(this->loc, this->q, this->size, this->matrix);
|
||||
quat_to_eul(this->rot, this->q);
|
||||
}
|
||||
|
||||
void BCMatrix::get_matrix(DMatrix &mat, const bool transposed, const int precision) const
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
float val = (transposed) ? matrix[j][i] : matrix[i][j];
|
||||
if (precision >= 0) {
|
||||
val = floor(val * pow(10, precision) + 0.5) / pow(10, precision);
|
||||
}
|
||||
mat[i][j] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BCMatrix::get_matrix(Matrix &mat,
|
||||
const bool transposed,
|
||||
const int precision,
|
||||
const bool inverted) const
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
float val = (transposed) ? matrix[j][i] : matrix[i][j];
|
||||
if (precision >= 0) {
|
||||
val = floor(val * pow(10, precision) + 0.5) / pow(10, precision);
|
||||
}
|
||||
mat[i][j] = val;
|
||||
}
|
||||
}
|
||||
|
||||
if (inverted) {
|
||||
invert_m4(mat);
|
||||
}
|
||||
}
|
||||
|
||||
bool BCMatrix::in_range(const BCMatrix &other, float distance) const
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
if (fabs(other.matrix[i][j] - matrix[i][j]) > distance) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
float (&BCMatrix::location() const)[3]
|
||||
{
|
||||
return loc;
|
||||
}
|
||||
|
||||
float (&BCMatrix::rotation() const)[3]
|
||||
{
|
||||
return rot;
|
||||
}
|
||||
|
||||
float (&BCMatrix::scale() const)[3]
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
float (&BCMatrix::quat() const)[4]
|
||||
{
|
||||
return q;
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BKE_object.hh"
|
||||
#include "BLI_math_rotation.h"
|
||||
#include "BLI_math_vector.h"
|
||||
#include "BlenderTypes.h"
|
||||
|
||||
class BCQuat {
|
||||
private:
|
||||
mutable Quat q;
|
||||
|
||||
public:
|
||||
BCQuat(const BCQuat &other)
|
||||
{
|
||||
copy_v4_v4(q, other.q);
|
||||
}
|
||||
|
||||
BCQuat(Quat &other)
|
||||
{
|
||||
copy_v4_v4(q, other);
|
||||
}
|
||||
|
||||
BCQuat()
|
||||
{
|
||||
unit_qt(q);
|
||||
}
|
||||
|
||||
Quat &quat()
|
||||
{
|
||||
return q;
|
||||
}
|
||||
|
||||
void rotate_to(Matrix &mat_to);
|
||||
};
|
||||
|
||||
class BCMatrix {
|
||||
|
||||
private:
|
||||
mutable float matrix[4][4];
|
||||
mutable float size[3];
|
||||
mutable float rot[3];
|
||||
mutable float loc[3];
|
||||
mutable float q[4];
|
||||
|
||||
void unit();
|
||||
void copy(Matrix &r, Matrix &a);
|
||||
|
||||
public:
|
||||
float (&location() const)[3];
|
||||
float (&rotation() const)[3];
|
||||
float (&scale() const)[3];
|
||||
float (&quat() const)[4];
|
||||
|
||||
BCMatrix(BC_global_forward_axis global_forward_axis, BC_global_up_axis global_up_axis);
|
||||
BCMatrix(const BCMatrix &mat);
|
||||
BCMatrix(Matrix &mat);
|
||||
BCMatrix(Object *ob);
|
||||
BCMatrix();
|
||||
|
||||
/**
|
||||
* We need double here because the OpenCollada API needs it.
|
||||
* precision = -1 indicates to not limit the precision.
|
||||
*/
|
||||
void get_matrix(DMatrix &matrix, bool transposed = false, int precision = -1) const;
|
||||
void get_matrix(Matrix &matrix,
|
||||
bool transposed = false,
|
||||
int precision = -1,
|
||||
bool inverted = false) const;
|
||||
void set_transform(Object *ob);
|
||||
void set_transform(Matrix &mat);
|
||||
void add_transform(Matrix &to,
|
||||
const Matrix &transform,
|
||||
const Matrix &from,
|
||||
bool inverted = false);
|
||||
void apply_transform(Matrix &to,
|
||||
const Matrix &transform,
|
||||
const Matrix &from,
|
||||
bool inverse = false);
|
||||
void add_inverted_transform(Matrix &to, const Matrix &transform, const Matrix &from);
|
||||
void add_transform(const Matrix &matrix, bool inverted = false);
|
||||
void add_transform(const BCMatrix &matrix, bool inverted = false);
|
||||
void apply_transform(const BCMatrix &matrix, bool inverted = false);
|
||||
|
||||
bool in_range(const BCMatrix &other, float distance) const;
|
||||
|
||||
static void sanitize(Matrix &matrix, int precision);
|
||||
static void sanitize(DMatrix &matrix, int precision);
|
||||
static void transpose(Matrix &matrix);
|
||||
};
|
@ -1,81 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2008 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BCSampleData.h"
|
||||
#include "collada_utils.h"
|
||||
|
||||
BCSample::~BCSample()
|
||||
{
|
||||
BCBoneMatrixMap::iterator it;
|
||||
for (it = bonemats.begin(); it != bonemats.end(); ++it) {
|
||||
delete it->second;
|
||||
}
|
||||
}
|
||||
|
||||
void BCSample::add_bone_matrix(Bone *bone, Matrix &mat)
|
||||
{
|
||||
BCMatrix *matrix;
|
||||
BCBoneMatrixMap::const_iterator it = bonemats.find(bone);
|
||||
if (it != bonemats.end()) {
|
||||
throw std::invalid_argument("bone " + std::string(bone->name) + " already defined before");
|
||||
}
|
||||
matrix = new BCMatrix(mat);
|
||||
bonemats[bone] = matrix;
|
||||
}
|
||||
|
||||
bool BCSample::get_value(std::string channel_target, const int array_index, float *val) const
|
||||
{
|
||||
std::string bname = bc_string_before(channel_target, ".");
|
||||
std::string channel_type = bc_string_after(channel_target, ".");
|
||||
|
||||
const BCMatrix *matrix = &obmat;
|
||||
if (bname != channel_target) {
|
||||
bname = bname.substr(2);
|
||||
bname = bc_string_before(bname, "\"");
|
||||
BCBoneMatrixMap::const_iterator it;
|
||||
for (it = bonemats.begin(); it != bonemats.end(); ++it) {
|
||||
Bone *bone = it->first;
|
||||
if (bname == bone->name) {
|
||||
matrix = it->second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
matrix = &obmat;
|
||||
}
|
||||
|
||||
if (channel_type == "location") {
|
||||
*val = matrix->location()[array_index];
|
||||
}
|
||||
else if (channel_type == "scale") {
|
||||
*val = matrix->scale()[array_index];
|
||||
}
|
||||
else if (ELEM(channel_type, "rotation", "rotation_euler")) {
|
||||
*val = matrix->rotation()[array_index];
|
||||
}
|
||||
else if (channel_type == "rotation_quaternion") {
|
||||
*val = matrix->quat()[array_index];
|
||||
}
|
||||
else {
|
||||
*val = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const BCMatrix *BCSample::get_matrix(Bone *bone) const
|
||||
{
|
||||
BCBoneMatrixMap::const_iterator it = bonemats.find(bone);
|
||||
if (it == bonemats.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
const BCMatrix &BCSample::get_matrix() const
|
||||
{
|
||||
return obmat;
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2008 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "BCMath.h"
|
||||
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
using BCBoneMatrixMap = std::map<Bone *, BCMatrix *>;
|
||||
|
||||
class BCSample {
|
||||
private:
|
||||
BCMatrix obmat;
|
||||
BCBoneMatrixMap bonemats; /* For Armature animation */
|
||||
|
||||
public:
|
||||
BCSample(Object *ob) : obmat(ob) {}
|
||||
|
||||
~BCSample();
|
||||
|
||||
void add_bone_matrix(Bone *bone, Matrix &mat);
|
||||
|
||||
/** Get channel value. */
|
||||
bool get_value(std::string channel_target, int array_index, float *val) const;
|
||||
const BCMatrix &get_matrix() const;
|
||||
const BCMatrix *get_matrix(Bone *bone) const; /* returns NULL if bone is not animated */
|
||||
};
|
||||
|
||||
using BCSampleMap = std::map<Object *, BCSample *>;
|
||||
using BCFrameSampleMap = std::map<int, const BCSample *>;
|
||||
using BCMatrixSampleMap = std::map<int, const BCMatrix *>;
|
@ -1,148 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2009-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "BlenderContext.h"
|
||||
#include "ExportSettings.h"
|
||||
|
||||
#include "BKE_layer.hh"
|
||||
#include "BKE_scene.hh"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
|
||||
bool bc_is_base_node(LinkNode *export_set, Object *ob, const Scene *scene, ViewLayer *view_layer)
|
||||
{
|
||||
Object *root = bc_get_highest_exported_ancestor_or_self(export_set, ob, scene, view_layer);
|
||||
return (root == ob);
|
||||
}
|
||||
|
||||
Object *bc_get_highest_exported_ancestor_or_self(LinkNode *export_set,
|
||||
Object *ob,
|
||||
const Scene *scene,
|
||||
ViewLayer *view_layer)
|
||||
{
|
||||
Object *ancestor = ob;
|
||||
while (ob->parent) {
|
||||
if (bc_is_in_Export_set(export_set, ob->parent, scene, view_layer)) {
|
||||
ancestor = ob->parent;
|
||||
}
|
||||
ob = ob->parent;
|
||||
}
|
||||
return ancestor;
|
||||
}
|
||||
|
||||
void bc_get_children(std::vector<Object *> &child_set,
|
||||
Object *ob,
|
||||
const Scene *scene,
|
||||
ViewLayer *view_layer)
|
||||
{
|
||||
BKE_view_layer_synced_ensure(scene, view_layer);
|
||||
LISTBASE_FOREACH (Base *, base, BKE_view_layer_object_bases_get(view_layer)) {
|
||||
Object *cob = base->object;
|
||||
if (cob->parent == ob) {
|
||||
switch (ob->type) {
|
||||
case OB_MESH:
|
||||
case OB_CAMERA:
|
||||
case OB_LAMP:
|
||||
case OB_EMPTY:
|
||||
case OB_ARMATURE:
|
||||
child_set.push_back(cob);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool bc_is_in_Export_set(LinkNode *export_set,
|
||||
Object *ob,
|
||||
const Scene *scene,
|
||||
ViewLayer *view_layer)
|
||||
{
|
||||
bool to_export = (BLI_linklist_index(export_set, ob) != -1);
|
||||
|
||||
if (!to_export) {
|
||||
/* Mark this object as to_export even if it is not in the
|
||||
* export list, but it contains children to export. */
|
||||
|
||||
std::vector<Object *> children;
|
||||
bc_get_children(children, ob, scene, view_layer);
|
||||
for (Object *child : children) {
|
||||
if (bc_is_in_Export_set(export_set, child, scene, view_layer)) {
|
||||
to_export = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return to_export;
|
||||
}
|
||||
|
||||
int bc_is_marked(Object *ob)
|
||||
{
|
||||
return ob && (ob->id.tag & ID_TAG_DOIT);
|
||||
}
|
||||
|
||||
void bc_remove_mark(Object *ob)
|
||||
{
|
||||
ob->id.tag &= ~ID_TAG_DOIT;
|
||||
}
|
||||
|
||||
void bc_set_mark(Object *ob)
|
||||
{
|
||||
ob->id.tag |= ID_TAG_DOIT;
|
||||
}
|
||||
|
||||
BlenderContext::BlenderContext(bContext *C)
|
||||
{
|
||||
context = C;
|
||||
main = CTX_data_main(C);
|
||||
scene = CTX_data_scene(C);
|
||||
view_layer = CTX_data_view_layer(C);
|
||||
depsgraph = nullptr; /* create only when needed */
|
||||
}
|
||||
|
||||
bContext *BlenderContext::get_context()
|
||||
{
|
||||
return context;
|
||||
}
|
||||
|
||||
Depsgraph *BlenderContext::get_depsgraph()
|
||||
{
|
||||
if (!depsgraph) {
|
||||
depsgraph = BKE_scene_ensure_depsgraph(main, scene, view_layer);
|
||||
}
|
||||
return depsgraph;
|
||||
}
|
||||
|
||||
Scene *BlenderContext::get_scene()
|
||||
{
|
||||
return scene;
|
||||
}
|
||||
|
||||
Scene *BlenderContext::get_evaluated_scene()
|
||||
{
|
||||
Scene *scene_eval = DEG_get_evaluated_scene(get_depsgraph());
|
||||
return scene_eval;
|
||||
}
|
||||
|
||||
Object *BlenderContext::get_evaluated_object(Object *ob)
|
||||
{
|
||||
Object *ob_eval = DEG_get_evaluated(depsgraph, ob);
|
||||
return ob_eval;
|
||||
}
|
||||
|
||||
ViewLayer *BlenderContext::get_view_layer()
|
||||
{
|
||||
return view_layer;
|
||||
}
|
||||
|
||||
Main *BlenderContext::get_main()
|
||||
{
|
||||
return main;
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_main.hh"
|
||||
#include "BLI_linklist.h"
|
||||
#include "BlenderTypes.h"
|
||||
#include "DEG_depsgraph.hh"
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
#include "DNA_layer_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
static const BC_global_forward_axis BC_DEFAULT_FORWARD = BC_GLOBAL_FORWARD_Y;
|
||||
static const BC_global_up_axis BC_DEFAULT_UP = BC_GLOBAL_UP_Z;
|
||||
|
||||
bool bc_is_in_Export_set(LinkNode *export_set,
|
||||
Object *ob,
|
||||
const Scene *scene,
|
||||
ViewLayer *view_layer);
|
||||
bool bc_is_base_node(LinkNode *export_set, Object *ob, const Scene *scene, ViewLayer *view_layer);
|
||||
/**
|
||||
* Returns the highest selected ancestor
|
||||
* returns NULL if no ancestor is selected
|
||||
* IMPORTANT: This function expects that all exported objects have set:
|
||||
* `ob->id.tag & ID_TAG_DOIT`
|
||||
*/
|
||||
Object *bc_get_highest_exported_ancestor_or_self(LinkNode *export_set,
|
||||
Object *ob,
|
||||
const Scene *scene,
|
||||
ViewLayer *view_layer);
|
||||
int bc_is_marked(Object *ob);
|
||||
void bc_remove_mark(Object *ob);
|
||||
void bc_set_mark(Object *ob);
|
||||
|
||||
class BlenderContext {
|
||||
private:
|
||||
bContext *context;
|
||||
Depsgraph *depsgraph;
|
||||
Scene *scene;
|
||||
ViewLayer *view_layer;
|
||||
Main *main;
|
||||
|
||||
public:
|
||||
BlenderContext(bContext *C);
|
||||
bContext *get_context();
|
||||
Depsgraph *get_depsgraph();
|
||||
Scene *get_scene();
|
||||
Scene *get_evaluated_scene();
|
||||
Object *get_evaluated_object(Object *ob);
|
||||
ViewLayer *get_view_layer();
|
||||
Main *get_main();
|
||||
};
|
@ -1,33 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
using Vector = float[3];
|
||||
using Quat = float[4];
|
||||
using Color = float[4];
|
||||
using Matrix = float[4][4];
|
||||
using DMatrix = double[4][4];
|
||||
|
||||
enum BC_global_forward_axis {
|
||||
BC_GLOBAL_FORWARD_X = 0,
|
||||
BC_GLOBAL_FORWARD_Y = 1,
|
||||
BC_GLOBAL_FORWARD_Z = 2,
|
||||
BC_GLOBAL_FORWARD_MINUS_X = 3,
|
||||
BC_GLOBAL_FORWARD_MINUS_Y = 4,
|
||||
BC_GLOBAL_FORWARD_MINUS_Z = 5
|
||||
};
|
||||
|
||||
enum BC_global_up_axis {
|
||||
BC_GLOBAL_UP_X = 0,
|
||||
BC_GLOBAL_UP_Y = 1,
|
||||
BC_GLOBAL_UP_Z = 2,
|
||||
BC_GLOBAL_UP_MINUS_X = 3,
|
||||
BC_GLOBAL_UP_MINUS_Y = 4,
|
||||
BC_GLOBAL_UP_MINUS_Z = 5
|
||||
};
|
@ -1,127 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2006 Blender Authors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
remove_strict_flags()
|
||||
find_file(OPENCOLLADA_ANIMATION_CLIP
|
||||
NAMES
|
||||
COLLADAFWAnimationClip.h
|
||||
PATHS
|
||||
${OPENCOLLADA_INCLUDE_DIRS}
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
if(OPENCOLLADA_ANIMATION_CLIP)
|
||||
add_definitions(-DWITH_OPENCOLLADA_ANIMATION_CLIP)
|
||||
endif()
|
||||
|
||||
# In CMAKE version 3.21 and up, we can instead use the NO_CACHE option for
|
||||
# find_file so we don't need to clear it from the cache here.
|
||||
unset(OPENCOLLADA_ANIMATION_CLIP CACHE)
|
||||
|
||||
set(INC
|
||||
.
|
||||
../../editors/include
|
||||
../../ikplugin
|
||||
../../makesrna
|
||||
../../../../intern/iksolver/extern
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
${OPENCOLLADA_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
set(SRC
|
||||
AnimationClipExporter.cpp
|
||||
AnimationExporter.cpp
|
||||
AnimationImporter.cpp
|
||||
ArmatureExporter.cpp
|
||||
ArmatureImporter.cpp
|
||||
BCAnimationCurve.cpp
|
||||
BCAnimationSampler.cpp
|
||||
BCMath.cpp
|
||||
BCSampleData.cpp
|
||||
BlenderContext.cpp
|
||||
CameraExporter.cpp
|
||||
ControllerExporter.cpp
|
||||
DocumentExporter.cpp
|
||||
DocumentImporter.cpp
|
||||
EffectExporter.cpp
|
||||
ErrorHandler.cpp
|
||||
ExportSettings.cpp
|
||||
ExtraHandler.cpp
|
||||
ExtraTags.cpp
|
||||
GeometryExporter.cpp
|
||||
ImageExporter.cpp
|
||||
ImportSettings.cpp
|
||||
InstanceWriter.cpp
|
||||
LightExporter.cpp
|
||||
MaterialExporter.cpp
|
||||
Materials.cpp
|
||||
MeshImporter.cpp
|
||||
SceneExporter.cpp
|
||||
SkinInfo.cpp
|
||||
TransformReader.cpp
|
||||
TransformWriter.cpp
|
||||
collada.cpp
|
||||
collada_internal.cpp
|
||||
collada_utils.cpp
|
||||
|
||||
AnimationClipExporter.h
|
||||
AnimationExporter.h
|
||||
AnimationImporter.h
|
||||
ArmatureExporter.h
|
||||
ArmatureImporter.h
|
||||
BCAnimationCurve.h
|
||||
BCAnimationSampler.h
|
||||
BCMath.h
|
||||
BCSampleData.h
|
||||
BlenderContext.h
|
||||
BlenderTypes.h
|
||||
CameraExporter.h
|
||||
ControllerExporter.h
|
||||
DocumentExporter.h
|
||||
DocumentImporter.h
|
||||
EffectExporter.h
|
||||
ErrorHandler.h
|
||||
ExportSettings.h
|
||||
ExtraHandler.h
|
||||
ExtraTags.h
|
||||
GeometryExporter.h
|
||||
ImageExporter.h
|
||||
ImportSettings.h
|
||||
InstanceWriter.h
|
||||
LightExporter.h
|
||||
MaterialExporter.h
|
||||
Materials.h
|
||||
MeshImporter.h
|
||||
SceneExporter.h
|
||||
SkinInfo.h
|
||||
TransformReader.h
|
||||
TransformWriter.h
|
||||
collada.h
|
||||
collada_internal.h
|
||||
collada_utils.h
|
||||
)
|
||||
|
||||
set(LIB
|
||||
${OPENCOLLADA_LIBRARIES}
|
||||
${XML2_LIBRARIES}
|
||||
PRIVATE bf::animrig
|
||||
PRIVATE bf::blenkernel
|
||||
PRIVATE bf::blenlib
|
||||
PRIVATE bf::blentranslation
|
||||
PRIVATE bf::bmesh
|
||||
PRIVATE bf::depsgraph
|
||||
PRIVATE bf::dna
|
||||
PRIVATE bf::imbuf
|
||||
PRIVATE bf::intern::guardedalloc
|
||||
PRIVATE bf::nodes
|
||||
PRIVATE bf::windowmanager
|
||||
)
|
||||
|
||||
if(WITH_BUILDINFO)
|
||||
add_definitions(-DWITH_BUILDINFO)
|
||||
endif()
|
||||
|
||||
blender_add_lib(bf_io_collada "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
@ -1,86 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2010-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "COLLADASWCamera.h"
|
||||
|
||||
#include "DNA_camera_types.h"
|
||||
|
||||
#include "CameraExporter.h"
|
||||
|
||||
#include "collada_internal.h"
|
||||
|
||||
CamerasExporter::CamerasExporter(COLLADASW::StreamWriter *sw, BCExportSettings &export_settings)
|
||||
: COLLADASW::LibraryCameras(sw), export_settings(export_settings)
|
||||
{
|
||||
}
|
||||
|
||||
template<class Functor>
|
||||
void forEachCameraObjectInExportSet(Scene *sce, Functor &f, LinkNode *export_set)
|
||||
{
|
||||
LinkNode *node;
|
||||
for (node = export_set; node; node = node->next) {
|
||||
Object *ob = (Object *)node->link;
|
||||
|
||||
if (ob->type == OB_CAMERA && ob->data) {
|
||||
f(ob, sce);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CamerasExporter::exportCameras(Scene *sce)
|
||||
{
|
||||
openLibrary();
|
||||
|
||||
forEachCameraObjectInExportSet(sce, *this, this->export_settings.get_export_set());
|
||||
|
||||
closeLibrary();
|
||||
}
|
||||
void CamerasExporter::operator()(Object *ob, Scene *sce)
|
||||
{
|
||||
Camera *cam = (Camera *)ob->data;
|
||||
std::string cam_id(get_camera_id(ob));
|
||||
std::string cam_name(id_name(cam));
|
||||
|
||||
switch (cam->type) {
|
||||
case CAM_CUSTOM:
|
||||
case CAM_PANO:
|
||||
case CAM_PERSP: {
|
||||
COLLADASW::PerspectiveOptic persp(mSW);
|
||||
persp.setXFov(RAD2DEGF(focallength_to_fov(cam->lens, cam->sensor_x)), "xfov");
|
||||
persp.setAspectRatio(float(sce->r.xsch) / float(sce->r.ysch), false, "aspect_ratio");
|
||||
persp.setZFar(cam->clip_end, false, "zfar");
|
||||
persp.setZNear(cam->clip_start, false, "znear");
|
||||
COLLADASW::Camera ccam(mSW, &persp, cam_id, cam_name);
|
||||
exportBlenderProfile(ccam, cam);
|
||||
addCamera(ccam);
|
||||
|
||||
break;
|
||||
}
|
||||
case CAM_ORTHO:
|
||||
default: {
|
||||
COLLADASW::OrthographicOptic ortho(mSW);
|
||||
ortho.setXMag(cam->ortho_scale / 2, "xmag");
|
||||
ortho.setAspectRatio(float(sce->r.xsch) / float(sce->r.ysch), false, "aspect_ratio");
|
||||
ortho.setZFar(cam->clip_end, false, "zfar");
|
||||
ortho.setZNear(cam->clip_start, false, "znear");
|
||||
COLLADASW::Camera ccam(mSW, &ortho, cam_id, cam_name);
|
||||
exportBlenderProfile(ccam, cam);
|
||||
addCamera(ccam);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool CamerasExporter::exportBlenderProfile(COLLADASW::Camera &cm, Camera *cam)
|
||||
{
|
||||
cm.addExtraTechniqueParameter("blender", "shiftx", cam->shiftx);
|
||||
cm.addExtraTechniqueParameter("blender", "shifty", cam->shifty);
|
||||
cm.addExtraTechniqueParameter("blender", "dof_distance", cam->dof.focus_distance);
|
||||
return true;
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "COLLADASWLibraryCameras.h"
|
||||
#include "COLLADASWStreamWriter.h"
|
||||
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "DNA_camera_types.h"
|
||||
#include "ExportSettings.h"
|
||||
|
||||
class CamerasExporter : COLLADASW::LibraryCameras {
|
||||
public:
|
||||
CamerasExporter(COLLADASW::StreamWriter *sw, BCExportSettings &export_settings);
|
||||
void exportCameras(Scene *sce);
|
||||
void operator()(Object *ob, Scene *sce);
|
||||
|
||||
private:
|
||||
bool exportBlenderProfile(COLLADASW::Camera &cm, Camera *cam);
|
||||
BCExportSettings &export_settings;
|
||||
};
|
@ -1,628 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2010-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include "COLLADASWBaseInputElement.h"
|
||||
#include "COLLADASWInstanceController.h"
|
||||
#include "COLLADASWPrimitves.h"
|
||||
#include "COLLADASWSource.h"
|
||||
|
||||
#include "DNA_action_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
||||
#include "BKE_action.hh"
|
||||
#include "BKE_armature.hh"
|
||||
#include "BKE_deform.hh"
|
||||
#include "BKE_key.hh"
|
||||
#include "BKE_lib_id.hh"
|
||||
#include "BKE_mesh.hh"
|
||||
|
||||
#include "ED_armature.hh"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
|
||||
#include "ControllerExporter.h"
|
||||
#include "GeometryExporter.h"
|
||||
|
||||
#include "collada_utils.h"
|
||||
|
||||
bool ControllerExporter::is_skinned_mesh(Object *ob)
|
||||
{
|
||||
return bc_get_assigned_armature(ob) != nullptr;
|
||||
}
|
||||
|
||||
void ControllerExporter::write_bone_URLs(COLLADASW::InstanceController &ins,
|
||||
Object *ob_arm,
|
||||
Bone *bone)
|
||||
{
|
||||
if (bc_is_root_bone(bone, this->export_settings.get_deform_bones_only())) {
|
||||
std::string node_id = translate_id(id_name(ob_arm) + "_" + bone->name);
|
||||
ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, node_id));
|
||||
}
|
||||
else {
|
||||
LISTBASE_FOREACH (Bone *, child, &bone->childbase) {
|
||||
write_bone_URLs(ins, ob_arm, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ControllerExporter::add_instance_controller(Object *ob)
|
||||
{
|
||||
Object *ob_arm = bc_get_assigned_armature(ob);
|
||||
bArmature *arm = (bArmature *)ob_arm->data;
|
||||
|
||||
const std::string &controller_id = get_controller_id(ob_arm, ob);
|
||||
|
||||
COLLADASW::InstanceController ins(mSW);
|
||||
ins.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, controller_id));
|
||||
|
||||
Mesh *mesh = (Mesh *)ob->data;
|
||||
if (mesh->deform_verts().is_empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* write root bone URLs */
|
||||
LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) {
|
||||
write_bone_URLs(ins, ob_arm, bone);
|
||||
}
|
||||
|
||||
InstanceWriter::add_material_bindings(
|
||||
ins.getBindMaterial(), ob, this->export_settings.get_active_uv_only());
|
||||
|
||||
ins.add();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ControllerExporter::export_controllers()
|
||||
{
|
||||
Scene *sce = blender_context.get_scene();
|
||||
openLibrary();
|
||||
|
||||
GeometryFunctor gf;
|
||||
gf.forEachMeshObjectInExportSet<ControllerExporter>(
|
||||
sce, *this, this->export_settings.get_export_set());
|
||||
|
||||
closeLibrary();
|
||||
}
|
||||
|
||||
void ControllerExporter::operator()(Object *ob)
|
||||
{
|
||||
Object *ob_arm = bc_get_assigned_armature(ob);
|
||||
Key *key = BKE_key_from_object(ob);
|
||||
|
||||
if (ob_arm) {
|
||||
export_skin_controller(ob, ob_arm);
|
||||
}
|
||||
if (key && this->export_settings.get_include_shapekeys()) {
|
||||
export_morph_controller(ob, key);
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
|
||||
bool ArmatureExporter::already_written(Object *ob_arm)
|
||||
{
|
||||
return std::find(written_armatures.begin(), written_armatures.end(), ob_arm) !=
|
||||
written_armatures.end();
|
||||
}
|
||||
|
||||
void ArmatureExporter::wrote(Object *ob_arm)
|
||||
{
|
||||
written_armatures.push_back(ob_arm);
|
||||
}
|
||||
|
||||
void ArmatureExporter::find_objects_using_armature(Object *ob_arm,
|
||||
std::vector<Object *> &objects,
|
||||
Scene *sce)
|
||||
{
|
||||
objects.clear();
|
||||
|
||||
Base *base = (Base *)sce->base.first;
|
||||
while (base) {
|
||||
Object *ob = base->object;
|
||||
|
||||
if (ob->type == OB_MESH && get_assigned_armature(ob) == ob_arm) {
|
||||
objects.push_back(ob);
|
||||
}
|
||||
|
||||
base = base->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string ControllerExporter::get_controller_id(Object *ob_arm, Object *ob)
|
||||
{
|
||||
return translate_id(id_name(ob_arm)) + "_" + translate_id(id_name(ob)) +
|
||||
SKIN_CONTROLLER_ID_SUFFIX;
|
||||
}
|
||||
|
||||
std::string ControllerExporter::get_controller_id(Key *key, Object *ob)
|
||||
{
|
||||
return translate_id(id_name(ob)) + MORPH_CONTROLLER_ID_SUFFIX;
|
||||
}
|
||||
|
||||
void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
|
||||
{
|
||||
/* joint names
|
||||
* joint inverse bind matrices
|
||||
* vertex weights */
|
||||
|
||||
/* input:
|
||||
* joint names: ob -> vertex group names
|
||||
* vertex group weights: mesh->dvert -> groups -> index, weight */
|
||||
|
||||
bool use_instantiation = this->export_settings.get_use_object_instantiation();
|
||||
Mesh *mesh;
|
||||
|
||||
if (((Mesh *)ob->data)->deform_verts().is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mesh = bc_get_mesh_copy(blender_context,
|
||||
ob,
|
||||
this->export_settings.get_export_mesh_type(),
|
||||
this->export_settings.get_apply_modifiers(),
|
||||
this->export_settings.get_triangulate());
|
||||
|
||||
std::string controller_name = id_name(ob_arm);
|
||||
std::string controller_id = get_controller_id(ob_arm, ob);
|
||||
|
||||
openSkin(controller_id,
|
||||
controller_name,
|
||||
COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob, use_instantiation)));
|
||||
|
||||
add_bind_shape_mat(ob);
|
||||
|
||||
const ListBase *defbase = BKE_object_defgroup_list(ob);
|
||||
std::string joints_source_id = add_joints_source(ob_arm, defbase, controller_id);
|
||||
std::string inv_bind_mat_source_id = add_inv_bind_mats_source(ob_arm, defbase, controller_id);
|
||||
|
||||
std::list<int> vcounts;
|
||||
std::list<int> joints;
|
||||
std::list<float> weights;
|
||||
|
||||
{
|
||||
int i, j;
|
||||
|
||||
/* def group index -> joint index */
|
||||
std::vector<int> joint_index_by_def_index;
|
||||
const bDeformGroup *def;
|
||||
|
||||
for (def = (const bDeformGroup *)defbase->first, i = 0, j = 0; def; def = def->next, i++) {
|
||||
if (is_bone_defgroup(ob_arm, def)) {
|
||||
joint_index_by_def_index.push_back(j++);
|
||||
}
|
||||
else {
|
||||
joint_index_by_def_index.push_back(-1);
|
||||
}
|
||||
}
|
||||
|
||||
const MDeformVert *dvert = mesh->deform_verts().data();
|
||||
int oob_counter = 0;
|
||||
for (i = 0; i < mesh->verts_num; i++) {
|
||||
const MDeformVert *vert = &dvert[i];
|
||||
std::map<int, float> jw;
|
||||
|
||||
/* We're normalizing the weights later */
|
||||
float sumw = 0.0f;
|
||||
|
||||
for (j = 0; j < vert->totweight; j++) {
|
||||
uint idx = vert->dw[j].def_nr;
|
||||
if (idx >= joint_index_by_def_index.size()) {
|
||||
/* XXX: Maybe better find out where and
|
||||
* why the Out Of Bound indexes get created? */
|
||||
oob_counter += 1;
|
||||
}
|
||||
else {
|
||||
int joint_index = joint_index_by_def_index[idx];
|
||||
if (joint_index != -1 && vert->dw[j].weight > 0.0f) {
|
||||
jw[joint_index] += vert->dw[j].weight;
|
||||
sumw += vert->dw[j].weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sumw > 0.0f) {
|
||||
float invsumw = 1.0f / sumw;
|
||||
vcounts.push_back(jw.size());
|
||||
for (auto &index_and_weight : jw) {
|
||||
joints.push_back(index_and_weight.first);
|
||||
weights.push_back(invsumw * index_and_weight.second);
|
||||
}
|
||||
}
|
||||
else {
|
||||
vcounts.push_back(0);
|
||||
#if 0
|
||||
vcounts.push_back(1);
|
||||
joints.push_back(-1);
|
||||
weights.push_back(1.0f);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (oob_counter > 0) {
|
||||
fprintf(stderr,
|
||||
"Ignored %d Vertex weights which use index to non existing VGroup %zu.\n",
|
||||
oob_counter,
|
||||
joint_index_by_def_index.size());
|
||||
}
|
||||
}
|
||||
|
||||
std::string weights_source_id = add_weights_source(mesh, controller_id, weights);
|
||||
add_joints_element(defbase, joints_source_id, inv_bind_mat_source_id);
|
||||
add_vertex_weights_element(weights_source_id, joints_source_id, vcounts, joints);
|
||||
|
||||
BKE_id_free(nullptr, mesh);
|
||||
|
||||
closeSkin();
|
||||
closeController();
|
||||
}
|
||||
|
||||
void ControllerExporter::export_morph_controller(Object *ob, Key *key)
|
||||
{
|
||||
bool use_instantiation = this->export_settings.get_use_object_instantiation();
|
||||
Mesh *mesh;
|
||||
|
||||
mesh = bc_get_mesh_copy(blender_context,
|
||||
ob,
|
||||
this->export_settings.get_export_mesh_type(),
|
||||
this->export_settings.get_apply_modifiers(),
|
||||
this->export_settings.get_triangulate());
|
||||
|
||||
std::string controller_name = id_name(ob) + "-morph";
|
||||
std::string controller_id = get_controller_id(key, ob);
|
||||
|
||||
openMorph(
|
||||
controller_id,
|
||||
controller_name,
|
||||
COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob, use_instantiation)));
|
||||
|
||||
std::string targets_id = add_morph_targets(key, ob);
|
||||
std::string morph_weights_id = add_morph_weights(key, ob);
|
||||
|
||||
COLLADASW::TargetsElement targets(mSW);
|
||||
|
||||
COLLADASW::InputList &input = targets.getInputList();
|
||||
|
||||
input.push_back(COLLADASW::Input(
|
||||
COLLADASW::InputSemantic::MORPH_TARGET, /* constant declared in COLLADASWInputList.h */
|
||||
COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, targets_id)));
|
||||
input.push_back(
|
||||
COLLADASW::Input(COLLADASW::InputSemantic::MORPH_WEIGHT,
|
||||
COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, morph_weights_id)));
|
||||
targets.add();
|
||||
|
||||
BKE_id_free(nullptr, mesh);
|
||||
|
||||
/* support for animations
|
||||
* can also try the base element and param alternative */
|
||||
add_weight_extras(key);
|
||||
closeMorph();
|
||||
closeController();
|
||||
}
|
||||
|
||||
std::string ControllerExporter::add_morph_targets(Key *key, Object *ob)
|
||||
{
|
||||
std::string source_id = translate_id(id_name(ob)) + TARGETS_SOURCE_ID_SUFFIX;
|
||||
|
||||
COLLADASW::IdRefSource source(mSW);
|
||||
source.setId(source_id);
|
||||
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
|
||||
source.setAccessorCount(key->totkey - 1);
|
||||
source.setAccessorStride(1);
|
||||
|
||||
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
||||
param.emplace_back("IDREF");
|
||||
|
||||
source.prepareToAppendValues();
|
||||
|
||||
KeyBlock *kb = (KeyBlock *)key->block.first;
|
||||
/* skip the basis */
|
||||
kb = kb->next;
|
||||
for (; kb; kb = kb->next) {
|
||||
std::string geom_id = get_geometry_id(ob, false) + "_morph_" + translate_id(kb->name);
|
||||
source.appendValues(geom_id);
|
||||
}
|
||||
|
||||
source.finish();
|
||||
|
||||
return source_id;
|
||||
}
|
||||
|
||||
std::string ControllerExporter::add_morph_weights(Key *key, Object *ob)
|
||||
{
|
||||
std::string source_id = translate_id(id_name(ob)) + WEIGHTS_SOURCE_ID_SUFFIX;
|
||||
|
||||
COLLADASW::FloatSourceF source(mSW);
|
||||
source.setId(source_id);
|
||||
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
|
||||
source.setAccessorCount(key->totkey - 1);
|
||||
source.setAccessorStride(1);
|
||||
|
||||
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
||||
param.emplace_back("MORPH_WEIGHT");
|
||||
|
||||
source.prepareToAppendValues();
|
||||
|
||||
KeyBlock *kb = (KeyBlock *)key->block.first;
|
||||
/* skip the basis */
|
||||
kb = kb->next;
|
||||
for (; kb; kb = kb->next) {
|
||||
float weight = kb->curval;
|
||||
source.appendValues(weight);
|
||||
}
|
||||
source.finish();
|
||||
|
||||
return source_id;
|
||||
}
|
||||
|
||||
void ControllerExporter::add_weight_extras(Key *key)
|
||||
{
|
||||
/* can also try the base element and param alternative */
|
||||
COLLADASW::BaseExtraTechnique extra;
|
||||
|
||||
KeyBlock *kb = (KeyBlock *)key->block.first;
|
||||
/* skip the basis */
|
||||
kb = kb->next;
|
||||
for (; kb; kb = kb->next) {
|
||||
/* XXX why is the weight not used here and set to 0.0?
|
||||
* float weight = kb->curval; */
|
||||
extra.addExtraTechniqueParameter("KHR", "morph_weights", 0.000, "MORPH_WEIGHT_TO_TARGET");
|
||||
}
|
||||
}
|
||||
|
||||
void ControllerExporter::add_joints_element(const ListBase *defbase,
|
||||
const std::string &joints_source_id,
|
||||
const std::string &inv_bind_mat_source_id)
|
||||
{
|
||||
COLLADASW::JointsElement joints(mSW);
|
||||
COLLADASW::InputList &input = joints.getInputList();
|
||||
|
||||
input.push_back(COLLADASW::Input(
|
||||
COLLADASW::InputSemantic::JOINT, /* constant declared in COLLADASWInputList.h */
|
||||
COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, joints_source_id)));
|
||||
input.push_back(
|
||||
COLLADASW::Input(COLLADASW::InputSemantic::BINDMATRIX,
|
||||
COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, inv_bind_mat_source_id)));
|
||||
joints.add();
|
||||
}
|
||||
|
||||
void ControllerExporter::add_bind_shape_mat(Object *ob)
|
||||
{
|
||||
double bind_mat[4][4];
|
||||
float f_obmat[4][4];
|
||||
BKE_object_matrix_local_get(ob, f_obmat);
|
||||
|
||||
if (export_settings.get_apply_global_orientation()) {
|
||||
/* do nothing, rotation is going to be applied to the Data */
|
||||
}
|
||||
else {
|
||||
bc_add_global_transform(f_obmat, export_settings.get_global_transform());
|
||||
}
|
||||
|
||||
// UnitConverter::mat4_to_dae_double(bind_mat, ob->object_to_world().ptr());
|
||||
UnitConverter::mat4_to_dae_double(bind_mat, f_obmat);
|
||||
if (this->export_settings.get_limit_precision()) {
|
||||
BCMatrix::sanitize(bind_mat, LIMITTED_PRECISION);
|
||||
}
|
||||
|
||||
addBindShapeTransform(bind_mat);
|
||||
}
|
||||
|
||||
std::string ControllerExporter::add_joints_source(Object *ob_arm,
|
||||
const ListBase *defbase,
|
||||
const std::string &controller_id)
|
||||
{
|
||||
std::string source_id = controller_id + JOINTS_SOURCE_ID_SUFFIX;
|
||||
|
||||
int totjoint = 0;
|
||||
LISTBASE_FOREACH (bDeformGroup *, def, defbase) {
|
||||
if (is_bone_defgroup(ob_arm, def)) {
|
||||
totjoint++;
|
||||
}
|
||||
}
|
||||
|
||||
COLLADASW::NameSource source(mSW);
|
||||
source.setId(source_id);
|
||||
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
|
||||
source.setAccessorCount(totjoint);
|
||||
source.setAccessorStride(1);
|
||||
|
||||
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
||||
param.emplace_back("JOINT");
|
||||
|
||||
source.prepareToAppendValues();
|
||||
|
||||
LISTBASE_FOREACH (bDeformGroup *, def, defbase) {
|
||||
Bone *bone = get_bone_from_defgroup(ob_arm, def);
|
||||
if (bone) {
|
||||
source.appendValues(get_joint_sid(bone));
|
||||
}
|
||||
}
|
||||
|
||||
source.finish();
|
||||
|
||||
return source_id;
|
||||
}
|
||||
|
||||
std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm,
|
||||
const ListBase *defbase,
|
||||
const std::string &controller_id)
|
||||
{
|
||||
std::string source_id = controller_id + BIND_POSES_SOURCE_ID_SUFFIX;
|
||||
|
||||
int totjoint = 0;
|
||||
LISTBASE_FOREACH (bDeformGroup *, def, defbase) {
|
||||
if (is_bone_defgroup(ob_arm, def)) {
|
||||
totjoint++;
|
||||
}
|
||||
}
|
||||
|
||||
COLLADASW::FloatSourceF source(mSW);
|
||||
source.setId(source_id);
|
||||
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
|
||||
source.setAccessorCount(totjoint); // BLI_listbase_count(defbase));
|
||||
source.setAccessorStride(16);
|
||||
|
||||
source.setParameterTypeName(&COLLADASW::CSWC::CSW_VALUE_TYPE_FLOAT4x4);
|
||||
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
||||
param.emplace_back("TRANSFORM");
|
||||
|
||||
source.prepareToAppendValues();
|
||||
|
||||
bPose *pose = ob_arm->pose;
|
||||
bArmature *arm = (bArmature *)ob_arm->data;
|
||||
|
||||
int flag = arm->flag;
|
||||
|
||||
/* put armature in rest position */
|
||||
if (!(arm->flag & ARM_RESTPOS)) {
|
||||
Depsgraph *depsgraph = blender_context.get_depsgraph();
|
||||
Scene *scene = blender_context.get_scene();
|
||||
|
||||
arm->flag |= ARM_RESTPOS;
|
||||
BKE_pose_where_is(depsgraph, scene, ob_arm);
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (bDeformGroup *, def, defbase) {
|
||||
if (is_bone_defgroup(ob_arm, def)) {
|
||||
bPoseChannel *pchan = BKE_pose_channel_find_name(pose, def->name);
|
||||
|
||||
float mat[4][4];
|
||||
float world[4][4];
|
||||
float inv_bind_mat[4][4];
|
||||
|
||||
float bind_mat[4][4]; /* derived from bone->arm_mat */
|
||||
|
||||
bool has_bindmat = bc_get_property_matrix(pchan->bone, "bind_mat", bind_mat);
|
||||
|
||||
if (!has_bindmat) {
|
||||
|
||||
/* Have no bind matrix stored, try old style <= Blender 2.78 */
|
||||
|
||||
bc_create_restpose_mat(
|
||||
this->export_settings, pchan->bone, bind_mat, pchan->bone->arm_mat, true);
|
||||
|
||||
/* SL/OPEN_SIM COMPATIBILITY */
|
||||
if (export_settings.get_open_sim()) {
|
||||
float loc[3];
|
||||
float rot[3] = {0, 0, 0};
|
||||
float scale[3];
|
||||
bc_decompose(bind_mat, loc, nullptr, nullptr, scale);
|
||||
|
||||
/* Only translations, no rotation vs armature */
|
||||
loc_eulO_size_to_mat4(bind_mat, loc, rot, scale, 6);
|
||||
}
|
||||
}
|
||||
|
||||
/* make world-space matrix (bind_mat is armature-space) */
|
||||
mul_m4_m4m4(world, ob_arm->object_to_world().ptr(), bind_mat);
|
||||
|
||||
if (!has_bindmat) {
|
||||
if (export_settings.get_apply_global_orientation()) {
|
||||
bc_apply_global_transform(world, export_settings.get_global_transform());
|
||||
}
|
||||
}
|
||||
|
||||
invert_m4_m4(mat, world);
|
||||
UnitConverter::mat4_to_dae(inv_bind_mat, mat);
|
||||
if (this->export_settings.get_limit_precision()) {
|
||||
BCMatrix::sanitize(inv_bind_mat, LIMITTED_PRECISION);
|
||||
}
|
||||
source.appendValues(inv_bind_mat);
|
||||
}
|
||||
}
|
||||
|
||||
/* back from rest position */
|
||||
if (!(flag & ARM_RESTPOS)) {
|
||||
Depsgraph *depsgraph = blender_context.get_depsgraph();
|
||||
Scene *scene = blender_context.get_scene();
|
||||
arm->flag = flag;
|
||||
BKE_pose_where_is(depsgraph, scene, ob_arm);
|
||||
}
|
||||
|
||||
source.finish();
|
||||
|
||||
return source_id;
|
||||
}
|
||||
|
||||
Bone *ControllerExporter::get_bone_from_defgroup(Object *ob_arm, const bDeformGroup *def)
|
||||
{
|
||||
bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, def->name);
|
||||
return pchan ? pchan->bone : nullptr;
|
||||
}
|
||||
|
||||
bool ControllerExporter::is_bone_defgroup(Object *ob_arm, const bDeformGroup *def)
|
||||
{
|
||||
return get_bone_from_defgroup(ob_arm, def) != nullptr;
|
||||
}
|
||||
|
||||
std::string ControllerExporter::add_weights_source(Mesh *mesh,
|
||||
const std::string &controller_id,
|
||||
const std::list<float> &weights)
|
||||
{
|
||||
std::string source_id = controller_id + WEIGHTS_SOURCE_ID_SUFFIX;
|
||||
|
||||
COLLADASW::FloatSourceF source(mSW);
|
||||
source.setId(source_id);
|
||||
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
|
||||
source.setAccessorCount(weights.size());
|
||||
source.setAccessorStride(1);
|
||||
|
||||
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
||||
param.emplace_back("WEIGHT");
|
||||
|
||||
source.prepareToAppendValues();
|
||||
|
||||
for (float weight : weights) {
|
||||
source.appendValues(weight);
|
||||
}
|
||||
|
||||
source.finish();
|
||||
|
||||
return source_id;
|
||||
}
|
||||
|
||||
void ControllerExporter::add_vertex_weights_element(const std::string &weights_source_id,
|
||||
const std::string &joints_source_id,
|
||||
const std::list<int> &vcounts,
|
||||
const std::list<int> &joints)
|
||||
{
|
||||
COLLADASW::VertexWeightsElement weightselem(mSW);
|
||||
COLLADASW::InputList &input = weightselem.getInputList();
|
||||
|
||||
int offset = 0;
|
||||
input.push_back(COLLADASW::Input(
|
||||
COLLADASW::InputSemantic::JOINT, /* constant declared in COLLADASWInputList.h */
|
||||
COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, joints_source_id),
|
||||
offset++));
|
||||
input.push_back(
|
||||
COLLADASW::Input(COLLADASW::InputSemantic::WEIGHT,
|
||||
COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, weights_source_id),
|
||||
offset++));
|
||||
|
||||
weightselem.setCount(vcounts.size());
|
||||
|
||||
/* write number of deformers per vertex */
|
||||
COLLADASW::PrimitivesBase::VCountList vcountlist;
|
||||
|
||||
vcountlist.resize(vcounts.size());
|
||||
std::copy(vcounts.begin(), vcounts.end(), vcountlist.begin());
|
||||
|
||||
weightselem.prepareToAppendVCountValues();
|
||||
weightselem.appendVertexCount(vcountlist);
|
||||
|
||||
weightselem.CloseVCountAndOpenVElement();
|
||||
|
||||
/* write deformer index - weight index pairs */
|
||||
int weight_index = 0;
|
||||
for (int joint_index : joints) {
|
||||
weightselem.appendValues(joint_index, weight_index++);
|
||||
}
|
||||
|
||||
weightselem.finish();
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
// #include <vector>
|
||||
|
||||
#include "COLLADASWInstanceController.h"
|
||||
#include "COLLADASWLibraryControllers.h"
|
||||
#include "COLLADASWStreamWriter.h"
|
||||
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_key_types.h"
|
||||
#include "DNA_listBase.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "InstanceWriter.h"
|
||||
#include "TransformWriter.h"
|
||||
|
||||
#include "ExportSettings.h"
|
||||
|
||||
class SceneExporter;
|
||||
|
||||
class ControllerExporter : public COLLADASW::LibraryControllers,
|
||||
protected TransformWriter,
|
||||
protected InstanceWriter {
|
||||
private:
|
||||
BlenderContext &blender_context;
|
||||
BCExportSettings export_settings;
|
||||
|
||||
public:
|
||||
/* XXX exporter writes wrong data for shared armatures. A separate
|
||||
* controller should be written for each armature-mesh binding how do
|
||||
* we make controller ids then? */
|
||||
ControllerExporter(BlenderContext &blender_context,
|
||||
COLLADASW::StreamWriter *sw,
|
||||
BCExportSettings &export_settings)
|
||||
: COLLADASW::LibraryControllers(sw),
|
||||
blender_context(blender_context),
|
||||
export_settings(export_settings)
|
||||
{
|
||||
}
|
||||
|
||||
bool is_skinned_mesh(Object *ob);
|
||||
|
||||
bool add_instance_controller(Object *ob);
|
||||
|
||||
void export_controllers();
|
||||
|
||||
void operator()(Object *ob);
|
||||
|
||||
private:
|
||||
#if 0
|
||||
std::vector<Object *> written_armatures;
|
||||
|
||||
bool already_written(Object *ob_arm);
|
||||
|
||||
void wrote(Object *ob_arm);
|
||||
|
||||
void find_objects_using_armature(Object *ob_arm, std::vector<Object *> &objects, Scene *sce);
|
||||
#endif
|
||||
|
||||
std::string get_controller_id(Object *ob_arm, Object *ob);
|
||||
|
||||
std::string get_controller_id(Key *key, Object *ob);
|
||||
|
||||
/** `ob` should be of type OB_MESH, both arguments are required. */
|
||||
void export_skin_controller(Object *ob, Object *ob_arm);
|
||||
|
||||
void export_morph_controller(Object *ob, Key *key);
|
||||
|
||||
void add_joints_element(const ListBase *defbase,
|
||||
const std::string &joints_source_id,
|
||||
const std::string &inv_bind_mat_source_id);
|
||||
|
||||
void add_bind_shape_mat(Object *ob);
|
||||
|
||||
std::string add_morph_targets(Key *key, Object *ob);
|
||||
|
||||
std::string add_morph_weights(Key *key, Object *ob);
|
||||
|
||||
/**
|
||||
* Added to implement support for animations.
|
||||
*/
|
||||
void add_weight_extras(Key *key);
|
||||
|
||||
std::string add_joints_source(Object *ob_arm,
|
||||
const ListBase *defbase,
|
||||
const std::string &controller_id);
|
||||
|
||||
std::string add_inv_bind_mats_source(Object *ob_arm,
|
||||
const ListBase *defbase,
|
||||
const std::string &controller_id);
|
||||
|
||||
Bone *get_bone_from_defgroup(Object *ob_arm, const bDeformGroup *def);
|
||||
|
||||
bool is_bone_defgroup(Object *ob_arm, const bDeformGroup *def);
|
||||
|
||||
std::string add_weights_source(Mesh *mesh,
|
||||
const std::string &controller_id,
|
||||
const std::list<float> &weights);
|
||||
|
||||
void add_vertex_weights_element(const std::string &weights_source_id,
|
||||
const std::string &joints_source_id,
|
||||
const std::list<int> &vcount,
|
||||
const std::list<int> &joints);
|
||||
|
||||
void write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone);
|
||||
};
|
@ -1,270 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2009-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "COLLADASWAsset.h"
|
||||
#include "COLLADASWCamera.h"
|
||||
#include "COLLADASWException.h"
|
||||
#include "COLLADASWScene.h"
|
||||
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BLI_fileops.h"
|
||||
#include "BLI_path_utils.hh"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BKE_animsys.h"
|
||||
#include "BKE_appdir.hh"
|
||||
#include "BKE_blender_version.h"
|
||||
#include "BKE_customdata.hh"
|
||||
#include "BKE_fcurve.hh"
|
||||
|
||||
#include "ED_keyframing.hh"
|
||||
#ifdef WITH_BUILDINFO
|
||||
extern "C" char build_commit_date[];
|
||||
extern "C" char build_commit_time[];
|
||||
extern "C" char build_hash[];
|
||||
#endif
|
||||
|
||||
#include "RNA_access.hh"
|
||||
|
||||
#include "DocumentExporter.h"
|
||||
#include "collada_internal.h"
|
||||
#include "collada_utils.h"
|
||||
|
||||
/* can probably go after refactor is complete */
|
||||
|
||||
#include "AnimationExporter.h"
|
||||
#include "ArmatureExporter.h"
|
||||
#include "CameraExporter.h"
|
||||
#include "ControllerExporter.h"
|
||||
#include "EffectExporter.h"
|
||||
#include "GeometryExporter.h"
|
||||
#include "ImageExporter.h"
|
||||
#include "LightExporter.h"
|
||||
#include "MaterialExporter.h"
|
||||
#include "SceneExporter.h"
|
||||
|
||||
#include <cerrno>
|
||||
|
||||
const char *bc_CustomData_get_layer_name(const CustomData *data, const eCustomDataType type, int n)
|
||||
{
|
||||
int layer_index = CustomData_get_layer_index(data, type);
|
||||
if (layer_index < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return data->layers[layer_index + n].name;
|
||||
}
|
||||
|
||||
const char *bc_CustomData_get_active_layer_name(const CustomData *data, const eCustomDataType type)
|
||||
{
|
||||
/* get the layer index of the active layer of type */
|
||||
int layer_index = CustomData_get_active_layer_index(data, type);
|
||||
if (layer_index < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return data->layers[layer_index].name;
|
||||
}
|
||||
|
||||
DocumentExporter::DocumentExporter(BlenderContext &blender_context,
|
||||
ExportSettings *export_settings)
|
||||
: blender_context(blender_context),
|
||||
export_settings(BCExportSettings(export_settings, blender_context))
|
||||
{
|
||||
}
|
||||
|
||||
static COLLADABU::NativeString make_temp_filepath(const char *name, const char *extension)
|
||||
{
|
||||
char tempfile[FILE_MAX];
|
||||
|
||||
if (name == nullptr) {
|
||||
name = "untitled";
|
||||
}
|
||||
|
||||
BLI_path_join(tempfile, sizeof(tempfile), BKE_tempdir_session(), name);
|
||||
|
||||
if (extension) {
|
||||
BLI_path_extension_ensure(tempfile, FILE_MAX, extension);
|
||||
}
|
||||
|
||||
COLLADABU::NativeString native_filename = COLLADABU::NativeString(
|
||||
tempfile, COLLADABU::NativeString::ENCODING_UTF8);
|
||||
return native_filename;
|
||||
}
|
||||
|
||||
/* TODO: it would be better to instantiate animations rather than create a new one per object
|
||||
* COLLADA allows this through multiple <channel>s in <animation>.
|
||||
* For this to work, we need to know objects that use a certain action. */
|
||||
|
||||
int DocumentExporter::exportCurrentScene()
|
||||
{
|
||||
Scene *sce = blender_context.get_scene();
|
||||
bContext *C = blender_context.get_context();
|
||||
|
||||
PointerRNA unit_settings;
|
||||
PropertyRNA *system; /* unused, *scale; */
|
||||
|
||||
clear_global_id_map();
|
||||
|
||||
COLLADABU::NativeString native_filename = make_temp_filepath(nullptr, ".dae");
|
||||
COLLADASW::StreamWriter *writer;
|
||||
try {
|
||||
writer = new COLLADASW::StreamWriter(native_filename);
|
||||
}
|
||||
catch (COLLADASW::StreamWriterException &e) {
|
||||
e.printMessage();
|
||||
fprintf(stderr, "Collada: No Objects will be exported.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* open <collada> */
|
||||
writer->startDocument();
|
||||
|
||||
/* <asset> */
|
||||
COLLADASW::Asset asset(writer);
|
||||
|
||||
PointerRNA sceneptr = RNA_id_pointer_create(&sce->id);
|
||||
unit_settings = RNA_pointer_get(&sceneptr, "unit_settings");
|
||||
system = RNA_struct_find_property(&unit_settings, "system");
|
||||
// scale = RNA_struct_find_property(&unit_settings, "scale_length");
|
||||
|
||||
std::string unitname = "meter";
|
||||
float linearmeasure = RNA_float_get(&unit_settings, "scale_length");
|
||||
|
||||
switch (RNA_property_enum_get(&unit_settings, system)) {
|
||||
case USER_UNIT_NONE:
|
||||
case USER_UNIT_METRIC:
|
||||
if (linearmeasure == 0.001f) {
|
||||
unitname = "millimeter";
|
||||
}
|
||||
else if (linearmeasure == 0.01f) {
|
||||
unitname = "centimeter";
|
||||
}
|
||||
else if (linearmeasure == 0.1f) {
|
||||
unitname = "decimeter";
|
||||
}
|
||||
else if (linearmeasure == 1.0f) {
|
||||
unitname = "meter";
|
||||
}
|
||||
else if (linearmeasure == 1000.0f) {
|
||||
unitname = "kilometer";
|
||||
}
|
||||
break;
|
||||
case USER_UNIT_IMPERIAL:
|
||||
if (linearmeasure == 0.0254f) {
|
||||
unitname = "inch";
|
||||
}
|
||||
else if (linearmeasure == 0.3048f) {
|
||||
unitname = "foot";
|
||||
}
|
||||
else if (linearmeasure == 0.9144f) {
|
||||
unitname = "yard";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
asset.setUnit(unitname, linearmeasure);
|
||||
asset.setUpAxisType(COLLADASW::Asset::Z_UP);
|
||||
asset.getContributor().mAuthor = "Blender User";
|
||||
char version_buf[128];
|
||||
#ifdef WITH_BUILDINFO
|
||||
SNPRINTF(version_buf,
|
||||
"Blender %s commit date:%s, commit time:%s, hash:%s",
|
||||
BKE_blender_version_string(),
|
||||
build_commit_date,
|
||||
build_commit_time,
|
||||
build_hash);
|
||||
#else
|
||||
SNPRINTF(version_buf, "Blender %s", BKE_blender_version_string());
|
||||
#endif
|
||||
asset.getContributor().mAuthoringTool = version_buf;
|
||||
asset.add();
|
||||
|
||||
LinkNode *export_set = this->export_settings.get_export_set();
|
||||
/* <library_cameras> */
|
||||
if (bc_has_object_type(export_set, OB_CAMERA)) {
|
||||
CamerasExporter ce(writer, this->export_settings);
|
||||
ce.exportCameras(sce);
|
||||
}
|
||||
|
||||
/* <library_lights> */
|
||||
if (bc_has_object_type(export_set, OB_LAMP)) {
|
||||
LightsExporter le(writer, this->export_settings);
|
||||
le.exportLights(sce);
|
||||
}
|
||||
|
||||
/* <library_effects> */
|
||||
EffectsExporter ee(writer, this->export_settings, key_image_map);
|
||||
ee.exportEffects(C, sce);
|
||||
|
||||
/* <library_images> */
|
||||
ImagesExporter ie(writer, this->export_settings, key_image_map);
|
||||
ie.exportImages(sce);
|
||||
|
||||
/* <library_materials> */
|
||||
MaterialsExporter me(writer, this->export_settings);
|
||||
me.exportMaterials(sce);
|
||||
|
||||
/* <library_geometries> */
|
||||
if (bc_has_object_type(export_set, OB_MESH)) {
|
||||
GeometryExporter ge(blender_context, writer, this->export_settings);
|
||||
ge.exportGeom();
|
||||
}
|
||||
|
||||
/* <library_controllers> */
|
||||
ArmatureExporter arm_exporter(blender_context, writer, this->export_settings);
|
||||
ControllerExporter controller_exporter(blender_context, writer, this->export_settings);
|
||||
if (bc_has_object_type(export_set, OB_ARMATURE) || this->export_settings.get_include_shapekeys())
|
||||
{
|
||||
controller_exporter.export_controllers();
|
||||
}
|
||||
|
||||
/* <library_visual_scenes> */
|
||||
|
||||
SceneExporter se(blender_context, writer, &arm_exporter, this->export_settings);
|
||||
|
||||
if (this->export_settings.get_include_animations()) {
|
||||
/* <library_animations> */
|
||||
AnimationExporter ae(writer, this->export_settings);
|
||||
ae.exportAnimations();
|
||||
}
|
||||
|
||||
se.exportScene();
|
||||
|
||||
/* <scene> */
|
||||
std::string scene_name(translate_id(id_name(sce)));
|
||||
COLLADASW::Scene scene(writer, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, scene_name));
|
||||
scene.add();
|
||||
|
||||
/* close <Collada> */
|
||||
writer->endDocument();
|
||||
delete writer;
|
||||
|
||||
/* Finally move the created document into place */
|
||||
fprintf(stdout, "Collada export to: %s\n", this->export_settings.get_filepath());
|
||||
int status = BLI_rename_overwrite(native_filename.c_str(), this->export_settings.get_filepath());
|
||||
if (status != 0) {
|
||||
status = BLI_copy(native_filename.c_str(), this->export_settings.get_filepath());
|
||||
BLI_delete(native_filename.c_str(), false, false);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTES:
|
||||
*
|
||||
* AnimationExporter::sample_animation enables all curves on armature, this is undesirable for a
|
||||
* user
|
||||
*/
|
@ -1,23 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BlenderContext.h"
|
||||
#include "collada_utils.h"
|
||||
|
||||
class DocumentExporter {
|
||||
public:
|
||||
DocumentExporter(BlenderContext &blender_context, ExportSettings *export_settings);
|
||||
int exportCurrentScene();
|
||||
|
||||
private:
|
||||
BlenderContext &blender_context;
|
||||
BCExportSettings export_settings;
|
||||
KeyImageMap key_image_map;
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -1,213 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "COLLADAFWController.h"
|
||||
#include "COLLADAFWEffect.h"
|
||||
#include "COLLADAFWEffectCommon.h"
|
||||
#include "COLLADAFWIWriter.h"
|
||||
#include "COLLADAFWImage.h"
|
||||
#include "COLLADAFWMaterial.h"
|
||||
|
||||
#include "AnimationImporter.h"
|
||||
#include "ArmatureImporter.h"
|
||||
#include "ImportSettings.h"
|
||||
#include "MeshImporter.h"
|
||||
|
||||
struct bContext;
|
||||
|
||||
/** Importer class. */
|
||||
class DocumentImporter : COLLADAFW::IWriter {
|
||||
public:
|
||||
/** Enumeration to denote the stage of import */
|
||||
enum ImportStage {
|
||||
Fetching_Scene_data, /* First pass to collect all data except controller */
|
||||
Fetching_Controller_data, /* Second pass to collect controller data */
|
||||
};
|
||||
/** Constructor */
|
||||
DocumentImporter(bContext *C, const ImportSettings *import_settings);
|
||||
|
||||
/** Destructor */
|
||||
~DocumentImporter() override;
|
||||
|
||||
/** Function called by blender UI */
|
||||
bool import();
|
||||
|
||||
/** these should not be here */
|
||||
Object *create_camera_object(COLLADAFW::InstanceCamera *, Scene *);
|
||||
Object *create_light_object(COLLADAFW::InstanceLight *, Scene *);
|
||||
Object *create_instance_node(Object *, COLLADAFW::Node *, COLLADAFW::Node *, Scene *, bool);
|
||||
/**
|
||||
* To create constraints off node <extra> tags. Assumes only constraint data in
|
||||
* current <extra> with blender profile.
|
||||
*/
|
||||
void create_constraints(ExtraTags *et, Object *ob);
|
||||
std::vector<Object *> *write_node(COLLADAFW::Node *, COLLADAFW::Node *, Scene *, Object *, bool);
|
||||
void write_profile_COMMON(COLLADAFW::EffectCommon *, Material *);
|
||||
|
||||
void translate_anim_recursive(COLLADAFW::Node *, COLLADAFW::Node *, Object *);
|
||||
|
||||
/**
|
||||
* This method will be called if an error in the loading process occurred and the loader cannot
|
||||
* continue to load. The writer should undo all operations that have been performed.
|
||||
* \param errorMessage: A message containing information about the error that occurred.
|
||||
*/
|
||||
void cancel(const COLLADAFW::String &errorMessage) override;
|
||||
|
||||
/** This is the method called. The writer hast to prepare to receive data. */
|
||||
void start() override;
|
||||
|
||||
/**
|
||||
* This method is called after the last write* method.
|
||||
* No other methods will be called after this.
|
||||
*/
|
||||
void finish() override;
|
||||
|
||||
/**
|
||||
* When this method is called, the writer must write the global document asset.
|
||||
* \return The writer should return true, if writing succeeded, false otherwise.
|
||||
*/
|
||||
bool writeGlobalAsset(const COLLADAFW::FileInfo * /*asset*/) override;
|
||||
/**
|
||||
* If the imported file was made with Blender, return the Blender version used,
|
||||
* otherwise return an empty std::string
|
||||
*/
|
||||
std::string get_import_version(const COLLADAFW::FileInfo *asset);
|
||||
|
||||
/**
|
||||
* When this method is called, the writer must write the scene.
|
||||
* \return The writer should return true, if writing succeeded, false otherwise.
|
||||
*/
|
||||
bool writeScene(const COLLADAFW::Scene * /*scene*/) override;
|
||||
|
||||
/**
|
||||
* When this method is called, the writer must write the entire visual scene.
|
||||
* Return The writer should return true, if writing succeeded, false otherwise.
|
||||
*/
|
||||
bool writeVisualScene(const COLLADAFW::VisualScene * /*visualScene*/) override;
|
||||
|
||||
/**
|
||||
* When this method is called, the writer must handle all nodes contained in the
|
||||
* library nodes.
|
||||
* \return The writer should return true, if writing succeeded, false otherwise.
|
||||
*/
|
||||
bool writeLibraryNodes(const COLLADAFW::LibraryNodes * /*libraryNodes*/) override;
|
||||
|
||||
/**
|
||||
* This function is called only for animations that pass COLLADAFW::validate.
|
||||
*/
|
||||
bool writeAnimation(const COLLADAFW::Animation * /*animation*/) override;
|
||||
|
||||
/**
|
||||
* Called on post-process stage after writeVisualScenes.
|
||||
*/
|
||||
bool writeAnimationList(const COLLADAFW::AnimationList * /*animationList*/) override;
|
||||
|
||||
#if WITH_OPENCOLLADA_ANIMATION_CLIP
|
||||
/* Please enable this when building with Collada 1.6.65 or newer (also in DocumentImporter.cpp)
|
||||
*/
|
||||
bool writeAnimationClip(const COLLADAFW::AnimationClip *animationClip) override;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* When this method is called, the writer must write the geometry.
|
||||
* \return The writer should return true, if writing succeeded, false otherwise.
|
||||
*/
|
||||
bool writeGeometry(const COLLADAFW::Geometry * /*geometry*/) override;
|
||||
|
||||
/**
|
||||
* When this method is called, the writer must write the material.
|
||||
* \return The writer should return true, if writing succeeded, false otherwise.
|
||||
*/
|
||||
bool writeMaterial(const COLLADAFW::Material * /*material*/) override;
|
||||
|
||||
/**
|
||||
* When this method is called, the writer must write the effect.
|
||||
* \return The writer should return true, if writing succeeded, false otherwise.
|
||||
*/
|
||||
bool writeEffect(const COLLADAFW::Effect * /*effect*/) override;
|
||||
|
||||
/**
|
||||
* When this method is called, the writer must write the camera.
|
||||
* \return The writer should return true, if writing succeeded, false otherwise.
|
||||
*/
|
||||
bool writeCamera(const COLLADAFW::Camera * /*camera*/) override;
|
||||
|
||||
/**
|
||||
* When this method is called, the writer must write the image.
|
||||
* \return The writer should return true, if writing succeeded, false otherwise.
|
||||
*/
|
||||
bool writeImage(const COLLADAFW::Image * /*image*/) override;
|
||||
|
||||
/**
|
||||
* When this method is called, the writer must write the light.
|
||||
* \return The writer should return true, if writing succeeded, false otherwise.
|
||||
*/
|
||||
bool writeLight(const COLLADAFW::Light * /*light*/) override;
|
||||
|
||||
/**
|
||||
* When this method is called, the writer must write the skin controller data.
|
||||
* \return The writer should return true, if writing succeeded, false otherwise.
|
||||
*/
|
||||
bool writeSkinControllerData(
|
||||
const COLLADAFW::SkinControllerData * /*skinControllerData*/) override;
|
||||
|
||||
/** This is called on post-process, before writeVisualScenes. */
|
||||
bool writeController(const COLLADAFW::Controller * /*controller*/) override;
|
||||
|
||||
bool writeFormulas(const COLLADAFW::Formulas * /*formulas*/) override;
|
||||
|
||||
bool writeKinematicsScene(const COLLADAFW::KinematicsScene * /*kinematicsScene*/) override;
|
||||
|
||||
/** Add element and data for UniqueId */
|
||||
bool addExtraTags(const COLLADAFW::UniqueId &uid, ExtraTags *extra_tags);
|
||||
/** Get an existing #ExtraTags for uid */
|
||||
ExtraTags *getExtraTags(const COLLADAFW::UniqueId &uid);
|
||||
|
||||
bool is_armature(COLLADAFW::Node *node);
|
||||
|
||||
private:
|
||||
const ImportSettings *import_settings;
|
||||
|
||||
/** Current import stage we're in. */
|
||||
ImportStage mImportStage;
|
||||
|
||||
bContext *mContext;
|
||||
ViewLayer *view_layer;
|
||||
|
||||
UnitConverter unit_converter;
|
||||
ArmatureImporter armature_importer;
|
||||
MeshImporter mesh_importer;
|
||||
AnimationImporter anim_importer;
|
||||
|
||||
/** TagsMap typedef for uid_tags_map. */
|
||||
using TagsMap = std::map<std::string, ExtraTags *>;
|
||||
/** Tags map of unique id as a string and ExtraTags instance. */
|
||||
TagsMap uid_tags_map;
|
||||
|
||||
UidImageMap uid_image_map;
|
||||
std::map<COLLADAFW::UniqueId, Material *> uid_material_map;
|
||||
std::map<COLLADAFW::UniqueId, Material *> uid_effect_map;
|
||||
std::map<COLLADAFW::UniqueId, Camera *> uid_camera_map;
|
||||
std::map<COLLADAFW::UniqueId, Light *> uid_light_map;
|
||||
std::map<Material *, TexIndexTextureArrayMap> material_texture_mapping_map;
|
||||
std::multimap<COLLADAFW::UniqueId, Object *> object_map;
|
||||
std::map<COLLADAFW::UniqueId, COLLADAFW::Node *> node_map;
|
||||
std::vector<const COLLADAFW::VisualScene *> vscenes;
|
||||
std::vector<Object *> libnode_ob;
|
||||
|
||||
std::map<COLLADAFW::UniqueId, COLLADAFW::Node *>
|
||||
root_map; /* find root joint by child joint uid, for bone tree evaluation during resampling
|
||||
*/
|
||||
std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map;
|
||||
|
||||
std::string import_from_version;
|
||||
|
||||
void report_unknown_reference(const COLLADAFW::Node &node, const std::string object_type);
|
||||
};
|
@ -1,298 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2010-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "COLLADASWEffectProfile.h"
|
||||
|
||||
#include "EffectExporter.h"
|
||||
#include "MaterialExporter.h"
|
||||
#include "Materials.h"
|
||||
|
||||
#include "collada_internal.h"
|
||||
#include "collada_utils.h"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
|
||||
#include "BKE_collection.hh"
|
||||
#include "BKE_customdata.hh"
|
||||
#include "BKE_material.hh"
|
||||
|
||||
static std::string getActiveUVLayerName(Object *ob)
|
||||
{
|
||||
Mesh *mesh = (Mesh *)ob->data;
|
||||
|
||||
int num_layers = CustomData_number_of_layers(&mesh->corner_data, CD_PROP_FLOAT2);
|
||||
if (num_layers) {
|
||||
return std::string(bc_CustomData_get_active_layer_name(&mesh->corner_data, CD_PROP_FLOAT2));
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
EffectsExporter::EffectsExporter(COLLADASW::StreamWriter *sw,
|
||||
BCExportSettings &export_settings,
|
||||
KeyImageMap &key_image_map)
|
||||
: COLLADASW::LibraryEffects(sw), export_settings(export_settings), key_image_map(key_image_map)
|
||||
{
|
||||
}
|
||||
|
||||
bool EffectsExporter::hasEffects(Scene *sce)
|
||||
{
|
||||
bool result = false;
|
||||
FOREACH_SCENE_OBJECT_BEGIN (sce, ob) {
|
||||
int a;
|
||||
for (a = 0; a < ob->totcol; a++) {
|
||||
Material *ma = BKE_object_material_get(ob, a + 1);
|
||||
|
||||
/* no material, but check all of the slots */
|
||||
if (!ma) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
FOREACH_SCENE_OBJECT_END;
|
||||
return result;
|
||||
}
|
||||
|
||||
void EffectsExporter::exportEffects(bContext *C, Scene *sce)
|
||||
{
|
||||
if (hasEffects(sce)) {
|
||||
this->mContext = C;
|
||||
this->scene = sce;
|
||||
openLibrary();
|
||||
MaterialFunctor mf;
|
||||
mf.forEachMaterialInExportSet<EffectsExporter>(
|
||||
sce, *this, this->export_settings.get_export_set());
|
||||
|
||||
closeLibrary();
|
||||
}
|
||||
}
|
||||
|
||||
void EffectsExporter::set_shader_type(COLLADASW::EffectProfile &ep, Material *ma)
|
||||
{
|
||||
/* XXX check if BLINN and PHONG can be supported as well */
|
||||
ep.setShaderType(COLLADASW::EffectProfile::LAMBERT);
|
||||
}
|
||||
|
||||
void EffectsExporter::set_transparency(COLLADASW::EffectProfile &ep, Material *ma)
|
||||
{
|
||||
double alpha = bc_get_alpha(ma);
|
||||
if (alpha < 1) {
|
||||
/* workaround use <transparent> to avoid wrong handling of <transparency> by other tools */
|
||||
COLLADASW::ColorOrTexture cot = bc_get_cot(0, 0, 0, alpha);
|
||||
ep.setTransparent(cot, false, "alpha");
|
||||
ep.setOpaque(COLLADASW::EffectProfile::A_ONE);
|
||||
}
|
||||
}
|
||||
|
||||
void EffectsExporter::set_diffuse_color(COLLADASW::EffectProfile &ep, Material *ma)
|
||||
{
|
||||
COLLADASW::ColorOrTexture cot = bc_get_base_color(ma);
|
||||
ep.setDiffuse(cot, false, "diffuse");
|
||||
}
|
||||
|
||||
void EffectsExporter::set_ambient(COLLADASW::EffectProfile &ep, Material *ma)
|
||||
{
|
||||
COLLADASW::ColorOrTexture cot = bc_get_ambient(ma);
|
||||
ep.setAmbient(cot, false, "ambient");
|
||||
}
|
||||
void EffectsExporter::set_specular(COLLADASW::EffectProfile &ep, Material *ma)
|
||||
{
|
||||
COLLADASW::ColorOrTexture cot = bc_get_specular(ma);
|
||||
ep.setSpecular(cot, false, "specular");
|
||||
}
|
||||
void EffectsExporter::set_reflective(COLLADASW::EffectProfile &ep, Material *ma)
|
||||
{
|
||||
COLLADASW::ColorOrTexture cot = bc_get_reflective(ma);
|
||||
ep.setReflective(cot, false, "reflective");
|
||||
}
|
||||
|
||||
void EffectsExporter::set_reflectivity(COLLADASW::EffectProfile &ep, Material *ma)
|
||||
{
|
||||
double reflectivity = bc_get_reflectivity(ma);
|
||||
if (reflectivity > 0.0) {
|
||||
ep.setReflectivity(reflectivity, false, "specular");
|
||||
}
|
||||
}
|
||||
|
||||
void EffectsExporter::set_emission(COLLADASW::EffectProfile &ep, Material *ma)
|
||||
{
|
||||
COLLADASW::ColorOrTexture cot = bc_get_emission(ma);
|
||||
ep.setEmission(cot, false, "emission");
|
||||
}
|
||||
|
||||
void EffectsExporter::set_ior(COLLADASW::EffectProfile &ep, Material *ma)
|
||||
{
|
||||
double alpha = bc_get_ior(ma);
|
||||
ep.setIndexOfRefraction(alpha, false, "ior");
|
||||
}
|
||||
|
||||
void EffectsExporter::set_shininess(COLLADASW::EffectProfile &ep, Material *ma)
|
||||
{
|
||||
double shininess = bc_get_shininess(ma);
|
||||
ep.setShininess(shininess, false, "shininess");
|
||||
}
|
||||
|
||||
void EffectsExporter::get_images(Material *ma, KeyImageMap &material_image_map)
|
||||
{
|
||||
if (!ma->use_nodes) {
|
||||
return;
|
||||
}
|
||||
|
||||
MaterialNode material = MaterialNode(mContext, ma, key_image_map);
|
||||
Image *image = material.get_diffuse_image();
|
||||
if (image == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string uid(id_name(image));
|
||||
std::string key = translate_id(uid);
|
||||
|
||||
if (material_image_map.find(key) == material_image_map.end()) {
|
||||
material_image_map[key] = image;
|
||||
key_image_map[key] = image;
|
||||
}
|
||||
}
|
||||
|
||||
void EffectsExporter::create_image_samplers(COLLADASW::EffectProfile &ep,
|
||||
KeyImageMap &material_image_map,
|
||||
std::string &active_uv)
|
||||
{
|
||||
KeyImageMap::iterator iter;
|
||||
|
||||
for (iter = material_image_map.begin(); iter != material_image_map.end(); iter++) {
|
||||
|
||||
Image *image = iter->second;
|
||||
std::string uid(id_name(image));
|
||||
std::string key = translate_id(uid);
|
||||
|
||||
COLLADASW::Sampler *sampler = new COLLADASW::Sampler(
|
||||
COLLADASW::Sampler::SAMPLER_TYPE_2D,
|
||||
key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
|
||||
key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
|
||||
|
||||
sampler->setImageId(key);
|
||||
|
||||
ep.setDiffuse(createTexture(image, active_uv, sampler), false, "diffuse");
|
||||
}
|
||||
}
|
||||
|
||||
void EffectsExporter::operator()(Material *ma, Object *ob)
|
||||
{
|
||||
KeyImageMap material_image_map;
|
||||
|
||||
openEffect(get_effect_id(ma));
|
||||
|
||||
COLLADASW::EffectProfile ep(mSW);
|
||||
ep.setProfileType(COLLADASW::EffectProfile::COMMON);
|
||||
ep.openProfile();
|
||||
set_shader_type(ep, ma); /* creates a Lambert Shader for now */
|
||||
|
||||
COLLADASW::ColorOrTexture cot;
|
||||
|
||||
set_diffuse_color(ep, ma);
|
||||
set_emission(ep, ma);
|
||||
set_ior(ep, ma);
|
||||
set_reflectivity(ep, ma);
|
||||
set_transparency(ep, ma);
|
||||
|
||||
/* TODO: */
|
||||
#if 0
|
||||
set_shininess(ep, ma); /* Shininess not supported for lambert. */
|
||||
set_ambient(ep, ma);
|
||||
set_specular(ep, ma);
|
||||
#endif
|
||||
|
||||
get_images(ma, material_image_map);
|
||||
std::string active_uv(getActiveUVLayerName(ob));
|
||||
create_image_samplers(ep, material_image_map, active_uv);
|
||||
|
||||
#if 0
|
||||
uint a, b;
|
||||
for (a = 0, b = 0; a < tex_indices.size(); a++) {
|
||||
MTex *t = ma->mtex[tex_indices[a]];
|
||||
Image *ima = t->tex->ima;
|
||||
|
||||
/* Image not set for texture */
|
||||
if (!ima) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string key(id_name(ima));
|
||||
key = translate_id(key);
|
||||
|
||||
/* create only one <sampler>/<surface> pair for each unique image */
|
||||
if (im_samp_map.find(key) == im_samp_map.end()) {
|
||||
/* <newparam> <sampler> <source> */
|
||||
COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D,
|
||||
key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
|
||||
key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
|
||||
sampler.setImageId(key);
|
||||
/* copy values to arrays since they will live longer */
|
||||
samplers[a] = sampler;
|
||||
|
||||
/* store pointers so they can be used later when we create <texture>s */
|
||||
samp_surf[b] = &samplers[a];
|
||||
// samp_surf[b][1] = &surfaces[a];
|
||||
|
||||
im_samp_map[key] = b;
|
||||
b++;
|
||||
}
|
||||
}
|
||||
|
||||
for (a = 0; a < tex_indices.size(); a++) {
|
||||
MTex *t = ma->mtex[tex_indices[a]];
|
||||
Image *ima = t->tex->ima;
|
||||
|
||||
if (!ima) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string key(id_name(ima));
|
||||
key = translate_id(key);
|
||||
int i = im_samp_map[key];
|
||||
std::string uvname = strlen(t->uvname) ? t->uvname : active_uv;
|
||||
COLLADASW::Sampler *sampler = (COLLADASW::Sampler *)
|
||||
samp_surf[i]; /* possibly uninitialized memory ... */
|
||||
writeTextures(ep, key, sampler, t, ima, uvname);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* performs the actual writing */
|
||||
ep.addProfileElements();
|
||||
ep.addExtraTechniques(mSW);
|
||||
|
||||
ep.closeProfile();
|
||||
closeEffect();
|
||||
}
|
||||
|
||||
COLLADASW::ColorOrTexture EffectsExporter::createTexture(Image *ima,
|
||||
std::string &uv_layer_name,
|
||||
COLLADASW::Sampler *sampler
|
||||
/*COLLADASW::Surface *surface*/)
|
||||
{
|
||||
|
||||
COLLADASW::Texture texture(translate_id(id_name(ima)));
|
||||
texture.setTexcoord(uv_layer_name);
|
||||
// texture.setSurface(*surface);
|
||||
texture.setSampler(*sampler);
|
||||
|
||||
COLLADASW::ColorOrTexture cot(texture);
|
||||
return cot;
|
||||
}
|
||||
|
||||
COLLADASW::ColorOrTexture EffectsExporter::getcol(float r, float g, float b, float a)
|
||||
{
|
||||
COLLADASW::Color color(r, g, b, a);
|
||||
COLLADASW::ColorOrTexture cot(color);
|
||||
return cot;
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "COLLADASWColorOrTexture.h"
|
||||
#include "COLLADASWLibraryEffects.h"
|
||||
#include "COLLADASWSampler.h"
|
||||
#include "COLLADASWStreamWriter.h"
|
||||
|
||||
#include "DNA_image_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "ExportSettings.h"
|
||||
#include "collada_utils.h"
|
||||
|
||||
class EffectsExporter : COLLADASW::LibraryEffects {
|
||||
public:
|
||||
EffectsExporter(COLLADASW::StreamWriter *sw,
|
||||
BCExportSettings &export_settings,
|
||||
KeyImageMap &key_image_map);
|
||||
void exportEffects(bContext *C, Scene *sce);
|
||||
|
||||
void operator()(Material *ma, Object *ob);
|
||||
|
||||
COLLADASW::ColorOrTexture createTexture(Image *ima,
|
||||
std::string &uv_layer_name,
|
||||
COLLADASW::Sampler *sampler
|
||||
/*COLLADASW::Surface *surface*/);
|
||||
|
||||
COLLADASW::ColorOrTexture getcol(float r, float g, float b, float a);
|
||||
|
||||
private:
|
||||
void set_shader_type(COLLADASW::EffectProfile &ep, Material *ma);
|
||||
|
||||
void set_diffuse_color(COLLADASW::EffectProfile &ep, Material *ma);
|
||||
void set_emission(COLLADASW::EffectProfile &ep, Material *ma);
|
||||
void set_ior(COLLADASW::EffectProfile &ep, Material *ma);
|
||||
void set_shininess(COLLADASW::EffectProfile &ep, Material *ma);
|
||||
void set_reflectivity(COLLADASW::EffectProfile &ep, Material *ma);
|
||||
void set_transparency(COLLADASW::EffectProfile &ep, Material *ma);
|
||||
void set_ambient(COLLADASW::EffectProfile &ep, Material *ma);
|
||||
void set_specular(COLLADASW::EffectProfile &ep, Material *ma);
|
||||
void set_reflective(COLLADASW::EffectProfile &ep, Material *ma);
|
||||
|
||||
void get_images(Material *ma, KeyImageMap &material_image_map);
|
||||
void create_image_samplers(COLLADASW::EffectProfile &ep,
|
||||
KeyImageMap &material_image_map,
|
||||
std::string &active_uv);
|
||||
|
||||
void writeTextures(COLLADASW::EffectProfile &ep,
|
||||
std::string &key,
|
||||
COLLADASW::Sampler *sampler,
|
||||
MTex *t,
|
||||
Image *ima,
|
||||
std::string &uvname);
|
||||
|
||||
bool hasEffects(Scene *sce);
|
||||
|
||||
BCExportSettings &export_settings;
|
||||
KeyImageMap &key_image_map;
|
||||
Scene *scene;
|
||||
bContext *mContext;
|
||||
};
|
@ -1,104 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
#include "ErrorHandler.h"
|
||||
#include <iostream>
|
||||
|
||||
#include "COLLADASaxFWLIError.h"
|
||||
#include "COLLADASaxFWLSaxFWLError.h"
|
||||
#include "COLLADASaxFWLSaxParserError.h"
|
||||
|
||||
#include "GeneratedSaxParserParserError.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
ErrorHandler::ErrorHandler() : mError(false) {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
bool ErrorHandler::handleError(const COLLADASaxFWL::IError *error)
|
||||
{
|
||||
/* This method must return false when Collada should continue.
|
||||
* See https://github.com/KhronosGroup/OpenCOLLADA/issues/442
|
||||
*/
|
||||
bool isError = true;
|
||||
std::string error_context;
|
||||
std::string error_message;
|
||||
|
||||
if (error->getErrorClass() == COLLADASaxFWL::IError::ERROR_SAXPARSER) {
|
||||
error_context = "Schema validation";
|
||||
|
||||
COLLADASaxFWL::SaxParserError *saxParserError = (COLLADASaxFWL::SaxParserError *)error;
|
||||
const GeneratedSaxParser::ParserError &parserError = saxParserError->getError();
|
||||
error_message = parserError.getErrorMessage();
|
||||
|
||||
if (parserError.getErrorType() ==
|
||||
GeneratedSaxParser::ParserError::ERROR_VALIDATION_MIN_OCCURS_UNMATCHED)
|
||||
{
|
||||
if (STREQ(parserError.getElement(), "effect")) {
|
||||
isError = false;
|
||||
}
|
||||
}
|
||||
|
||||
else if (parserError.getErrorType() ==
|
||||
GeneratedSaxParser::ParserError::
|
||||
ERROR_VALIDATION_SEQUENCE_PREVIOUS_SIBLING_NOT_PRESENT)
|
||||
{
|
||||
if (!(STREQ(parserError.getElement(), "extra") &&
|
||||
STREQ(parserError.getAdditionalText().c_str(), "sibling: fx_profile_abstract")))
|
||||
{
|
||||
isError = false;
|
||||
}
|
||||
}
|
||||
|
||||
else if (parserError.getErrorType() ==
|
||||
GeneratedSaxParser::ParserError::ERROR_COULD_NOT_OPEN_FILE)
|
||||
{
|
||||
isError = true;
|
||||
error_context = "File access";
|
||||
}
|
||||
|
||||
else if (parserError.getErrorType() ==
|
||||
GeneratedSaxParser::ParserError::ERROR_REQUIRED_ATTRIBUTE_MISSING)
|
||||
{
|
||||
isError = true;
|
||||
}
|
||||
|
||||
else {
|
||||
isError = (parserError.getSeverity() !=
|
||||
GeneratedSaxParser::ParserError::Severity::SEVERITY_ERROR_NONCRITICAL);
|
||||
}
|
||||
}
|
||||
else if (error->getErrorClass() == COLLADASaxFWL::IError::ERROR_SAXFWL) {
|
||||
error_context = "Sax FWL";
|
||||
COLLADASaxFWL::SaxFWLError *saxFWLError = (COLLADASaxFWL::SaxFWLError *)error;
|
||||
error_message = saxFWLError->getErrorMessage();
|
||||
|
||||
/*
|
||||
* Accept non critical errors as warnings (i.e. texture not found)
|
||||
* This makes the importer more graceful, so it now imports what makes sense.
|
||||
*/
|
||||
|
||||
isError = (saxFWLError->getSeverity() != COLLADASaxFWL::IError::SEVERITY_ERROR_NONCRITICAL);
|
||||
}
|
||||
else {
|
||||
error_context = "OpenCollada";
|
||||
error_message = error->getFullErrorMessage();
|
||||
isError = true;
|
||||
}
|
||||
|
||||
std::string severity = (isError) ? "Error" : "Warning";
|
||||
std::cout << error_context << " (" << severity << "): " << error_message << std::endl;
|
||||
if (isError) {
|
||||
std::cout << "The Collada import has been forced to stop." << std::endl;
|
||||
std::cout << "Please fix the reported error and then try again.";
|
||||
mError = true;
|
||||
}
|
||||
return isError;
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "COLLADASaxFWLIErrorHandler.h"
|
||||
|
||||
/** \brief Handler class for parser errors
|
||||
*/
|
||||
class ErrorHandler : public COLLADASaxFWL::IErrorHandler {
|
||||
public:
|
||||
/** Constructor. */
|
||||
ErrorHandler();
|
||||
|
||||
/** handle any error thrown by the parser. */
|
||||
bool handleError(const COLLADASaxFWL::IError *error) override;
|
||||
/** True if there was an error during parsing. */
|
||||
bool hasError()
|
||||
{
|
||||
return mError;
|
||||
}
|
||||
|
||||
private:
|
||||
/** Disable default copy constructor. */
|
||||
ErrorHandler(const ErrorHandler &pre);
|
||||
/** Disable default assignment operator. */
|
||||
const ErrorHandler &operator=(const ErrorHandler &pre);
|
||||
/** Hold error status. */
|
||||
bool mError;
|
||||
};
|
@ -1,9 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2002-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include "ExportSettings.h"
|
@ -1,282 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_linklist.h"
|
||||
#include "BlenderContext.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
# include "BCMath.h"
|
||||
# include <vector>
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum BC_export_mesh_type {
|
||||
BC_MESH_TYPE_VIEW,
|
||||
BC_MESH_TYPE_RENDER,
|
||||
};
|
||||
|
||||
enum BC_export_transformation_type {
|
||||
BC_TRANSFORMATION_TYPE_MATRIX,
|
||||
BC_TRANSFORMATION_TYPE_DECOMPOSED,
|
||||
};
|
||||
|
||||
enum BC_export_animation_type {
|
||||
BC_ANIMATION_EXPORT_SAMPLES,
|
||||
BC_ANIMATION_EXPORT_KEYS,
|
||||
};
|
||||
|
||||
enum BC_ui_export_section {
|
||||
BC_UI_SECTION_MAIN,
|
||||
BC_UI_SECTION_GEOMETRY,
|
||||
BC_UI_SECTION_ARMATURE,
|
||||
BC_UI_SECTION_ANIMATION,
|
||||
BC_UI_SECTION_COLLADA,
|
||||
};
|
||||
|
||||
struct ExportSettings {
|
||||
bool apply_modifiers;
|
||||
BC_global_forward_axis global_forward;
|
||||
BC_global_up_axis global_up;
|
||||
bool apply_global_orientation;
|
||||
|
||||
BC_export_mesh_type export_mesh_type;
|
||||
|
||||
bool selected;
|
||||
bool include_children;
|
||||
bool include_armatures;
|
||||
bool include_shapekeys;
|
||||
bool deform_bones_only;
|
||||
bool include_animations;
|
||||
bool include_all_actions;
|
||||
int sampling_rate;
|
||||
bool keep_smooth_curves;
|
||||
bool keep_keyframes;
|
||||
bool keep_flat_curves;
|
||||
|
||||
bool active_uv_only;
|
||||
BC_export_animation_type export_animation_type;
|
||||
bool use_texture_copies;
|
||||
|
||||
bool triangulate;
|
||||
bool use_object_instantiation;
|
||||
bool use_blender_profile;
|
||||
bool sort_by_name;
|
||||
BC_export_transformation_type object_transformation_type;
|
||||
BC_export_transformation_type animation_transformation_type;
|
||||
|
||||
bool open_sim;
|
||||
bool limit_precision;
|
||||
bool keep_bind_info;
|
||||
|
||||
char *filepath;
|
||||
LinkNode *export_set;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
void bc_get_children(std::vector<Object *> &child_set,
|
||||
Object *ob,
|
||||
const Scene *scene,
|
||||
ViewLayer *view_layer);
|
||||
|
||||
class BCExportSettings {
|
||||
|
||||
private:
|
||||
const ExportSettings &export_settings;
|
||||
BlenderContext &blender_context;
|
||||
const BCMatrix global_transform;
|
||||
|
||||
public:
|
||||
BCExportSettings(ExportSettings *exportSettings, BlenderContext &blenderContext)
|
||||
: export_settings(*exportSettings),
|
||||
blender_context(blenderContext),
|
||||
global_transform(BCMatrix(exportSettings->global_forward, exportSettings->global_up))
|
||||
{
|
||||
}
|
||||
|
||||
const BCMatrix &get_global_transform()
|
||||
{
|
||||
return global_transform;
|
||||
}
|
||||
|
||||
bool get_apply_modifiers()
|
||||
{
|
||||
return export_settings.apply_modifiers;
|
||||
}
|
||||
|
||||
BC_global_forward_axis get_global_forward()
|
||||
{
|
||||
return export_settings.global_forward;
|
||||
}
|
||||
|
||||
BC_global_up_axis get_global_up()
|
||||
{
|
||||
return export_settings.global_up;
|
||||
}
|
||||
|
||||
bool get_apply_global_orientation()
|
||||
{
|
||||
return export_settings.apply_global_orientation;
|
||||
}
|
||||
|
||||
BC_export_mesh_type get_export_mesh_type()
|
||||
{
|
||||
return export_settings.export_mesh_type;
|
||||
}
|
||||
|
||||
bool get_selected()
|
||||
{
|
||||
return export_settings.selected;
|
||||
}
|
||||
|
||||
bool get_include_children()
|
||||
{
|
||||
return export_settings.include_children;
|
||||
}
|
||||
|
||||
bool get_include_armatures()
|
||||
{
|
||||
return export_settings.include_armatures;
|
||||
}
|
||||
|
||||
bool get_include_shapekeys()
|
||||
{
|
||||
return export_settings.include_shapekeys;
|
||||
}
|
||||
|
||||
bool get_deform_bones_only()
|
||||
{
|
||||
return export_settings.deform_bones_only;
|
||||
}
|
||||
|
||||
bool get_include_animations()
|
||||
{
|
||||
return export_settings.include_animations;
|
||||
}
|
||||
|
||||
bool get_include_all_actions()
|
||||
{
|
||||
return export_settings.include_all_actions;
|
||||
}
|
||||
|
||||
int get_sampling_rate()
|
||||
{
|
||||
return export_settings.sampling_rate;
|
||||
}
|
||||
|
||||
bool get_keep_smooth_curves()
|
||||
{
|
||||
return export_settings.keep_smooth_curves;
|
||||
}
|
||||
|
||||
bool get_keep_keyframes()
|
||||
{
|
||||
return export_settings.keep_keyframes;
|
||||
}
|
||||
|
||||
bool get_keep_flat_curves()
|
||||
{
|
||||
return export_settings.keep_flat_curves;
|
||||
}
|
||||
|
||||
bool get_active_uv_only()
|
||||
{
|
||||
return export_settings.active_uv_only;
|
||||
}
|
||||
|
||||
BC_export_animation_type get_export_animation_type()
|
||||
{
|
||||
return export_settings.export_animation_type;
|
||||
}
|
||||
|
||||
bool get_use_texture_copies()
|
||||
{
|
||||
return export_settings.use_texture_copies;
|
||||
}
|
||||
|
||||
bool get_triangulate()
|
||||
{
|
||||
return export_settings.triangulate;
|
||||
}
|
||||
|
||||
bool get_use_object_instantiation()
|
||||
{
|
||||
return export_settings.use_object_instantiation;
|
||||
}
|
||||
|
||||
bool get_use_blender_profile()
|
||||
{
|
||||
return export_settings.use_blender_profile;
|
||||
}
|
||||
|
||||
bool get_sort_by_name()
|
||||
{
|
||||
return export_settings.sort_by_name;
|
||||
}
|
||||
|
||||
BC_export_transformation_type get_object_transformation_type()
|
||||
{
|
||||
return export_settings.object_transformation_type;
|
||||
}
|
||||
|
||||
BC_export_transformation_type get_animation_transformation_type()
|
||||
{
|
||||
return export_settings.animation_transformation_type;
|
||||
}
|
||||
|
||||
bool get_open_sim()
|
||||
{
|
||||
return export_settings.open_sim;
|
||||
}
|
||||
|
||||
bool get_limit_precision()
|
||||
{
|
||||
return export_settings.limit_precision;
|
||||
}
|
||||
|
||||
bool get_keep_bind_info()
|
||||
{
|
||||
return export_settings.keep_bind_info;
|
||||
}
|
||||
|
||||
char *get_filepath()
|
||||
{
|
||||
return export_settings.filepath;
|
||||
}
|
||||
|
||||
LinkNode *get_export_set()
|
||||
{
|
||||
return export_settings.export_set;
|
||||
}
|
||||
|
||||
BlenderContext &get_blender_context()
|
||||
{
|
||||
return blender_context;
|
||||
}
|
||||
|
||||
Scene *get_scene()
|
||||
{
|
||||
return blender_context.get_scene();
|
||||
}
|
||||
|
||||
ViewLayer *get_view_layer()
|
||||
{
|
||||
return blender_context.get_view_layer();
|
||||
}
|
||||
|
||||
bool is_export_root(Object *ob)
|
||||
{
|
||||
return bc_is_base_node(get_export_set(), ob, get_scene(), get_view_layer());
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
@ -1,80 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "ExtraHandler.h"
|
||||
|
||||
ExtraHandler::ExtraHandler(DocumentImporter *dimp, AnimationImporter *aimp)
|
||||
: currentExtraTags(nullptr)
|
||||
{
|
||||
this->dimp = dimp;
|
||||
this->aimp = aimp;
|
||||
}
|
||||
|
||||
bool ExtraHandler::elementBegin(const char *elementName, const char **attributes)
|
||||
{
|
||||
/* \todo attribute handling for profile tags */
|
||||
currentElement = std::string(elementName);
|
||||
// addToSidTree(attributes[0], attributes[1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExtraHandler::elementEnd(const char *elementName)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExtraHandler::textData(const char *text, size_t textLength)
|
||||
{
|
||||
char buf[1024];
|
||||
|
||||
if (currentElement.length() == 0 || currentExtraTags == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BLI_strncpy(buf, text, textLength + 1);
|
||||
currentExtraTags->addTag(currentElement, std::string(buf));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExtraHandler::parseElement(const char *profileName,
|
||||
const ulong &elementHash,
|
||||
const COLLADAFW::UniqueId &uniqueId)
|
||||
{
|
||||
/* implement for backwards compatibility, new version added object parameter */
|
||||
return parseElement(profileName, elementHash, uniqueId, nullptr);
|
||||
}
|
||||
|
||||
bool ExtraHandler::parseElement(const char *profileName,
|
||||
const ulong &elementHash,
|
||||
const COLLADAFW::UniqueId &uniqueId,
|
||||
COLLADAFW::Object *object)
|
||||
{
|
||||
if (BLI_strcaseeq(profileName, "blender")) {
|
||||
#if 0
|
||||
printf("In parseElement for supported profile %s for id %s\n",
|
||||
profileName,
|
||||
uniqueId.toAscii().c_str());
|
||||
#endif
|
||||
currentUid = uniqueId;
|
||||
ExtraTags *et = dimp->getExtraTags(uniqueId);
|
||||
if (!et) {
|
||||
et = new ExtraTags(std::string(profileName));
|
||||
dimp->addExtraTags(uniqueId, et);
|
||||
}
|
||||
currentExtraTags = et;
|
||||
return true;
|
||||
}
|
||||
// printf("In parseElement for unsupported profile %s for id %s\n", profileName,
|
||||
// uniqueId.toAscii().c_str());
|
||||
return false;
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "COLLADASaxFWLIExtraDataCallbackHandler.h"
|
||||
|
||||
#include "AnimationImporter.h"
|
||||
#include "DocumentImporter.h"
|
||||
|
||||
/** \brief Handler class for \<extra\> data, through which different
|
||||
* profiles can be handled
|
||||
*/
|
||||
class ExtraHandler : public COLLADASaxFWL::IExtraDataCallbackHandler {
|
||||
public:
|
||||
/** Constructor. */
|
||||
ExtraHandler(DocumentImporter *dimp, AnimationImporter *aimp);
|
||||
|
||||
/** Handle the beginning of an element. */
|
||||
bool elementBegin(const char *elementName, const char **attributes) override;
|
||||
|
||||
/** Handle the end of an element. */
|
||||
bool elementEnd(const char *elementName) override;
|
||||
|
||||
/** Receive the data in text format. */
|
||||
bool textData(const char *text, size_t textLength) override;
|
||||
|
||||
/** Method to ask, if the current callback handler want to read the data of the given extra
|
||||
* element. */
|
||||
bool parseElement(const char *profileName,
|
||||
const unsigned long &elementHash,
|
||||
const COLLADAFW::UniqueId &uniqueId,
|
||||
COLLADAFW::Object *object) override;
|
||||
|
||||
/** For backwards compatibility with older OpenCollada, new version added object parameter */
|
||||
bool parseElement(const char *profileName,
|
||||
const unsigned long &elementHash,
|
||||
const COLLADAFW::UniqueId &uniqueId);
|
||||
|
||||
private:
|
||||
/** Disable default copy constructor. */
|
||||
ExtraHandler(const ExtraHandler &pre);
|
||||
/** Disable default assignment operator. */
|
||||
const ExtraHandler &operator=(const ExtraHandler &pre);
|
||||
|
||||
/** Handle to DocumentImporter for interface to extra element data saving. */
|
||||
DocumentImporter *dimp;
|
||||
AnimationImporter *aimp;
|
||||
/** Holds Id of element for which <extra> XML elements are handled. */
|
||||
COLLADAFW::UniqueId currentUid;
|
||||
ExtraTags *currentExtraTags;
|
||||
std::string currentElement;
|
||||
};
|
@ -1,131 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2002-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <regex>
|
||||
|
||||
#include "ExtraTags.h"
|
||||
|
||||
ExtraTags::ExtraTags(std::string profile)
|
||||
{
|
||||
this->profile = profile;
|
||||
this->tags = std::map<std::string, std::string>();
|
||||
}
|
||||
|
||||
ExtraTags::~ExtraTags() = default;
|
||||
|
||||
bool ExtraTags::isProfile(std::string profile)
|
||||
{
|
||||
return this->profile == profile;
|
||||
}
|
||||
|
||||
bool ExtraTags::addTag(std::string tag, std::string data)
|
||||
{
|
||||
tags[tag] = data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int ExtraTags::asInt(std::string tag, bool *r_ok)
|
||||
{
|
||||
if (tags.find(tag) == tags.end()) {
|
||||
*r_ok = false;
|
||||
return -1;
|
||||
}
|
||||
*r_ok = true;
|
||||
return atoi(tags[tag].c_str());
|
||||
}
|
||||
|
||||
float ExtraTags::asFloat(std::string tag, bool *r_ok)
|
||||
{
|
||||
if (tags.find(tag) == tags.end()) {
|
||||
*r_ok = false;
|
||||
return -1.0f;
|
||||
}
|
||||
*r_ok = true;
|
||||
return float(atof(tags[tag].c_str()));
|
||||
}
|
||||
|
||||
std::string ExtraTags::asString(std::string tag, bool *r_ok)
|
||||
{
|
||||
if (tags.find(tag) == tags.end()) {
|
||||
*r_ok = false;
|
||||
return "";
|
||||
}
|
||||
*r_ok = true;
|
||||
return tags[tag];
|
||||
}
|
||||
|
||||
bool ExtraTags::setData(std::string tag, short *data)
|
||||
{
|
||||
bool ok = false;
|
||||
int tmp = asInt(tag, &ok);
|
||||
if (ok) {
|
||||
*data = short(tmp);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool ExtraTags::setData(std::string tag, int *data)
|
||||
{
|
||||
bool ok = false;
|
||||
int tmp = asInt(tag, &ok);
|
||||
if (ok) {
|
||||
*data = tmp;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool ExtraTags::setData(std::string tag, float *data)
|
||||
{
|
||||
bool ok = false;
|
||||
float tmp = asFloat(tag, &ok);
|
||||
if (ok) {
|
||||
*data = tmp;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool ExtraTags::setData(std::string tag, char *data)
|
||||
{
|
||||
bool ok = false;
|
||||
int tmp = asInt(tag, &ok);
|
||||
if (ok) {
|
||||
*data = char(tmp);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
std::string ExtraTags::setData(std::string tag, std::string &data)
|
||||
{
|
||||
bool ok = false;
|
||||
std::string tmp = asString(tag, &ok);
|
||||
return (ok) ? tmp : data;
|
||||
}
|
||||
|
||||
std::vector<std::string> ExtraTags::dataSplitString(const std::string &tag)
|
||||
{
|
||||
bool ok = false;
|
||||
const std::string value = asString(tag, &ok);
|
||||
if (!ok) {
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
|
||||
std::vector<std::string> values;
|
||||
|
||||
const std::regex newline_re("[^\\s][^\\r\\n]+");
|
||||
const std::sregex_token_iterator end;
|
||||
std::sregex_token_iterator iter(value.begin(), value.end(), newline_re);
|
||||
for (; iter != end; iter++) {
|
||||
values.push_back(*iter);
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/** \brief Class for saving \<extra\> tags for a specific UniqueId.
|
||||
*/
|
||||
class ExtraTags {
|
||||
public:
|
||||
/** Constructor. */
|
||||
ExtraTags(const std::string profile);
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~ExtraTags();
|
||||
|
||||
/** Handle the beginning of an element. */
|
||||
bool addTag(std::string tag, std::string data);
|
||||
|
||||
/** Set given short pointer to value of tag, if it exists. */
|
||||
bool setData(std::string tag, short *data);
|
||||
|
||||
/** Set given int pointer to value of tag, if it exists. */
|
||||
bool setData(std::string tag, int *data);
|
||||
|
||||
/** Set given float pointer to value of tag, if it exists. */
|
||||
bool setData(std::string tag, float *data);
|
||||
|
||||
/** Set given char pointer to value of tag, if it exists. */
|
||||
bool setData(std::string tag, char *data);
|
||||
std::string setData(std::string tag, std::string &data);
|
||||
|
||||
/** Get a string from the data, and split it by newlines. */
|
||||
std::vector<std::string> dataSplitString(const std::string &tag);
|
||||
|
||||
/** Return true if the extra tags is for specified profile. */
|
||||
bool isProfile(std::string profile);
|
||||
|
||||
private:
|
||||
/** Disable default copy constructor. */
|
||||
ExtraTags(const ExtraTags &pre);
|
||||
/** Disable default assignment operator. */
|
||||
const ExtraTags &operator=(const ExtraTags &pre);
|
||||
|
||||
/** The profile for which the tags are. */
|
||||
std::string profile;
|
||||
|
||||
/** Map of tag and text pairs. */
|
||||
std::map<std::string, std::string> tags;
|
||||
|
||||
/** Get text data for tag as an int. */
|
||||
int asInt(std::string tag, bool *r_ok);
|
||||
/** Get text data for tag as a float. */
|
||||
float asFloat(std::string tag, bool *r_ok);
|
||||
/** Get text data for tag as a string. */
|
||||
std::string asString(std::string tag, bool *r_ok);
|
||||
};
|
@ -1,706 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2010-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "COLLADABUUtils.h"
|
||||
#include "COLLADASWPrimitves.h"
|
||||
#include "COLLADASWSource.h"
|
||||
#include "COLLADASWVertices.h"
|
||||
|
||||
#include "GeometryExporter.h"
|
||||
|
||||
#include "DNA_key_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_customdata.hh"
|
||||
#include "BKE_key.hh"
|
||||
#include "BKE_lib_id.hh"
|
||||
#include "BKE_material.hh"
|
||||
#include "BKE_mesh.hh"
|
||||
|
||||
#include "collada_internal.h"
|
||||
#include "collada_utils.h"
|
||||
|
||||
using blender::float3;
|
||||
using blender::Span;
|
||||
|
||||
void GeometryExporter::exportGeom()
|
||||
{
|
||||
Scene *sce = blender_context.get_scene();
|
||||
openLibrary();
|
||||
|
||||
GeometryFunctor gf;
|
||||
gf.forEachMeshObjectInExportSet<GeometryExporter>(
|
||||
sce, *this, this->export_settings.get_export_set());
|
||||
|
||||
closeLibrary();
|
||||
}
|
||||
|
||||
void GeometryExporter::operator()(Object *ob)
|
||||
{
|
||||
bool use_instantiation = this->export_settings.get_use_object_instantiation();
|
||||
Mesh *mesh = bc_get_mesh_copy(blender_context,
|
||||
ob,
|
||||
this->export_settings.get_export_mesh_type(),
|
||||
this->export_settings.get_apply_modifiers(),
|
||||
this->export_settings.get_triangulate());
|
||||
|
||||
std::string geom_id = get_geometry_id(ob, use_instantiation);
|
||||
std::vector<Normal> nor;
|
||||
std::vector<BCPolygonNormalsIndices> norind;
|
||||
|
||||
/* Skip if linked geometry was already exported from another reference */
|
||||
if (use_instantiation && exportedGeometry.find(geom_id) != exportedGeometry.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string geom_name = (use_instantiation) ? id_name(ob->data) : id_name(ob);
|
||||
geom_name = encode_xml(geom_name);
|
||||
|
||||
exportedGeometry.insert(geom_id);
|
||||
|
||||
bool has_color = CustomData_has_layer(&mesh->fdata_legacy, CD_MCOL);
|
||||
|
||||
create_normals(nor, norind, mesh);
|
||||
|
||||
/* openMesh(geoId, geoName, meshId) */
|
||||
openMesh(geom_id, geom_name);
|
||||
|
||||
/* writes <source> for vertex coords */
|
||||
createVertsSource(geom_id, mesh);
|
||||
|
||||
/* writes <source> for normal coords */
|
||||
createNormalsSource(geom_id, mesh, nor);
|
||||
|
||||
bool has_uvs = CustomData_has_layer(&mesh->corner_data, CD_PROP_FLOAT2);
|
||||
|
||||
/* writes <source> for uv coords if mesh has uv coords */
|
||||
if (has_uvs) {
|
||||
createTexcoordsSource(geom_id, mesh);
|
||||
}
|
||||
|
||||
if (has_color) {
|
||||
createVertexColorSource(geom_id, mesh);
|
||||
}
|
||||
/* <vertices> */
|
||||
|
||||
COLLADASW::Vertices verts(mSW);
|
||||
verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX));
|
||||
COLLADASW::InputList &input_list = verts.getInputList();
|
||||
COLLADASW::Input input(COLLADASW::InputSemantic::POSITION,
|
||||
getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
|
||||
input_list.push_back(input);
|
||||
verts.add();
|
||||
|
||||
createLooseEdgeList(ob, mesh, geom_id);
|
||||
|
||||
/* Only create poly-lists if number of faces > 0. */
|
||||
if (mesh->totface_legacy > 0) {
|
||||
/* XXX slow */
|
||||
if (ob->totcol) {
|
||||
for (int a = 0; a < ob->totcol; a++) {
|
||||
create_mesh_primitive_list(a, has_uvs, has_color, ob, mesh, geom_id, norind);
|
||||
}
|
||||
}
|
||||
else {
|
||||
create_mesh_primitive_list(0, has_uvs, has_color, ob, mesh, geom_id, norind);
|
||||
}
|
||||
}
|
||||
|
||||
closeMesh();
|
||||
|
||||
closeGeometry();
|
||||
|
||||
if (this->export_settings.get_include_shapekeys()) {
|
||||
Key *key = BKE_key_from_object(ob);
|
||||
if (key) {
|
||||
blender::MutableSpan<float3> positions = mesh->vert_positions_for_write();
|
||||
KeyBlock *kb = (KeyBlock *)key->block.first;
|
||||
/* skip the basis */
|
||||
kb = kb->next;
|
||||
for (; kb; kb = kb->next) {
|
||||
BKE_keyblock_convert_to_mesh(kb, positions);
|
||||
export_key_mesh(ob, mesh, kb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BKE_id_free(nullptr, mesh);
|
||||
}
|
||||
|
||||
void GeometryExporter::export_key_mesh(Object *ob, Mesh *mesh, KeyBlock *kb)
|
||||
{
|
||||
std::string geom_id = get_geometry_id(ob, false) + "_morph_" + translate_id(kb->name);
|
||||
std::vector<Normal> nor;
|
||||
std::vector<BCPolygonNormalsIndices> norind;
|
||||
|
||||
if (exportedGeometry.find(geom_id) != exportedGeometry.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string geom_name = kb->name;
|
||||
|
||||
exportedGeometry.insert(geom_id);
|
||||
|
||||
bool has_color = CustomData_has_layer(&mesh->fdata_legacy, CD_MCOL);
|
||||
|
||||
create_normals(nor, norind, mesh);
|
||||
|
||||
// openMesh(geoId, geoName, meshId)
|
||||
openMesh(geom_id, geom_name);
|
||||
|
||||
/* writes <source> for vertex coords */
|
||||
createVertsSource(geom_id, mesh);
|
||||
|
||||
/* writes <source> for normal coords */
|
||||
createNormalsSource(geom_id, mesh, nor);
|
||||
|
||||
bool has_uvs = CustomData_has_layer(&mesh->corner_data, CD_PROP_FLOAT2);
|
||||
|
||||
/* writes <source> for uv coords if mesh has uv coords */
|
||||
if (has_uvs) {
|
||||
createTexcoordsSource(geom_id, mesh);
|
||||
}
|
||||
|
||||
if (has_color) {
|
||||
createVertexColorSource(geom_id, mesh);
|
||||
}
|
||||
|
||||
/* <vertices> */
|
||||
|
||||
COLLADASW::Vertices verts(mSW);
|
||||
verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX));
|
||||
COLLADASW::InputList &input_list = verts.getInputList();
|
||||
COLLADASW::Input input(COLLADASW::InputSemantic::POSITION,
|
||||
getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
|
||||
input_list.push_back(input);
|
||||
verts.add();
|
||||
|
||||
// createLooseEdgeList(ob, mesh, geom_id, norind);
|
||||
|
||||
/* XXX slow */
|
||||
if (ob->totcol) {
|
||||
for (int a = 0; a < ob->totcol; a++) {
|
||||
create_mesh_primitive_list(a, has_uvs, has_color, ob, mesh, geom_id, norind);
|
||||
}
|
||||
}
|
||||
else {
|
||||
create_mesh_primitive_list(0, has_uvs, has_color, ob, mesh, geom_id, norind);
|
||||
}
|
||||
|
||||
closeMesh();
|
||||
|
||||
closeGeometry();
|
||||
}
|
||||
|
||||
void GeometryExporter::createLooseEdgeList(Object *ob, Mesh *mesh, std::string &geom_id)
|
||||
{
|
||||
using namespace blender;
|
||||
const Span<int2> edges = mesh->edges();
|
||||
int edges_in_linelist = 0;
|
||||
std::vector<uint> edge_list;
|
||||
int index;
|
||||
|
||||
/* Find all loose edges in Mesh
|
||||
* and save vertex indices in edge_list */
|
||||
const bke::LooseEdgeCache &loose_edges = mesh->loose_edges();
|
||||
if (loose_edges.count > 0) {
|
||||
for (const int64_t i : edges.index_range()) {
|
||||
if (loose_edges.is_loose_bits[i]) {
|
||||
const int2 &edge = edges[i];
|
||||
edges_in_linelist += 1;
|
||||
edge_list.push_back(edge[0]);
|
||||
edge_list.push_back(edge[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (edges_in_linelist > 0) {
|
||||
/* Create the list of loose edges */
|
||||
COLLADASW::Lines lines(mSW);
|
||||
|
||||
lines.setCount(edges_in_linelist);
|
||||
|
||||
COLLADASW::InputList &til = lines.getInputList();
|
||||
|
||||
/* creates <input> in <lines> for vertices */
|
||||
COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX,
|
||||
getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX),
|
||||
0);
|
||||
til.push_back(input1);
|
||||
|
||||
lines.prepareToAppendValues();
|
||||
|
||||
for (index = 0; index < edges_in_linelist; index++) {
|
||||
lines.appendValues(edge_list[2 * index + 1]);
|
||||
lines.appendValues(edge_list[2 * index]);
|
||||
}
|
||||
lines.finish();
|
||||
}
|
||||
}
|
||||
|
||||
static void prepareToAppendValues(bool is_triangulated,
|
||||
COLLADASW::PrimitivesBase &primitive_list,
|
||||
std::vector<ulong> &vcount_list)
|
||||
{
|
||||
/* performs the actual writing */
|
||||
if (is_triangulated) {
|
||||
((COLLADASW::Triangles &)primitive_list).prepareToAppendValues();
|
||||
}
|
||||
else {
|
||||
/* sets <vcount> */
|
||||
primitive_list.setVCountList(vcount_list);
|
||||
((COLLADASW::Polylist &)primitive_list).prepareToAppendValues();
|
||||
}
|
||||
}
|
||||
|
||||
static void finish_and_delete_primitive_List(bool is_triangulated,
|
||||
COLLADASW::PrimitivesBase *primitive_list)
|
||||
{
|
||||
if (is_triangulated) {
|
||||
((COLLADASW::Triangles *)primitive_list)->finish();
|
||||
}
|
||||
else {
|
||||
((COLLADASW::Polylist *)primitive_list)->finish();
|
||||
}
|
||||
delete primitive_list;
|
||||
}
|
||||
|
||||
static COLLADASW::PrimitivesBase *create_primitive_list(bool is_triangulated,
|
||||
COLLADASW::StreamWriter *mSW)
|
||||
{
|
||||
COLLADASW::PrimitivesBase *primitive_list;
|
||||
|
||||
if (is_triangulated) {
|
||||
primitive_list = new COLLADASW::Triangles(mSW);
|
||||
}
|
||||
else {
|
||||
primitive_list = new COLLADASW::Polylist(mSW);
|
||||
}
|
||||
return primitive_list;
|
||||
}
|
||||
|
||||
static bool collect_vertex_counts_per_poly(Mesh *mesh,
|
||||
int material_index,
|
||||
std::vector<ulong> &vcount_list)
|
||||
{
|
||||
using namespace blender;
|
||||
const blender::OffsetIndices faces = mesh->faces();
|
||||
const blender::bke::AttributeAccessor attributes = mesh->attributes();
|
||||
const blender::VArray<int> material_indices = *attributes.lookup_or_default<int>(
|
||||
"material_index", bke::AttrDomain::Face, 0);
|
||||
bool is_triangulated = true;
|
||||
|
||||
/* Expecting that the material index is always 0 if the mesh has no materials assigned */
|
||||
for (const int i : faces.index_range()) {
|
||||
if (material_indices[i] == material_index) {
|
||||
const int vertex_count = faces[i].size();
|
||||
vcount_list.push_back(vertex_count);
|
||||
if (vertex_count != 3) {
|
||||
is_triangulated = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return is_triangulated;
|
||||
}
|
||||
|
||||
std::string GeometryExporter::makeVertexColorSourceId(std::string &geom_id, const char *layer_name)
|
||||
{
|
||||
std::string result = getIdBySemantics(geom_id, COLLADASW::InputSemantic::COLOR) + "-" +
|
||||
layer_name;
|
||||
return result;
|
||||
}
|
||||
|
||||
void GeometryExporter::create_mesh_primitive_list(short material_index,
|
||||
bool has_uvs,
|
||||
bool has_color,
|
||||
Object *ob,
|
||||
Mesh *mesh,
|
||||
std::string &geom_id,
|
||||
std::vector<BCPolygonNormalsIndices> &norind)
|
||||
{
|
||||
using namespace blender;
|
||||
const blender::OffsetIndices faces = mesh->faces();
|
||||
const Span<int> corner_verts = mesh->corner_verts();
|
||||
|
||||
std::vector<ulong> vcount_list;
|
||||
|
||||
bool is_triangulated = collect_vertex_counts_per_poly(mesh, material_index, vcount_list);
|
||||
int polygon_count = vcount_list.size();
|
||||
|
||||
/* no faces using this material */
|
||||
if (polygon_count == 0) {
|
||||
fprintf(
|
||||
stderr, "%s: material with index %d is not used.\n", id_name(ob).c_str(), material_index);
|
||||
return;
|
||||
}
|
||||
|
||||
Material *ma = ob->totcol ? BKE_object_material_get(ob, material_index + 1) : nullptr;
|
||||
COLLADASW::PrimitivesBase *primitive_list = create_primitive_list(is_triangulated, mSW);
|
||||
|
||||
/* sets count attribute in `<polylist>`. */
|
||||
primitive_list->setCount(polygon_count);
|
||||
|
||||
/* sets material name */
|
||||
if (ma) {
|
||||
std::string material_id = get_material_id(ma);
|
||||
std::ostringstream ostr;
|
||||
ostr << translate_id(material_id);
|
||||
primitive_list->setMaterial(ostr.str());
|
||||
}
|
||||
|
||||
COLLADASW::Input vertex_input(COLLADASW::InputSemantic::VERTEX,
|
||||
getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX),
|
||||
0);
|
||||
COLLADASW::Input normals_input(COLLADASW::InputSemantic::NORMAL,
|
||||
getUrlBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL),
|
||||
1);
|
||||
|
||||
COLLADASW::InputList &til = primitive_list->getInputList();
|
||||
til.push_back(vertex_input);
|
||||
til.push_back(normals_input);
|
||||
|
||||
/* if mesh has uv coords writes <input> for TEXCOORD */
|
||||
int num_layers = CustomData_number_of_layers(&mesh->corner_data, CD_PROP_FLOAT2);
|
||||
int active_uv = CustomData_get_active_layer(&mesh->corner_data, CD_PROP_FLOAT2);
|
||||
for (int i = 0; i < num_layers; i++) {
|
||||
if (!this->export_settings.get_active_uv_only() || i == active_uv) {
|
||||
|
||||
// char *name = CustomData_get_layer_name(&mesh->ldata, CD_PROP_FLOAT2, i);
|
||||
COLLADASW::Input texcoord_input(
|
||||
COLLADASW::InputSemantic::TEXCOORD,
|
||||
makeUrl(makeTexcoordSourceId(geom_id, i, this->export_settings.get_active_uv_only())),
|
||||
2, /* this is only until we have optimized UV sets */
|
||||
this->export_settings.get_active_uv_only() ? 0 : i /* set (0,1,2,...) */
|
||||
);
|
||||
til.push_back(texcoord_input);
|
||||
}
|
||||
}
|
||||
|
||||
int totlayer_mcol = CustomData_number_of_layers(&mesh->corner_data, CD_PROP_BYTE_COLOR);
|
||||
if (totlayer_mcol > 0) {
|
||||
int map_index = 0;
|
||||
|
||||
for (int a = 0; a < totlayer_mcol; a++) {
|
||||
const char *layer_name = bc_CustomData_get_layer_name(
|
||||
&mesh->corner_data, CD_PROP_BYTE_COLOR, a);
|
||||
COLLADASW::Input input4(COLLADASW::InputSemantic::COLOR,
|
||||
makeUrl(makeVertexColorSourceId(geom_id, layer_name)),
|
||||
(has_uvs) ? 3 : 2, /* all color layers have same index order */
|
||||
map_index /* set number equals color map index */
|
||||
);
|
||||
til.push_back(input4);
|
||||
map_index++;
|
||||
}
|
||||
}
|
||||
|
||||
/* performs the actual writing */
|
||||
prepareToAppendValues(is_triangulated, *primitive_list, vcount_list);
|
||||
|
||||
const blender::bke::AttributeAccessor attributes = mesh->attributes();
|
||||
const blender::VArray<int> material_indices = *attributes.lookup_or_default<int>(
|
||||
"material_index", bke::AttrDomain::Face, 0);
|
||||
|
||||
/* <p> */
|
||||
int texindex = 0;
|
||||
for (const int i : faces.index_range()) {
|
||||
const blender::IndexRange poly = faces[i];
|
||||
int loop_count = poly.size();
|
||||
|
||||
if (material_indices[i] == material_index) {
|
||||
BCPolygonNormalsIndices normal_indices = norind[i];
|
||||
|
||||
for (int j = 0; j < loop_count; j++) {
|
||||
const int vert = corner_verts[poly[j]];
|
||||
primitive_list->appendValues(vert);
|
||||
primitive_list->appendValues(normal_indices[j]);
|
||||
if (has_uvs) {
|
||||
primitive_list->appendValues(texindex + j);
|
||||
}
|
||||
|
||||
if (has_color) {
|
||||
primitive_list->appendValues(texindex + j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
texindex += loop_count;
|
||||
}
|
||||
|
||||
finish_and_delete_primitive_List(is_triangulated, primitive_list);
|
||||
}
|
||||
|
||||
void GeometryExporter::createVertsSource(std::string geom_id, Mesh *mesh)
|
||||
{
|
||||
const Span<float3> positions = mesh->vert_positions();
|
||||
|
||||
COLLADASW::FloatSourceF source(mSW);
|
||||
source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
|
||||
source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION) +
|
||||
ARRAY_ID_SUFFIX);
|
||||
source.setAccessorCount(positions.size());
|
||||
source.setAccessorStride(3);
|
||||
|
||||
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
||||
param.emplace_back("X");
|
||||
param.emplace_back("Y");
|
||||
param.emplace_back("Z");
|
||||
/* main function, it creates <source id = "">, <float_array id = ""
|
||||
* count = ""> */
|
||||
source.prepareToAppendValues();
|
||||
/* appends data to <float_array> */
|
||||
for (const int i : positions.index_range()) {
|
||||
Vector co;
|
||||
if (export_settings.get_apply_global_orientation()) {
|
||||
float co_c[3];
|
||||
copy_v3_v3(co_c, positions[i]);
|
||||
bc_add_global_transform(co, co_c, export_settings.get_global_transform());
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(co, positions[i]);
|
||||
}
|
||||
source.appendValues(co[0], co[1], co[2]);
|
||||
}
|
||||
|
||||
source.finish();
|
||||
}
|
||||
|
||||
void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *mesh)
|
||||
{
|
||||
/* Find number of vertex color layers */
|
||||
int totlayer_mcol = CustomData_number_of_layers(&mesh->corner_data, CD_PROP_BYTE_COLOR);
|
||||
if (totlayer_mcol == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int map_index = 0;
|
||||
for (int a = 0; a < totlayer_mcol; a++) {
|
||||
|
||||
map_index++;
|
||||
const MLoopCol *mloopcol = (const MLoopCol *)CustomData_get_layer_n(
|
||||
&mesh->corner_data, CD_PROP_BYTE_COLOR, a);
|
||||
|
||||
COLLADASW::FloatSourceF source(mSW);
|
||||
|
||||
const char *layer_name = bc_CustomData_get_layer_name(
|
||||
&mesh->corner_data, CD_PROP_BYTE_COLOR, a);
|
||||
std::string layer_id = makeVertexColorSourceId(geom_id, layer_name);
|
||||
source.setId(layer_id);
|
||||
|
||||
source.setNodeName(layer_name);
|
||||
|
||||
source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
|
||||
source.setAccessorCount(mesh->corners_num);
|
||||
source.setAccessorStride(4);
|
||||
|
||||
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
||||
param.emplace_back("R");
|
||||
param.emplace_back("G");
|
||||
param.emplace_back("B");
|
||||
param.emplace_back("A");
|
||||
|
||||
source.prepareToAppendValues();
|
||||
|
||||
const blender::OffsetIndices faces = mesh->faces();
|
||||
for (const int i : faces.index_range()) {
|
||||
for (const int corner : faces[i]) {
|
||||
const MLoopCol *mlc = &mloopcol[corner];
|
||||
source.appendValues(mlc->r / 255.0f, mlc->g / 255.0f, mlc->b / 255.0f, mlc->a / 255.0f);
|
||||
}
|
||||
}
|
||||
|
||||
source.finish();
|
||||
}
|
||||
}
|
||||
|
||||
std::string GeometryExporter::makeTexcoordSourceId(std::string &geom_id,
|
||||
int layer_index,
|
||||
bool is_single_layer)
|
||||
{
|
||||
char suffix[20];
|
||||
if (is_single_layer) {
|
||||
suffix[0] = '\0';
|
||||
}
|
||||
else {
|
||||
SNPRINTF(suffix, "-%d", layer_index);
|
||||
}
|
||||
return getIdBySemantics(geom_id, COLLADASW::InputSemantic::TEXCOORD) + suffix;
|
||||
}
|
||||
|
||||
void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *mesh)
|
||||
{
|
||||
int totuv = mesh->corners_num;
|
||||
const blender::OffsetIndices faces = mesh->faces();
|
||||
|
||||
int num_layers = CustomData_number_of_layers(&mesh->corner_data, CD_PROP_FLOAT2);
|
||||
|
||||
/* write <source> for each layer
|
||||
* each <source> will get id like meshName + "map-channel-1" */
|
||||
int active_uv_index = CustomData_get_active_layer_index(&mesh->corner_data, CD_PROP_FLOAT2);
|
||||
for (int a = 0; a < num_layers; a++) {
|
||||
int layer_index = CustomData_get_layer_index_n(&mesh->corner_data, CD_PROP_FLOAT2, a);
|
||||
if (!this->export_settings.get_active_uv_only() || layer_index == active_uv_index) {
|
||||
const blender::float2 *uv_map = static_cast<const blender::float2 *>(
|
||||
CustomData_get_layer_n(&mesh->corner_data, CD_PROP_FLOAT2, a));
|
||||
|
||||
COLLADASW::FloatSourceF source(mSW);
|
||||
std::string layer_id = makeTexcoordSourceId(
|
||||
geom_id, a, this->export_settings.get_active_uv_only());
|
||||
source.setId(layer_id);
|
||||
source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
|
||||
|
||||
source.setAccessorCount(totuv);
|
||||
source.setAccessorStride(2);
|
||||
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
||||
param.emplace_back("S");
|
||||
param.emplace_back("T");
|
||||
|
||||
source.prepareToAppendValues();
|
||||
|
||||
for (const int i : faces.index_range()) {
|
||||
for (const int corner : faces[i]) {
|
||||
source.appendValues(uv_map[corner][0], uv_map[corner][1]);
|
||||
}
|
||||
}
|
||||
|
||||
source.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool operator<(const Normal &a, const Normal &b)
|
||||
{
|
||||
/* Only needed to sort normal vectors and find() them later in a map. */
|
||||
return a.x < b.x || (a.x == b.x && (a.y < b.y || (a.y == b.y && a.z < b.z)));
|
||||
}
|
||||
|
||||
void GeometryExporter::createNormalsSource(std::string geom_id,
|
||||
Mesh *mesh,
|
||||
std::vector<Normal> &nor)
|
||||
{
|
||||
COLLADASW::FloatSourceF source(mSW);
|
||||
source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL));
|
||||
source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL) + ARRAY_ID_SUFFIX);
|
||||
source.setAccessorCount(ulong(nor.size()));
|
||||
source.setAccessorStride(3);
|
||||
COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
|
||||
param.emplace_back("X");
|
||||
param.emplace_back("Y");
|
||||
param.emplace_back("Z");
|
||||
|
||||
source.prepareToAppendValues();
|
||||
|
||||
std::vector<Normal>::iterator it;
|
||||
for (it = nor.begin(); it != nor.end(); it++) {
|
||||
Normal &n = *it;
|
||||
|
||||
Vector no{n.x, n.y, n.z};
|
||||
if (export_settings.get_apply_global_orientation()) {
|
||||
bc_add_global_transform(no, export_settings.get_global_transform());
|
||||
}
|
||||
source.appendValues(no[0], no[1], no[2]);
|
||||
}
|
||||
|
||||
source.finish();
|
||||
}
|
||||
|
||||
void GeometryExporter::create_normals(std::vector<Normal> &normals,
|
||||
std::vector<BCPolygonNormalsIndices> &polygons_normals,
|
||||
Mesh *mesh)
|
||||
{
|
||||
using namespace blender;
|
||||
std::map<Normal, uint> shared_normal_indices;
|
||||
int last_normal_index = -1;
|
||||
|
||||
const Span<float3> positions = mesh->vert_positions();
|
||||
const Span<float3> vert_normals = mesh->vert_normals();
|
||||
const blender::OffsetIndices faces = mesh->faces();
|
||||
const Span<int> corner_verts = mesh->corner_verts();
|
||||
|
||||
const bke::AttributeAccessor attributes = mesh->attributes();
|
||||
const VArray<bool> sharp_faces = *attributes.lookup_or_default<bool>(
|
||||
"sharp_face", bke::AttrDomain::Face, false);
|
||||
|
||||
blender::Span<blender::float3> corner_normals;
|
||||
if (mesh->normals_domain() == blender::bke::MeshNormalDomain::Corner) {
|
||||
corner_normals = mesh->corner_normals();
|
||||
}
|
||||
|
||||
for (const int face_index : faces.index_range()) {
|
||||
const IndexRange face = faces[face_index];
|
||||
bool use_vert_normals = !corner_normals.is_empty() || !sharp_faces[face_index];
|
||||
|
||||
if (!use_vert_normals) {
|
||||
/* For flat faces use face normal as vertex normal: */
|
||||
|
||||
const float3 vector = blender::bke::mesh::face_normal_calc(positions,
|
||||
corner_verts.slice(face));
|
||||
|
||||
Normal n = {vector[0], vector[1], vector[2]};
|
||||
normals.push_back(n);
|
||||
last_normal_index++;
|
||||
}
|
||||
|
||||
BCPolygonNormalsIndices poly_indices;
|
||||
for (const int corner : face) {
|
||||
if (use_vert_normals) {
|
||||
float normalized[3];
|
||||
|
||||
if (!corner_normals.is_empty()) {
|
||||
normalize_v3_v3(normalized, corner_normals[corner]);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(normalized, vert_normals[corner_verts[corner]]);
|
||||
normalize_v3(normalized);
|
||||
}
|
||||
Normal n = {normalized[0], normalized[1], normalized[2]};
|
||||
|
||||
if (shared_normal_indices.find(n) != shared_normal_indices.end()) {
|
||||
poly_indices.add_index(shared_normal_indices[n]);
|
||||
}
|
||||
else {
|
||||
last_normal_index++;
|
||||
poly_indices.add_index(last_normal_index);
|
||||
shared_normal_indices[n] = last_normal_index;
|
||||
normals.push_back(n);
|
||||
}
|
||||
}
|
||||
else {
|
||||
poly_indices.add_index(last_normal_index);
|
||||
}
|
||||
}
|
||||
|
||||
polygons_normals.push_back(poly_indices);
|
||||
}
|
||||
}
|
||||
|
||||
std::string GeometryExporter::getIdBySemantics(std::string geom_id,
|
||||
COLLADASW::InputSemantic::Semantics type,
|
||||
std::string other_suffix)
|
||||
{
|
||||
return geom_id + getSuffixBySemantic(type) + other_suffix;
|
||||
}
|
||||
|
||||
COLLADASW::URI GeometryExporter::getUrlBySemantics(std::string geom_id,
|
||||
COLLADASW::InputSemantic::Semantics type,
|
||||
std::string other_suffix)
|
||||
{
|
||||
|
||||
std::string id(getIdBySemantics(geom_id, type, other_suffix));
|
||||
return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
|
||||
}
|
||||
|
||||
COLLADASW::URI GeometryExporter::makeUrl(std::string id)
|
||||
{
|
||||
return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "COLLADASWInputList.h"
|
||||
#include "COLLADASWLibraryGeometries.h"
|
||||
#include "COLLADASWStreamWriter.h"
|
||||
|
||||
#include "DNA_key_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BlenderContext.h"
|
||||
#include "ExportSettings.h"
|
||||
#include "collada_utils.h"
|
||||
|
||||
class Normal {
|
||||
public:
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
|
||||
friend bool operator<(const Normal &, const Normal &);
|
||||
};
|
||||
|
||||
bool operator<(const Normal &, const Normal &);
|
||||
|
||||
/* TODO: optimize UV sets by making indexed list with duplicates removed */
|
||||
class GeometryExporter : COLLADASW::LibraryGeometries {
|
||||
struct Face {
|
||||
unsigned int v1, v2, v3, v4;
|
||||
};
|
||||
|
||||
public:
|
||||
/* TODO: optimize UV sets by making indexed list with duplicates removed */
|
||||
GeometryExporter(BlenderContext &blender_context,
|
||||
COLLADASW::StreamWriter *sw,
|
||||
BCExportSettings &export_settings)
|
||||
: COLLADASW::LibraryGeometries(sw),
|
||||
blender_context(blender_context),
|
||||
export_settings(export_settings)
|
||||
{
|
||||
}
|
||||
|
||||
void exportGeom();
|
||||
|
||||
void operator()(Object *ob);
|
||||
|
||||
void createLooseEdgeList(Object *ob, Mesh *mesh, std::string &geom_id);
|
||||
|
||||
/** Powerful because it handles both cases when there is material and when there's not. */
|
||||
void create_mesh_primitive_list(short material_index,
|
||||
bool has_uvs,
|
||||
bool has_color,
|
||||
Object *ob,
|
||||
Mesh *mesh,
|
||||
std::string &geom_id,
|
||||
std::vector<BCPolygonNormalsIndices> &norind);
|
||||
|
||||
/** Creates <source> for positions. */
|
||||
void createVertsSource(std::string geom_id, Mesh *mesh);
|
||||
|
||||
void createVertexColorSource(std::string geom_id, Mesh *mesh);
|
||||
|
||||
std::string makeTexcoordSourceId(std::string &geom_id, int layer_index, bool is_single_layer);
|
||||
|
||||
/** Creates <source> for texture-coordinates. */
|
||||
void createTexcoordsSource(std::string geom_id, Mesh *mesh);
|
||||
|
||||
/** Creates <source> for normals. */
|
||||
void createNormalsSource(std::string geom_id, Mesh *mesh, std::vector<Normal> &nor);
|
||||
|
||||
void create_normals(std::vector<Normal> &nor,
|
||||
std::vector<BCPolygonNormalsIndices> &polygons_normals,
|
||||
Mesh *mesh);
|
||||
|
||||
std::string getIdBySemantics(std::string geom_id,
|
||||
COLLADASW::InputSemantic::Semantics type,
|
||||
std::string other_suffix = "");
|
||||
std::string makeVertexColorSourceId(std::string &geom_id, const char *layer_name);
|
||||
|
||||
COLLADASW::URI getUrlBySemantics(std::string geom_id,
|
||||
COLLADASW::InputSemantic::Semantics type,
|
||||
std::string other_suffix = "");
|
||||
|
||||
COLLADASW::URI makeUrl(std::string id);
|
||||
|
||||
void export_key_mesh(Object *ob, Mesh *mesh, KeyBlock *kb);
|
||||
|
||||
private:
|
||||
std::set<std::string> exportedGeometry;
|
||||
BlenderContext &blender_context;
|
||||
BCExportSettings &export_settings;
|
||||
|
||||
Mesh *get_mesh(Scene *sce, Object *ob, int apply_modifiers);
|
||||
};
|
||||
|
||||
struct GeometryFunctor {
|
||||
/* f should have
|
||||
* void operator()(Object *ob) */
|
||||
template<class Functor>
|
||||
void forEachMeshObjectInExportSet(Scene *sce, Functor &f, LinkNode *export_set)
|
||||
{
|
||||
LinkNode *node;
|
||||
for (node = export_set; node; node = node->next) {
|
||||
Object *ob = (Object *)node->link;
|
||||
if (ob->type == OB_MESH) {
|
||||
f(ob);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
@ -1,147 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2010-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include "COLLADABUURI.h"
|
||||
#include "COLLADASWImage.h"
|
||||
|
||||
#include "DNA_image_types.h"
|
||||
|
||||
#include "BKE_image.hh"
|
||||
#include "BKE_image_format.hh"
|
||||
#include "BKE_library.hh"
|
||||
#include "BKE_main.hh"
|
||||
|
||||
#include "BLI_fileops.h"
|
||||
#include "BLI_path_utils.hh"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "IMB_imbuf_types.hh"
|
||||
|
||||
#include "ImageExporter.h"
|
||||
|
||||
ImagesExporter::ImagesExporter(COLLADASW::StreamWriter *sw,
|
||||
BCExportSettings &export_settings,
|
||||
KeyImageMap &key_image_map)
|
||||
: COLLADASW::LibraryImages(sw), export_settings(export_settings), key_image_map(key_image_map)
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void ImagesExporter::export_UV_Image(Image *image, bool use_copies)
|
||||
{
|
||||
std::string name(id_name(image));
|
||||
std::string translated_name(translate_id(name));
|
||||
|
||||
ImBuf *imbuf = BKE_image_acquire_ibuf(image, nullptr, nullptr);
|
||||
if (!imbuf) {
|
||||
fprintf(stderr, "Collada export: image does not exist:\n%s\n", image->filepath);
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_dirty = BKE_image_is_dirty(image);
|
||||
|
||||
ImageFormatData imageFormat;
|
||||
BKE_image_format_from_imbuf(&imageFormat, imbuf);
|
||||
|
||||
short image_source = image->source;
|
||||
bool is_generated = image_source == IMA_SRC_GENERATED;
|
||||
bool is_packed = BKE_image_has_packedfile(image);
|
||||
|
||||
char export_path[FILE_MAX];
|
||||
char source_path[FILE_MAX];
|
||||
char export_dir[FILE_MAX];
|
||||
char export_file[FILE_MAX];
|
||||
|
||||
/* Destination folder for exported assets */
|
||||
BLI_path_split_dir_part(this->export_settings.get_filepath(), export_dir, sizeof(export_dir));
|
||||
|
||||
if (is_generated || is_dirty || use_copies || is_packed) {
|
||||
|
||||
/* make absolute destination path */
|
||||
|
||||
STRNCPY(export_file, name.c_str());
|
||||
BKE_image_path_ext_from_imformat_ensure(export_file, sizeof(export_file), &imageFormat);
|
||||
|
||||
BLI_path_join(export_path, sizeof(export_path), export_dir, export_file);
|
||||
|
||||
BLI_file_ensure_parent_dir_exists(export_path);
|
||||
}
|
||||
|
||||
if (is_generated || is_dirty || is_packed) {
|
||||
|
||||
/* This image in its current state only exists in Blender memory.
|
||||
* So we have to export it. The export will keep the image state intact,
|
||||
* so the exported file will not be associated with the image. */
|
||||
|
||||
if (BKE_imbuf_write_as(imbuf, export_path, &imageFormat, true) == false) {
|
||||
fprintf(stderr, "Collada export: Cannot export image to:\n%s\n", export_path);
|
||||
return;
|
||||
}
|
||||
STRNCPY(export_path, export_file);
|
||||
}
|
||||
else {
|
||||
|
||||
/* make absolute source path */
|
||||
STRNCPY(source_path, image->filepath);
|
||||
BLI_path_abs(source_path, ID_BLEND_PATH_FROM_GLOBAL(&image->id));
|
||||
BLI_path_normalize(source_path);
|
||||
|
||||
if (use_copies) {
|
||||
|
||||
/* This image is already located on the file system.
|
||||
* But we want to create copies here.
|
||||
* To move images into the same export directory.
|
||||
* NOTE: If an image is already located in the export folder,
|
||||
* then skip the copy (as it would result in a file copy error). */
|
||||
|
||||
if (BLI_path_cmp(source_path, export_path) != 0) {
|
||||
if (BLI_copy(source_path, export_path) != 0) {
|
||||
fprintf(stderr,
|
||||
"Collada export: Cannot copy image:\n source:%s\ndest :%s\n",
|
||||
source_path,
|
||||
export_path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
STRNCPY(export_path, export_file);
|
||||
}
|
||||
else {
|
||||
|
||||
/* Do not make any copies, but use the source path directly as reference
|
||||
* to the original image */
|
||||
|
||||
STRNCPY(export_path, source_path);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set name also to mNameNC.
|
||||
* This helps other viewers import files exported from Blender better. */
|
||||
COLLADASW::Image img(COLLADABU::URI(COLLADABU::URI::nativePathToUri(export_path)),
|
||||
translated_name,
|
||||
translated_name);
|
||||
img.add(mSW);
|
||||
fprintf(stdout, "Collada export: Added image: %s\n", export_file);
|
||||
|
||||
BKE_image_release_ibuf(image, imbuf, nullptr);
|
||||
}
|
||||
|
||||
void ImagesExporter::exportImages(Scene *sce)
|
||||
{
|
||||
bool use_texture_copies = this->export_settings.get_use_texture_copies();
|
||||
openLibrary();
|
||||
|
||||
KeyImageMap::iterator iter;
|
||||
for (iter = key_image_map.begin(); iter != key_image_map.end(); iter++) {
|
||||
|
||||
Image *image = iter->second;
|
||||
export_UV_Image(image, use_texture_copies);
|
||||
}
|
||||
|
||||
closeLibrary();
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "COLLADASWLibraryImages.h"
|
||||
#include "COLLADASWStreamWriter.h"
|
||||
|
||||
#include "DNA_image_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "ExportSettings.h"
|
||||
#include "collada_utils.h"
|
||||
|
||||
class ImagesExporter : COLLADASW::LibraryImages {
|
||||
public:
|
||||
ImagesExporter(COLLADASW::StreamWriter *sw,
|
||||
BCExportSettings &export_settings,
|
||||
KeyImageMap &key_image_map);
|
||||
void exportImages(Scene *sce);
|
||||
|
||||
private:
|
||||
BCExportSettings &export_settings;
|
||||
KeyImageMap &key_image_map;
|
||||
void export_UV_Image(Image *image, bool use_copies);
|
||||
};
|
@ -1,9 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2002-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include "ImportSettings.h"
|
@ -1,20 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct ImportSettings {
|
||||
bool import_units;
|
||||
bool custom_normals;
|
||||
bool find_chains;
|
||||
bool auto_connect;
|
||||
bool fix_orientation;
|
||||
int min_chain_length;
|
||||
char *filepath;
|
||||
bool keep_bind_info;
|
||||
};
|
@ -1,57 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2010-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "COLLADASWInstanceMaterial.h"
|
||||
|
||||
#include "BKE_customdata.hh"
|
||||
#include "BKE_material.hh"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
|
||||
#include "InstanceWriter.h"
|
||||
#include "collada_internal.h"
|
||||
#include "collada_utils.h"
|
||||
|
||||
void InstanceWriter::add_material_bindings(COLLADASW::BindMaterial &bind_material,
|
||||
Object *ob,
|
||||
bool active_uv_only)
|
||||
{
|
||||
for (int a = 0; a < ob->totcol; a++) {
|
||||
Material *ma = BKE_object_material_get(ob, a + 1);
|
||||
|
||||
COLLADASW::InstanceMaterialList &iml = bind_material.getInstanceMaterialList();
|
||||
|
||||
if (ma) {
|
||||
std::string matid(get_material_id(ma));
|
||||
matid = translate_id(matid);
|
||||
std::ostringstream ostr;
|
||||
ostr << matid;
|
||||
COLLADASW::InstanceMaterial im(ostr.str(),
|
||||
COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, matid));
|
||||
|
||||
/* Create <bind_vertex_input> for each uv map. */
|
||||
Mesh *mesh = (Mesh *)ob->data;
|
||||
|
||||
int num_layers = CustomData_number_of_layers(&mesh->corner_data, CD_PROP_FLOAT2);
|
||||
|
||||
int map_index = 0;
|
||||
int active_uv_index = CustomData_get_active_layer_index(&mesh->corner_data, CD_PROP_FLOAT2);
|
||||
for (int b = 0; b < num_layers; b++) {
|
||||
if (!active_uv_only || b == active_uv_index) {
|
||||
const char *name = bc_CustomData_get_layer_name(&mesh->corner_data, CD_PROP_FLOAT2, b);
|
||||
im.push_back(COLLADASW::BindVertexInput(name, "TEXCOORD", map_index++));
|
||||
}
|
||||
}
|
||||
|
||||
iml.push_back(im);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "COLLADASWBindMaterial.h"
|
||||
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
class InstanceWriter {
|
||||
protected:
|
||||
void add_material_bindings(COLLADASW::BindMaterial &bind_material,
|
||||
Object *ob,
|
||||
bool active_uv_only);
|
||||
};
|
@ -1,112 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2010-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "COLLADASWColor.h"
|
||||
#include "COLLADASWLight.h"
|
||||
|
||||
#include "DNA_light_types.h"
|
||||
#include "LightExporter.h"
|
||||
#include "collada_internal.h"
|
||||
|
||||
#include "BKE_light.h"
|
||||
|
||||
template<class Functor>
|
||||
void forEachLightObjectInExportSet(Scene *sce, Functor &f, LinkNode *export_set)
|
||||
{
|
||||
LinkNode *node;
|
||||
for (node = export_set; node; node = node->next) {
|
||||
Object *ob = (Object *)node->link;
|
||||
|
||||
if (ob->type == OB_LAMP && ob->data) {
|
||||
f(ob);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LightsExporter::LightsExporter(COLLADASW::StreamWriter *sw, BCExportSettings &export_settings)
|
||||
: COLLADASW::LibraryLights(sw), export_settings(export_settings)
|
||||
{
|
||||
}
|
||||
|
||||
void LightsExporter::exportLights(Scene *sce)
|
||||
{
|
||||
openLibrary();
|
||||
|
||||
forEachLightObjectInExportSet(sce, *this, this->export_settings.get_export_set());
|
||||
|
||||
closeLibrary();
|
||||
}
|
||||
|
||||
void LightsExporter::operator()(Object *ob)
|
||||
{
|
||||
Light *la = (Light *)ob->data;
|
||||
std::string la_id(get_light_id(ob));
|
||||
std::string la_name(id_name(la));
|
||||
blender::float3 color = BKE_light_power(*la) * BKE_light_color(*la);
|
||||
if (la->mode & LA_UNNORMALIZED) {
|
||||
color *= BKE_light_area(*la, ob->runtime->object_to_world);
|
||||
}
|
||||
COLLADASW::Color col(color[0], color[1], color[2]);
|
||||
|
||||
/* sun */
|
||||
if (la->type == LA_SUN) {
|
||||
COLLADASW::DirectionalLight cla(mSW, la_id, la_name);
|
||||
cla.setColor(col, false, "color");
|
||||
exportBlenderProfile(cla, la);
|
||||
addLight(cla);
|
||||
}
|
||||
|
||||
/* spot */
|
||||
else if (la->type == LA_SPOT) {
|
||||
COLLADASW::SpotLight cla(mSW, la_id, la_name);
|
||||
cla.setColor(col, false, "color");
|
||||
cla.setFallOffAngle(RAD2DEGF(la->spotsize), false, "fall_off_angle");
|
||||
cla.setFallOffExponent(la->spotblend, false, "fall_off_exponent");
|
||||
exportBlenderProfile(cla, la);
|
||||
addLight(cla);
|
||||
}
|
||||
/* lamp */
|
||||
else if (la->type == LA_LOCAL) {
|
||||
COLLADASW::PointLight cla(mSW, la_id, la_name);
|
||||
cla.setColor(col, false, "color");
|
||||
exportBlenderProfile(cla, la);
|
||||
addLight(cla);
|
||||
}
|
||||
/* area light is not supported
|
||||
* it will be exported as a local lamp */
|
||||
else {
|
||||
COLLADASW::PointLight cla(mSW, la_id, la_name);
|
||||
cla.setColor(col, false, "color");
|
||||
exportBlenderProfile(cla, la);
|
||||
addLight(cla);
|
||||
}
|
||||
}
|
||||
|
||||
bool LightsExporter::exportBlenderProfile(COLLADASW::Light &cla, Light *la)
|
||||
{
|
||||
cla.addExtraTechniqueParameter("blender", "type", la->type);
|
||||
cla.addExtraTechniqueParameter("blender", "flag", la->flag);
|
||||
cla.addExtraTechniqueParameter("blender", "mode", la->mode);
|
||||
cla.addExtraTechniqueParameter("blender", "red", la->r);
|
||||
cla.addExtraTechniqueParameter("blender", "green", la->g);
|
||||
cla.addExtraTechniqueParameter("blender", "blue", la->b);
|
||||
cla.addExtraTechniqueParameter("blender", "energy", la->energy, "blender_energy");
|
||||
cla.addExtraTechniqueParameter("blender", "spotsize", RAD2DEGF(la->spotsize));
|
||||
cla.addExtraTechniqueParameter("blender", "spotblend", la->spotblend);
|
||||
cla.addExtraTechniqueParameter("blender", "clipsta", la->clipsta);
|
||||
cla.addExtraTechniqueParameter("blender", "clipend", la->att_dist);
|
||||
cla.addExtraTechniqueParameter("blender", "radius", la->radius);
|
||||
cla.addExtraTechniqueParameter("blender", "area_shape", la->area_shape);
|
||||
cla.addExtraTechniqueParameter("blender", "area_size", la->area_size);
|
||||
cla.addExtraTechniqueParameter("blender", "area_sizey", la->area_sizey);
|
||||
cla.addExtraTechniqueParameter("blender", "area_sizez", la->area_sizez);
|
||||
|
||||
return true;
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "COLLADASWLibraryLights.h"
|
||||
#include "COLLADASWStreamWriter.h"
|
||||
|
||||
#include "DNA_light_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "ExportSettings.h"
|
||||
|
||||
class LightsExporter : COLLADASW::LibraryLights {
|
||||
public:
|
||||
LightsExporter(COLLADASW::StreamWriter *sw, BCExportSettings &export_settings);
|
||||
void exportLights(Scene *sce);
|
||||
void operator()(Object *ob);
|
||||
|
||||
private:
|
||||
bool exportBlenderProfile(COLLADASW::Light &cla, Light *la);
|
||||
BCExportSettings &export_settings;
|
||||
};
|
@ -1,63 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2002-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include "MaterialExporter.h"
|
||||
#include "COLLADABUUtils.h"
|
||||
#include "collada_internal.h"
|
||||
|
||||
MaterialsExporter::MaterialsExporter(COLLADASW::StreamWriter *sw,
|
||||
BCExportSettings &export_settings)
|
||||
: COLLADASW::LibraryMaterials(sw), export_settings(export_settings)
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void MaterialsExporter::exportMaterials(Scene *sce)
|
||||
{
|
||||
if (hasMaterials(sce)) {
|
||||
openLibrary();
|
||||
|
||||
MaterialFunctor mf;
|
||||
mf.forEachMaterialInExportSet<MaterialsExporter>(
|
||||
sce, *this, this->export_settings.get_export_set());
|
||||
|
||||
closeLibrary();
|
||||
}
|
||||
}
|
||||
|
||||
bool MaterialsExporter::hasMaterials(Scene *sce)
|
||||
{
|
||||
LinkNode *node;
|
||||
for (node = this->export_settings.get_export_set(); node; node = node->next) {
|
||||
Object *ob = (Object *)node->link;
|
||||
int a;
|
||||
for (a = 0; a < ob->totcol; a++) {
|
||||
Material *ma = BKE_object_material_get(ob, a + 1);
|
||||
|
||||
/* no material, but check all of the slots */
|
||||
if (!ma) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MaterialsExporter::operator()(Material *ma, Object *ob)
|
||||
{
|
||||
std::string mat_name = encode_xml(id_name(ma));
|
||||
std::string mat_id = get_material_id(ma);
|
||||
std::string eff_id = get_effect_id(ma);
|
||||
|
||||
openMaterial(mat_id, mat_name);
|
||||
addInstanceEffect(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, eff_id));
|
||||
|
||||
closeMaterial();
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "COLLADASWLibraryMaterials.h"
|
||||
#include "COLLADASWStreamWriter.h"
|
||||
|
||||
#include "BKE_material.hh"
|
||||
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "ExportSettings.h"
|
||||
#include "GeometryExporter.h"
|
||||
#include "collada_internal.h"
|
||||
|
||||
class MaterialsExporter : COLLADASW::LibraryMaterials {
|
||||
public:
|
||||
MaterialsExporter(COLLADASW::StreamWriter *sw, BCExportSettings &export_settings);
|
||||
void exportMaterials(Scene *sce);
|
||||
void operator()(Material *ma, Object *ob);
|
||||
|
||||
private:
|
||||
bool hasMaterials(Scene *sce);
|
||||
BCExportSettings &export_settings;
|
||||
};
|
||||
|
||||
/* Used in `forEachMaterialInScene`. */
|
||||
template<class Functor> class ForEachMaterialFunctor {
|
||||
std::vector<std::string>
|
||||
mMat; /* contains list of material names, to avoid duplicate calling of f */
|
||||
Functor *f;
|
||||
|
||||
public:
|
||||
ForEachMaterialFunctor(Functor *f) : f(f) {}
|
||||
|
||||
void operator()(Object *ob)
|
||||
{
|
||||
int a;
|
||||
for (a = 0; a < ob->totcol; a++) {
|
||||
|
||||
Material *ma = BKE_object_material_get(ob, a + 1);
|
||||
|
||||
if (!ma) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string translated_id = translate_id(id_name(ma));
|
||||
if (find(mMat.begin(), mMat.end(), translated_id) == mMat.end()) {
|
||||
(*this->f)(ma, ob);
|
||||
|
||||
mMat.push_back(translated_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct MaterialFunctor {
|
||||
/* calls f for each unique material linked to each object in sce
|
||||
* f should have */
|
||||
// void operator()(Material *ma)
|
||||
template<class Functor>
|
||||
void forEachMaterialInExportSet(Scene *sce, Functor &f, LinkNode *export_set)
|
||||
{
|
||||
ForEachMaterialFunctor<Functor> matfunc(&f);
|
||||
GeometryFunctor gf;
|
||||
gf.forEachMeshObjectInExportSet<ForEachMaterialFunctor<Functor>>(sce, matfunc, export_set);
|
||||
}
|
||||
};
|
@ -1,447 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2018-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "Materials.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BKE_node.hh"
|
||||
#include "BKE_node_legacy_types.hh"
|
||||
#include "BKE_node_runtime.hh"
|
||||
#include "BKE_node_tree_update.hh"
|
||||
|
||||
MaterialNode::MaterialNode(bContext *C, Material *ma, KeyImageMap &key_image_map)
|
||||
: mContext(C), material(ma), effect(nullptr), key_image_map(&key_image_map)
|
||||
{
|
||||
bNodeTree *new_ntree = prepare_material_nodetree();
|
||||
setShaderType();
|
||||
if (new_ntree) {
|
||||
shader_node = add_node(SH_NODE_BSDF_PRINCIPLED, 0, 300, "");
|
||||
output_node = add_node(SH_NODE_OUTPUT_MATERIAL, 300, 300, "");
|
||||
add_link(shader_node, 0, output_node, 0);
|
||||
}
|
||||
}
|
||||
|
||||
MaterialNode::MaterialNode(bContext *C,
|
||||
COLLADAFW::EffectCommon *ef,
|
||||
Material *ma,
|
||||
UidImageMap &uid_image_map)
|
||||
: mContext(C), material(ma), effect(ef), uid_image_map(&uid_image_map)
|
||||
{
|
||||
prepare_material_nodetree();
|
||||
setShaderType();
|
||||
|
||||
std::map<std::string, bNode *> nmap;
|
||||
#if 0
|
||||
nmap["main"] = add_node(C, ntree, SH_NODE_BSDF_PRINCIPLED, -300, 300);
|
||||
nmap["emission"] = add_node(C, ntree, SH_NODE_EMISSION, -300, 500, "emission");
|
||||
nmap["add"] = add_node(C, ntree, SH_NODE_ADD_SHADER, 100, 400);
|
||||
nmap["transparent"] = add_node(C, ntree, SH_NODE_BSDF_TRANSPARENT, 100, 200);
|
||||
nmap["mix"] = add_node(C, ntree, SH_NODE_MIX_SHADER, 400, 300, "transparency");
|
||||
nmap["out"] = add_node(C, ntree, SH_NODE_OUTPUT_MATERIAL, 600, 300);
|
||||
nmap["out"]->flag &= ~NODE_SELECT;
|
||||
|
||||
add_link(ntree, nmap["emission"], 0, nmap["add"], 0);
|
||||
add_link(ntree, nmap["main"], 0, nmap["add"], 1);
|
||||
add_link(ntree, nmap["add"], 0, nmap["mix"], 1);
|
||||
add_link(ntree, nmap["transparent"], 0, nmap["mix"], 2);
|
||||
|
||||
add_link(ntree, nmap["mix"], 0, nmap["out"], 0);
|
||||
/* experimental, probably not used. */
|
||||
make_group(C, ntree, nmap);
|
||||
#else
|
||||
shader_node = add_node(SH_NODE_BSDF_PRINCIPLED, 0, 300, "");
|
||||
output_node = add_node(SH_NODE_OUTPUT_MATERIAL, 300, 300, "");
|
||||
add_link(shader_node, 0, output_node, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MaterialNode::setShaderType()
|
||||
{
|
||||
#if 0
|
||||
COLLADAFW::EffectCommon::ShaderType shader = ef->getShaderType();
|
||||
/* Currently we only support PBR based shaders */
|
||||
/* TODO: simulate the effects with PBR */
|
||||
|
||||
/* blinn */
|
||||
if (shader == COLLADAFW::EffectCommon::SHADER_BLINN) {
|
||||
ma->spec_shader = MA_SPEC_BLINN;
|
||||
ma->spec = ef->getShininess().getFloatValue();
|
||||
}
|
||||
/* phong */
|
||||
else if (shader == COLLADAFW::EffectCommon::SHADER_PHONG) {
|
||||
ma->spec_shader = MA_SPEC_PHONG;
|
||||
ma->har = ef->getShininess().getFloatValue();
|
||||
}
|
||||
/* lambert */
|
||||
else if (shader == COLLADAFW::EffectCommon::SHADER_LAMBERT) {
|
||||
ma->diff_shader = MA_DIFF_LAMBERT;
|
||||
}
|
||||
/* default - lambert */
|
||||
else {
|
||||
ma->diff_shader = MA_DIFF_LAMBERT;
|
||||
fprintf(stderr, "Current shader type is not supported, default to lambert.\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bNodeTree *MaterialNode::prepare_material_nodetree()
|
||||
{
|
||||
if (material->nodetree) {
|
||||
ntree = material->nodetree;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
blender::bke::node_tree_add_tree_embedded(
|
||||
nullptr, &material->id, "Shader Nodetree", "ShaderNodeTree");
|
||||
material->use_nodes = true;
|
||||
ntree = material->nodetree;
|
||||
return ntree;
|
||||
}
|
||||
|
||||
void MaterialNode::update_material_nodetree()
|
||||
{
|
||||
BKE_ntree_update_after_single_tree_change(*CTX_data_main(mContext), *ntree);
|
||||
}
|
||||
|
||||
bNode *MaterialNode::add_node(int node_type, int locx, int locy, std::string label)
|
||||
{
|
||||
bNode *node = blender::bke::node_add_static_node(mContext, *ntree, node_type);
|
||||
if (node) {
|
||||
if (label.length() > 0) {
|
||||
STRNCPY(node->label, label.c_str());
|
||||
}
|
||||
node->location[0] = locx;
|
||||
node->location[1] = locy;
|
||||
node->flag |= NODE_SELECT;
|
||||
}
|
||||
node_map[label] = node;
|
||||
return node;
|
||||
}
|
||||
|
||||
void MaterialNode::add_link(bNode *from_node, int from_index, bNode *to_node, int to_index)
|
||||
{
|
||||
bNodeSocket *from_socket = (bNodeSocket *)BLI_findlink(&from_node->outputs, from_index);
|
||||
bNodeSocket *to_socket = (bNodeSocket *)BLI_findlink(&to_node->inputs, to_index);
|
||||
|
||||
blender::bke::node_add_link(*ntree, *from_node, *from_socket, *to_node, *to_socket);
|
||||
}
|
||||
|
||||
void MaterialNode::add_link(bNode *from_node,
|
||||
const char *from_label,
|
||||
bNode *to_node,
|
||||
const char *to_label)
|
||||
{
|
||||
bNodeSocket *from_socket = blender::bke::node_find_socket(*from_node, SOCK_OUT, from_label);
|
||||
bNodeSocket *to_socket = blender::bke::node_find_socket(*to_node, SOCK_IN, to_label);
|
||||
|
||||
if (from_socket && to_socket) {
|
||||
blender::bke::node_add_link(*ntree, *from_node, *from_socket, *to_node, *to_socket);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialNode::set_reflectivity(COLLADAFW::FloatOrParam &val)
|
||||
{
|
||||
float reflectivity = val.getFloatValue();
|
||||
if (reflectivity >= 0) {
|
||||
bNodeSocket *socket = blender::bke::node_find_socket(*shader_node, SOCK_IN, "Metallic");
|
||||
((bNodeSocketValueFloat *)socket->default_value)->value = reflectivity;
|
||||
material->metallic = reflectivity;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* needs rework to be done for 2.81 */
|
||||
void MaterialNode::set_shininess(COLLADAFW::FloatOrParam &val)
|
||||
{
|
||||
float roughness = val.getFloatValue();
|
||||
if (roughness >= 0) {
|
||||
bNodeSocket *socket = blender::bke::node_find_socket(*shader_node, SOCK_IN, "Roughness");
|
||||
((bNodeSocketValueFloat *)socket->default_value)->value = roughness;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void MaterialNode::set_ior(COLLADAFW::FloatOrParam &val)
|
||||
{
|
||||
float ior = val.getFloatValue();
|
||||
if (ior < 0) {
|
||||
fprintf(stderr,
|
||||
"IOR of negative value is not allowed for materials (using Blender default value "
|
||||
"instead)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bNodeSocket *socket = blender::bke::node_find_socket(*shader_node, SOCK_IN, "IOR");
|
||||
((bNodeSocketValueFloat *)socket->default_value)->value = ior;
|
||||
}
|
||||
|
||||
void MaterialNode::set_alpha(COLLADAFW::EffectCommon::OpaqueMode mode,
|
||||
COLLADAFW::ColorOrTexture &cot,
|
||||
COLLADAFW::FloatOrParam &val)
|
||||
{
|
||||
/* Handling the alpha value according to the Collada 1.4 reference guide
|
||||
* see page 7-5 Determining Transparency (Opacity). */
|
||||
|
||||
if (effect == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cot.isColor() || !cot.isValid()) {
|
||||
/* transparent_cot is either a color or not defined */
|
||||
|
||||
float transparent_alpha;
|
||||
if (cot.isValid()) {
|
||||
COLLADAFW::Color col = cot.getColor();
|
||||
transparent_alpha = col.getAlpha();
|
||||
}
|
||||
else {
|
||||
/* no transparent color defined */
|
||||
transparent_alpha = 1;
|
||||
}
|
||||
|
||||
float transparency_alpha = val.getFloatValue();
|
||||
if (transparency_alpha < 0) {
|
||||
/* transparency is not defined */
|
||||
transparency_alpha = 1; /* set to opaque */
|
||||
}
|
||||
|
||||
float alpha = transparent_alpha * transparency_alpha;
|
||||
if (mode == COLLADAFW::EffectCommon::RGB_ZERO) {
|
||||
alpha = 1 - alpha;
|
||||
}
|
||||
|
||||
bNodeSocket *socket = blender::bke::node_find_socket(*shader_node, SOCK_IN, "Alpha");
|
||||
((bNodeSocketValueFloat *)socket->default_value)->value = alpha;
|
||||
material->a = alpha;
|
||||
}
|
||||
else if (cot.isTexture()) {
|
||||
int locy = -300 * (node_map.size() - 2);
|
||||
add_texture_node(cot, -300, locy, "Alpha");
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialNode::set_diffuse(COLLADAFW::ColorOrTexture &cot)
|
||||
{
|
||||
int locy = -300 * (node_map.size() - 2);
|
||||
|
||||
if (cot.isTexture()) {
|
||||
bNode *texture_node = add_texture_node(cot, -300, locy, "Base Color");
|
||||
if (texture_node != nullptr) {
|
||||
add_link(texture_node, 0, shader_node, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
bNodeSocket *socket = blender::bke::node_find_socket(*shader_node, SOCK_IN, "Base Color");
|
||||
float *fcol = (float *)socket->default_value;
|
||||
|
||||
if (cot.isColor()) {
|
||||
COLLADAFW::Color col = cot.getColor();
|
||||
fcol[0] = material->r = col.getRed();
|
||||
fcol[1] = material->g = col.getGreen();
|
||||
fcol[2] = material->b = col.getBlue();
|
||||
fcol[3] = material->a = col.getAlpha();
|
||||
}
|
||||
else {
|
||||
/* no diffuse term = same as black */
|
||||
fcol[0] = material->r = 0.0f;
|
||||
fcol[1] = material->g = 0.0f;
|
||||
fcol[2] = material->b = 0.0f;
|
||||
fcol[3] = material->a = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image *MaterialNode::get_diffuse_image()
|
||||
{
|
||||
ntree->ensure_topology_cache();
|
||||
const blender::Span<const bNode *> nodes = ntree->nodes_by_type("ShaderNodeBsdfPrincipled");
|
||||
if (nodes.is_empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
const bNode *shader = nodes.first();
|
||||
|
||||
const bNodeSocket *in_socket = blender::bke::node_find_socket(*shader, SOCK_IN, "Base Color");
|
||||
if (in_socket == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const bNodeLink *link = in_socket->link;
|
||||
if (link == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const bNode *texture = link->fromnode;
|
||||
if (texture == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (texture->type_legacy != SH_NODE_TEX_IMAGE) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Image *image = (Image *)texture->id;
|
||||
return image;
|
||||
}
|
||||
|
||||
static bNodeSocket *set_color(bNode *node, COLLADAFW::Color col)
|
||||
{
|
||||
bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->outputs, 0);
|
||||
float *fcol = (float *)socket->default_value;
|
||||
fcol[0] = col.getRed();
|
||||
fcol[1] = col.getGreen();
|
||||
fcol[2] = col.getBlue();
|
||||
|
||||
return socket;
|
||||
}
|
||||
|
||||
void MaterialNode::set_ambient(COLLADAFW::ColorOrTexture &cot)
|
||||
{
|
||||
int locy = -300 * (node_map.size() - 2);
|
||||
if (cot.isColor()) {
|
||||
COLLADAFW::Color col = cot.getColor();
|
||||
bNode *node = add_node(SH_NODE_RGB, -300, locy, "Ambient");
|
||||
set_color(node, col);
|
||||
/* TODO: Connect node */
|
||||
}
|
||||
/* texture */
|
||||
else if (cot.isTexture()) {
|
||||
add_texture_node(cot, -300, locy, "Ambient");
|
||||
/* TODO: Connect node */
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialNode::set_reflective(COLLADAFW::ColorOrTexture &cot)
|
||||
{
|
||||
int locy = -300 * (node_map.size() - 2);
|
||||
if (cot.isColor()) {
|
||||
COLLADAFW::Color col = cot.getColor();
|
||||
bNode *node = add_node(SH_NODE_RGB, -300, locy, "Reflective");
|
||||
set_color(node, col);
|
||||
/* TODO: Connect node */
|
||||
}
|
||||
/* texture */
|
||||
else if (cot.isTexture()) {
|
||||
add_texture_node(cot, -300, locy, "Reflective");
|
||||
/* TODO: Connect node */
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialNode::set_emission(COLLADAFW::ColorOrTexture &cot)
|
||||
{
|
||||
int locy = -300 * (node_map.size() - 2);
|
||||
if (cot.isColor()) {
|
||||
COLLADAFW::Color col = cot.getColor();
|
||||
bNodeSocket *socket = blender::bke::node_find_socket(*shader_node, SOCK_IN, "Emission Color");
|
||||
float *fcol = (float *)socket->default_value;
|
||||
|
||||
fcol[0] = col.getRed();
|
||||
fcol[1] = col.getGreen();
|
||||
fcol[2] = col.getBlue();
|
||||
fcol[3] = col.getAlpha();
|
||||
}
|
||||
// texture
|
||||
else if (cot.isTexture()) {
|
||||
bNode *texture_node = add_texture_node(cot, -300, locy, "Emission Color");
|
||||
if (texture_node != nullptr) {
|
||||
add_link(texture_node, "Color", shader_node, "Emission Color");
|
||||
}
|
||||
}
|
||||
|
||||
bNodeSocket *socket = blender::bke::node_find_socket(*shader_node, SOCK_IN, "Emission Strength");
|
||||
if (socket) {
|
||||
*(float *)socket->default_value = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialNode::set_opacity(COLLADAFW::ColorOrTexture &cot)
|
||||
{
|
||||
if (effect == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
int locy = -300 * (node_map.size() - 2);
|
||||
if (cot.isColor()) {
|
||||
COLLADAFW::Color col = effect->getTransparent().getColor();
|
||||
float alpha = effect->getTransparency().getFloatValue();
|
||||
|
||||
if (col.isValid()) {
|
||||
alpha *= col.getAlpha(); /* Assuming A_ONE opaque mode */
|
||||
}
|
||||
|
||||
bNodeSocket *socket = blender::bke::node_find_socket(*shader_node, SOCK_IN, "Alpha");
|
||||
((bNodeSocketValueFloat *)socket->default_value)->value = alpha;
|
||||
}
|
||||
/* texture */
|
||||
else if (cot.isTexture()) {
|
||||
add_texture_node(cot, -300, locy, "Alpha");
|
||||
/* TODO: Connect node */
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialNode::set_specular(COLLADAFW::ColorOrTexture &cot)
|
||||
{
|
||||
bool has_specularity = true;
|
||||
int locy = -300 * (node_map.size() - 2);
|
||||
if (cot.isColor()) {
|
||||
COLLADAFW::Color col = cot.getColor();
|
||||
|
||||
if (col.getRed() == 0 && col.getGreen() == 0 && col.getBlue() == 0) {
|
||||
has_specularity = false;
|
||||
}
|
||||
else {
|
||||
bNode *node = add_node(SH_NODE_RGB, -300, locy, "Specular IOR Level");
|
||||
set_color(node, col);
|
||||
/* TODO: Connect node */
|
||||
}
|
||||
}
|
||||
else if (cot.isTexture()) {
|
||||
add_texture_node(cot, -300, locy, "Specular IOR Level");
|
||||
/* TODO: Connect node */
|
||||
}
|
||||
else {
|
||||
/* no specular term) */
|
||||
has_specularity = false;
|
||||
}
|
||||
|
||||
if (!has_specularity) {
|
||||
/* If specularity is black or not defined reset the Specular value to 0
|
||||
* TODO: This is a solution only for a corner case. We must find a better
|
||||
* way to handle specularity in general. Also note that currently we
|
||||
* do not export specularity values, see EffectExporter::operator() */
|
||||
bNodeSocket *socket = blender::bke::node_find_socket(
|
||||
*shader_node, SOCK_IN, "Specular IOR Level");
|
||||
((bNodeSocketValueFloat *)socket->default_value)->value = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
bNode *MaterialNode::add_texture_node(COLLADAFW::ColorOrTexture &cot,
|
||||
int locx,
|
||||
int locy,
|
||||
std::string label)
|
||||
{
|
||||
if (effect == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UidImageMap &image_map = *uid_image_map;
|
||||
|
||||
COLLADAFW::Texture ctex = cot.getTexture();
|
||||
|
||||
COLLADAFW::SamplerPointerArray &samp_array = effect->getSamplerPointerArray();
|
||||
COLLADAFW::Sampler *sampler = samp_array[ctex.getSamplerId()];
|
||||
|
||||
const COLLADAFW::UniqueId &ima_uid = sampler->getSourceImage();
|
||||
|
||||
if (image_map.find(ima_uid) == image_map.end()) {
|
||||
fprintf(stderr, "Couldn't find an image by UID.\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Image *ima = image_map[ima_uid];
|
||||
bNode *texture_node = add_node(SH_NODE_TEX_IMAGE, locx, locy, label);
|
||||
texture_node->id = &ima->id;
|
||||
return texture_node;
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_node.hh"
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_node_types.h"
|
||||
|
||||
#include "COLLADAFWEffectCommon.h"
|
||||
#include "collada_utils.h"
|
||||
|
||||
using NodeMap = std::map<std::string, bNode *>;
|
||||
|
||||
class MaterialNode {
|
||||
|
||||
private:
|
||||
bContext *mContext;
|
||||
Material *material;
|
||||
COLLADAFW::EffectCommon *effect;
|
||||
UidImageMap *uid_image_map = nullptr;
|
||||
KeyImageMap *key_image_map = nullptr;
|
||||
|
||||
NodeMap node_map;
|
||||
bNodeTree *ntree;
|
||||
|
||||
bNode *shader_node;
|
||||
bNode *output_node;
|
||||
|
||||
/** Returns null if material already has a node tree. */
|
||||
bNodeTree *prepare_material_nodetree();
|
||||
bNode *add_node(int node_type, int locx, int locy, std::string label);
|
||||
void add_link(bNode *from_node, int from_index, bNode *to_node, int to_index);
|
||||
void add_link(bNode *from_node, const char *from_label, bNode *to_node, const char *to_label);
|
||||
bNode *add_texture_node(COLLADAFW::ColorOrTexture &cot, int locx, int locy, std::string label);
|
||||
void setShaderType();
|
||||
|
||||
public:
|
||||
MaterialNode(bContext *C, COLLADAFW::EffectCommon *ef, Material *ma, UidImageMap &uid_image_map);
|
||||
MaterialNode(bContext *C, Material *ma, KeyImageMap &key_image_map);
|
||||
Image *get_diffuse_image();
|
||||
|
||||
void set_diffuse(COLLADAFW::ColorOrTexture &cot);
|
||||
void set_specular(COLLADAFW::ColorOrTexture &cot);
|
||||
void set_ambient(COLLADAFW::ColorOrTexture &cot);
|
||||
void set_reflective(COLLADAFW::ColorOrTexture &cot);
|
||||
void set_emission(COLLADAFW::ColorOrTexture &cot);
|
||||
void set_opacity(COLLADAFW::ColorOrTexture &cot);
|
||||
void set_reflectivity(COLLADAFW::FloatOrParam &val);
|
||||
void set_shininess(COLLADAFW::FloatOrParam &val);
|
||||
void set_ior(COLLADAFW::FloatOrParam &val);
|
||||
void set_alpha(COLLADAFW::EffectCommon::OpaqueMode mode,
|
||||
COLLADAFW::ColorOrTexture &cot,
|
||||
COLLADAFW::FloatOrParam &val);
|
||||
|
||||
void update_material_nodetree();
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -1,238 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "COLLADAFWIndexList.h"
|
||||
#include "COLLADAFWInstanceGeometry.h"
|
||||
#include "COLLADAFWMaterialBinding.h"
|
||||
#include "COLLADAFWMesh.h"
|
||||
#include "COLLADAFWMeshVertexData.h"
|
||||
#include "COLLADAFWNode.h"
|
||||
#include "COLLADAFWPolygons.h"
|
||||
#include "COLLADAFWTypes.h"
|
||||
#include "COLLADAFWUniqueId.h"
|
||||
|
||||
#include "collada_utils.h"
|
||||
|
||||
#include "BLI_math_vector_types.hh"
|
||||
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
class ArmatureImporter;
|
||||
struct MLoopCol;
|
||||
|
||||
/* only for ArmatureImporter to "see" MeshImporter::get_object_by_geom_uid */
|
||||
class MeshImporterBase {
|
||||
public:
|
||||
virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId &geom_uid) = 0;
|
||||
virtual Mesh *get_mesh_by_geom_uid(const COLLADAFW::UniqueId &mesh_uid) = 0;
|
||||
virtual std::string *get_geometry_name(const std::string &mesh_name) = 0;
|
||||
};
|
||||
|
||||
class UVDataWrapper {
|
||||
COLLADAFW::MeshVertexData *mVData;
|
||||
|
||||
public:
|
||||
UVDataWrapper(COLLADAFW::MeshVertexData &vdata);
|
||||
|
||||
#ifdef COLLADA_DEBUG
|
||||
void print();
|
||||
#endif
|
||||
|
||||
void getUV(int uv_index, float *uv);
|
||||
};
|
||||
|
||||
class VCOLDataWrapper {
|
||||
COLLADAFW::MeshVertexData *mVData;
|
||||
|
||||
public:
|
||||
VCOLDataWrapper(COLLADAFW::MeshVertexData &vdata);
|
||||
void get_vcol(int v_index, MLoopCol *mloopcol);
|
||||
};
|
||||
|
||||
class MeshImporter : public MeshImporterBase {
|
||||
private:
|
||||
UnitConverter *unitconverter;
|
||||
bool use_custom_normals;
|
||||
|
||||
Main *m_bmain;
|
||||
Scene *scene;
|
||||
ViewLayer *view_layer;
|
||||
|
||||
ArmatureImporter *armature_importer;
|
||||
|
||||
std::map<std::string, std::string> mesh_geom_map; /* needed for correct shape key naming */
|
||||
std::map<COLLADAFW::UniqueId, Mesh *> uid_mesh_map; /* geometry unique id-to-mesh map */
|
||||
std::map<COLLADAFW::UniqueId, Object *> uid_object_map; /* geom UID-to-object */
|
||||
std::vector<Object *> imported_objects; /* list of imported objects */
|
||||
|
||||
/* this structure is used to assign material indices to faces
|
||||
* it holds a portion of Mesh faces and corresponds to a DAE primitive list
|
||||
* (`<triangles>`, `<polylist>`, etc.) */
|
||||
struct Primitive {
|
||||
int face_index;
|
||||
int *material_indices;
|
||||
uint faces_num;
|
||||
};
|
||||
using MaterialIdPrimitiveArrayMap = std::map<COLLADAFW::MaterialId, std::vector<Primitive>>;
|
||||
/* crazy name! */
|
||||
std::map<COLLADAFW::UniqueId, MaterialIdPrimitiveArrayMap> geom_uid_mat_mapping_map;
|
||||
/* < materials that have already been mapped to a geometry.
|
||||
* A pair/of geom UID and mat UID, one geometry can have several materials. */
|
||||
std::multimap<COLLADAFW::UniqueId, COLLADAFW::UniqueId> materials_mapped_to_geom;
|
||||
|
||||
bool set_poly_indices(int *face_verts, int loop_index, const uint *indices, int loop_count);
|
||||
|
||||
void set_face_uv(blender::float2 *mloopuv,
|
||||
UVDataWrapper &uvs,
|
||||
int start_index,
|
||||
COLLADAFW::IndexList &index_list,
|
||||
int count);
|
||||
|
||||
void set_vcol(MLoopCol *mloopcol,
|
||||
VCOLDataWrapper &vob,
|
||||
int loop_index,
|
||||
COLLADAFW::IndexList &index_list,
|
||||
int count);
|
||||
|
||||
#ifdef COLLADA_DEBUG
|
||||
void print_index_list(COLLADAFW::IndexList &index_list);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Checks if mesh has supported primitive types:
|
||||
* `lines`, `polylist`, `triangles`, `triangle_fans`.
|
||||
*/
|
||||
bool is_nice_mesh(COLLADAFW::Mesh *mesh);
|
||||
|
||||
void read_vertices(COLLADAFW::Mesh *mesh, Mesh *blender_mesh);
|
||||
|
||||
/**
|
||||
* Condition 1: The Primitive has normals
|
||||
* condition 2: The number of normals equals the number of faces.
|
||||
* return true if both conditions apply.
|
||||
* return false otherwise.
|
||||
*/
|
||||
bool primitive_has_useable_normals(COLLADAFW::MeshPrimitive *mp);
|
||||
/**
|
||||
* Assume that only TRIANGLES, TRIANGLE_FANS, POLYLIST and POLYGONS
|
||||
* have faces. (to be verified).
|
||||
*/
|
||||
bool primitive_has_faces(COLLADAFW::MeshPrimitive *mp);
|
||||
|
||||
/**
|
||||
* This function is copied from `source/blender/editors/mesh/mesh_data.cc`
|
||||
*
|
||||
* TODO: (As discussed with sergey-) :
|
||||
* Maybe move this function to `blenderkernel/intern/mesh.cc`.
|
||||
* and add definition to BKE_mesh.c.
|
||||
*/
|
||||
static void mesh_add_edges(Mesh *mesh, int len);
|
||||
|
||||
uint get_loose_edge_count(COLLADAFW::Mesh *mesh);
|
||||
|
||||
/**
|
||||
* Return the number of faces by summing up
|
||||
* the face-counts of the parts.
|
||||
* HINT: This is done because `mesh->getFacesCount()` does
|
||||
* count loose edges as extra faces, which is not what we want here.
|
||||
*/
|
||||
void allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *mesh);
|
||||
|
||||
/* TODO: import uv set names */
|
||||
/**
|
||||
* Read all faces from TRIANGLES, TRIANGLE_FANS, POLYLIST, POLYGON
|
||||
* IMPORTANT: This function MUST be called before read_lines()
|
||||
* Otherwise we will lose all edges from faces (see read_lines() above)
|
||||
*
|
||||
* TODO: import uv set names.
|
||||
*/
|
||||
void read_polys(COLLADAFW::Mesh *mesh,
|
||||
Mesh *blender_mesh,
|
||||
blender::Vector<blender::float3> &loop_normals);
|
||||
/**
|
||||
* Read all loose edges.
|
||||
* IMPORTANT: This function assumes that all edges from existing
|
||||
* faces have already been generated and added to me->medge
|
||||
* So this function MUST be called after read_faces() (see below)
|
||||
*/
|
||||
void read_lines(COLLADAFW::Mesh *mesh, Mesh *blender_mesh);
|
||||
uint get_vertex_count(COLLADAFW::Polygons *mp, int index);
|
||||
|
||||
void get_vector(float v[3], COLLADAFW::MeshVertexData &arr, int i, int stride);
|
||||
|
||||
bool is_flat_face(uint *nind, COLLADAFW::MeshVertexData &nor, int count);
|
||||
|
||||
/**
|
||||
* Returns the list of Users of the given Mesh object.
|
||||
* NOTE: This function uses the object user flag to control
|
||||
* which objects have already been processed.
|
||||
*/
|
||||
std::vector<Object *> get_all_users_of(Mesh *reference_mesh);
|
||||
|
||||
public:
|
||||
MeshImporter(UnitConverter *unitconv,
|
||||
bool use_custom_normals,
|
||||
ArmatureImporter *arm,
|
||||
Main *bmain,
|
||||
Scene *sce,
|
||||
ViewLayer *view_layer);
|
||||
|
||||
Object *get_object_by_geom_uid(const COLLADAFW::UniqueId &geom_uid) override;
|
||||
|
||||
Mesh *get_mesh_by_geom_uid(const COLLADAFW::UniqueId &geom_uid) override;
|
||||
|
||||
/**
|
||||
*
|
||||
* During import all materials have been assigned to Object.
|
||||
* Now we iterate over the imported objects and optimize
|
||||
* the assignments as follows:
|
||||
*
|
||||
* for each imported geometry:
|
||||
* if number of users is 1:
|
||||
* get the user (object)
|
||||
* move the materials from Object to Data
|
||||
* else:
|
||||
* determine which materials are assigned to the first user
|
||||
* check if all other users have the same materials in the same order
|
||||
* if the check is positive:
|
||||
* Add the materials of the first user to the geometry
|
||||
* adjust all other users accordingly.
|
||||
*/
|
||||
void optimize_material_assignements();
|
||||
|
||||
/**
|
||||
* We do not know in advance which objects will share geometries.
|
||||
* And we do not know either if the objects which share geometries
|
||||
* come along with different materials. So we first create the objects
|
||||
* and assign the materials to Object, then in a later cleanup we decide
|
||||
* which materials shall be moved to the created geometries. Also see
|
||||
* optimize_material_assignements() above.
|
||||
*/
|
||||
void assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial,
|
||||
std::map<COLLADAFW::UniqueId, Material *> &uid_material_map,
|
||||
Object *ob,
|
||||
const COLLADAFW::UniqueId *geom_uid,
|
||||
short mat_index);
|
||||
|
||||
Object *create_mesh_object(COLLADAFW::Node *node,
|
||||
COLLADAFW::InstanceGeometry *geom,
|
||||
bool isController,
|
||||
std::map<COLLADAFW::UniqueId, Material *> &uid_material_map);
|
||||
|
||||
/** Create a mesh storing a pointer in a map so it can be retrieved later by geometry UID. */
|
||||
bool write_geometry(const COLLADAFW::Geometry *geom);
|
||||
std::string *get_geometry_name(const std::string &mesh_name) override;
|
||||
};
|
@ -1,225 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include "COLLADASWInstanceCamera.h"
|
||||
#include "COLLADASWInstanceGeometry.h"
|
||||
#include "COLLADASWInstanceLight.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
|
||||
#include "BKE_collection.hh"
|
||||
#include "BKE_constraint.h"
|
||||
|
||||
#include "SceneExporter.h"
|
||||
#include "collada_utils.h"
|
||||
|
||||
void SceneExporter::exportScene()
|
||||
{
|
||||
Scene *scene = blender_context.get_scene();
|
||||
|
||||
/* <library_visual_scenes> <visual_scene> */
|
||||
std::string name = id_name(scene);
|
||||
openVisualScene(translate_id(name), encode_xml(name));
|
||||
exportHierarchy();
|
||||
closeVisualScene();
|
||||
closeLibrary();
|
||||
}
|
||||
|
||||
void SceneExporter::exportHierarchy()
|
||||
{
|
||||
LinkNode *node;
|
||||
ColladaBaseNodes base_objects;
|
||||
|
||||
/* Ensure all objects in the export_set are marked */
|
||||
for (node = this->export_settings.get_export_set(); node; node = node->next) {
|
||||
Object *ob = (Object *)node->link;
|
||||
ob->id.tag |= ID_TAG_DOIT;
|
||||
}
|
||||
|
||||
/* Now find all exportable base objects (highest in export hierarchy) */
|
||||
for (node = this->export_settings.get_export_set(); node; node = node->next) {
|
||||
Object *ob = (Object *)node->link;
|
||||
if (this->export_settings.is_export_root(ob)) {
|
||||
switch (ob->type) {
|
||||
case OB_MESH:
|
||||
case OB_CAMERA:
|
||||
case OB_LAMP:
|
||||
case OB_EMPTY:
|
||||
case OB_ARMATURE:
|
||||
base_objects.add(ob);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* And now export the base objects: */
|
||||
for (int index = 0; index < base_objects.size(); index++) {
|
||||
Object *ob = base_objects.get(index);
|
||||
writeNode(ob);
|
||||
if (bc_is_marked(ob)) {
|
||||
bc_remove_mark(ob);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SceneExporter::writeNodeList(std::vector<Object *> &child_objects, Object *parent)
|
||||
{
|
||||
/* TODO: Handle the case where a parent is not exported
|
||||
* Actually i am not even sure if this can be done at all
|
||||
* in a good way.
|
||||
* I really prefer to enforce the export of hidden
|
||||
* elements in an object hierarchy. When the children of
|
||||
* the hidden elements are exported as well. */
|
||||
for (auto *child : child_objects) {
|
||||
writeNode(child);
|
||||
if (bc_is_marked(child)) {
|
||||
bc_remove_mark(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SceneExporter::writeNode(Object *ob)
|
||||
{
|
||||
const Scene *scene = blender_context.get_scene();
|
||||
ViewLayer *view_layer = blender_context.get_view_layer();
|
||||
|
||||
std::vector<Object *> child_objects;
|
||||
bc_get_children(child_objects, ob, scene, view_layer);
|
||||
bool can_export = bc_is_in_Export_set(
|
||||
this->export_settings.get_export_set(), ob, scene, view_layer);
|
||||
|
||||
/* Add associated armature first if available */
|
||||
bool armature_exported = false;
|
||||
Object *ob_arm = bc_get_assigned_armature(ob);
|
||||
|
||||
if (ob_arm != nullptr) {
|
||||
armature_exported = bc_is_in_Export_set(
|
||||
this->export_settings.get_export_set(), ob_arm, scene, view_layer);
|
||||
if (armature_exported && bc_is_marked(ob_arm)) {
|
||||
writeNode(ob_arm);
|
||||
bc_remove_mark(ob_arm);
|
||||
armature_exported = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (can_export) {
|
||||
COLLADASW::Node colladaNode(mSW);
|
||||
colladaNode.setNodeId(translate_id(id_name(ob)));
|
||||
colladaNode.setNodeName(encode_xml(id_name(ob)));
|
||||
colladaNode.setType(COLLADASW::Node::NODE);
|
||||
|
||||
colladaNode.start();
|
||||
if (ob->type == OB_MESH && armature_exported) {
|
||||
/* for skinned mesh we write obmat in <bind_shape_matrix> */
|
||||
TransformWriter::add_node_transform_identity(colladaNode, this->export_settings);
|
||||
}
|
||||
else {
|
||||
TransformWriter::add_node_transform_ob(colladaNode, ob, this->export_settings);
|
||||
}
|
||||
|
||||
/* <instance_geometry> */
|
||||
if (ob->type == OB_MESH) {
|
||||
bool instance_controller_created = false;
|
||||
if (armature_exported) {
|
||||
instance_controller_created = arm_exporter->add_instance_controller(ob);
|
||||
}
|
||||
if (!instance_controller_created) {
|
||||
COLLADASW::InstanceGeometry instGeom(mSW);
|
||||
instGeom.setUrl(COLLADASW::URI(
|
||||
COLLADABU::Utils::EMPTY_STRING,
|
||||
get_geometry_id(ob, this->export_settings.get_use_object_instantiation())));
|
||||
instGeom.setName(encode_xml(id_name(ob)));
|
||||
InstanceWriter::add_material_bindings(
|
||||
instGeom.getBindMaterial(), ob, this->export_settings.get_active_uv_only());
|
||||
instGeom.add();
|
||||
}
|
||||
}
|
||||
|
||||
/* <instance_controller> */
|
||||
else if (ob->type == OB_ARMATURE) {
|
||||
arm_exporter->add_bone_collections(ob, colladaNode);
|
||||
arm_exporter->add_armature_bones(ob, view_layer, this, child_objects);
|
||||
}
|
||||
|
||||
/* <instance_camera> */
|
||||
else if (ob->type == OB_CAMERA) {
|
||||
COLLADASW::InstanceCamera instCam(
|
||||
mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_camera_id(ob)));
|
||||
instCam.add();
|
||||
}
|
||||
|
||||
/* <instance_light> */
|
||||
else if (ob->type == OB_LAMP) {
|
||||
COLLADASW::InstanceLight instLa(
|
||||
mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_light_id(ob)));
|
||||
instLa.add();
|
||||
}
|
||||
|
||||
/* empty object */
|
||||
else if (ob->type == OB_EMPTY) { /* TODO: handle groups (OB_DUPLICOLLECTION */
|
||||
if ((ob->transflag & OB_DUPLICOLLECTION) == OB_DUPLICOLLECTION && ob->instance_collection) {
|
||||
Collection *collection = ob->instance_collection;
|
||||
// printf("group detected '%s'\n", group->id.name + 2);
|
||||
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, object) {
|
||||
printf("\t%s\n", object->id.name);
|
||||
}
|
||||
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
|
||||
}
|
||||
|
||||
if (BLI_listbase_is_empty(&ob->constraints) == false) {
|
||||
bConstraint *con = (bConstraint *)ob->constraints.first;
|
||||
while (con) {
|
||||
std::string con_name(encode_xml(con->name));
|
||||
std::string con_tag = con_name + "_constraint";
|
||||
printf("%s\n", con_name.c_str());
|
||||
printf("%s\n\n", con_tag.c_str());
|
||||
colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "type", con->type);
|
||||
colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "enforce", con->enforce);
|
||||
colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "flag", con->flag);
|
||||
colladaNode.addExtraTechniqueChildParameter(
|
||||
"blender", con_tag, "headtail", con->headtail);
|
||||
colladaNode.addExtraTechniqueChildParameter(
|
||||
"blender", con_tag, "lin_error", con->lin_error);
|
||||
colladaNode.addExtraTechniqueChildParameter(
|
||||
"blender", con_tag, "own_space", con->ownspace);
|
||||
colladaNode.addExtraTechniqueChildParameter(
|
||||
"blender", con_tag, "rot_error", con->rot_error);
|
||||
colladaNode.addExtraTechniqueChildParameter(
|
||||
"blender", con_tag, "tar_space", con->tarspace);
|
||||
colladaNode.addExtraTechniqueChildParameter(
|
||||
"blender", con_tag, "lin_error", con->lin_error);
|
||||
|
||||
/* not ideal: add the target object name as another parameter.
|
||||
* No real mapping in the `.dae`.
|
||||
* Need support for multiple target objects also. */
|
||||
|
||||
ListBase targets = {nullptr, nullptr};
|
||||
if (BKE_constraint_targets_get(con, &targets)) {
|
||||
Object *obtar;
|
||||
|
||||
LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
|
||||
obtar = ct->tar;
|
||||
std::string tar_id((obtar) ? id_name(obtar) : "");
|
||||
colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "target_id", tar_id);
|
||||
}
|
||||
|
||||
BKE_constraint_targets_flush(con, &targets, true);
|
||||
}
|
||||
|
||||
con = con->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
bc_remove_mark(ob);
|
||||
writeNodeList(child_objects, ob);
|
||||
colladaNode.end();
|
||||
}
|
||||
else {
|
||||
writeNodeList(child_objects, ob);
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "COLLADASWLibraryVisualScenes.h"
|
||||
|
||||
#include "ArmatureExporter.h"
|
||||
#include "ExportSettings.h"
|
||||
|
||||
class SceneExporter : COLLADASW::LibraryVisualScenes,
|
||||
protected TransformWriter,
|
||||
protected InstanceWriter {
|
||||
public:
|
||||
SceneExporter(BlenderContext &blender_context,
|
||||
COLLADASW::StreamWriter *sw,
|
||||
ArmatureExporter *arm,
|
||||
BCExportSettings &export_settings)
|
||||
: COLLADASW::LibraryVisualScenes(sw),
|
||||
blender_context(blender_context),
|
||||
arm_exporter(arm),
|
||||
export_settings(export_settings)
|
||||
{
|
||||
}
|
||||
|
||||
void exportScene();
|
||||
|
||||
private:
|
||||
BlenderContext &blender_context;
|
||||
friend class ArmatureExporter;
|
||||
ArmatureExporter *arm_exporter;
|
||||
BCExportSettings &export_settings;
|
||||
|
||||
void exportHierarchy();
|
||||
void writeNodeList(std::vector<Object *> &child_objects, Object *parent);
|
||||
void writeNode(Object *ob);
|
||||
};
|
@ -1,323 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2010-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BKE_action.hh"
|
||||
#include "BKE_deform.hh"
|
||||
#include "BKE_object.hh"
|
||||
#include "BKE_object_deform.h"
|
||||
|
||||
#include "ED_mesh.hh"
|
||||
#include "ED_object.hh"
|
||||
#include "ED_object_vgroup.hh"
|
||||
|
||||
#include "SkinInfo.h"
|
||||
#include "collada_utils.h"
|
||||
|
||||
/* use name, or fall back to original id if name not present (name is optional) */
|
||||
template<class T> static const char *bc_get_joint_name(T *node)
|
||||
{
|
||||
const std::string &id = node->getName();
|
||||
return id.empty() ? node->getOriginalId().c_str() : id.c_str();
|
||||
}
|
||||
|
||||
SkinInfo::SkinInfo() = default;
|
||||
|
||||
SkinInfo::SkinInfo(const SkinInfo &skin)
|
||||
: weights(skin.weights),
|
||||
joint_data(skin.joint_data),
|
||||
unit_converter(skin.unit_converter),
|
||||
ob_arm(skin.ob_arm),
|
||||
controller_uid(skin.controller_uid),
|
||||
parent(skin.parent)
|
||||
{
|
||||
copy_m4_m4(bind_shape_matrix, (float(*)[4])skin.bind_shape_matrix);
|
||||
|
||||
transfer_uint_array_data_const(skin.joints_per_vertex, joints_per_vertex);
|
||||
transfer_uint_array_data_const(skin.weight_indices, weight_indices);
|
||||
transfer_int_array_data_const(skin.joint_indices, joint_indices);
|
||||
}
|
||||
|
||||
SkinInfo::SkinInfo(UnitConverter *conv) : unit_converter(conv), ob_arm(nullptr), parent(nullptr) {}
|
||||
|
||||
template<class T> void SkinInfo::transfer_array_data(T &src, T &dest)
|
||||
{
|
||||
dest.setData(src.getData(), src.getCount());
|
||||
src.yieldOwnerShip();
|
||||
dest.yieldOwnerShip();
|
||||
}
|
||||
|
||||
void SkinInfo::transfer_int_array_data_const(const COLLADAFW::IntValuesArray &src,
|
||||
COLLADAFW::IntValuesArray &dest)
|
||||
{
|
||||
dest.setData((int *)src.getData(), src.getCount());
|
||||
dest.yieldOwnerShip();
|
||||
}
|
||||
|
||||
void SkinInfo::transfer_uint_array_data_const(const COLLADAFW::UIntValuesArray &src,
|
||||
COLLADAFW::UIntValuesArray &dest)
|
||||
{
|
||||
dest.setData((uint *)src.getData(), src.getCount());
|
||||
dest.yieldOwnerShip();
|
||||
}
|
||||
|
||||
void SkinInfo::borrow_skin_controller_data(const COLLADAFW::SkinControllerData *skin)
|
||||
{
|
||||
transfer_array_data((COLLADAFW::UIntValuesArray &)skin->getJointsPerVertex(), joints_per_vertex);
|
||||
transfer_array_data((COLLADAFW::UIntValuesArray &)skin->getWeightIndices(), weight_indices);
|
||||
transfer_array_data((COLLADAFW::IntValuesArray &)skin->getJointIndices(), joint_indices);
|
||||
// transfer_array_data(skin->getWeights(), weights);
|
||||
|
||||
/* cannot transfer data for FloatOrDoubleArray, copy values manually */
|
||||
const COLLADAFW::FloatOrDoubleArray &weight = skin->getWeights();
|
||||
for (uint i = 0; i < weight.getValuesCount(); i++) {
|
||||
weights.push_back(bc_get_float_value(weight, i));
|
||||
}
|
||||
|
||||
UnitConverter::dae_matrix_to_mat4_(bind_shape_matrix, skin->getBindShapeMatrix());
|
||||
}
|
||||
|
||||
void SkinInfo::free()
|
||||
{
|
||||
joints_per_vertex.releaseMemory();
|
||||
weight_indices.releaseMemory();
|
||||
joint_indices.releaseMemory();
|
||||
// weights.releaseMemory();
|
||||
}
|
||||
|
||||
void SkinInfo::add_joint(const COLLADABU::Math::Matrix4 &matrix)
|
||||
{
|
||||
JointData jd;
|
||||
UnitConverter::dae_matrix_to_mat4_(jd.inv_bind_mat, matrix);
|
||||
joint_data.push_back(jd);
|
||||
}
|
||||
|
||||
void SkinInfo::set_controller(const COLLADAFW::SkinController *co)
|
||||
{
|
||||
controller_uid = co->getUniqueId();
|
||||
|
||||
/* fill in joint UIDs */
|
||||
const COLLADAFW::UniqueIdArray &joint_uids = co->getJoints();
|
||||
for (uint i = 0; i < joint_uids.getCount(); i++) {
|
||||
joint_data[i].joint_uid = joint_uids[i];
|
||||
|
||||
/* store armature pointer */
|
||||
// JointData& jd = joint_index_to_joint_info_map[i];
|
||||
// jd.ob_arm = ob_arm;
|
||||
|
||||
/* now we'll be able to get inv bind matrix from joint id */
|
||||
// joint_id_to_joint_index_map[joint_ids[i]] = i;
|
||||
}
|
||||
}
|
||||
|
||||
Object *SkinInfo::create_armature(Main *bmain, Scene *scene, ViewLayer *view_layer)
|
||||
{
|
||||
ob_arm = bc_add_object(bmain, scene, view_layer, OB_ARMATURE, nullptr);
|
||||
return ob_arm;
|
||||
}
|
||||
|
||||
Object *SkinInfo::set_armature(Object *ob_arm)
|
||||
{
|
||||
if (this->ob_arm) {
|
||||
return this->ob_arm;
|
||||
}
|
||||
|
||||
this->ob_arm = ob_arm;
|
||||
return ob_arm;
|
||||
}
|
||||
|
||||
bool SkinInfo::get_joint_inv_bind_matrix(float inv_bind_mat[4][4], COLLADAFW::Node *node)
|
||||
{
|
||||
const COLLADAFW::UniqueId &uid = node->getUniqueId();
|
||||
std::vector<JointData>::iterator it;
|
||||
for (it = joint_data.begin(); it != joint_data.end(); it++) {
|
||||
if ((*it).joint_uid == uid) {
|
||||
copy_m4_m4(inv_bind_mat, (*it).inv_bind_mat);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Object *SkinInfo::BKE_armature_from_object()
|
||||
{
|
||||
return ob_arm;
|
||||
}
|
||||
|
||||
const COLLADAFW::UniqueId &SkinInfo::get_controller_uid()
|
||||
{
|
||||
return controller_uid;
|
||||
}
|
||||
|
||||
bool SkinInfo::uses_joint_or_descendant(COLLADAFW::Node *node)
|
||||
{
|
||||
const COLLADAFW::UniqueId &uid = node->getUniqueId();
|
||||
std::vector<JointData>::iterator it;
|
||||
for (it = joint_data.begin(); it != joint_data.end(); it++) {
|
||||
if ((*it).joint_uid == uid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
COLLADAFW::NodePointerArray &children = node->getChildNodes();
|
||||
for (uint i = 0; i < children.getCount(); i++) {
|
||||
if (uses_joint_or_descendant(children[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SkinInfo::link_armature(bContext *C,
|
||||
Object *ob,
|
||||
std::map<COLLADAFW::UniqueId, COLLADAFW::Node *> &joint_by_uid,
|
||||
TransformReader *tm)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
|
||||
ModifierData *md = blender::ed::object::modifier_add(
|
||||
nullptr, bmain, scene, ob, nullptr, eModifierType_Armature);
|
||||
ArmatureModifierData *amd = (ArmatureModifierData *)md;
|
||||
amd->object = ob_arm;
|
||||
|
||||
#if 1
|
||||
/* XXX Why do we enforce objects to be children of Armatures if they weren't so before? */
|
||||
if (!BKE_object_is_child_recursive(ob_arm, ob)) {
|
||||
bc_set_parent(ob, ob_arm, C);
|
||||
}
|
||||
#else
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
|
||||
ob->parent = ob_arm;
|
||||
ob->partype = PAROBJECT;
|
||||
|
||||
invert_m4_m4(ob->parentinv, BKE_object_calc_parent(depsgraph, scene, ob).ptr());
|
||||
|
||||
DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
|
||||
#endif
|
||||
copy_m4_m4(ob->runtime->object_to_world.ptr(), bind_shape_matrix);
|
||||
BKE_object_apply_mat4(ob, ob->object_to_world().ptr(), false, false);
|
||||
|
||||
amd->deformflag = ARM_DEF_VGROUP;
|
||||
|
||||
/* create all vertex groups */
|
||||
std::vector<JointData>::iterator it;
|
||||
int joint_index;
|
||||
for (it = joint_data.begin(), joint_index = 0; it != joint_data.end(); it++, joint_index++) {
|
||||
const char *name = "Group";
|
||||
|
||||
/* skip joints that have invalid UID */
|
||||
if ((*it).joint_uid == COLLADAFW::UniqueId::INVALID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* name group by joint node name */
|
||||
|
||||
if (joint_by_uid.find((*it).joint_uid) != joint_by_uid.end()) {
|
||||
name = bc_get_joint_name(joint_by_uid[(*it).joint_uid]);
|
||||
}
|
||||
|
||||
BKE_object_defgroup_add_name(ob, name);
|
||||
}
|
||||
|
||||
/* <vcount> - number of joints per vertex - joints_per_vertex
|
||||
* <v> - [[bone index, weight index] * joints per vertex] * vertices - weight indices
|
||||
* ^ bone index can be -1 meaning weight toward bind shape, how to express this in Blender?
|
||||
*
|
||||
* for each vertex in weight indices
|
||||
* for each bone index in vertex
|
||||
* add vertex to group at group index
|
||||
* treat group index -1 specially
|
||||
*
|
||||
* get def group by index with BLI_findlink */
|
||||
|
||||
for (uint vertex = 0, weight = 0; vertex < joints_per_vertex.getCount(); vertex++) {
|
||||
|
||||
uint limit = weight + joints_per_vertex[vertex];
|
||||
for (; weight < limit; weight++) {
|
||||
int joint = joint_indices[weight], joint_weight = weight_indices[weight];
|
||||
|
||||
/* -1 means "weight towards the bind shape", we just don't assign it to any group */
|
||||
if (joint != -1) {
|
||||
const ListBase *defbase = BKE_object_defgroup_list(ob);
|
||||
bDeformGroup *def = (bDeformGroup *)BLI_findlink(defbase, joint);
|
||||
|
||||
blender::ed::object::vgroup_vert_add(
|
||||
ob, def, vertex, weights[joint_weight], WEIGHT_REPLACE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bPoseChannel *SkinInfo::get_pose_channel_from_node(COLLADAFW::Node *node)
|
||||
{
|
||||
return BKE_pose_channel_find_name(ob_arm->pose, bc_get_joint_name(node));
|
||||
}
|
||||
|
||||
void SkinInfo::set_parent(Object *_parent)
|
||||
{
|
||||
parent = _parent;
|
||||
}
|
||||
|
||||
Object *SkinInfo::get_parent()
|
||||
{
|
||||
return parent;
|
||||
}
|
||||
|
||||
void SkinInfo::find_root_joints(const std::vector<COLLADAFW::Node *> &root_joints,
|
||||
std::map<COLLADAFW::UniqueId, COLLADAFW::Node *> &joint_by_uid,
|
||||
std::vector<COLLADAFW::Node *> &result)
|
||||
{
|
||||
std::vector<COLLADAFW::Node *>::const_iterator it;
|
||||
/* for each root_joint */
|
||||
for (it = root_joints.begin(); it != root_joints.end(); it++) {
|
||||
COLLADAFW::Node *root = *it;
|
||||
std::vector<JointData>::iterator ji;
|
||||
/* for each joint_data in this skin */
|
||||
for (ji = joint_data.begin(); ji != joint_data.end(); ji++) {
|
||||
if (joint_by_uid.find((*ji).joint_uid) != joint_by_uid.end()) {
|
||||
/* get joint node from joint map */
|
||||
COLLADAFW::Node *joint = joint_by_uid[(*ji).joint_uid];
|
||||
|
||||
/* find if joint node is in the tree belonging to the root_joint */
|
||||
if (find_node_in_tree(joint, root)) {
|
||||
if (std::find(result.begin(), result.end(), root) == result.end()) {
|
||||
result.push_back(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SkinInfo::find_node_in_tree(COLLADAFW::Node *node, COLLADAFW::Node *tree_root)
|
||||
{
|
||||
if (node == tree_root) {
|
||||
return true;
|
||||
}
|
||||
|
||||
COLLADAFW::NodePointerArray &children = tree_root->getChildNodes();
|
||||
for (uint i = 0; i < children.getCount(); i++) {
|
||||
if (find_node_in_tree(node, children[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
@ -1,121 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "COLLADAFWNode.h"
|
||||
#include "COLLADAFWSkinController.h"
|
||||
#include "COLLADAFWSkinControllerData.h"
|
||||
#include "COLLADAFWTypes.h"
|
||||
#include "COLLADAFWUniqueId.h"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "TransformReader.h"
|
||||
#include "collada_internal.h"
|
||||
|
||||
/**
|
||||
* This is used to store data passed in write_controller_data.
|
||||
* Arrays from #COLLADAFW::SkinControllerData lose ownership, so do this class members
|
||||
* so that arrays don't get freed until we free them explicitly.
|
||||
*/
|
||||
class SkinInfo {
|
||||
private:
|
||||
/* to build armature bones from inverse bind matrices */
|
||||
struct JointData {
|
||||
float inv_bind_mat[4][4]; /* joint inverse bind matrix */
|
||||
COLLADAFW::UniqueId joint_uid; /* joint node UID */
|
||||
// Object *ob_arm; /* armature object */
|
||||
};
|
||||
|
||||
float bind_shape_matrix[4][4];
|
||||
|
||||
/* data from COLLADAFW::SkinControllerData, each array should be freed */
|
||||
COLLADAFW::UIntValuesArray joints_per_vertex;
|
||||
COLLADAFW::UIntValuesArray weight_indices;
|
||||
COLLADAFW::IntValuesArray joint_indices;
|
||||
// COLLADAFW::FloatOrDoubleArray weights;
|
||||
std::vector<float> weights;
|
||||
|
||||
std::vector<JointData> joint_data; /* index to this vector is joint index */
|
||||
|
||||
UnitConverter *unit_converter;
|
||||
|
||||
Object *ob_arm;
|
||||
COLLADAFW::UniqueId controller_uid;
|
||||
Object *parent;
|
||||
|
||||
public:
|
||||
SkinInfo();
|
||||
SkinInfo(const SkinInfo &skin);
|
||||
SkinInfo(UnitConverter *conv);
|
||||
|
||||
/** Nobody owns the data after this, so it should be freed manually with releaseMemory. */
|
||||
template<typename T> void transfer_array_data(T &src, T &dest);
|
||||
|
||||
/** When src is const we cannot `src.yieldOwnerShip`, this is used by copy constructor. */
|
||||
void transfer_int_array_data_const(const COLLADAFW::IntValuesArray &src,
|
||||
COLLADAFW::IntValuesArray &dest);
|
||||
|
||||
void transfer_uint_array_data_const(const COLLADAFW::UIntValuesArray &src,
|
||||
COLLADAFW::UIntValuesArray &dest);
|
||||
|
||||
void borrow_skin_controller_data(const COLLADAFW::SkinControllerData *skin);
|
||||
|
||||
void free();
|
||||
|
||||
/**
|
||||
* Using inverse bind matrices to construct armature
|
||||
* it is safe to invert them to get the original matrices
|
||||
* because if they are inverse matrices, they can be inverted.
|
||||
*/
|
||||
void add_joint(const COLLADABU::Math::Matrix4 &matrix);
|
||||
|
||||
void set_controller(const COLLADAFW::SkinController *co);
|
||||
|
||||
/** Called from write_controller. */
|
||||
Object *create_armature(Main *bmain, Scene *scene, ViewLayer *view_layer);
|
||||
|
||||
Object *set_armature(Object *ob_arm);
|
||||
|
||||
bool get_joint_inv_bind_matrix(float inv_bind_mat[4][4], COLLADAFW::Node *node);
|
||||
|
||||
Object *BKE_armature_from_object();
|
||||
|
||||
const COLLADAFW::UniqueId &get_controller_uid();
|
||||
|
||||
/**
|
||||
* Check if this skin controller references a joint or any descendant of it
|
||||
*
|
||||
* some nodes may not be referenced by SkinController,
|
||||
* in this case to determine if the node belongs to this armature,
|
||||
* we need to search down the tree.
|
||||
*/
|
||||
bool uses_joint_or_descendant(COLLADAFW::Node *node);
|
||||
|
||||
void link_armature(bContext *C,
|
||||
Object *ob,
|
||||
std::map<COLLADAFW::UniqueId, COLLADAFW::Node *> &joint_by_uid,
|
||||
TransformReader *tm);
|
||||
|
||||
bPoseChannel *get_pose_channel_from_node(COLLADAFW::Node *node);
|
||||
|
||||
void set_parent(Object *_parent);
|
||||
|
||||
Object *get_parent();
|
||||
|
||||
void find_root_joints(const std::vector<COLLADAFW::Node *> &root_joints,
|
||||
std::map<COLLADAFW::UniqueId, COLLADAFW::Node *> &joint_by_uid,
|
||||
std::vector<COLLADAFW::Node *> &result);
|
||||
|
||||
bool find_node_in_tree(COLLADAFW::Node *node, COLLADAFW::Node *tree_root);
|
||||
};
|
@ -1,146 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2010-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include "COLLADAFWMatrix.h"
|
||||
#include "COLLADAFWRotate.h"
|
||||
#include "COLLADAFWScale.h"
|
||||
#include "COLLADAFWTranslate.h"
|
||||
|
||||
#include "TransformReader.h"
|
||||
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_math_rotation.h"
|
||||
|
||||
TransformReader::TransformReader(UnitConverter *conv) : unit_converter(conv)
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void TransformReader::get_node_mat(float mat[4][4],
|
||||
COLLADAFW::Node *node,
|
||||
std::map<COLLADAFW::UniqueId, Animation> *animation_map,
|
||||
Object *ob)
|
||||
{
|
||||
get_node_mat(mat, node, animation_map, ob, nullptr);
|
||||
}
|
||||
|
||||
void TransformReader::get_node_mat(float mat[4][4],
|
||||
COLLADAFW::Node *node,
|
||||
std::map<COLLADAFW::UniqueId, Animation> *animation_map,
|
||||
Object *ob,
|
||||
float parent_mat[4][4])
|
||||
{
|
||||
float cur[4][4];
|
||||
float copy[4][4];
|
||||
|
||||
unit_m4(mat);
|
||||
|
||||
for (uint i = 0; i < node->getTransformations().getCount(); i++) {
|
||||
|
||||
COLLADAFW::Transformation *tm = node->getTransformations()[i];
|
||||
COLLADAFW::Transformation::TransformationType type = tm->getTransformationType();
|
||||
|
||||
switch (type) {
|
||||
case COLLADAFW::Transformation::MATRIX:
|
||||
/* When matrix AND Trans/Rot/Scale are defined for a node,
|
||||
* then this is considered as redundant information.
|
||||
* So if we find a Matrix we use that and return. */
|
||||
dae_matrix_to_mat4(tm, mat);
|
||||
if (parent_mat) {
|
||||
mul_m4_m4m4(mat, parent_mat, mat);
|
||||
}
|
||||
return;
|
||||
case COLLADAFW::Transformation::TRANSLATE:
|
||||
dae_translate_to_mat4(tm, cur);
|
||||
break;
|
||||
case COLLADAFW::Transformation::ROTATE:
|
||||
dae_rotate_to_mat4(tm, cur);
|
||||
break;
|
||||
case COLLADAFW::Transformation::SCALE:
|
||||
dae_scale_to_mat4(tm, cur);
|
||||
break;
|
||||
case COLLADAFW::Transformation::LOOKAT:
|
||||
fprintf(stderr, "|! LOOKAT transformations are not supported yet.\n");
|
||||
break;
|
||||
case COLLADAFW::Transformation::SKEW:
|
||||
fprintf(stderr, "|! SKEW transformations are not supported yet.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
copy_m4_m4(copy, mat);
|
||||
mul_m4_m4m4(mat, copy, cur);
|
||||
|
||||
if (animation_map) {
|
||||
/* AnimationList that drives this Transformation */
|
||||
const COLLADAFW::UniqueId &anim_list_id = tm->getAnimationList();
|
||||
|
||||
/* store this so later we can link animation data with ob */
|
||||
Animation anim = {ob, node, tm};
|
||||
(*animation_map)[anim_list_id] = anim;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent_mat) {
|
||||
mul_m4_m4m4(mat, parent_mat, mat);
|
||||
}
|
||||
}
|
||||
|
||||
void TransformReader::dae_rotate_to_mat4(COLLADAFW::Transformation *tm, float m[4][4])
|
||||
{
|
||||
COLLADAFW::Rotate *ro = (COLLADAFW::Rotate *)tm;
|
||||
COLLADABU::Math::Vector3 &axis = ro->getRotationAxis();
|
||||
const float angle = float(DEG2RAD(ro->getRotationAngle()));
|
||||
const float ax[] = {float(axis[0]), float(axis[1]), float(axis[2])};
|
||||
#if 0
|
||||
float quat[4];
|
||||
axis_angle_to_quat(quat, axis, angle);
|
||||
quat_to_mat4(m, quat);
|
||||
#endif
|
||||
axis_angle_to_mat4(m, ax, angle);
|
||||
}
|
||||
|
||||
void TransformReader::dae_translate_to_mat4(COLLADAFW::Transformation *tm, float m[4][4])
|
||||
{
|
||||
COLLADAFW::Translate *tra = (COLLADAFW::Translate *)tm;
|
||||
COLLADABU::Math::Vector3 &t = tra->getTranslation();
|
||||
|
||||
unit_m4(m);
|
||||
|
||||
m[3][0] = float(t[0]);
|
||||
m[3][1] = float(t[1]);
|
||||
m[3][2] = float(t[2]);
|
||||
}
|
||||
|
||||
void TransformReader::dae_scale_to_mat4(COLLADAFW::Transformation *tm, float m[4][4])
|
||||
{
|
||||
COLLADABU::Math::Vector3 &s = ((COLLADAFW::Scale *)tm)->getScale();
|
||||
float size[3] = {float(s[0]), float(s[1]), float(s[2])};
|
||||
size_to_mat4(m, size);
|
||||
}
|
||||
|
||||
void TransformReader::dae_matrix_to_mat4(COLLADAFW::Transformation *tm, float m[4][4])
|
||||
{
|
||||
UnitConverter::dae_matrix_to_mat4_(m, ((COLLADAFW::Matrix *)tm)->getMatrix());
|
||||
}
|
||||
|
||||
void TransformReader::dae_translate_to_v3(COLLADAFW::Transformation *tm, float v[3])
|
||||
{
|
||||
dae_vector3_to_v3(((COLLADAFW::Translate *)tm)->getTranslation(), v);
|
||||
}
|
||||
|
||||
void TransformReader::dae_scale_to_v3(COLLADAFW::Transformation *tm, float v[3])
|
||||
{
|
||||
dae_vector3_to_v3(((COLLADAFW::Scale *)tm)->getScale(), v);
|
||||
}
|
||||
|
||||
void TransformReader::dae_vector3_to_v3(const COLLADABU::Math::Vector3 &v3, float v[3])
|
||||
{
|
||||
v[0] = v3.x;
|
||||
v[1] = v3.y;
|
||||
v[2] = v3.z;
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "COLLADAFWNode.h"
|
||||
#include "COLLADAFWTransformation.h"
|
||||
#include "COLLADAFWUniqueId.h"
|
||||
#include "Math/COLLADABUMathVector3.h"
|
||||
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "collada_internal.h"
|
||||
|
||||
// struct Object;
|
||||
|
||||
class TransformReader {
|
||||
protected:
|
||||
UnitConverter *unit_converter;
|
||||
|
||||
public:
|
||||
struct Animation {
|
||||
Object *ob;
|
||||
COLLADAFW::Node *node;
|
||||
COLLADAFW::Transformation *tm; /* which transform is animated by an AnimationList->id */
|
||||
};
|
||||
|
||||
TransformReader(UnitConverter *conv);
|
||||
|
||||
void get_node_mat(float mat[4][4],
|
||||
COLLADAFW::Node *node,
|
||||
std::map<COLLADAFW::UniqueId, Animation> *animation_map,
|
||||
Object *ob);
|
||||
void get_node_mat(float mat[4][4],
|
||||
COLLADAFW::Node *node,
|
||||
std::map<COLLADAFW::UniqueId, Animation> *animation_map,
|
||||
Object *ob,
|
||||
float parent_mat[4][4]);
|
||||
|
||||
void dae_rotate_to_mat4(COLLADAFW::Transformation *tm, float m[4][4]);
|
||||
void dae_translate_to_mat4(COLLADAFW::Transformation *tm, float m[4][4]);
|
||||
void dae_scale_to_mat4(COLLADAFW::Transformation *tm, float m[4][4]);
|
||||
void dae_matrix_to_mat4(COLLADAFW::Transformation *tm, float m[4][4]);
|
||||
void dae_translate_to_v3(COLLADAFW::Transformation *tm, float v[3]);
|
||||
void dae_scale_to_v3(COLLADAFW::Transformation *tm, float v[3]);
|
||||
void dae_vector3_to_v3(const COLLADABU::Math::Vector3 &v3, float v[3]);
|
||||
};
|
@ -1,127 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2010-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include "BLI_math_matrix.h"
|
||||
|
||||
#include "BKE_object.hh"
|
||||
|
||||
#include "TransformWriter.h"
|
||||
|
||||
#include "collada_utils.h"
|
||||
|
||||
void TransformWriter::add_joint_transform(COLLADASW::Node &node,
|
||||
float mat[4][4],
|
||||
float parent_mat[4][4],
|
||||
BCExportSettings &export_settings,
|
||||
bool has_restmat)
|
||||
{
|
||||
float local[4][4];
|
||||
|
||||
if (parent_mat) {
|
||||
float invpar[4][4];
|
||||
invert_m4_m4(invpar, parent_mat);
|
||||
mul_m4_m4m4(local, invpar, mat);
|
||||
}
|
||||
else {
|
||||
copy_m4_m4(local, mat);
|
||||
}
|
||||
|
||||
if (!has_restmat && export_settings.get_apply_global_orientation()) {
|
||||
bc_apply_global_transform(local, export_settings.get_global_transform());
|
||||
}
|
||||
|
||||
double dmat[4][4];
|
||||
UnitConverter::mat4_to_dae_double(dmat, local);
|
||||
|
||||
if (export_settings.get_object_transformation_type() == BC_TRANSFORMATION_TYPE_MATRIX) {
|
||||
node.addMatrix("transform", dmat);
|
||||
}
|
||||
else {
|
||||
float loc[3], rot[3], scale[3];
|
||||
bc_decompose(local, loc, rot, nullptr, scale);
|
||||
add_transform(node, loc, rot, scale);
|
||||
}
|
||||
}
|
||||
|
||||
void TransformWriter::add_node_transform_ob(COLLADASW::Node &node,
|
||||
Object *ob,
|
||||
BCExportSettings &export_settings)
|
||||
{
|
||||
bool limit_precision = export_settings.get_limit_precision();
|
||||
|
||||
/* Export the local Matrix (relative to the object parent,
|
||||
* be it an object, bone or vertices (one or more)). */
|
||||
Matrix f_obmat;
|
||||
BKE_object_matrix_local_get(ob, f_obmat);
|
||||
|
||||
if (export_settings.get_apply_global_orientation()) {
|
||||
bc_apply_global_transform(f_obmat, export_settings.get_global_transform());
|
||||
}
|
||||
else {
|
||||
bc_add_global_transform(f_obmat, export_settings.get_global_transform());
|
||||
}
|
||||
|
||||
switch (export_settings.get_object_transformation_type()) {
|
||||
case BC_TRANSFORMATION_TYPE_MATRIX: {
|
||||
double d_obmat[4][4];
|
||||
UnitConverter::mat4_to_dae_double(d_obmat, f_obmat);
|
||||
|
||||
if (limit_precision) {
|
||||
BCMatrix::sanitize(d_obmat, LIMITTED_PRECISION);
|
||||
}
|
||||
node.addMatrix("transform", d_obmat);
|
||||
break;
|
||||
}
|
||||
case BC_TRANSFORMATION_TYPE_DECOMPOSED: {
|
||||
float loc[3], rot[3], scale[3];
|
||||
bc_decompose(f_obmat, loc, rot, nullptr, scale);
|
||||
if (limit_precision) {
|
||||
bc_sanitize_v3(loc, LIMITTED_PRECISION);
|
||||
bc_sanitize_v3(rot, LIMITTED_PRECISION);
|
||||
bc_sanitize_v3(scale, LIMITTED_PRECISION);
|
||||
}
|
||||
add_transform(node, loc, rot, scale);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TransformWriter::add_node_transform_identity(COLLADASW::Node &node,
|
||||
BCExportSettings &export_settings)
|
||||
{
|
||||
BC_export_transformation_type transformation_type =
|
||||
export_settings.get_object_transformation_type();
|
||||
switch (transformation_type) {
|
||||
case BC_TRANSFORMATION_TYPE_MATRIX: {
|
||||
BCMatrix mat;
|
||||
DMatrix d_obmat;
|
||||
mat.get_matrix(d_obmat);
|
||||
node.addMatrix("transform", d_obmat);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
float loc[3] = {0.0f, 0.0f, 0.0f};
|
||||
float scale[3] = {1.0f, 1.0f, 1.0f};
|
||||
float rot[3] = {0.0f, 0.0f, 0.0f};
|
||||
add_transform(node, loc, rot, scale);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TransformWriter::add_transform(COLLADASW::Node &node,
|
||||
const float loc[3],
|
||||
const float rot[3],
|
||||
const float scale[3])
|
||||
{
|
||||
node.addScale("scale", scale[0], scale[1], scale[2]);
|
||||
node.addRotateZ("rotationZ", RAD2DEGF(rot[2]));
|
||||
node.addRotateY("rotationY", RAD2DEGF(rot[1]));
|
||||
node.addRotateX("rotationX", RAD2DEGF(rot[0]));
|
||||
node.addTranslate("location", loc[0], loc[1], loc[2]);
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "COLLADASWNode.h"
|
||||
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "ExportSettings.h"
|
||||
|
||||
class TransformWriter {
|
||||
protected:
|
||||
void add_joint_transform(COLLADASW::Node &node,
|
||||
float mat[4][4],
|
||||
float parent_mat[4][4],
|
||||
BCExportSettings &export_settings,
|
||||
bool has_restmat);
|
||||
|
||||
void add_node_transform_ob(COLLADASW::Node &node, Object *ob, BCExportSettings &export_settings);
|
||||
|
||||
void add_node_transform_identity(COLLADASW::Node &node, BCExportSettings &export_settings);
|
||||
|
||||
private:
|
||||
void add_transform(COLLADASW::Node &node,
|
||||
const float loc[3],
|
||||
const float rot[3],
|
||||
const float scale[3]);
|
||||
};
|
@ -1,95 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2009-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include "collada.h"
|
||||
#include "DocumentExporter.h"
|
||||
#include "DocumentImporter.h"
|
||||
#include "ExportSettings.h"
|
||||
#include "ImportSettings.h"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
|
||||
#include "BLI_linklist.h"
|
||||
|
||||
static void print_import_header(ImportSettings &import_settings)
|
||||
{
|
||||
fprintf(stderr, "+-- Collada Import parameters------\n");
|
||||
fprintf(stderr, "| input file : %s\n", import_settings.filepath);
|
||||
fprintf(stderr, "| use units : %s\n", (import_settings.import_units) ? "yes" : "no");
|
||||
fprintf(stderr, "| custom normals : %s\n", (import_settings.custom_normals) ? "yes" : "no");
|
||||
fprintf(stderr, "| autoconnect : %s\n", (import_settings.auto_connect) ? "yes" : "no");
|
||||
fprintf(stderr, "+-- Armature Import parameters ----\n");
|
||||
fprintf(stderr, "| find bone chains: %s\n", (import_settings.find_chains) ? "yes" : "no");
|
||||
fprintf(stderr, "| min chain len : %d\n", import_settings.min_chain_length);
|
||||
fprintf(stderr, "| fix orientation : %s\n", (import_settings.fix_orientation) ? "yes" : "no");
|
||||
fprintf(stderr, "| keep bind info : %s\n", (import_settings.keep_bind_info) ? "yes" : "no");
|
||||
}
|
||||
|
||||
static void print_import_footer(int status)
|
||||
{
|
||||
fprintf(stderr, "+----------------------------------\n");
|
||||
fprintf(stderr, "| Collada Import : %s\n", (status) ? "OK" : "FAIL");
|
||||
fprintf(stderr, "+----------------------------------\n");
|
||||
}
|
||||
|
||||
int collada_import(bContext *C, ImportSettings *import_settings)
|
||||
{
|
||||
print_import_header(*import_settings);
|
||||
DocumentImporter imp(C, import_settings);
|
||||
int status = imp.import() ? 1 : 0;
|
||||
print_import_footer(status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int collada_export(bContext *C, ExportSettings *export_settings)
|
||||
{
|
||||
BlenderContext blender_context(C);
|
||||
const Scene *scene = blender_context.get_scene();
|
||||
ViewLayer *view_layer = blender_context.get_view_layer();
|
||||
|
||||
int includeFilter = OB_REL_NONE;
|
||||
if (export_settings->include_armatures) {
|
||||
includeFilter |= OB_REL_MOD_ARMATURE;
|
||||
}
|
||||
if (export_settings->include_children) {
|
||||
includeFilter |= OB_REL_CHILDREN_RECURSIVE;
|
||||
}
|
||||
|
||||
/* Fetch the complete set of exported objects
|
||||
* ATTENTION: Invisible objects will not be exported
|
||||
*/
|
||||
eObjectSet objectSet = (export_settings->selected) ? OB_SET_SELECTED : OB_SET_ALL;
|
||||
export_settings->export_set = BKE_object_relational_superset(
|
||||
scene, view_layer, objectSet, (eObRelationTypes)includeFilter);
|
||||
|
||||
int export_count = BLI_linklist_count(export_settings->export_set);
|
||||
|
||||
if (export_count == 0) {
|
||||
if (export_settings->selected) {
|
||||
fprintf(stderr,
|
||||
"Collada: Found no objects to export.\nPlease ensure that all objects which shall "
|
||||
"be exported are also visible in the 3D Viewport.\n");
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "Collada: Your scene seems to be empty. No Objects will be exported.\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (export_settings->sort_by_name) {
|
||||
bc_bubble_sort_by_Object_name(export_settings->export_set);
|
||||
}
|
||||
}
|
||||
|
||||
DocumentExporter exporter(blender_context, export_settings);
|
||||
int status = exporter.exportCurrentScene();
|
||||
|
||||
BLI_linklist_free(export_settings->export_set, nullptr);
|
||||
|
||||
return (status) ? -1 : export_count;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "ExportSettings.h"
|
||||
#include "ImportSettings.h"
|
||||
|
||||
#include "RNA_types.hh"
|
||||
|
||||
struct bContext;
|
||||
|
||||
/*
|
||||
* both return 1 on success, 0 on error
|
||||
*/
|
||||
int collada_import(struct bContext *C, ImportSettings *import_settings);
|
||||
|
||||
int collada_export(struct bContext *C, ExportSettings *export_settings);
|
@ -1,330 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2010-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#include "collada_internal.h"
|
||||
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_math_rotation.h"
|
||||
|
||||
#include "BKE_armature.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
|
||||
#include <map>
|
||||
|
||||
UnitConverter::UnitConverter() : up_axis(COLLADAFW::FileInfo::Z_UP)
|
||||
{
|
||||
axis_angle_to_mat4_single(x_up_mat4, 'Y', -M_PI_2);
|
||||
axis_angle_to_mat4_single(y_up_mat4, 'X', M_PI_2);
|
||||
|
||||
unit_m4(z_up_mat4);
|
||||
unit_m4(scale_mat4);
|
||||
}
|
||||
|
||||
void UnitConverter::read_asset(const COLLADAFW::FileInfo *asset)
|
||||
{
|
||||
unit = asset->getUnit();
|
||||
up_axis = asset->getUpAxisType();
|
||||
}
|
||||
|
||||
UnitConverter::UnitSystem UnitConverter::isMetricSystem()
|
||||
{
|
||||
switch (unit.getLinearUnitUnit()) {
|
||||
case COLLADAFW::FileInfo::Unit::MILLIMETER:
|
||||
case COLLADAFW::FileInfo::Unit::CENTIMETER:
|
||||
case COLLADAFW::FileInfo::Unit::DECIMETER:
|
||||
case COLLADAFW::FileInfo::Unit::METER:
|
||||
case COLLADAFW::FileInfo::Unit::KILOMETER:
|
||||
return UnitConverter::Metric;
|
||||
case COLLADAFW::FileInfo::Unit::INCH:
|
||||
case COLLADAFW::FileInfo::Unit::FOOT:
|
||||
case COLLADAFW::FileInfo::Unit::YARD:
|
||||
return UnitConverter::Imperial;
|
||||
default:
|
||||
return UnitConverter::None;
|
||||
}
|
||||
}
|
||||
|
||||
float UnitConverter::getLinearMeter()
|
||||
{
|
||||
return float(unit.getLinearUnitMeter());
|
||||
}
|
||||
|
||||
void UnitConverter::convertVector3(COLLADABU::Math::Vector3 &vec, float *v)
|
||||
{
|
||||
v[0] = vec.x;
|
||||
v[1] = vec.y;
|
||||
v[2] = vec.z;
|
||||
}
|
||||
|
||||
/* TODO: need also for angle conversion, time conversion... */
|
||||
|
||||
void UnitConverter::dae_matrix_to_mat4_(float out[4][4], const COLLADABU::Math::Matrix4 &in)
|
||||
{
|
||||
/* in DAE, matrices use columns vectors, (see comments in COLLADABUMathMatrix4.h)
|
||||
* so here, to make a blender matrix, we swap columns and rows. */
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
out[i][j] = in[j][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UnitConverter::mat4_to_dae(float out[4][4], float in[4][4])
|
||||
{
|
||||
transpose_m4_m4(out, in);
|
||||
}
|
||||
|
||||
void UnitConverter::mat4_to_dae_double(double out[4][4], float in[4][4])
|
||||
{
|
||||
float mat[4][4];
|
||||
|
||||
mat4_to_dae(mat, in);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
out[i][j] = mat[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float (&UnitConverter::get_rotation())[4][4]
|
||||
{
|
||||
switch (up_axis) {
|
||||
case COLLADAFW::FileInfo::X_UP:
|
||||
return x_up_mat4;
|
||||
break;
|
||||
case COLLADAFW::FileInfo::Y_UP:
|
||||
return y_up_mat4;
|
||||
break;
|
||||
default:
|
||||
return z_up_mat4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
float (&UnitConverter::get_scale())[4][4]
|
||||
{
|
||||
return scale_mat4;
|
||||
}
|
||||
|
||||
void UnitConverter::calculate_scale(Scene &sce)
|
||||
{
|
||||
PointerRNA unit_settings;
|
||||
PropertyRNA *system_ptr, *scale_ptr;
|
||||
PointerRNA scene_ptr = RNA_id_pointer_create(&sce.id);
|
||||
|
||||
unit_settings = RNA_pointer_get(&scene_ptr, "unit_settings");
|
||||
system_ptr = RNA_struct_find_property(&unit_settings, "system");
|
||||
scale_ptr = RNA_struct_find_property(&unit_settings, "scale_length");
|
||||
|
||||
int type = RNA_property_enum_get(&unit_settings, system_ptr);
|
||||
|
||||
float bl_scale;
|
||||
|
||||
switch (type) {
|
||||
case USER_UNIT_NONE:
|
||||
bl_scale = 1.0; /* map 1 Blender unit to 1 Meter. */
|
||||
break;
|
||||
|
||||
case USER_UNIT_METRIC:
|
||||
bl_scale = RNA_property_float_get(&unit_settings, scale_ptr);
|
||||
break;
|
||||
|
||||
default:
|
||||
bl_scale = RNA_property_float_get(&unit_settings, scale_ptr);
|
||||
/* It looks like the conversion to Imperial is done implicitly.
|
||||
* So nothing to do here. */
|
||||
break;
|
||||
}
|
||||
|
||||
float rescale[3];
|
||||
rescale[0] = rescale[1] = rescale[2] = getLinearMeter() / bl_scale;
|
||||
|
||||
size_to_mat4(scale_mat4, rescale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translation map.
|
||||
* Used to translate every COLLADA id to a valid id, no matter what "wrong" letters may be
|
||||
* included. Look at the IDREF XSD declaration for more.
|
||||
* Follows strictly the COLLADA XSD declaration which explicitly allows non-English chars,
|
||||
* like special chars (e.g. micro sign), umlauts and so on.
|
||||
* The COLLADA spec also allows additional chars for member access ('.'), these
|
||||
* must obviously be removed too, otherwise they would be heavily misinterpreted.
|
||||
*/
|
||||
const uchar translate_start_name_map[256] = {
|
||||
|
||||
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
|
||||
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
|
||||
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
|
||||
95, 95, 95, 95, 95, 95, 95, 95, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
|
||||
76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 95, 95, 95, 95,
|
||||
95, 95, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
|
||||
114, 115, 116, 117, 118, 119, 120, 121, 122, 95, 95, 95, 95, 95,
|
||||
|
||||
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146,
|
||||
147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165,
|
||||
166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184,
|
||||
185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203,
|
||||
204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222,
|
||||
223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
|
||||
242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
|
||||
};
|
||||
|
||||
const uchar translate_name_map[256] = {
|
||||
|
||||
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
|
||||
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
|
||||
95, 95, 95, 95, 95, 95, 95, 45, 95, 95, 48, 49, 50, 51, 52, 53, 54, 55, 56,
|
||||
57, 95, 95, 95, 95, 95, 95, 95, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
|
||||
76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 95, 95, 95, 95,
|
||||
95, 95, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
|
||||
114, 115, 116, 117, 118, 119, 120, 121, 122, 95, 95, 95, 95, 95,
|
||||
|
||||
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146,
|
||||
147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165,
|
||||
166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184,
|
||||
185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203,
|
||||
204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222,
|
||||
223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
|
||||
242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
|
||||
};
|
||||
|
||||
using map_string_list = std::map<std::string, std::vector<std::string>>;
|
||||
map_string_list global_id_map;
|
||||
|
||||
void clear_global_id_map()
|
||||
{
|
||||
global_id_map.clear();
|
||||
}
|
||||
|
||||
std::string translate_id(const char *idString)
|
||||
{
|
||||
std::string id = std::string(idString);
|
||||
return translate_id(id);
|
||||
}
|
||||
|
||||
std::string translate_id(const std::string &id)
|
||||
{
|
||||
if (id.empty()) {
|
||||
return id;
|
||||
}
|
||||
|
||||
std::string id_translated = id;
|
||||
id_translated[0] = translate_start_name_map[uint(id_translated[0])];
|
||||
for (uint i = 1; i < id_translated.size(); i++) {
|
||||
id_translated[i] = translate_name_map[uint(id_translated[i])];
|
||||
}
|
||||
/* It's so much workload now, the if () should speed up things. */
|
||||
if (id_translated != id) {
|
||||
/* Search duplicates. */
|
||||
map_string_list::iterator iter = global_id_map.find(id_translated);
|
||||
if (iter != global_id_map.end()) {
|
||||
uint i = 0;
|
||||
bool found = false;
|
||||
for (i = 0; i < iter->second.size(); i++) {
|
||||
if (id == iter->second[i]) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bool convert = false;
|
||||
if (found) {
|
||||
if (i > 0) {
|
||||
convert = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
convert = true;
|
||||
global_id_map[id_translated].push_back(id);
|
||||
}
|
||||
if (convert) {
|
||||
std::stringstream out;
|
||||
out << ++i;
|
||||
id_translated += out.str();
|
||||
}
|
||||
}
|
||||
else {
|
||||
global_id_map[id_translated].push_back(id);
|
||||
}
|
||||
}
|
||||
return id_translated;
|
||||
}
|
||||
|
||||
std::string id_name(void *id)
|
||||
{
|
||||
return ((ID *)id)->name + 2;
|
||||
}
|
||||
|
||||
std::string encode_xml(const std::string &xml)
|
||||
{
|
||||
const std::map<char, std::string> escape{
|
||||
{'<', "<"}, {'>', ">"}, {'"', """}, {'\'', "'"}, {'&', "&"}};
|
||||
|
||||
std::map<char, std::string>::const_iterator it;
|
||||
std::string encoded_xml;
|
||||
|
||||
for (char c : xml) {
|
||||
it = escape.find(c);
|
||||
|
||||
if (it == escape.end()) {
|
||||
encoded_xml += c;
|
||||
}
|
||||
else {
|
||||
encoded_xml += it->second;
|
||||
}
|
||||
}
|
||||
return encoded_xml;
|
||||
}
|
||||
|
||||
std::string get_geometry_id(Object *ob)
|
||||
{
|
||||
return translate_id(id_name(ob->data)) + "-mesh";
|
||||
}
|
||||
|
||||
std::string get_geometry_id(Object *ob, bool use_instantiation)
|
||||
{
|
||||
std::string geom_name = (use_instantiation) ? id_name(ob->data) : id_name(ob);
|
||||
|
||||
return translate_id(geom_name) + "-mesh";
|
||||
}
|
||||
|
||||
std::string get_light_id(Object *ob)
|
||||
{
|
||||
return translate_id(id_name(ob)) + "-light";
|
||||
}
|
||||
|
||||
std::string get_joint_sid(Bone *bone)
|
||||
{
|
||||
return translate_id(bone->name);
|
||||
}
|
||||
static std::string get_joint_sid(EditBone *bone)
|
||||
{
|
||||
return translate_id(bone->name);
|
||||
}
|
||||
|
||||
std::string get_camera_id(Object *ob)
|
||||
{
|
||||
return translate_id(id_name(ob)) + "-camera";
|
||||
}
|
||||
|
||||
std::string get_effect_id(Material *mat)
|
||||
{
|
||||
return translate_id(id_name(mat)) + "-effect";
|
||||
}
|
||||
|
||||
std::string get_material_id(Material *mat)
|
||||
{
|
||||
return translate_id(id_name(mat)) + "-material";
|
||||
}
|
||||
|
||||
std::string get_morph_id(Object *ob)
|
||||
{
|
||||
return translate_id(id_name(ob)) + "-morph";
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup collada
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "COLLADAFWFileInfo.h"
|
||||
#include "Math/COLLADABUMathMatrix4.h"
|
||||
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
class UnitConverter {
|
||||
private:
|
||||
COLLADAFW::FileInfo::Unit unit;
|
||||
COLLADAFW::FileInfo::UpAxisType up_axis;
|
||||
|
||||
float x_up_mat4[4][4];
|
||||
float y_up_mat4[4][4];
|
||||
float z_up_mat4[4][4];
|
||||
float scale_mat4[4][4];
|
||||
|
||||
public:
|
||||
enum UnitSystem {
|
||||
None,
|
||||
Metric,
|
||||
Imperial,
|
||||
};
|
||||
|
||||
/* Initialize with Z_UP, since Blender uses right-handed, z-up */
|
||||
UnitConverter();
|
||||
|
||||
void read_asset(const COLLADAFW::FileInfo *asset);
|
||||
|
||||
void convertVector3(COLLADABU::Math::Vector3 &vec, float *v);
|
||||
|
||||
UnitConverter::UnitSystem isMetricSystem();
|
||||
|
||||
float getLinearMeter();
|
||||
|
||||
/* TODO: need also for angle conversion, time conversion... */
|
||||
|
||||
static void dae_matrix_to_mat4_(float out[4][4], const COLLADABU::Math::Matrix4 &in);
|
||||
static void mat4_to_dae(float out[4][4], float in[4][4]);
|
||||
static void mat4_to_dae_double(double out[4][4], float in[4][4]);
|
||||
|
||||
float (&get_rotation())[4][4];
|
||||
float (&get_scale())[4][4];
|
||||
void calculate_scale(Scene &sce);
|
||||
};
|
||||
|
||||
extern void clear_global_id_map();
|
||||
/** Look at documentation of translate_map */
|
||||
extern std::string translate_id(const std::string &id);
|
||||
/** Look at documentation of translate_map */
|
||||
extern std::string translate_id(const char *idString);
|
||||
|
||||
extern std::string id_name(void *id);
|
||||
extern std::string encode_xml(const std::string &xml);
|
||||
|
||||
extern std::string get_geometry_id(Object *ob);
|
||||
extern std::string get_geometry_id(Object *ob, bool use_instantiation);
|
||||
|
||||
extern std::string get_light_id(Object *ob);
|
||||
|
||||
extern std::string get_joint_sid(Bone *bone);
|
||||
|
||||
extern std::string get_camera_id(Object *ob);
|
||||
extern std::string get_morph_id(Object *ob);
|
||||
|
||||
extern std::string get_effect_id(Material *mat);
|
||||
extern std::string get_material_id(Material *mat);
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user