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:
Aras Pranckevicius 2025-06-06 08:38:57 +02:00 committed by Aras Pranckevicius
parent 65fe5f4b0f
commit 5ad6d42c83
123 changed files with 6 additions and 21581 deletions

View File

@ -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)

View File

@ -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()

View File

@ -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)

View File

@ -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()

View File

@ -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)

View File

@ -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")

View File

@ -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;

View File

@ -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=(),

View File

@ -1,2 +0,0 @@
# Files contains mixed line endings, patch needs to preserve them to apply.
opencollada.diff binary

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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})

View File

@ -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()

View File

@ -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

View File

@ -288,10 +288,6 @@
/** \defgroup externformats External Formats
* \ingroup blender */
/** \defgroup collada COLLADA
* \ingroup externformats
*/
/** \defgroup avi AVI
* \ingroup externformats
*/

View File

@ -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` |

View File

@ -511,7 +511,6 @@ class SpellChecker:
"clearcoat",
"codec", "codecs",
"codepoint",
"collada",
"colorspace",
"compositing",
"crossfade",

View File

@ -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

View File

@ -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

View File

@ -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",

View File

@ -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):

View File

@ -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. . */

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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();
}

View 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;

View File

@ -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;
}

View File

@ -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()

View File

@ -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();
}

View File

@ -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);
};

View File

@ -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 &param,
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 &param = 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 &param = 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 &param = 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 &param = 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 &param = 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

View File

@ -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 &param,
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

View File

@ -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);
};

View File

@ -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;
}

View File

@ -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

View File

@ -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);
};

View File

@ -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];
}
}

View File

@ -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 *>;

View File

@ -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();
}

View File

@ -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);
};

View File

@ -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;
}

View File

@ -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);
};

View File

@ -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;
}

View File

@ -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 *>;

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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
};

View File

@ -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}")

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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 &param = 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 &param = 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 &param = 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 &param = 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 &param = 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();
}

View File

@ -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);
};

View File

@ -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
*/

View File

@ -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

View File

@ -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);
};

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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;
};

View File

@ -1,9 +0,0 @@
/* SPDX-FileCopyrightText: 2002-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup collada
*/
#include "ExportSettings.h"

View File

@ -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

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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);
};

View File

@ -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 &param = 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 &param = 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 &param = 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 &param = 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);
}

View File

@ -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);
}
}
}
};

View File

@ -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();
}

View File

@ -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);
};

View File

@ -1,9 +0,0 @@
/* SPDX-FileCopyrightText: 2002-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup collada
*/
#include "ImportSettings.h"

View File

@ -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;
};

View File

@ -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);
}
}
}

View File

@ -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);
};

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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();
}

View File

@ -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);
}
};

View File

@ -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;
}

View File

@ -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

View File

@ -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;
};

View File

@ -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);
}
}

View File

@ -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);
};

View File

@ -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;
}

View File

@ -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);
};

View File

@ -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;
}

View File

@ -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]);
};

View File

@ -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]);
}

View File

@ -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]);
};

View File

@ -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;
}

View File

@ -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);

View File

@ -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{
{'<', "&lt;"}, {'>', "&gt;"}, {'"', "&quot;"}, {'\'', "&apos;"}, {'&', "&amp;"}};
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";
}

View File

@ -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