diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index ce6a5713..00000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,12 +0,0 @@ -# These are supported funding model platforms - -github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] -patreon: # pragma37 -open_collective: # Replace with a single Open Collective username -ko_fi: # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -otechie: # Replace with a single Otechie username -custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/workflows/BlenderMalt.yml b/.github/workflows/BlenderMalt.yml index 0042463f..248576fc 100644 --- a/.github/workflows/BlenderMalt.yml +++ b/.github/workflows/BlenderMalt.yml @@ -32,8 +32,7 @@ jobs: body: | [**BlenderMalt-Windows.zip**](https://github.com/${{github.repository}}/releases/download/${{env.BRANCH_NAME}}-latest/BlenderMalt-Windows.zip) [**BlenderMalt-Linux.zip**](https://github.com/${{github.repository}}/releases/download/${{env.BRANCH_NAME}}-latest/BlenderMalt-Linux.zip) - - *(Requires Blender 4.1)* + - name: Rollback Tagged Release uses: author/action-rollback@stable @@ -56,7 +55,6 @@ jobs: [**BlenderMalt-Windows.zip**](https://github.com/${{github.repository}}/releases/download/${{github.ref_name}}/BlenderMalt-Windows.zip) [**BlenderMalt-Linux.zip**](https://github.com/${{github.repository}}/releases/download/${{github.ref_name}}/BlenderMalt-Linux.zip) - *(Requires Blender 4.1)* outputs: upload_url: ${{ steps.create_release.outputs.upload_url }} diff --git a/BlenderMalt/CBlenderMalt/CBlenderMalt.cpp b/BlenderMalt/CBlenderMalt/CBlenderMalt.cpp index b2cf924e..3669a692 100644 --- a/BlenderMalt/CBlenderMalt/CBlenderMalt.cpp +++ b/BlenderMalt/CBlenderMalt/CBlenderMalt.cpp @@ -1,5 +1,5 @@ #include "stdio.h" -#include "string.h" +#include "mikktspace.h" #ifdef _WIN32 #define EXPORT extern "C" __declspec( dllexport ) @@ -7,86 +7,6 @@ #define EXPORT extern "C" __attribute__ ((visibility ("default"))) #endif -#include "blender_dna/DNA_mesh_types.h" -#include "blender_dna/DNA_meshdata_types.h" - -//blenkernel/intern/customdata.cc - -int CustomData_get_active_layer_index(const CustomData *data, int type) -{ - const int layer_index = data->typemap[type]; - //BLI_assert(customdata_typemap_is_valid(data)); - return (layer_index != -1) ? layer_index + data->layers[layer_index].active : -1; -} - -void *CustomData_get_layer(const CustomData *data, int type) -{ - /* get the layer index of the active layer of type */ - int layer_index = CustomData_get_active_layer_index(data, type); - if (layer_index == -1) { - return nullptr; - } - - return data->layers[layer_index].data; -} - -int CustomData_get_layer_index(const CustomData *data, int type) -{ - //BLI_assert(customdata_typemap_is_valid(data)); - return data->typemap[type]; -} - -int CustomData_get_layer_index_n(const struct CustomData *data, int type, int n) -{ - //BLI_assert(n >= 0); - int i = CustomData_get_layer_index(data, type); - - if (i != -1) { - //BLI_assert(i + n < data->totlayer); - i = (data->layers[i + n].type == type) ? (i + n) : (-1); - } - - return i; -} - -#define STREQ(a, b) (strcmp(a, b) == 0) - -int CustomData_get_named_layer_index(const CustomData *data, const int type, const char *name) -{ - for (int i = 0; i < data->totlayer; i++) { - if (data->layers[i].type == type) { - if (STREQ(data->layers[i].name, name)) { - return i; - } - } - } - - return -1; -} - -void *CustomData_get_layer_named(const CustomData *data, const int type, const char *name) -{ - int layer_index = CustomData_get_named_layer_index(data, type, name); - if (layer_index == -1) { - return nullptr; - } - - return data->layers[layer_index].data; -} - -void *CustomData_get_layer_n(const CustomData *data, int type, int n) -{ - /* get the layer index of the active layer of type */ - int layer_index = CustomData_get_layer_index_n(data, type, n); - if (layer_index == -1) { - return nullptr; - } - - return data->layers[layer_index].data; -} - -// CBlenderMalt API - EXPORT void retrieve_mesh_data( float* in_positions, int* in_loop_verts, int loop_count, @@ -113,10 +33,74 @@ EXPORT void retrieve_mesh_data( } } -EXPORT float* mesh_tangents_ptr(void* in_mesh) +EXPORT bool mesh_tangents( + int* in_indices, int index_len, + float* in_positions, float* in_normals, float* in_uvs, + float* out_tangents) { - Mesh* mesh = (Mesh*)in_mesh; - float* ptr = (float*)CustomData_get_layer(&mesh->corner_data, CD_MLOOPTANGENT); - - return ptr; + struct MData + { + int* indices; + int index_len; + float* positions; + float* normals; + float* uvs; + float* tangents; + }; + + MData data = { + in_indices, + index_len, + in_positions, + in_normals, + in_uvs, + out_tangents, + }; + + SMikkTSpaceInterface mti = {0}; + mti.m_getNumFaces = [](const SMikkTSpaceContext * pContext){ + return ((MData*)pContext->m_pUserData)->index_len / 3; + }; + + mti.m_getNumVerticesOfFace = [](const SMikkTSpaceContext * pContext, const int iFace){ + return 3; + }; + + mti.m_getPosition = [](const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert){ + MData* m = (MData*)pContext->m_pUserData; + int i = iFace * 3 + iVert; + fvPosOut[0] = m->positions[m->indices[i] * 3 + 0]; + fvPosOut[1] = m->positions[m->indices[i] * 3 + 1]; + fvPosOut[2] = m->positions[m->indices[i] * 3 + 2]; + }; + + mti.m_getNormal = [](const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert){ + MData* m = (MData*)pContext->m_pUserData; + int i = iFace * 3 + iVert; + fvNormOut[0] = m->normals[m->indices[i] * 3 + 0]; + fvNormOut[1] = m->normals[m->indices[i] * 3 + 1]; + fvNormOut[2] = m->normals[m->indices[i] * 3 + 2]; + }; + + mti.m_getTexCoord = [](const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert){ + MData* m = (MData*)pContext->m_pUserData; + int i = iFace * 3 + iVert; + fvTexcOut[0] = m->uvs[m->indices[i] * 2 + 0]; + fvTexcOut[1] = m->uvs[m->indices[i] * 2 + 1]; + }; + + mti.m_setTSpaceBasic = [](const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert){ + MData* m = (MData*)pContext->m_pUserData; + int i = iFace * 3 + iVert; + m->tangents[m->indices[i] * 4 + 0] = fvTangent[0]; + m->tangents[m->indices[i] * 4 + 1] = fvTangent[1]; + m->tangents[m->indices[i] * 4 + 2] = fvTangent[2]; + m->tangents[m->indices[i] * 4 + 3] = fSign; + }; + + SMikkTSpaceContext mtc; + mtc.m_pInterface = &mti; + mtc.m_pUserData = &data; + + return genTangSpaceDefault(&mtc); } diff --git a/BlenderMalt/CBlenderMalt/CMakeLists.txt b/BlenderMalt/CBlenderMalt/CMakeLists.txt index d27a1544..b4573824 100644 --- a/BlenderMalt/CBlenderMalt/CMakeLists.txt +++ b/BlenderMalt/CBlenderMalt/CMakeLists.txt @@ -8,8 +8,7 @@ project(CBlenderMalt) SET(CMAKE_BUILD_TYPE Release) SET(BUILD_SHARED_LIBS ON) -add_library(CBlenderMalt CBlenderMalt.cpp) +add_library(CBlenderMalt CBlenderMalt.cpp mikktspace.c) target_include_directories(CBlenderMalt PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/blender_dna) install(TARGETS CBlenderMalt CONFIGURATIONS Release DESTINATION ${PROJECT_SOURCE_DIR}) - diff --git a/BlenderMalt/CBlenderMalt/__init__.py b/BlenderMalt/CBlenderMalt/__init__.py index 46422111..7256f7ee 100644 --- a/BlenderMalt/CBlenderMalt/__init__.py +++ b/BlenderMalt/CBlenderMalt/__init__.py @@ -23,6 +23,10 @@ ] retrieve_mesh_data.restype = None -mesh_tangents_ptr = CBlenderMalt['mesh_tangents_ptr'] -mesh_tangents_ptr.argtypes = [ctypes.c_void_p] -mesh_tangents_ptr.restype = ctypes.POINTER(ctypes.c_float) +mesh_tangents = CBlenderMalt['mesh_tangents'] +mesh_tangents.argtypes = [ + ctypes.POINTER(ctypes.c_int), ctypes.c_int, + ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float), + ctypes.POINTER(ctypes.c_float) +] +mesh_tangents.restype = ctypes.c_bool diff --git a/BlenderMalt/CBlenderMalt/blender_dna/BLI_sys_types.h b/BlenderMalt/CBlenderMalt/blender_dna/BLI_sys_types.h deleted file mode 100644 index e7e429fd..00000000 --- a/BlenderMalt/CBlenderMalt/blender_dna/BLI_sys_types.h +++ /dev/null @@ -1,74 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2001-2002 NaN Holding BV. All rights reserved. */ - -/** \file - * \ingroup bli - * - * A platform-independent definition of [u]intXX_t - * Plus the accompanying header include for htonl/ntohl - * - * This file includes to define [u]intXX_t types, where - * XX can be 8, 16, 32 or 64. Unfortunately, not all systems have this - * file. - * - Windows uses __intXX compiler-builtin types. These are signed, - * so we have to flip the signs. - * For these rogue platforms, we make the typedefs ourselves. - */ - -#pragma once - -#ifdef UNDEFINED -extern "C" { -#endif - -#if defined(__linux__) || defined(__GNU__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ - defined(__FreeBSD_kernel__) || defined(__HAIKU__) - -/* Linux-i386, Linux-Alpha, Linux-PPC */ -# include - -/* XXX */ -# ifndef UINT64_MAX -# define UINT64_MAX 18446744073709551615 -typedef uint8_t u_int8_t; -typedef uint16_t u_int16_t; -typedef uint32_t u_int32_t; -typedef uint64_t u_int64_t; -# endif - -#elif defined(__APPLE__) - -# include - -/* MSVC >= 2010 */ -#elif defined(_MSC_VER) -# include - -#else - -/* FreeBSD, Solaris */ -# include -# include - -#endif /* ifdef platform for types */ - -#include -#include /* size_t define */ - -#ifndef UNDEFINED -/* The standard header is missing on some systems. */ -# if defined(__APPLE__) || defined(__NetBSD__) -typedef unsigned int char32_t; -# else -# include -# endif -#endif - -typedef unsigned int uint; -typedef unsigned short ushort; -typedef unsigned long ulong; -typedef unsigned char uchar; - -#ifdef UNDEFINED -} -#endif diff --git a/BlenderMalt/CBlenderMalt/blender_dna/DNA_ID.h b/BlenderMalt/CBlenderMalt/blender_dna/DNA_ID.h deleted file mode 100644 index 01cef171..00000000 --- a/BlenderMalt/CBlenderMalt/blender_dna/DNA_ID.h +++ /dev/null @@ -1,1338 +0,0 @@ -/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved. - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup DNA - * \brief ID and Library types, which are fundamental for sdna. - */ - -#pragma once - -#include "DNA_ID_enums.h" -#include "DNA_defs.h" -#include "DNA_listBase.h" - -#ifdef UNDEFINED -extern "C" { -#endif - -struct FileData; -struct GHash; -struct GPUTexture; -struct ID; -struct Library; -struct PackedFile; -struct UniqueName_Map; - -/* Runtime display data */ -struct DrawData; -typedef void (*DrawDataInitCb)(struct DrawData *engine_data); -typedef void (*DrawDataFreeCb)(struct DrawData *engine_data); - -# -# -typedef struct DrawData { - struct DrawData *next, *prev; - struct DrawEngineType *engine_type; - /* Only nested data, NOT the engine data itself. */ - DrawDataFreeCb free; - /* Accumulated recalc flags, which corresponds to ID->recalc flags. */ - unsigned int recalc; -} DrawData; - -typedef struct DrawDataList { - struct DrawData *first, *last; -} DrawDataList; - -typedef struct IDPropertyUIData { - /** Tool-tip / property description pointer. Owned by the #IDProperty. */ - char *description; - /** RNA `subtype`, used for every type except string properties (#PropertySubType). */ - int rna_subtype; - - char _pad[4]; -} IDPropertyUIData; - -/* DNA version of #EnumPropertyItem. */ -typedef struct IDPropertyUIDataEnumItem { - /* Unique identifier, used for string lookup. */ - char *identifier; - /* UI name of the item. */ - char *name; - /* Optional description. */ - char *description; - /* Unique integer value, should never change. */ - int value; - /* Optional icon. */ - int icon; -} IDPropertyUIDataEnumItem; - -/* IDP_UI_DATA_TYPE_INT */ -typedef struct IDPropertyUIDataInt { - IDPropertyUIData base; - int *default_array; /* Only for array properties. */ - int default_array_len; - - int min; - int max; - int soft_min; - int soft_max; - int step; - int default_value; - - int enum_items_num; - IDPropertyUIDataEnumItem *enum_items; -} IDPropertyUIDataInt; - -/** For #IDP_UI_DATA_TYPE_BOOLEAN Use `int8_t` because DNA does not support `bool`. */ -typedef struct IDPropertyUIDataBool { - IDPropertyUIData base; - int8_t *default_array; /* Only for array properties. */ - int default_array_len; - char _pad[3]; - - int8_t default_value; -} IDPropertyUIDataBool; - -/** For #IDP_UI_DATA_TYPE_FLOAT */ -typedef struct IDPropertyUIDataFloat { - IDPropertyUIData base; - double *default_array; /* Only for array properties. */ - int default_array_len; - char _pad[4]; - - float step; - int precision; - - double min; - double max; - double soft_min; - double soft_max; - double default_value; -} IDPropertyUIDataFloat; - -/** For #IDP_UI_DATA_TYPE_STRING */ -typedef struct IDPropertyUIDataString { - IDPropertyUIData base; - char *default_value; -} IDPropertyUIDataString; - -/** For #IDP_UI_DATA_TYPE_ID. */ -typedef struct IDPropertyUIDataID { - IDPropertyUIData base; - /** - * #ID_Type. With python-defined properties, this type is not enforced. A value of `0` means any - * ID type. - * - * However, when defined/edited from the UI (Custom Properties panel), it must/will be defined, - * as generic 'Any ID type' selection is a TODO UI-wise. - */ - short id_type; - char _pad[6]; -} IDPropertyUIDataID; - -typedef struct IDPropertyData { - void *pointer; - ListBase group; - /** NOTE: a `double` is written into two 32bit integers. */ - int val, val2; -} IDPropertyData; - -typedef struct IDProperty { - struct IDProperty *next, *prev; - /** #eIDPropertyType */ - char type; - /** - * #eIDPropertySubType when `type` is #IDP_STRING. - * #eIDPropertyType for all other types. - */ - char subtype; - /** #IDP_FLAG_GHOST and others. */ - short flag; - /** Size matches #MAX_IDPROP_NAME. */ - char name[64]; - - char _pad0[4]; - - /** NOTE: alignment for 64 bits. */ - IDPropertyData data; - - /** - * Array length, and importantly string length + 1. - * the idea is to be able to reuse array reallocation functions on strings. - */ - int len; - /** - * Strings and arrays are both buffered, though the buffer isn't saved. - * `totallen` is total length of allocated array/string, including a buffer. - * \note the buffering is mild; see #IDP_ResizeIDPArray for details. - */ - int totallen; - - IDPropertyUIData *ui_data; -} IDProperty; - -#define MAX_IDPROP_NAME 64 -#define DEFAULT_ALLOC_FOR_NULL_STRINGS 64 - -/** #IDProperty.type */ -typedef enum eIDPropertyType { - IDP_STRING = 0, - IDP_INT = 1, - IDP_FLOAT = 2, - /** Array containing int, floats, doubles or groups. */ - IDP_ARRAY = 5, - IDP_GROUP = 6, - IDP_ID = 7, - IDP_DOUBLE = 8, - IDP_IDPARRAY = 9, - /** - * True or false value, backed by an `int8_t` underlying type for arrays. Values are expected to - * be 0 or 1. - */ - IDP_BOOLEAN = 10, -} eIDPropertyType; -#define IDP_NUMTYPES 11 - -/** Used by some IDP utils, keep values in sync with type enum above. */ -enum { - IDP_TYPE_FILTER_STRING = 1 << 0, - IDP_TYPE_FILTER_INT = 1 << 1, - IDP_TYPE_FILTER_FLOAT = 1 << 2, - IDP_TYPE_FILTER_ARRAY = 1 << 5, - IDP_TYPE_FILTER_GROUP = 1 << 6, - IDP_TYPE_FILTER_ID = 1 << 7, - IDP_TYPE_FILTER_DOUBLE = 1 << 8, - IDP_TYPE_FILTER_IDPARRAY = 1 << 9, - IDP_TYPE_FILTER_BOOLEAN = 1 << 10, -}; - -/** #IDProperty.subtype for #IDP_STRING properties. */ -typedef enum eIDPropertySubType { - IDP_STRING_SUB_UTF8 = 0, /* default */ - IDP_STRING_SUB_BYTE = 1, /* arbitrary byte array, _not_ null terminated */ -} eIDPropertySubType; - -/** #IDProperty.flag. */ -enum { - /** - * This #IDProperty may be statically overridden. - * Should only be used/be relevant for custom properties. - */ - IDP_FLAG_OVERRIDABLE_LIBRARY = 1 << 0, - /** - * This collection item #IDProperty has been inserted in a local override. - * This is used by internal code to distinguish between library-originated items and - * local-inserted ones, as many operations are not allowed on the former. - */ - IDP_FLAG_OVERRIDELIBRARY_LOCAL = 1 << 1, - /** - * This means the property is set but RNA will return false when checking - * #RNA_property_is_set, currently this is a runtime flag. - */ - IDP_FLAG_GHOST = 1 << 7, -}; - -/* add any future new id property types here. */ - -/* Static ID override structs. */ - -typedef struct IDOverrideLibraryPropertyOperation { - struct IDOverrideLibraryPropertyOperation *next, *prev; - - /* Type of override. */ - short operation; - short flag; - - /** Runtime, tags are common to both #IDOverrideProperty and #IDOverridePropertyOperation. */ - short tag; - char _pad0[2]; - - /* Sub-item references, if needed (for arrays or collections only). - * We need both reference and local values to allow e.g. insertion into RNA collections - * (constraints, modifiers...). - * In RNA collection case, if names are defined, they are used in priority. - * Names are pointers (instead of char[64]) to save some space, NULL or empty string when unset. - * Indices are -1 when unset. - * - * NOTE: For insertion operations in RNA collections, reference may not actually exist in the - * linked reference data. It is used to identify the anchor of the insertion operation (i.e. the - * item after or before which the new local item should be inserted), in the local override. */ - char *subitem_reference_name; - char *subitem_local_name; - int subitem_reference_index; - int subitem_local_index; - /** Additional pointer to an ID. Only used and relevant when the related RNA collection stores ID - * pointers, to help disambiguate cases where several IDs from different libraries have the exact - * same name. */ - struct ID *subitem_reference_id; - struct ID *subitem_local_id; -} IDOverrideLibraryPropertyOperation; - -/* IDOverrideLibraryPropertyOperation->operation. */ -enum { - /* Basic operations. */ - LIBOVERRIDE_OP_NOOP = 0, /* Special value, forbids any overriding. */ - - LIBOVERRIDE_OP_REPLACE = 1, /* Fully replace local value by reference one. */ - - /* Numeric-only operations. */ - LIBOVERRIDE_OP_ADD = 101, /* Add local value to reference one. */ - /* Subtract local value from reference one (needed due to unsigned values etc.). */ - LIBOVERRIDE_OP_SUBTRACT = 102, - /* Multiply reference value by local one (more useful than diff for scales and the like). */ - LIBOVERRIDE_OP_MULTIPLY = 103, - - /* Collection-only operations. */ - LIBOVERRIDE_OP_INSERT_AFTER = 201, /* Insert after given reference's subitem. */ - LIBOVERRIDE_OP_INSERT_BEFORE = 202, /* Insert before given reference's subitem. */ - /* We can add more if needed (move, delete, ...). */ -}; - -/* IDOverrideLibraryPropertyOperation->flag. */ -enum { - /** User cannot remove that override operation. */ - LIBOVERRIDE_OP_FLAG_MANDATORY = 1 << 0, - /** User cannot change that override operation. */ - LIBOVERRIDE_OP_FLAG_LOCKED = 1 << 1, - - /** - * For overrides of ID pointers: this override still matches (follows) the hierarchy of the - * reference linked data. - */ - LIBOVERRIDE_OP_FLAG_IDPOINTER_MATCH_REFERENCE = 1 << 8, - /** - * For overrides of ID pointers within RNA collections: this override is using the ID - * pointer in addition to the item name (to fully disambiguate the reference, since IDs from - * different libraries can have a same name). - */ - LIBOVERRIDE_OP_FLAG_IDPOINTER_ITEM_USE_ID = 1 << 9, -}; - -/** A single overridden property, contain all operations on this one. */ -typedef struct IDOverrideLibraryProperty { - struct IDOverrideLibraryProperty *next, *prev; - - /** - * Path from ID to overridden property. - * *Does not* include indices/names for final arrays/collections items. - */ - char *rna_path; - - /** - * List of overriding operations (IDOverrideLibraryPropertyOperation) applied to this property. - * Recreated as part of the diffing, so do not store any of these elsewhere. - */ - ListBase operations; - - /** - * Runtime, tags are common to both IDOverrideLibraryProperty and - * IDOverrideLibraryPropertyOperation. */ - short tag; - char _pad[2]; - - /** The property type matching the rna_path. */ - unsigned int rna_prop_type; -} IDOverrideLibraryProperty; - -/* IDOverrideLibraryProperty->tag and IDOverrideLibraryPropertyOperation->tag. */ -enum { - /** This override property (operation) is unused and should be removed by cleanup process. */ - LIBOVERRIDE_PROP_OP_TAG_UNUSED = 1 << 0, - - /** This override property is forbidden and should be restored to its linked reference value. */ - LIBOVERRIDE_PROP_TAG_NEEDS_RETORE = 1 << 1, -}; - -# -# -typedef struct IDOverrideLibraryRuntime { - struct GHash *rna_path_to_override_properties; - uint tag; -} IDOverrideLibraryRuntime; - -/* IDOverrideLibraryRuntime->tag. */ -enum { - /** This override needs to be reloaded. */ - LIBOVERRIDE_TAG_NEEDS_RELOAD = 1 << 0, - - /** - * This override contains properties with forbidden changes, which should be restored to their - * linked reference value. - */ - LIBOVERRIDE_TAG_NEEDS_RESTORE = 1 << 1, - - /** - * This override is detected as being cut from its hierarchy root. Temporarily used during - * resync process. - */ - LIBOVERRIDE_TAG_RESYNC_ISOLATED_FROM_ROOT = 1 << 2, - /** - * This override was detected as needing resync outside of the resync process (it is a 'really - * need resync' case, not a 'need resync for hierarchy reasons' one). Temporarily used during - * resync process. - */ - LIBOVERRIDE_TAG_NEED_RESYNC_ORIGINAL = 1 << 3, -}; - -/* Main container for all overriding data info of a data-block. */ -typedef struct IDOverrideLibrary { - /** Reference linked ID which this one overrides. */ - struct ID *reference; - /** List of IDOverrideLibraryProperty structs. */ - ListBase properties; - - /** - * Override hierarchy root ID. Usually the actual root of the hierarchy, but not always - * in degenerated cases. - * - * All liboverrides of a same hierarchy (e.g. a character collection) share the same root. - */ - struct ID *hierarchy_root; - - /* Read/write data. */ - /* Temp ID storing extra override data (used for differential operations only currently). - * Always NULL outside of read/write context. */ - struct ID *storage; - - IDOverrideLibraryRuntime *runtime; - - unsigned int flag; - char _pad_1[4]; -} IDOverrideLibrary; - -/* IDOverrideLibrary->flag */ -enum { - /** - * The override data-block should not be considered as part of an override hierarchy (generally - * because it was created as an single override, outside of any hierarchy consideration). - */ - LIBOVERRIDE_FLAG_NO_HIERARCHY = 1 << 0, - /** - * The override ID is required for the system to work (because of ID dependencies), but is not - * seen as editable by the user. - */ - LIBOVERRIDE_FLAG_SYSTEM_DEFINED = 1 << 1, -}; - -/* watch it: Sequence has identical beginning. */ -/** - * ID is the first thing included in all serializable types. It - * provides a common handle to place all data in double-linked lists. - */ - -/* 2 characters for ID code and 64 for actual name */ -#define MAX_ID_NAME 66 - -/** #ID_Runtime_Remap.status */ -enum { - /** new_id is directly linked in current .blend. */ - ID_REMAP_IS_LINKED_DIRECT = 1 << 0, - /** There was some skipped 'user_one' usages of old_id. */ - ID_REMAP_IS_USER_ONE_SKIPPED = 1 << 1, -}; - -/** Status used and counters created during id-remapping. */ -typedef struct ID_Runtime_Remap { - /** Status during ID remapping. */ - int status; - /** During ID remapping the number of skipped use cases that refcount the data-block. */ - int skipped_refcounted; - /** - * During ID remapping the number of direct use cases that could be remapped - * (e.g. obdata when in edit mode). - */ - int skipped_direct; - /** During ID remapping, the number of indirect use cases that could not be remapped. */ - int skipped_indirect; -} ID_Runtime_Remap; - -typedef struct ID_Runtime { - ID_Runtime_Remap remap; -} ID_Runtime; - -/* There's a nasty circular dependency here.... 'void *' to the rescue! I - * really wonder why this is needed. */ -typedef struct ID { - void *next, *prev; - struct ID *newid; - - struct Library *lib; - - /** If the ID is an asset, this pointer is set. Owning pointer. */ - struct AssetMetaData *asset_data; - - /** MAX_ID_NAME. */ - char name[66]; - /** - * LIB_... flags report on status of the data-block this ID belongs to - * (persistent, saved to and read from .blend). - */ - short flag; - /** - * LIB_TAG_... tags (runtime only, cleared at read time). - */ - int tag; - int us; - int icon_id; - unsigned int recalc; - /** - * Used by undo code. recalc_after_undo_push contains the changes between the - * last undo push and the current state. This is accumulated as IDs are tagged - * for update in the depsgraph, and only cleared on undo push. - * - * recalc_up_to_undo_push is saved to undo memory, and is the value of - * recalc_after_undo_push at the time of the undo push. This means it can be - * used to find the changes between undo states. - */ - unsigned int recalc_up_to_undo_push; - unsigned int recalc_after_undo_push; - - /** - * A session-wide unique identifier for a given ID, that remain the same across potential - * re-allocations (e.g. due to undo/redo steps). - */ - unsigned int session_uid; - - IDProperty *properties; - - /** Reference linked ID which this one overrides. */ - IDOverrideLibrary *override_library; - - /** - * Only set for data-blocks which are coming from copy-on-write, points to - * the original version of it. - * Also used temporarily during memfile undo to keep a reference to old ID when found. - */ - struct ID *orig_id; - - /** - * Holds the #PyObject reference to the ID (initialized on demand). - * - * This isn't essential, it could be removed however it gives some advantages: - * - * - Every time the #ID is accessed a #BPy_StructRNA doesn't have to be created & destroyed - * (consider all the polling and drawing functions that access ID's). - * - * - When this #ID is deleted, the #BPy_StructRNA can be invalidated - * so accessing it from Python raises an exception instead of crashing. - * - * This is of limited benefit though, as it doesn't apply to non #ID data - * that references this ID (the bones of an armature or the modifiers of an object for e.g.). - */ - void *py_instance; - - /** - * Weak reference to an ID in a given library file, used to allow re-using already appended data - * in some cases, instead of appending it again. - * - * May be NULL. - */ - struct LibraryWeakReference *library_weak_reference; - - struct ID_Runtime runtime; -} ID; - -typedef struct Library_Runtime { - /* Used for efficient calculations of unique names. */ - struct UniqueName_Map *name_map; -} Library_Runtime; - -/** - * For each library file used, a Library struct is added to Main - * WARNING: `readfile.cc`, expand_doit() reads this struct without DNA check! - */ -typedef struct Library { - ID id; - struct FileData *filedata; - /** Path name used for reading, can be relative and edited in the outliner. */ - char filepath[1024]; - - /** - * Run-time only, absolute file-path (set on read). - * This is only for convenience, `filepath` is the real path - * used on file read but in some cases its useful to access the absolute one. - * - * Use #BKE_library_filepath_set() rather than setting `filepath` - * directly and it will be kept in sync - campbell - */ - char filepath_abs[1024]; - - /** Set for indirectly linked libraries, used in the outliner and while reading. */ - struct Library *parent; - - struct PackedFile *packedfile; - - ushort tag; - char _pad_0[6]; - - /** Temp data needed by read/write code, and lib-override recursive re-synchronized. */ - int temp_index; - /** See BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION, needed for do_versions. */ - short versionfile, subversionfile; - - struct Library_Runtime runtime; -} Library; - -/** #Library.tag */ -enum eLibrary_Tag { - /* Automatic recursive resync was needed when linking/loading data from that library. */ - LIBRARY_TAG_RESYNC_REQUIRED = 1 << 0, -}; - -/** - * A weak library/ID reference for local data that has been appended, to allow re-using that local - * data instead of creating a new copy of it in future appends. - * - * NOTE: This is by design a week reference, in other words code should be totally fine and perform - * a regular append if it cannot find a valid matching local ID. - * - * NOTE: There should always be only one single ID in current Main matching a given linked - * reference. - */ -typedef struct LibraryWeakReference { - /** Expected to match a `Library.filepath`. */ - char library_filepath[1024]; - - /** MAX_ID_NAME. May be different from the current local ID name. */ - char library_id_name[66]; - - char _pad[2]; -} LibraryWeakReference; - -/* PreviewImage.flag */ -enum ePreviewImage_Flag { - PRV_CHANGED = (1 << 0), - /** If user-edited, do not auto-update this anymore! */ - PRV_USER_EDITED = (1 << 1), - /* Rendering was invoked. Cleared on file read. */ - PRV_RENDERING = (1 << 2), -}; - -/* PreviewImage.tag */ -enum { - /** Actual loading of preview is deferred. */ - PRV_TAG_DEFFERED = (1 << 0), - /** Deferred preview is being loaded. */ - PRV_TAG_DEFFERED_RENDERING = (1 << 1), - /** Deferred preview should be deleted asap. */ - PRV_TAG_DEFFERED_DELETE = (1 << 2), -}; - -/** - * This type allows shallow copies. Use #BKE_previewimg_free() to release contained resources. - * Don't call this for shallow copies (or the original instance will have dangling pointers). - */ -typedef struct PreviewImage { - /* All values of 2 are really NUM_ICON_SIZES */ - unsigned int w[2]; - unsigned int h[2]; - short flag[2]; - short changed_timestamp[2]; - unsigned int *rect[2]; - - /* Runtime-only data. */ - struct GPUTexture *gputexture[2]; - /** Used by previews outside of ID context. */ - int icon_id; - - /** Runtime data. */ - short tag; - char _pad[2]; - -#ifdef UNDEFINED - PreviewImage(); - /* Shallow copy! Contained data is not copied. */ - PreviewImage(const PreviewImage &) = default; - /* Don't free contained data to allow shallow copies. */ - ~PreviewImage() = default; - /* Shallow copy! Contained data is not copied. */ - PreviewImage &operator=(const PreviewImage &) = default; -#endif -} PreviewImage; - -#define ID_FAKE_USERS(id) ((((const ID *)id)->flag & LIB_FAKEUSER) ? 1 : 0) -#define ID_REAL_USERS(id) (((const ID *)id)->us - ID_FAKE_USERS(id)) -#define ID_EXTRA_USERS(id) (((const ID *)id)->tag & LIB_TAG_EXTRAUSER ? 1 : 0) - -#define ID_CHECK_UNDO(id) \ - ((GS((id)->name) != ID_SCR) && (GS((id)->name) != ID_WM) && (GS((id)->name) != ID_WS)) - -#define ID_BLEND_PATH(_bmain, _id) \ - ((_id)->lib ? (_id)->lib->filepath_abs : BKE_main_blendfile_path((_bmain))) -#define ID_BLEND_PATH_FROM_GLOBAL(_id) \ - ((_id)->lib ? (_id)->lib->filepath_abs : BKE_main_blendfile_path_from_global()) - -#define ID_MISSING(_id) ((((const ID *)(_id))->tag & LIB_TAG_MISSING) != 0) - -#define ID_IS_LINKED(_id) (((const ID *)(_id))->lib != NULL) - -/* Note that these are fairly high-level checks, should be used at user interaction level, not in - * BKE_library_override typically (especially due to the check on LIB_TAG_EXTERN). */ -#define ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(_id) \ - (ID_IS_LINKED(_id) && !ID_MISSING(_id) && \ - (BKE_idtype_get_info_from_id((const ID *)(_id))->flags & IDTYPE_FLAGS_NO_LIBLINKING) == 0 && \ - !ELEM(GS(((ID *)(_id))->name), ID_SCE)) -#define ID_IS_OVERRIDABLE_LIBRARY(_id) \ - (ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY((_id)) && (((const ID *)(_id))->tag & LIB_TAG_EXTERN) != 0) - -/* NOTE: The three checks below do not take into account whether given ID is linked or not (when - * chaining overrides over several libraries). User must ensure the ID is not linked itself - * currently. */ -/* TODO: add `_EDITABLE` versions of those macros (that would check if ID is linked or not)? */ -#define ID_IS_OVERRIDE_LIBRARY_REAL(_id) \ - (((const ID *)(_id))->override_library != NULL && \ - ((const ID *)(_id))->override_library->reference != NULL) - -#define ID_IS_OVERRIDE_LIBRARY_VIRTUAL(_id) \ - ((((const ID *)(_id))->flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE) != 0) - -#define ID_IS_OVERRIDE_LIBRARY(_id) \ - (ID_IS_OVERRIDE_LIBRARY_REAL(_id) || ID_IS_OVERRIDE_LIBRARY_VIRTUAL(_id)) - -#define ID_IS_OVERRIDE_LIBRARY_HIERARCHY_ROOT(_id) \ - (!ID_IS_OVERRIDE_LIBRARY_REAL(_id) || \ - ((ID *)(_id))->override_library->hierarchy_root == ((ID *)(_id))) - -#define ID_IS_ASSET(_id) (((const ID *)(_id))->asset_data != NULL) - -/* Check whether datablock type is covered by copy-on-write. */ -#define ID_TYPE_IS_COW(_id_type) \ - (!ELEM(_id_type, ID_LI, ID_IP, ID_SCR, ID_VF, ID_BR, ID_WM, ID_PAL, ID_PC, ID_WS, ID_IM)) - -/* Check whether data-block type requires copy-on-write from #ID_RECALC_PARAMETERS. - * Keep in sync with #BKE_id_eval_properties_copy. */ -#define ID_TYPE_SUPPORTS_PARAMS_WITHOUT_COW(id_type) ELEM(id_type, ID_ME) - -#define ID_TYPE_IS_DEPRECATED(id_type) ELEM(id_type, ID_IP) - -#ifdef GS -# undef GS -#endif -#define GS(a) (CHECK_TYPE_ANY(a, char *, const char *), (ID_Type)(*((const short *)(a)))) - -#define ID_NEW_SET(_id, _idn) \ - (((ID *)(_id))->newid = (ID *)(_idn), \ - ((ID *)(_id))->newid->tag |= LIB_TAG_NEW, \ - (void *)((ID *)(_id))->newid) -#define ID_NEW_REMAP(a) \ - if ((a) && (a)->id.newid) { \ - *(void **)&(a) = (a)->id.newid; \ - } \ - ((void)0) - -/** id->flag (persistent). */ -enum { - /** Don't delete the data-block even if unused. */ - LIB_FAKEUSER = 1 << 9, - /** - * The data-block is a sub-data of another one. - * Direct persistent references are not allowed. - */ - LIB_EMBEDDED_DATA = 1 << 10, - /** - * Data-block is from a library and linked indirectly, with LIB_TAG_INDIRECT - * tag set. But the current .blend file also has a weak pointer to it that - * we want to restore if possible, and silently drop if it's missing. - */ - LIB_INDIRECT_WEAK_LINK = 1 << 11, - /** - * The data-block is a sub-data of another one, which is an override. - * Note that this also applies to shape-keys, even though they are not 100% embedded data. - */ - LIB_EMBEDDED_DATA_LIB_OVERRIDE = 1 << 12, - /** - * The override data-block appears to not be needed anymore after resync with linked data, but it - * was kept around (because e.g. detected as user-edited). - */ - LIB_LIB_OVERRIDE_RESYNC_LEFTOVER = 1 << 13, - /** - * This `id` was explicitly copied as part of a clipboard copy operation. - * When reading the clipboard back, this can be used to check which ID's are - * intended to be part of the clipboard, compared with ID's that were indirectly referenced. - * - * While the flag is typically cleared, a saved file may have this set for some data-blocks, - * so it must be treated as dirty. - */ - LIB_CLIPBOARD_MARK = 1 << 14, -}; - -/** - * id->tag (runtime-only). - * - * Those tags belong to three different categories, which have different expected handling in - * code: - * - * - RESET_BEFORE_USE: piece of code that wants to use such flag has to ensure they are properly - * 'reset' first. - * - RESET_AFTER_USE: piece of code that wants to use such flag has to ensure they are properly - * 'reset' after usage (though 'lifetime' of those flags is a bit fuzzy, e.g. _RECALC ones are - * reset on depsgraph evaluation...). - * - RESET_NEVER: these flags are 'status' ones, and never actually need any reset (except on - * initialization during .blend file reading). - * - * \note: These tags are purely runtime, so changing there value is not an issue. When adding new - * tags, please put them in the relevant category and always keep their values strictly increasing. - */ -enum { - /** - * Long-life tags giving important info about general ID management. - * - * These tags are typically not changed often, if ever, during an ID's life. - */ - - /** - * ID is from current .blend file. - * - * RESET_NEVER - */ - LIB_TAG_LOCAL = 0, - /** - * ID is from a library, but is used (linked) directly by current .blend file. - * - * RESET_NEVER - */ - LIB_TAG_EXTERN = 1 << 0, - /** - * ID is from a library, and is only used (linked) indirectly through other libraries. - * - * RESET_NEVER - */ - LIB_TAG_INDIRECT = 1 << 1, - - /** - * ID is considered as runtime, and should not be saved when writing .blend file, nor influence - * (in)direct status of linked data. - * - * Only meaningful for IDs belonging to regular Main database, all other cases are implicitly - * considered runtime-only. - * - * RESET_NEVER - */ - LIB_TAG_RUNTIME = 1 << 2, - - /** - * ID is a place-holder, an 'empty shell' (because the real one could not be linked from its - * library e.g.). - * - * RESET_NEVER - */ - LIB_TAG_MISSING = 1 << 3, - - /** - * ID has an extra virtual user (aka 'ensured real', as set by e.g. some editors, not to be - * confused with the `LIB_FAKEUSER` flag). - * - * RESET_NEVER - * - * \note This tag does not necessarily mean the actual user count of the ID is increased, this is - * defined by #LIB_TAG_EXTRAUSER_SET. - */ - LIB_TAG_EXTRAUSER = 1 << 4, - /** - * ID actually has increased user-count for the extra virtual user. - * - * RESET_NEVER - */ - LIB_TAG_EXTRAUSER_SET = 1 << 5, - - /** - * ID is up-to-date regarding its reference (only for library overrides). - * - * RESET_NEVER - */ - LIB_TAG_LIBOVERRIDE_REFOK = 1 << 6, - /** - * ID needs an auto-diffing execution, if enabled (only for library overrides). - * - * RESET_NEVER - */ - LIB_TAG_LIBOVERRIDE_AUTOREFRESH = 1 << 7, - /** - * ID is a library override that needs re-sync to its linked reference. - * - * \note Also used by readfile code when creating a missing ID placeholder if it is detected as - * being a linked liboverride ID. - * - * RESET_NEVER - */ - LIB_TAG_LIBOVERRIDE_NEED_RESYNC = 1 << 8, - - /** - * Short-life tags used during specific processes, like blend-file reading. - */ - - /** - * ID is newly duplicated/copied (see #ID_NEW_SET macro above). - * - * RESET_AFTER_USE - * - * \note Also used internally in `readfile.cc` to mark data-blocks needing do_versions. - */ - LIB_TAG_NEW = 1 << 12, - /** - * ID is already existing. Set before linking, to distinguish between existing data-blocks and - * newly linked ones. - * - * RESET_AFTER_USE - */ - LIB_TAG_PRE_EXISTING = 1 << 13, - - /** - * Tag used internally in `readfile.cc`, to mark IDs needing to be expanded (only done once). - * - * RESET_AFTER_USE - */ - LIB_TAG_NEED_EXPAND = 1 << 14, - /** - * Tag used internally in `readfile.cc`, to mark ID placeholders for linked data-blocks needing - * to be read. - * - * RESET_AFTER_USE - */ - LIB_TAG_ID_LINK_PLACEHOLDER = 1 << 15, - /** - * Tag used internally in `readfile.cc`, to mark IDs needing to be 'lib-linked', i.e. to get - * their pointers to other data-blocks updated from the 'UID' values stored in `.blend` files to - * the new, actual pointers. - * - * RESET_AFTER_USE - */ - LIB_TAG_NEED_LINK = 1 << 16, - /** - * ID is being re-used from the old Main (instead of read from memfile), during memfile undo - * processing, because it was detected as unchanged. - * - * \note: Also means that such ID does not need to be lib-linked during undo readfile process. - * - * RESET_AFTER_USE - */ - LIB_TAG_UNDO_OLD_ID_REUSED_UNCHANGED = 1 << 17, - /** - * ID is being re-used from the old Main (instead of read from memfile), during memfile undo - * processing, because it is a 'NO_UNDO' type of ID. - * - * \note: Also means that such ID does not need to be lib-linked during undo readfile process. It - * does need to be relinked in a different way however, doing a `session_uid`-based lookup into - * the newly read main database. - * - * RESET_AFTER_USE - */ - LIB_TAG_UNDO_OLD_ID_REUSED_NOUNDO = 1 << 18, - /** - * ID has be re-read in-place, the ID address is the same as in the old main, but the content is - * different. - * - * RESET_AFTER_USE - */ - LIB_TAG_UNDO_OLD_ID_REREAD_IN_PLACE = 1 << 19, - - /* ------------------------------------------------------------------------------------------- */ - /** - * Tags for special kind of IDs, not living in regular BMain data-base. - * - * IDs with such tags have typically a short life. - */ - - /** - * ID is part of a temporary #Main which is expected to be freed in a short time-frame. - * - * RESET_NEVER - * - * Don't allow assigning this to non-temporary members (since it's likely to cause errors). - * When set #ID.session_uid isn't initialized, since the data isn't part of the session. - */ - LIB_TAG_TEMP_MAIN = 1 << 20, - /** General ID management info, for freeing or copying behavior e.g. */ - /** - * ID is not listed/stored in any #Main database. - * - * RESET_NEVER - */ - LIB_TAG_NO_MAIN = 1 << 21, - /** - * ID is fully outside of any ID management area, and should be considered as a purely - * independent data. - * - * RESET_NEVER - * - * \note Only used by node-trees currently. - */ - LIB_TAG_LOCALIZED = 1 << 22, - /** - * ID is a copy-on-write/localized version. - * - * RESET_NEVER - * - * \warning This should not be cleared on existing data. - * If support for this is needed, see #88026 as this flag controls memory ownership - * of physics *shared* pointers. - */ - LIB_TAG_COPIED_ON_WRITE = 1 << 23, - /** - * ID is not the original COW ID created by the depsgraph, but has been re-allocated during the - * evaluation process of another ID. - * - * RESET_NEVER - * - * Typical example is object data, when evaluating the object's modifier stack the final obdata - * can be different than the COW initial obdata ID. - */ - LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT = 1 << 24, - - /** - * ID management status tags related to non-standard BMain IDs. - */ - - /** - * Datablock does not refcount usages of other IDs. - * - * RESET_NEVER - */ - LIB_TAG_NO_USER_REFCOUNT = 1 << 25, - /** - * ID was not allocated by standard system (BKE_libblock_alloc), do not free its memory - * (usual type-specific freeing is called though). - * - * RESET_NEVER - */ - LIB_TAG_NOT_ALLOCATED = 1 << 26, - - /* ------------------------------------------------------------------------------------------- */ - - /** - * Free to use tag, often used in BKE code to mark IDs to be processed. - * - * RESET_BEFORE_USE - * - * \todo Make it a RESET_AFTER_USE too. - */ - LIB_TAG_DOIT = 1 << 31, -}; - -/** - * Most of ID tags are cleared on file write (i.e. also when storing undo steps), since they - * either have of very short lifetime (not expected to exist across undo steps), or are info that - * will be re-generated when reading undo steps. - * - * However a few of these need to be explicitly preserved across undo steps. - */ -#define LIB_TAG_KEEP_ON_UNDO (LIB_TAG_EXTRAUSER | LIB_TAG_MISSING | LIB_TAG_RUNTIME) - -/* Tag given ID for an update in all the dependency graphs. */ -typedef enum IDRecalcFlag { - /*************************************************************************** - * Individual update tags, this is what ID gets tagged for update with. */ - - /* ** Object transformation changed. ** */ - ID_RECALC_TRANSFORM = (1 << 0), - - /* ** Geometry changed. ** - * - * When object of armature type gets tagged with this flag, its pose is - * re-evaluated. - * - * When object of other type is tagged with this flag it makes the modifier - * stack to be re-evaluated. - * - * When object data type (mesh, curve, ...) gets tagged with this flag it - * makes all objects which shares this data-block to be updated. - * - * Note that the evaluation depends on the object-mode. - * So edit-mesh data for example only reevaluate with the updated edit-mesh. - * When geometry in the original ID has been modified #ID_RECALC_GEOMETRY_ALL_MODES - * must be used instead. - * - * When a collection gets tagged with this flag, all objects depending on the geometry and - * transforms on any of the objects in the collection are updated. */ - ID_RECALC_GEOMETRY = (1 << 1), - - /* ** Animation or time changed and animation is to be re-evaluated. ** */ - ID_RECALC_ANIMATION = (1 << 2), - - /* ** Particle system changed. ** */ - /* Only do path-cache etc. */ - ID_RECALC_PSYS_REDO = (1 << 3), - /* Reset everything including point-cache. */ - ID_RECALC_PSYS_RESET = (1 << 4), - /* Only child settings changed. */ - ID_RECALC_PSYS_CHILD = (1 << 5), - /* Physics type changed. */ - ID_RECALC_PSYS_PHYS = (1 << 6), - - /* ** Material and shading ** */ - - /* For materials and node trees this means that topology of the shader tree - * changed, and the shader is to be recompiled. - * For objects it means that the draw batch cache is to be redone. */ - ID_RECALC_SHADING = (1 << 7), - /* TODO(sergey): Consider adding an explicit ID_RECALC_SHADING_PARAMETERS - * which can be used for cases when only socket value changed, to speed up - * redraw update in that case. */ - - /* Selection of the ID itself or its components (for example, vertices) did - * change, and all the drawing data is to be updated. */ - ID_RECALC_SELECT = (1 << 9), - /* Flags on the base did change, and is to be copied onto all the copies of - * corresponding objects. */ - ID_RECALC_BASE_FLAGS = (1 << 10), - ID_RECALC_POINT_CACHE = (1 << 11), - /* Only inform editors about the change. Is used to force update of editors - * when data-block which is not a part of dependency graph did change. - * - * For example, brush texture did change and the preview is to be - * re-rendered. */ - ID_RECALC_EDITORS = (1 << 12), - - /* ** Update copy on write component. ** - * - * This is most generic tag which should only be used when nothing else matches. - * It is not to explicitly mixed in with other recalculation flags. - */ - ID_RECALC_COPY_ON_WRITE = (1 << 13), - - /* Sequences in the sequencer did change. - * Use this tag with a scene ID which owns the sequences. */ - ID_RECALC_SEQUENCER_STRIPS = (1 << 14), - - /* Runs on frame-change (used for seeking audio too). */ - ID_RECALC_FRAME_CHANGE = (1 << 15), - - ID_RECALC_AUDIO_FPS = (1 << 16), - ID_RECALC_AUDIO_VOLUME = (1 << 17), - ID_RECALC_AUDIO_MUTE = (1 << 18), - ID_RECALC_AUDIO_LISTENER = (1 << 19), - - ID_RECALC_AUDIO = (1 << 20), - - /* NOTE: This triggers copy on write for types that require it. - * Exceptions to this can be added using #ID_TYPE_SUPPORTS_PARAMS_WITHOUT_COW, - * this has the advantage that large arrays stored in the idea data don't - * have to be copied on every update. */ - ID_RECALC_PARAMETERS = (1 << 21), - - /* Input has changed and datablock is to be reload from disk. - * Applies to movie clips to inform that copy-on-written version is to be refreshed for the new - * input file or for color space changes. */ - ID_RECALC_SOURCE = (1 << 23), - - /* Virtual recalc tag/marker required for undo in some cases, where actual data does not change - * and hence do not require an update, but conceptually we are dealing with something new. - * - * Current known case: linked IDs made local without requiring any copy. While their users do not - * require any update, they have actually been 'virtually' remapped from the linked ID to the - * local one. - */ - ID_RECALC_TAG_FOR_UNDO = (1 << 24), - - /* The node tree has changed in a way that affects its output nodes. */ - ID_RECALC_NTREE_OUTPUT = (1 << 25), - - /* Hierarchy of collection and object within collection changed. */ - ID_RECALC_HIERARCHY = (1 << 26), - - /* Provisioned flags. - * - * Not for actual use. The idea of them is to have all bits of the `IDRecalcFlag` defined to a - * known value, silencing sanitizer warnings when checking bits of the ID_RECALC_ALL. */ - ID_RECALC_PROVISION_27 = (1 << 27), - ID_RECALC_PROVISION_28 = (1 << 28), - ID_RECALC_PROVISION_29 = (1 << 29), - ID_RECALC_PROVISION_30 = (1 << 30), - ID_RECALC_PROVISION_31 = (1u << 31), - - /*************************************************************************** - * Pseudonyms, to have more semantic meaning in the actual code without - * using too much low-level and implementation specific tags. */ - - /* Update animation data-block itself, without doing full re-evaluation of - * all dependent objects. */ - ID_RECALC_ANIMATION_NO_FLUSH = ID_RECALC_COPY_ON_WRITE, - - /* Ensure geometry of object and edit modes are both up-to-date in the evaluated data-block. - * Example usage is when mesh validation modifies the non-edit-mode data, - * which we want to be copied over to the evaluated data-block. */ - ID_RECALC_GEOMETRY_ALL_MODES = ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE, - - /*************************************************************************** - * Aggregate flags, use only for checks on runtime. - * Do NOT use those for tagging. */ - - /* Identifies that SOMETHING has been changed in this ID. */ - ID_RECALC_ALL = (0xffffffff), - - /* Identifies that something in particle system did change. */ - ID_RECALC_PSYS_ALL = (ID_RECALC_PSYS_REDO | ID_RECALC_PSYS_RESET | ID_RECALC_PSYS_CHILD | - ID_RECALC_PSYS_PHYS), - -} IDRecalcFlag; - -/* To filter ID types (filter_id). 64 bit to fit all types. */ -#define FILTER_ID_AC (1ULL << 0) -#define FILTER_ID_AR (1ULL << 1) -#define FILTER_ID_BR (1ULL << 2) -#define FILTER_ID_CA (1ULL << 3) -#define FILTER_ID_CU_LEGACY (1ULL << 4) -#define FILTER_ID_GD_LEGACY (1ULL << 5) -#define FILTER_ID_GR (1ULL << 6) -#define FILTER_ID_IM (1ULL << 7) -#define FILTER_ID_LA (1ULL << 8) -#define FILTER_ID_LS (1ULL << 9) -#define FILTER_ID_LT (1ULL << 10) -#define FILTER_ID_MA (1ULL << 11) -#define FILTER_ID_MB (1ULL << 12) -#define FILTER_ID_MC (1ULL << 13) -#define FILTER_ID_ME (1ULL << 14) -#define FILTER_ID_MSK (1ULL << 15) -#define FILTER_ID_NT (1ULL << 16) -#define FILTER_ID_OB (1ULL << 17) -#define FILTER_ID_PAL (1ULL << 18) -#define FILTER_ID_PC (1ULL << 19) -#define FILTER_ID_SCE (1ULL << 20) -#define FILTER_ID_SPK (1ULL << 21) -#define FILTER_ID_SO (1ULL << 22) -#define FILTER_ID_TE (1ULL << 23) -#define FILTER_ID_TXT (1ULL << 24) -#define FILTER_ID_VF (1ULL << 25) -#define FILTER_ID_WO (1ULL << 26) -#define FILTER_ID_PA (1ULL << 27) -#define FILTER_ID_CF (1ULL << 28) -#define FILTER_ID_WS (1ULL << 29) -#define FILTER_ID_LP (1ULL << 31) -#define FILTER_ID_CV (1ULL << 32) -#define FILTER_ID_PT (1ULL << 33) -#define FILTER_ID_VO (1ULL << 34) -#define FILTER_ID_SIM (1ULL << 35) -#define FILTER_ID_KE (1ULL << 36) -#define FILTER_ID_SCR (1ULL << 37) -#define FILTER_ID_WM (1ULL << 38) -#define FILTER_ID_LI (1ULL << 39) -#define FILTER_ID_GP (1ULL << 40) - -#define FILTER_ID_ALL \ - (FILTER_ID_AC | FILTER_ID_AR | FILTER_ID_BR | FILTER_ID_CA | FILTER_ID_CU_LEGACY | \ - FILTER_ID_GD_LEGACY | FILTER_ID_GR | FILTER_ID_IM | FILTER_ID_LA | FILTER_ID_LS | \ - FILTER_ID_LT | FILTER_ID_MA | FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME | FILTER_ID_MSK | \ - FILTER_ID_NT | FILTER_ID_OB | FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | \ - FILTER_ID_SPK | FILTER_ID_SO | FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | \ - FILTER_ID_CF | FILTER_ID_WS | FILTER_ID_LP | FILTER_ID_CV | FILTER_ID_PT | FILTER_ID_VO | \ - FILTER_ID_SIM | FILTER_ID_KE | FILTER_ID_SCR | FILTER_ID_WM | FILTER_ID_LI | FILTER_ID_GP) - -/** - * This enum defines the index assigned to each type of IDs in the array returned by - * #set_listbasepointers, and by extension, controls the default order in which each ID type is - * processed during standard 'foreach' looping over all IDs of a #Main data-base. - * - * About Order: - * ------------ - * - * This is (loosely) defined with a relationship order in mind, from lowest level (ID types using, - * referencing almost no other ID types) to highest level (ID types potentially using many other ID - * types). - * - * So e.g. it ensures that this dependency chain is respected: - * #Material <- #Mesh <- #Object <- #Collection <- #Scene - * - * Default order of processing of IDs in 'foreach' macros (#FOREACH_MAIN_ID_BEGIN and the like), - * built on top of #set_listbasepointers, is actually reversed compared to the order defined here, - * since processing usually needs to happen on users before it happens on used IDs (when freeing - * e.g.). - * - * DO NOT rely on this order as being full-proofed dependency order, there are many cases were it - * can be violated (most obvious cases being custom properties and drivers, which can reference any - * other ID types). - * - * However, this order can be considered as an optimization heuristic, especially when processing - * relationships in a non-recursive pattern: in typical cases, a vast majority of those - * relationships can be processed fine in the first pass, and only few additional passes are - * required to address all remaining relationship cases. - * See e.g. how #BKE_library_unused_linked_data_set_tag is doing this. - */ -typedef enum eID_Index { - /* Special case: Library, should never ever depend on any other type. */ - INDEX_ID_LI = 0, - - /* Animation types, might be used by almost all other types. */ - INDEX_ID_IP, /* Deprecated. */ - INDEX_ID_AC, - - /* Grease Pencil, special case, should be with the other obdata, but it can also be used by many - * other ID types, including node trees e.g. - * So there is no proper place for those, for now keep close to the lower end of the processing - * hierarchy, but we may want to re-evaluate that at some point. */ - INDEX_ID_GD_LEGACY, - - /* Node trees, abstraction for procedural data, potentially used by many other ID types. - * - * NOTE: While node trees can also use many other ID types, they should not /own/ any of those, - * while they are being owned by many other ID types. This is why they are placed here. */ - INDEX_ID_NT, - - /* File-wrapper types, those usually 'embed' external files in Blender, with no dependencies to - * other ID types. */ - INDEX_ID_VF, - INDEX_ID_TXT, - INDEX_ID_SO, - - /* Image/movie types, can be used by shading ID types, but also directly by Objects, Scenes, etc. - */ - INDEX_ID_MSK, - INDEX_ID_IM, - INDEX_ID_MC, - - /* Shading types. */ - INDEX_ID_TE, - INDEX_ID_MA, - INDEX_ID_LS, - INDEX_ID_WO, - - /* Simulation-related types. */ - INDEX_ID_CF, - INDEX_ID_PA, - - /* Shape Keys snow-flake, can be used by several obdata types. */ - INDEX_ID_KE, - - /* Object data types. */ - INDEX_ID_AR, - INDEX_ID_ME, - INDEX_ID_CU_LEGACY, - INDEX_ID_MB, - INDEX_ID_CV, - INDEX_ID_PT, - INDEX_ID_VO, - INDEX_ID_LT, - INDEX_ID_LA, - INDEX_ID_CA, - INDEX_ID_SPK, - INDEX_ID_LP, - INDEX_ID_GP, - - /* Collection and object types. */ - INDEX_ID_OB, - INDEX_ID_GR, - - /* Preset-like, not-really-data types, can use many other ID types but should never be used by - * any actual data type (besides Scene, due to tool settings). */ - INDEX_ID_PAL, - INDEX_ID_PC, - INDEX_ID_BR, - - /* Scene, after preset-like ID types because of tool settings. */ - INDEX_ID_SCE, - - /* UI-related types, should never be used by any other data type. */ - INDEX_ID_SCR, - INDEX_ID_WS, - INDEX_ID_WM, - - /* Special values. */ - INDEX_ID_NULL, -} eID_Index; - -#define INDEX_ID_MAX (INDEX_ID_NULL + 1) - -#ifdef UNDEFINED -} -#endif diff --git a/BlenderMalt/CBlenderMalt/blender_dna/DNA_ID_enums.h b/BlenderMalt/CBlenderMalt/blender_dna/DNA_ID_enums.h deleted file mode 100644 index 37499b0d..00000000 --- a/BlenderMalt/CBlenderMalt/blender_dna/DNA_ID_enums.h +++ /dev/null @@ -1,108 +0,0 @@ -/* SPDX-FileCopyrightText: 2023 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup DNA - * \brief Enumerations for `DNA_ID.h`. - */ - -#pragma once - -#ifdef UNDEFINED -extern "C" { -#endif - -enum eIconSizes { - ICON_SIZE_ICON = 0, - ICON_SIZE_PREVIEW = 1, - - NUM_ICON_SIZES, -}; - -/** - * Defines for working with IDs. - * - * The tags represent types! This is a dirty way of enabling RTTI. The - * sig_byte end endian defines aren't really used much. - */ - -#ifdef __BIG_ENDIAN__ -/* big endian */ -# define MAKE_ID2(c, d) ((c) << 8 | (d)) -#else -/* little endian */ -# define MAKE_ID2(c, d) ((d) << 8 | (c)) -#endif - -/** - * ID from database. - * - * Written to #BHead.code (for file IO) - * and the first 2 bytes of #ID.name (for runtime checks, see #GS macro). - * - * Update #ID_TYPE_IS_DEPRECATED() when deprecating types. - */ -typedef enum ID_Type { - ID_SCE = MAKE_ID2('S', 'C'), /* Scene */ - ID_LI = MAKE_ID2('L', 'I'), /* Library */ - ID_OB = MAKE_ID2('O', 'B'), /* Object */ - ID_ME = MAKE_ID2('M', 'E'), /* Mesh */ - ID_CU_LEGACY = MAKE_ID2('C', 'U'), /* Curve. ID_CV should be used in the future (see #95355). */ - ID_MB = MAKE_ID2('M', 'B'), /* MetaBall */ - ID_MA = MAKE_ID2('M', 'A'), /* Material */ - ID_TE = MAKE_ID2('T', 'E'), /* Tex (Texture) */ - ID_IM = MAKE_ID2('I', 'M'), /* Image */ - ID_LT = MAKE_ID2('L', 'T'), /* Lattice */ - ID_LA = MAKE_ID2('L', 'A'), /* Light */ - ID_CA = MAKE_ID2('C', 'A'), /* Camera */ - ID_IP = MAKE_ID2('I', 'P'), /* Ipo (depreciated, replaced by FCurves) */ - ID_KE = MAKE_ID2('K', 'E'), /* Key (shape key) */ - ID_WO = MAKE_ID2('W', 'O'), /* World */ - ID_SCR = MAKE_ID2('S', 'R'), /* Screen */ - ID_VF = MAKE_ID2('V', 'F'), /* VFont (Vector Font) */ - ID_TXT = MAKE_ID2('T', 'X'), /* Text */ - ID_SPK = MAKE_ID2('S', 'K'), /* Speaker */ - ID_SO = MAKE_ID2('S', 'O'), /* Sound */ - ID_GR = MAKE_ID2('G', 'R'), /* Collection */ - ID_AR = MAKE_ID2('A', 'R'), /* bArmature */ - ID_AC = MAKE_ID2('A', 'C'), /* bAction */ - ID_NT = MAKE_ID2('N', 'T'), /* bNodeTree */ - ID_BR = MAKE_ID2('B', 'R'), /* Brush */ - ID_PA = MAKE_ID2('P', 'A'), /* ParticleSettings */ - ID_GD_LEGACY = MAKE_ID2('G', 'D'), /* bGPdata, (legacy Grease Pencil) */ - ID_WM = MAKE_ID2('W', 'M'), /* WindowManager */ - ID_MC = MAKE_ID2('M', 'C'), /* MovieClip */ - ID_MSK = MAKE_ID2('M', 'S'), /* Mask */ - ID_LS = MAKE_ID2('L', 'S'), /* FreestyleLineStyle */ - ID_PAL = MAKE_ID2('P', 'L'), /* Palette */ - ID_PC = MAKE_ID2('P', 'C'), /* PaintCurve */ - ID_CF = MAKE_ID2('C', 'F'), /* CacheFile */ - ID_WS = MAKE_ID2('W', 'S'), /* WorkSpace */ - ID_LP = MAKE_ID2('L', 'P'), /* LightProbe */ - ID_CV = MAKE_ID2('C', 'V'), /* Curves */ - ID_PT = MAKE_ID2('P', 'T'), /* PointCloud */ - ID_VO = MAKE_ID2('V', 'O'), /* Volume */ - ID_GP = MAKE_ID2('G', 'P'), /* Grease Pencil */ -} ID_Type; - -/* Only used as 'placeholder' in .blend files for directly linked data-blocks. */ -#define ID_LINK_PLACEHOLDER MAKE_ID2('I', 'D') /* (internal use only) */ - -/* Deprecated. */ -#define ID_SCRN MAKE_ID2('S', 'N') - -/* NOTE: Fake IDs, needed for `g.sipo->blocktype` or outliner. */ -#define ID_SEQ MAKE_ID2('S', 'Q') -/* constraint */ -#define ID_CO MAKE_ID2('C', 'O') -/* pose (action channel, used to be ID_AC in code, so we keep code for backwards compatible). */ -#define ID_PO MAKE_ID2('A', 'C') -/* used in outliner... */ -#define ID_NLA MAKE_ID2('N', 'L') -/* fluidsim Ipo */ -#define ID_FLUIDSIM MAKE_ID2('F', 'S') - -#ifdef UNDEFINED -} -#endif diff --git a/BlenderMalt/CBlenderMalt/blender_dna/DNA_customdata_types.h b/BlenderMalt/CBlenderMalt/blender_dna/DNA_customdata_types.h deleted file mode 100644 index 48c7b769..00000000 --- a/BlenderMalt/CBlenderMalt/blender_dna/DNA_customdata_types.h +++ /dev/null @@ -1,278 +0,0 @@ -/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved. - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup DNA - * - * Used for custom mesh data types (stored per vert/edge/loop/face) - */ - -#pragma once - -#include "DNA_defs.h" - -//#include "BLI_implicit_sharing.h" - -/** Workaround to forward-declare C++ type in C header. */ -#ifdef UNDEFINED -namespace blender::bke { -class AnonymousAttributeID; -} // namespace blender::bke -using AnonymousAttributeIDHandle = blender::bke::AnonymousAttributeID; -#else -typedef struct AnonymousAttributeIDHandle AnonymousAttributeIDHandle; -typedef struct ImplicitSharingInfoHandle ImplicitSharingInfoHandle; -#endif - -/** Descriptor and storage for a custom data layer. */ -typedef struct CustomDataLayer { - /** Type of data in layer. */ - int type; - /** In editmode, offset of layer in block. */ - int offset; - /** General purpose flag. */ - int flag; - /** Number of the active layer of this type. */ - int active; - /** Number of the layer to render. */ - int active_rnd; - /** Number of the layer to render. */ - int active_clone; - /** Number of the layer to render. */ - int active_mask; - /** Shape key-block unique id reference. */ - int uid; - /** Layer name, MAX_CUSTOMDATA_LAYER_NAME. */ - char name[68]; - char _pad1[4]; - /** Layer data. */ - void *data; - /** - * Run-time identifier for this layer. Can be used to retrieve information about where this - * attribute was created. - */ - const AnonymousAttributeIDHandle *anonymous_id; - /** - * Run-time data that allows sharing `data` with other entities (mostly custom data layers on - * other geometries). - */ - const ImplicitSharingInfoHandle *sharing_info; -} CustomDataLayer; - -#define MAX_CUSTOMDATA_LAYER_NAME 68 -#define MAX_CUSTOMDATA_LAYER_NAME_NO_PREFIX 64 - -typedef struct CustomDataExternal { - /** FILE_MAX. */ - char filepath[1024]; -} CustomDataExternal; - -/** - * #CustomData stores an arbitrary number of typed data "layers" for multiple elements. - * The layers are typically geometry attributes, and the elements are typically geometry - * elements like vertices, edges, or curves. - * - * Each layer has a type, often with certain semantics beyond the type of the raw data. However, - * a subset of the layer types are exposed as attributes and accessed with a higher level API - * built around #AttributeAccessor. - * - * For #BMesh, #CustomData is adapted to store the data from all layers in a single "block" which - * is allocated for each element. Each layer's data is stored at a certain offset into every - * block's data. - */ -typedef struct CustomData { - /** Layers ordered by type. */ - CustomDataLayer *layers; - /** - * Runtime only map from types to indices of first layer of that type, - * Correct size of #CD_NUMTYPES is ensured by CustomData_update_typemap. - */ - int typemap[53]; - /** Number of layers, size of layers array. */ - int totlayer, maxlayer; - /** In editmode, total size of all data layers. */ - int totsize; - /** (BMesh Only): Memory pool for allocation of blocks. */ - struct BLI_mempool *pool; - /** External file storing custom-data layers. */ - CustomDataExternal *external; -} CustomData; - -/** #CustomDataLayer.type */ -typedef enum eCustomDataType { - /** - * Used by GPU attributes in the cases when we don't know which layer - * we are addressing in advance. - */ - CD_AUTO_FROM_NAME = -1, - -#ifdef DNA_DEPRECATED_ALLOW - CD_MVERT = 0, - CD_MSTICKY = 1, -#endif - CD_MDEFORMVERT = 2, /* Array of #MDeformVert. */ -#ifdef DNA_DEPRECATED_ALLOW - CD_MEDGE = 3, -#endif - CD_MFACE = 4, - CD_MTFACE = 5, - CD_MCOL = 6, - CD_ORIGINDEX = 7, - /** - * Used as temporary storage for some areas that support interpolating custom normals. - * Using a separate type from generic 3D vectors is a simple way of keeping values normalized. - */ - CD_NORMAL = 8, -#ifdef DNA_DEPRECATED_ALLOW - CD_FACEMAP = 9, -#endif - CD_PROP_FLOAT = 10, - CD_PROP_INT32 = 11, - CD_PROP_STRING = 12, - CD_ORIGSPACE = 13, /* for modifier stack face location mapping */ - CD_ORCO = 14, /* undeformed vertex coordinates, normalized to 0..1 range */ -#ifdef DNA_DEPRECATED_ALLOW - CD_MTEXPOLY = 15, - CD_MLOOPUV = 16, -#endif - CD_PROP_BYTE_COLOR = 17, - CD_TANGENT = 18, - CD_MDISPS = 19, - /* CD_PREVIEW_MCOL = 20, */ /* UNUSED */ - /* CD_ID_MCOL = 21, */ - /* CD_TEXTURE_MLOOPCOL = 22, */ /* UNUSED */ - CD_CLOTH_ORCO = 23, -/* CD_RECAST = 24, */ /* UNUSED */ - -#ifdef DNA_DEPRECATED_ALLOW - CD_MPOLY = 25, - CD_MLOOP = 26, -#endif - CD_SHAPE_KEYINDEX = 27, - CD_SHAPEKEY = 28, -#ifdef DNA_DEPRECATED_ALLOW - CD_BWEIGHT = 29, - CD_CREASE = 30, -#endif - CD_ORIGSPACE_MLOOP = 31, - /* CD_PREVIEW_MLOOPCOL = 32, */ /* UNUSED */ - CD_BM_ELEM_PYPTR = 33, - -#ifdef DNA_DEPRECATED_ALLOW - CD_PAINT_MASK = 34, -#endif - CD_GRID_PAINT_MASK = 35, - CD_MVERT_SKIN = 36, - CD_FREESTYLE_EDGE = 37, - CD_FREESTYLE_FACE = 38, - CD_MLOOPTANGENT = 39, - CD_TESSLOOPNORMAL = 40, - CD_CUSTOMLOOPNORMAL = 41, -#ifdef DNA_DEPRECATED_ALLOW - CD_SCULPT_FACE_SETS = 42, -#endif - - /* CD_LOCATION = 43, */ /* UNUSED */ - /* CD_RADIUS = 44, */ /* UNUSED */ - CD_PROP_INT8 = 45, - /* Two 32-bit signed integers. */ - CD_PROP_INT32_2D = 46, - - CD_PROP_COLOR = 47, - CD_PROP_FLOAT3 = 48, - CD_PROP_FLOAT2 = 49, - CD_PROP_BOOL = 50, - - /* CD_HAIRLENGTH = 51, */ /* UNUSED */ - - CD_PROP_QUATERNION = 52, - - CD_NUMTYPES = 53, -} eCustomDataType; - -#ifdef __cplusplus -using eCustomDataMask = uint64_t; -#endif - -/* Bits for eCustomDataMask */ -#define CD_MASK_MDEFORMVERT (1 << CD_MDEFORMVERT) -#define CD_MASK_MFACE (1 << CD_MFACE) -#define CD_MASK_MTFACE (1 << CD_MTFACE) -#define CD_MASK_MCOL (1 << CD_MCOL) -#define CD_MASK_ORIGINDEX (1 << CD_ORIGINDEX) -#define CD_MASK_NORMAL (1 << CD_NORMAL) -#define CD_MASK_PROP_FLOAT (1 << CD_PROP_FLOAT) -#define CD_MASK_PROP_INT32 (1 << CD_PROP_INT32) -#define CD_MASK_PROP_STRING (1 << CD_PROP_STRING) -#define CD_MASK_ORIGSPACE (1 << CD_ORIGSPACE) -#define CD_MASK_ORCO (1 << CD_ORCO) -#define CD_MASK_PROP_BYTE_COLOR (1 << CD_PROP_BYTE_COLOR) -#define CD_MASK_TANGENT (1 << CD_TANGENT) -#define CD_MASK_MDISPS (1 << CD_MDISPS) -#define CD_MASK_CLOTH_ORCO (1 << CD_CLOTH_ORCO) - -#define CD_MASK_SHAPE_KEYINDEX (1 << CD_SHAPE_KEYINDEX) -#define CD_MASK_SHAPEKEY (1 << CD_SHAPEKEY) -#define CD_MASK_ORIGSPACE_MLOOP (1LL << CD_ORIGSPACE_MLOOP) -#define CD_MASK_BM_ELEM_PYPTR (1LL << CD_BM_ELEM_PYPTR) - -#define CD_MASK_GRID_PAINT_MASK (1LL << CD_GRID_PAINT_MASK) -#define CD_MASK_MVERT_SKIN (1LL << CD_MVERT_SKIN) -#define CD_MASK_FREESTYLE_EDGE (1LL << CD_FREESTYLE_EDGE) -#define CD_MASK_FREESTYLE_FACE (1LL << CD_FREESTYLE_FACE) -#define CD_MASK_MLOOPTANGENT (1LL << CD_MLOOPTANGENT) -#define CD_MASK_TESSLOOPNORMAL (1LL << CD_TESSLOOPNORMAL) -#define CD_MASK_CUSTOMLOOPNORMAL (1LL << CD_CUSTOMLOOPNORMAL) -#define CD_MASK_PROP_COLOR (1ULL << CD_PROP_COLOR) -#define CD_MASK_PROP_FLOAT3 (1ULL << CD_PROP_FLOAT3) -#define CD_MASK_PROP_FLOAT2 (1ULL << CD_PROP_FLOAT2) -#define CD_MASK_PROP_BOOL (1ULL << CD_PROP_BOOL) -#define CD_MASK_PROP_INT8 (1ULL << CD_PROP_INT8) -#define CD_MASK_PROP_INT32_2D (1ULL << CD_PROP_INT32_2D) -#define CD_MASK_PROP_QUATERNION (1ULL << CD_PROP_QUATERNION) - -/** Multi-resolution loop data. */ -#define CD_MASK_MULTIRES_GRIDS (CD_MASK_MDISPS | CD_GRID_PAINT_MASK) - -/* All data layers. */ -#define CD_MASK_ALL (~0LL) - -/* All generic attributes. */ -#define CD_MASK_PROP_ALL \ - (CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 | CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 | \ - CD_MASK_PROP_COLOR | CD_MASK_PROP_STRING | CD_MASK_PROP_BYTE_COLOR | CD_MASK_PROP_BOOL | \ - CD_MASK_PROP_INT8 | CD_MASK_PROP_INT32_2D | CD_MASK_PROP_QUATERNION) - -/* All color attributes */ -#define CD_MASK_COLOR_ALL (CD_MASK_PROP_COLOR | CD_MASK_PROP_BYTE_COLOR) - -typedef struct CustomData_MeshMasks { - uint64_t vmask; - uint64_t emask; - uint64_t fmask; - uint64_t pmask; - uint64_t lmask; -} CustomData_MeshMasks; - -/** #CustomData.flag */ -enum { - /* Indicates layer should not be copied by CustomData_from_template or CustomData_copy_data */ - CD_FLAG_NOCOPY = (1 << 0), - CD_FLAG_UNUSED = (1 << 1), - /* Indicates the layer is only temporary, also implies no copy */ - CD_FLAG_TEMPORARY = ((1 << 2) | CD_FLAG_NOCOPY), - /* Indicates the layer is stored in an external file */ - CD_FLAG_EXTERNAL = (1 << 3), - /* Indicates external data is read into memory */ - CD_FLAG_IN_MEMORY = (1 << 4), -#ifdef DNA_DEPRECATED_ALLOW - CD_FLAG_COLOR_ACTIVE = (1 << 5), - CD_FLAG_COLOR_RENDER = (1 << 6) -#endif -}; - -/* Limits */ -#define MAX_MTFACE 8 - -#define DYNTOPO_NODE_NONE -1 diff --git a/BlenderMalt/CBlenderMalt/blender_dna/DNA_defs.h b/BlenderMalt/CBlenderMalt/blender_dna/DNA_defs.h deleted file mode 100644 index da1c7c84..00000000 --- a/BlenderMalt/CBlenderMalt/blender_dna/DNA_defs.h +++ /dev/null @@ -1,161 +0,0 @@ -/* SPDX-FileCopyrightText: 2023 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup DNA - * - * Group generic defines for all DNA headers may use in this file. - */ - -#pragma once - -/* `makesdna` ignores. */ -#ifdef DNA_DEPRECATED_ALLOW -/* allow use of deprecated items */ -# define DNA_DEPRECATED -#else -# ifndef DNA_DEPRECATED -# ifdef __GNUC__ -# define DNA_DEPRECATED __attribute__((deprecated)) -# else -/* TODO: MSVC & others. */ -# define DNA_DEPRECATED -# endif -# endif -#endif - -#ifdef __GNUC__ -# define DNA_PRIVATE_ATTR __attribute__((deprecated)) -#else -# define DNA_PRIVATE_ATTR -#endif - -/* poison pragma */ -#ifdef DNA_DEPRECATED_ALLOW -# define DNA_DEPRECATED_GCC_POISON 0 -#else -/* enable the pragma if we can */ -# ifdef __GNUC__ -# define DNA_DEPRECATED_GCC_POISON 1 -# else -# define DNA_DEPRECATED_GCC_POISON 0 -# endif -#endif - -/* hrmf, we need a better include then this */ -#include "BLI_sys_types.h" /* needed for int64_t only! */ - -/* non-id name variables should use this length */ -#define MAX_NAME 64 - -/* #DNA_DEFINE_CXX_METHODS is used to define C++ methods which are needed for proper/safe resource - * management, making unsafe (from an ownership perspective: i.e. pointers which sometimes needs to - * be set to nullptr on copy, sometimes needs to be dupalloc-ed) operations explicit, and taking - * care of compiler specific warnings when dealing with members marked with DNA_DEPRECATED. - * - * The `class_name` argument is to match the structure name the macro is used from. - * - * Typical usage example: - * - * typedef struct Object { - * DNA_DEFINE_CXX_METHODS(Object) - * } Object; - */ -#ifndef UNDEFINED -# define DNA_DEFINE_CXX_METHODS(class_name) -#else - -/* Forward-declared here since there is no simple header file to be pulled for this functionality. - * Avoids pulling `string.h` from this header to get access to #memcpy. */ -extern "C" void _DNA_internal_memcpy(void *dst, const void *src, size_t size); -extern "C" void _DNA_internal_memzero(void *dst, size_t size); -extern "C" void _DNA_internal_swap(void *a, void *b, size_t size); - -namespace blender::dna::internal { - -template class ShallowDataConstRef { - public: - constexpr explicit ShallowDataConstRef(const T &ref) : ref_(ref) {} - - inline const T *get_pointer() const - { - return &ref_; - } - - private: - const T &ref_; -}; - -class ShallowZeroInitializeTag {}; - -} // namespace blender::dna::internal - -# define DNA_DEFINE_CXX_METHODS(class_name) \ - class_name() = default; \ - ~class_name() = default; \ - /* Delete copy and assignment, which are not safe for resource ownership. */ \ - class_name(const class_name &other) = delete; \ - class_name(class_name &&other) noexcept = delete; \ - class_name &operator=(const class_name &other) = delete; \ - class_name &operator=(class_name &&other) = delete; \ - /* Support for shallow copy. */ \ - /* NOTE: Calling the default constructor works-around deprecated warning generated by GCC. */ \ - class_name(const blender::dna::internal::ShallowDataConstRef ref) : class_name() \ - { \ - _DNA_internal_memcpy(this, ref.get_pointer(), sizeof(class_name)); \ - } \ - class_name &operator=(const blender::dna::internal::ShallowDataConstRef ref) \ - { \ - if (this != ref.get_pointer()) { \ - _DNA_internal_memcpy(this, ref.get_pointer(), sizeof(class_name)); \ - } \ - return *this; \ - } \ - /* Create object which memory is filled with zeros. */ \ - class_name(const blender::dna::internal::ShallowZeroInitializeTag /*tag*/) : class_name() \ - { \ - _DNA_internal_memzero(this, sizeof(class_name)); \ - } \ - class_name &operator=(const blender::dna::internal::ShallowZeroInitializeTag /*tag*/) \ - { \ - _DNA_internal_memzero(this, sizeof(class_name)); \ - return *this; \ - } - -namespace blender::dna { - -/* Creates shallow copy of the given object. - * The entire object is copied as-is using memory copy. - * - * Typical usage: - * Object temp_object = blender::dna::shallow_copy(*input_object); - * - * From the implementation detail go via copy constructor/assign operator defined in the structure. - */ -template -[[nodiscard]] inline internal::ShallowDataConstRef shallow_copy(const T &other) -{ - return internal::ShallowDataConstRef(other); -} - -template inline void shallow_copy_array(T *dst, const T *src, const int64_t size) -{ - _DNA_internal_memcpy(dst, src, sizeof(T) * size_t(size)); -} - -/* DNA object initializer which leads to an object which underlying memory is filled with zeroes. - */ -[[nodiscard]] inline internal::ShallowZeroInitializeTag shallow_zero_initialize() -{ - return internal::ShallowZeroInitializeTag(); -} - -template inline void shallow_swap(T &a, T &b) -{ - _DNA_internal_swap(&a, &b, sizeof(T)); -} - -} // namespace blender::dna - -#endif diff --git a/BlenderMalt/CBlenderMalt/blender_dna/DNA_listBase.h b/BlenderMalt/CBlenderMalt/blender_dna/DNA_listBase.h deleted file mode 100644 index c316a375..00000000 --- a/BlenderMalt/CBlenderMalt/blender_dna/DNA_listBase.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved. - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup DNA - * \brief These structs are the foundation for all linked lists in the library system. - * - * Doubly-linked lists start from a ListBase and contain elements beginning - * with Link. - */ - -#pragma once - -/** Generic - all structs which are put into linked lists begin with this. */ -typedef struct Link { - struct Link *next, *prev; -} Link; - -/** Simple subclass of Link. Use this when it is not worth defining a custom one. */ -typedef struct LinkData { - struct LinkData *next, *prev; - void *data; -} LinkData; - -/** Never change the size of this! dna_genfile.cc detects pointer_size with it. */ -typedef struct ListBase { - void *first, *last; -} ListBase; - -/* 8 byte alignment! */ diff --git a/BlenderMalt/CBlenderMalt/blender_dna/DNA_mesh_types.h b/BlenderMalt/CBlenderMalt/blender_dna/DNA_mesh_types.h deleted file mode 100644 index ec687c91..00000000 --- a/BlenderMalt/CBlenderMalt/blender_dna/DNA_mesh_types.h +++ /dev/null @@ -1,522 +0,0 @@ -/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved. - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup DNA - */ - -#pragma once - -#include "DNA_ID.h" -#include "DNA_customdata_types.h" -#include "DNA_defs.h" -#include "DNA_session_uid_types.h" - -/** Workaround to forward-declare C++ type in C header. */ -#ifdef UNDEFINED - -# include - -# include "BLI_math_vector_types.hh" - -namespace blender { -template struct Bounds; -namespace offset_indices { -template struct GroupedSpan; -template class OffsetIndices; -} // namespace offset_indices -using offset_indices::GroupedSpan; -using offset_indices::OffsetIndices; -template class MutableSpan; -template class Span; -namespace bke { -struct MeshRuntime; -class AttributeAccessor; -class MutableAttributeAccessor; -struct LooseVertCache; -struct LooseEdgeCache; -enum class MeshNormalDomain : int8_t; -} // namespace bke -} // namespace blender -using MeshRuntimeHandle = blender::bke::MeshRuntime; -#else -typedef struct MeshRuntimeHandle MeshRuntimeHandle; -#endif - -struct AnimData; -struct Ipo; -struct Key; -struct MCol; -struct MEdge; -struct MFace; -struct Material; - -typedef struct Mesh { - DNA_DEFINE_CXX_METHODS(Mesh) - - ID id; - /** Animation data (must be immediately after id for utilities to use it). */ - struct AnimData *adt; - - /** Old animation system, deprecated for 2.5. */ - struct Ipo *ipo DNA_DEPRECATED; - struct Key *key; - - /** - * An array of materials, with length #totcol. These can be overridden by material slots - * on #Object. Indices in the "material_index" attribute control which material is used for every - * face. - */ - struct Material **mat; - - /** The number of vertices in the mesh, and the size of #vert_data. */ - int verts_num; - /** The number of edges in the mesh, and the size of #edge_data. */ - int edges_num; - /** The number of polygons/faces in the mesh, and the size of #face_data. */ - int faces_num; - /** The number of face corners in the mesh, and the size of #corner_data. */ - int corners_num; - - /** - * Array owned by mesh. See #Mesh::faces() and #OffsetIndices. - * - * This array is shared based on the bke::MeshRuntime::poly_offsets_sharing_info. - * Avoid accessing directly when possible. - */ - int *face_offset_indices; - - CustomData vert_data; - CustomData edge_data; - CustomData face_data; - CustomData corner_data; - - /** - * List of vertex group (#bDeformGroup) names and flags only. Actual weights are stored in dvert. - * \note This pointer is for convenient access to the #CD_MDEFORMVERT layer in #vert_data. - */ - ListBase vertex_group_names; - /** The active index in the #vertex_group_names list. */ - int vertex_group_active_index; - - /** - * The index of the active attribute in the UI. The attribute list is a combination of the - * generic type attributes from vertex, edge, face, and corner custom data. - */ - int attributes_active_index; - - /** - * Runtime storage of the edit mode mesh. If it exists, it generally has the most up-to-date - * information about the mesh. - * \note When the object is available, the preferred access method is #BKE_editmesh_from_object. - */ - struct BMEditMesh *edit_mesh; - - /** - * This array represents the selection order when the user manually picks elements in edit-mode, - * some tools take advantage of this information. All elements in this array are expected to be - * selected, see #BKE_mesh_mselect_validate which ensures this. For procedurally created meshes, - * this is generally empty (selections are stored as boolean attributes in the corresponding - * custom data). - */ - struct MSelect *mselect; - - /** The length of the #mselect array. */ - int totselect; - - /** - * In most cases the last selected element (see #mselect) represents the active element. - * For faces we make an exception and store the active face separately so it can be active - * even when no faces are selected. This is done to prevent flickering in the material properties - * and UV Editor which base the content they display on the current material which is controlled - * by the active face. - * - * \note This is mainly stored for use in edit-mode. - */ - int act_face; - - /** - * An optional mesh owned elsewhere (by #Main) that can be used to override - * the texture space #loc and #size. - * \note Vertex indices should be aligned for this to work usefully. - */ - struct Mesh *texcomesh; - - /** Texture space location and size, used for procedural coordinates when rendering. */ - float texspace_location[3]; - float texspace_size[3]; - char texspace_flag; - - /** Various flags used when editing the mesh. */ - char editflag; - /** Mostly more flags used when editing or displaying the mesh. */ - uint16_t flag; - - float smoothresh_legacy DNA_DEPRECATED; - - /** Per-mesh settings for voxel remesh. */ - float remesh_voxel_size; - float remesh_voxel_adaptivity; - - int face_sets_color_seed; - /* Stores the initial Face Set to be rendered white. This way the overlay can be enabled by - * default and Face Sets can be used without affecting the color of the mesh. */ - int face_sets_color_default; - - /** The color attribute currently selected in the list and edited by a user. */ - char *active_color_attribute; - /** The color attribute used by default (i.e. for rendering) if no name is given explicitly. */ - char *default_color_attribute; - - /** - * User-defined symmetry flag (#eMeshSymmetryType) that causes editing operations to maintain - * symmetrical geometry. Supported by operations such as transform and weight-painting. - */ - char symmetry; - - /** Choice between different remesh methods in the UI. */ - char remesh_mode; - - /** The length of the #mat array. */ - short totcol; - - /** - * Deprecated flag for choosing whether to store specific custom data that was built into #Mesh - * structs in edit mode. Replaced by separating that data to separate layers. Kept for forward - * and backwards compatibility. - */ - char cd_flag DNA_DEPRECATED; - char subdiv DNA_DEPRECATED; - char subdivr DNA_DEPRECATED; - char subsurftype DNA_DEPRECATED; - - /** Deprecated pointer to mesh polygons, kept for forward compatibility. */ - struct MPoly *mpoly DNA_DEPRECATED; - /** Deprecated pointer to face corners, kept for forward compatibility. */ - struct MLoop *mloop DNA_DEPRECATED; - - /** Deprecated array of mesh vertices, kept for reading old files, now stored in #CustomData. */ - struct MVert *mvert DNA_DEPRECATED; - /** Deprecated array of mesh edges, kept for reading old files, now stored in #CustomData. */ - struct MEdge *medge DNA_DEPRECATED; - /** Deprecated "Vertex group" data. Kept for reading old files, now stored in #CustomData. */ - struct MDeformVert *dvert DNA_DEPRECATED; - /** Deprecated runtime data for tessellation face UVs and texture, kept for reading old files. */ - struct MTFace *mtface DNA_DEPRECATED; - /** Deprecated, use mtface. */ - struct TFace *tface DNA_DEPRECATED; - /** Deprecated array of colors for the tessellated faces, kept for reading old files. */ - struct MCol *mcol DNA_DEPRECATED; - /** Deprecated face storage (quads & triangles only). Kept for reading old files. */ - struct MFace *mface DNA_DEPRECATED; - - /** - * Deprecated storage of old faces (only triangles or quads). - * - * \note This would be marked deprecated, however the particles still use this at run-time - * for placing particles on the mesh (something which should be eventually upgraded). - */ - CustomData fdata_legacy; - /* Deprecated size of #fdata. */ - int totface_legacy; - - char _pad1[4]; - - /** - * Data that isn't saved in files, including caches of derived data, temporary data to improve - * the editing experience, etc. The struct is created when reading files and can be accessed - * without null checks, with the exception of some temporary meshes which should allocate and - * free the data if they are passed to functions that expect run-time data. - */ - MeshRuntimeHandle *runtime; -#ifdef UNDEFINED - /** - * Array of vertex positions. Edges and faces are defined by indices into this array. - */ - blender::Span vert_positions() const; - /** Write access to vertex data. */ - blender::MutableSpan vert_positions_for_write(); - /** - * Array of edges, containing vertex indices, stored in the ".edge_verts" attributes. For simple - * triangle or quad meshes, edges could be calculated from the face and "corner edge" arrays, - * however, edges need to be stored explicitly to edge domain attributes and to support loose - * edges that aren't connected to faces. - */ - blender::Span edges() const; - /** Write access to edge data. */ - blender::MutableSpan edges_for_write(); - /** - * Face topology storage of the offset of each face's section of the face corners. The size of - * each face is encoded using the next offset value. Can be used to slice the #corner_verts or - * #corner_edges arrays to find the vertices or edges that make up each face. - */ - blender::OffsetIndices faces() const; - /** - * Index of the first corner of each face, and the size of the face encoded as the next - * offset. The total number of corners is the final value, and the first value is always zero. - * May be empty if there are no polygons. - */ - blender::Span face_offsets() const; - /** Write access to #poly_offsets data. */ - blender::MutableSpan face_offsets_for_write(); - - /** - * Array of vertices for every face corner, stored in the ".corner_vert" integer attribute. - * For example, the vertices in a face can be retrieved with the #slice method: - * \code{.cc} - * const Span poly_verts = corner_verts.slice(face); - * \endcode - * Such a span can often be passed as an argument in lieu of a polygon or the entire corner - * verts array. - */ - blender::Span corner_verts() const; - /** Write access to the #corner_verts data. */ - blender::MutableSpan corner_verts_for_write(); - - /** - * Array of edges following every face corner traveling around each face, stored in the - * ".corner_edge" attribute. The array sliced the same way as the #corner_verts data. The edge - * previous to a corner must be accessed with the index of the previous face corner. - */ - blender::Span corner_edges() const; - /** Write access to the #corner_edges data. */ - blender::MutableSpan corner_edges_for_write(); - - blender::bke::AttributeAccessor attributes() const; - blender::bke::MutableAttributeAccessor attributes_for_write(); - - /** - * Vertex group data, encoded as an array of indices and weights for every vertex. - * \warning: May be empty. - */ - blender::Span deform_verts() const; - /** Write access to vertex group data. */ - blender::MutableSpan deform_verts_for_write(); - - /** - * Cached triangulation of mesh faces, depending on the face topology and the vertex positions. - */ - blender::Span corner_tris() const; - - /** - * A map containing the face index that each cached triangle from #Mesh::corner_tris() came from. - */ - blender::Span corner_tri_faces() const; - - /** - * Calculate the largest and smallest position values of vertices. - */ - std::optional> bounds_min_max() const; - - /** Set cached mesh bounds to a known-correct value to avoid their lazy calculation later on. */ - void bounds_set_eager(const blender::Bounds &bounds); - - /** - * Cached map containing the index of the face using each face corner. - */ - blender::Span corner_to_face_map() const; - /** - * Offsets per vertex used to slice arrays containing data for connected faces or face corners. - */ - blender::OffsetIndices vert_to_face_map_offsets() const; - /** - * Cached map from each vertex to the corners using it. - */ - blender::GroupedSpan vert_to_corner_map() const; - /** - * Cached map from each vertex to the faces using it. - */ - blender::GroupedSpan vert_to_face_map() const; - - /** - * Cached information about loose edges, calculated lazily when necessary. - */ - const blender::bke::LooseEdgeCache &loose_edges() const; - /** - * Cached information about vertices that aren't used by any edges. - */ - const blender::bke::LooseVertCache &loose_verts() const; - /** - * Cached information about vertices that aren't used by faces (but may be used by loose edges). - */ - const blender::bke::LooseVertCache &verts_no_face() const; - /** - * True if the mesh has no faces or edges "inside" of other faces. Those edges or faces would - * reuse a subset of the vertices of a face. Knowing the mesh is "clean" or "good" can mean - * algorithms can skip checking for duplicate edges and faces when they create new edges and - * faces inside of faces. - * - * \note This is just a hint, so there still might be no overlapping geometry if it is false. - */ - bool no_overlapping_topology() const; - - /** - * Explicitly set the cached number of loose edges to zero. This can improve performance - * later on, because finding loose edges lazily can be skipped entirely. - * - * \note To allow setting this status on meshes without changing them, this does not tag the - * cache dirty. If the mesh was changed first, the relevant dirty tags should be called first. - */ - void tag_loose_edges_none() const; - /** - * Set the number of vertices not connected to edges to zero. Similar to #tag_loose_edges_none(). - * There may still be vertices only used by loose edges though. - * - * \note If both #tag_loose_edges_none() and #tag_loose_verts_none() are called, - * all vertices are used by faces, so #verts_no_faces() will be tagged empty as well. - */ - void tag_loose_verts_none() const; - /** Set the #no_overlapping_topology() hint when the mesh is "clean." */ - void tag_overlapping_none(); - - /** - * Returns the least complex attribute domain needed to store normals encoding all relevant mesh - * data. When all edges or faces are sharp, face normals are enough. When all are smooth, vertex - * normals are enough. With a combination of sharp and smooth, normals may be "split", - * requiring face corner storage. - * - * When possible, it's preferred to use face normals over vertex normals and vertex normals over - * face corner normals, since there is a 2-4x performance cost increase for each more complex - * domain. - * - * Optionally the consumer of the mesh can indicate that they support the sharp_face attribute - * natively, to avoid using corner normals in some cases. - */ - blender::bke::MeshNormalDomain normals_domain(const bool support_sharp_face = false) const; - /** - * Normal direction of polygons, defined by positions and the winding direction of face corners. - */ - blender::Span face_normals() const; - /** - * Normal direction of vertices, defined as the weighted average of face normals - * surrounding each vertex and the normalized position for loose vertices. - */ - blender::Span vert_normals() const; - /** - * Normal direction at each face corner. Defined by a combination of face normals, vertex - * normals, the `sharp_edge` and `sharp_face` attributes, and potentially by custom normals. - * - * \note Because of the large memory requirements of storing normals per face corner, prefer - * using #face_normals() or #vert_normals() when possible (see #normals_domain()). - */ - blender::Span corner_normals() const; - - /** Call after changing vertex positions to tag lazily calculated caches for recomputation. */ - void tag_positions_changed(); - /** Call after moving every mesh vertex by the same translation. */ - void tag_positions_changed_uniformly(); - /** Like #tag_positions_changed but doesn't tag normals; they must be updated separately. */ - void tag_positions_changed_no_normals(); - /** Call when changing "sharp_face" or "sharp_edge" data. */ - void tag_sharpness_changed(); - /** Call when changing #CD_CUSTOMLOOPNORMAL data. */ - void tag_custom_normals_changed(); - /** Call when face vertex order has changed but positions and faces haven't changed. */ - void tag_face_winding_changed(); - /** Call when new edges and vertices have been created but vertices and faces haven't changed. */ - void tag_edges_split(); - /** Call for topology updates not described by other update tags. */ - void tag_topology_changed(); -#endif -} Mesh; - -/* deprecated by MTFace, only here for file reading */ -#ifdef DNA_DEPRECATED_ALLOW -typedef struct TFace { - DNA_DEFINE_CXX_METHODS(TFace) - - /** The faces image for the active UVLayer. */ - void *tpage; - float uv[4][2]; - unsigned int col[4]; - char flag, transp; - short mode, tile, unwrap; -} TFace; -#endif - -/* **************** MESH ********************* */ - -/** #Mesh.texspace_flag */ -enum { - ME_TEXSPACE_FLAG_AUTO = 1 << 0, - ME_TEXSPACE_FLAG_AUTO_EVALUATED = 1 << 1, -}; - -/** #Mesh.editflag */ -enum { - ME_EDIT_MIRROR_VERTEX_GROUPS = 1 << 0, - ME_EDIT_MIRROR_Y = 1 << 1, /* unused so far */ - ME_EDIT_MIRROR_Z = 1 << 2, /* unused so far */ - - ME_EDIT_PAINT_FACE_SEL = 1 << 3, - ME_EDIT_MIRROR_TOPO = 1 << 4, - ME_EDIT_PAINT_VERT_SEL = 1 << 5, -}; - -/* Helper macro to see if vertex group X mirror is on. */ -#define ME_USING_MIRROR_X_VERTEX_GROUPS(_me) \ - (((_me)->editflag & ME_EDIT_MIRROR_VERTEX_GROUPS) && ((_me)->symmetry & ME_SYMMETRY_X)) - -/* We can't have both flags enabled at once, - * flags defined in DNA_scene_types.h */ -#define ME_EDIT_PAINT_SEL_MODE(_me) \ - (((_me)->editflag & ME_EDIT_PAINT_FACE_SEL) ? SCE_SELECT_FACE : \ - ((_me)->editflag & ME_EDIT_PAINT_VERT_SEL) ? SCE_SELECT_VERTEX : \ - 0) - -/** #Mesh.flag */ -enum { - ME_FLAG_UNUSED_0 = 1 << 0, /* cleared */ - ME_FLAG_UNUSED_1 = 1 << 1, /* cleared */ - ME_FLAG_DEPRECATED_2 = 1 << 2, /* deprecated */ - ME_FLAG_UNUSED_3 = 1 << 3, /* cleared */ - ME_FLAG_UNUSED_4 = 1 << 4, /* cleared */ - ME_AUTOSMOOTH_LEGACY = 1 << 5, /* deprecated */ - ME_FLAG_UNUSED_6 = 1 << 6, /* cleared */ - ME_FLAG_UNUSED_7 = 1 << 7, /* cleared */ - ME_REMESH_REPROJECT_ATTRIBUTES = 1 << 8, - ME_DS_EXPAND = 1 << 9, - ME_SCULPT_DYNAMIC_TOPOLOGY = 1 << 10, - /** - * Used to tag that the mesh has no overlapping topology (see #Mesh::no_overlapping_topology()). - * Theoretically this is runtime data that could always be recalculated, but since the intent is - * to improve performance and it only takes one bit, it is stored in the mesh instead. - */ - ME_NO_OVERLAPPING_TOPOLOGY = 1 << 11, - ME_FLAG_UNUSED_8 = 1 << 12, /* deprecated */ - ME_REMESH_FIX_POLES = 1 << 13, - ME_REMESH_REPROJECT_VOLUME = 1 << 14, - ME_FLAG_UNUSED_9 = 1 << 15, /* deprecated */ -}; - -#ifdef DNA_DEPRECATED_ALLOW -/** #Mesh.cd_flag */ -enum { - ME_CDFLAG_VERT_BWEIGHT = 1 << 0, - ME_CDFLAG_EDGE_BWEIGHT = 1 << 1, - ME_CDFLAG_EDGE_CREASE = 1 << 2, - ME_CDFLAG_VERT_CREASE = 1 << 3, -}; -#endif - -/** #Mesh.remesh_mode */ -enum { - REMESH_VOXEL = 0, - REMESH_QUAD = 1, -}; - -/** #SubsurfModifierData.subdivType */ -enum { - ME_CC_SUBSURF = 0, - ME_SIMPLE_SUBSURF = 1, -}; - -/** #Mesh.symmetry */ -typedef enum eMeshSymmetryType { - ME_SYMMETRY_X = 1 << 0, - ME_SYMMETRY_Y = 1 << 1, - ME_SYMMETRY_Z = 1 << 2, -} eMeshSymmetryType; - -#define MESH_MAX_VERTS 2000000000L diff --git a/BlenderMalt/CBlenderMalt/blender_dna/DNA_meshdata_types.h b/BlenderMalt/CBlenderMalt/blender_dna/DNA_meshdata_types.h deleted file mode 100644 index 24dff6b3..00000000 --- a/BlenderMalt/CBlenderMalt/blender_dna/DNA_meshdata_types.h +++ /dev/null @@ -1,442 +0,0 @@ -/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved. - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup DNA - */ - -#pragma once - -#include "BLI_sys_types.h" - -/* -------------------------------------------------------------------- */ -/** \name Ordered Selection Storage - * \{ */ - -/** - * Optionally store the order of selected elements. - * This won't always be set since only some selection operations have an order. - * - * Typically accessed from #Mesh.mselect - */ -typedef struct MSelect { - /** Index in the vertex, edge or polygon array. */ - int index; - /** #ME_VSEL, #ME_ESEL, #ME_FSEL. */ - int type; -} MSelect; - -/** #MSelect.type */ -enum { - ME_VSEL = 0, - ME_ESEL = 1, - ME_FSEL = 2, -}; - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Loop Tessellation Runtime Data - * \{ */ - -/** - * #Mesh::corner_tris() gives access to runtime triangulation data for #Mesh, for functionality - * that doesn't support ngons. - * - * Typical usage includes: - * - Viewport drawing. - * - #BVHTree creation. - * - Physics/collision detection. - * - * A mesh's triangulation data, which uses a cache that is lazily calculated from faces, corner - * vert, and position arrays. In rare cases it is calculated directly too, with - * #bke::mesh::corner_tris_calc. When the underlying mesh data changes, the array is recalculated - * from scratch; there is no extra attempt to maintain the validity over time. - * - * Triangles are stored in an array, where triangles from each face are stored sequentially. The - * triangles order is guaranteed to match the face order where the first triangle will always be - * from the first face, and the last triangle from the last face. The number of triangles for each - * polygon is guaranteed to be the corner count - 2, even for degenerate geometry (see - * #bke::mesh::face_triangles_num). - * - * Storing corner indices (instead of vertex indices) gives more flexibility for accessing mesh - * data stored per-corner, though it does often add an extra level of indirection. The index of the - * corresponding face for each triangle is stored in a separate array, accessed with - * #Mesh::corner_tri_faces(). - * - * Examples: - * \code{.cc} - * // Access vertex locations. - * std::array tri_positions{ - * positions[corner_verts[tri[0]]], - * positions[corner_verts[tri[1]]], - * positions[corner_verts[tri[2]]], - * }; - * - * // Access UV coordinates (works for all face corner data, vertex colors... etc). - * std::array tri_uvs{ - * uv_map[tri[0]], - * uv_map[tri[1]], - * uv_map[tri[2]], - * }; - * - * // Access all triangles in a given face. - * const IndexRange face = faces[i]; - * const Span corner_tris = corner_tris.slice(poly_to_tri_count(i, face.start()), - * bke::mesh::face_triangles_num(face.size())); - * \endcode - * - * It may also be useful to check whether or not two vertices of a triangle form an edge in the - * underlying mesh. See #bke::mesh::corner_tri for a utility that does this. Note - * that a triangle may be in the middle of an ngon and not reference **any** - * real edges. - */ - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Custom Data (Generic) - * \{ */ - -/** Custom Data Properties */ -typedef struct MFloatProperty { - float f; -} MFloatProperty; -typedef struct MIntProperty { - int i; -} MIntProperty; -typedef struct MStringProperty { - char s[255], s_len; -} MStringProperty; -typedef struct MBoolProperty { - uint8_t b; -} MBoolProperty; -typedef struct MInt8Property { - int8_t i; -} MInt8Property; - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Custom Data (Vertex) - * \{ */ - -/** - * Vertex group index and weight for #MDeformVert.dw - */ -typedef struct MDeformWeight { - /** The index for the vertex group, must *always* be unique when in an array. */ - unsigned int def_nr; - /** Weight between 0.0 and 1.0. */ - float weight; -} MDeformWeight; - -/** - * Stores all of an element's vertex groups, and their weight values. - */ -typedef struct MDeformVert { - /** - * Array of weight indices and values. - * - There must not be any duplicate #def_nr indices. - * - Groups in the array are unordered. - * - Indices outside the usable range of groups are ignored. - */ - struct MDeformWeight *dw; - /** - * The length of the #dw array. - * \note This is not necessarily the same length as the total number of vertex groups. - * However, generally it isn't larger. - */ - int totweight; - /** Flag is only in use as a run-time tag at the moment. */ - int flag; -} MDeformVert; - -typedef struct MVertSkin { - /** - * Radii of the skin, define how big the generated frames are. - * Currently only the first two elements are used. - */ - float radius[3]; - - /** #eMVertSkinFlag */ - int flag; -} MVertSkin; - -typedef enum eMVertSkinFlag { - /** - * Marks a vertex as the edge-graph root, used for calculating rotations for all connected - * edges (recursively). Also used to choose a root when generating an armature. - */ - MVERT_SKIN_ROOT = 1, - - /** - * Marks a branch vertex (vertex with more than two connected edges), so that its neighbors - * are directly hulled together, rather than the default of generating intermediate frames. - */ - MVERT_SKIN_LOOSE = 2, -} eMVertSkinFlag; - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Custom Data (Loop) - * \{ */ - -/** - * \note While alpha is not currently in the 3D Viewport, - * this may eventually be added back, keep this value set to 255. - */ -typedef struct MLoopCol { - unsigned char r, g, b, a; -} MLoopCol; - -typedef struct MPropCol { - float color[4]; -} MPropCol; - -/** Multi-Resolution loop data. */ -typedef struct MDisps { - /* Strange bug in SDNA: if disps pointer comes first, it fails to see totdisp */ - int totdisp; - int level; - float (*disps)[3]; - - /** - * Used for hiding parts of a multires mesh. - * Essentially the multires equivalent of the mesh ".hide_vert" boolean attribute. - * - * \note This is a bitmap, keep in sync with type used in BLI_bitmap.h - */ - unsigned int *hidden; -} MDisps; - -/** Multi-Resolution grid loop data. */ -typedef struct GridPaintMask { - /** - * The data array contains `grid_size * grid_size` elements. - * Where `grid_size = (1 << (level - 1)) + 1`. - */ - float *data; - - /** The maximum multires level associated with this grid. */ - unsigned int level; - - char _pad[4]; -} GridPaintMask; - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Custom Data (Original Space for Poly, Face) - * \{ */ - -/** - * Original space within a face (similar to UV coordinates), - * however they are used to determine the original position in a face. - * - * Unlike UVs these are not user editable and always start out using a fixed 0-1 range. - * Currently only used for particle placement. - */ -# -# -typedef struct OrigSpaceFace { - float uv[4][2]; -} OrigSpaceFace; - -# -# -typedef struct OrigSpaceLoop { - float uv[2]; -} OrigSpaceLoop; - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Custom Data (FreeStyle for Edge, Face) - * \{ */ - -typedef struct FreestyleEdge { - char flag; -} FreestyleEdge; - -/** #FreestyleEdge.flag */ -enum { - FREESTYLE_EDGE_MARK = 1, -}; - -typedef struct FreestyleFace { - char flag; -} FreestyleFace; - -/** #FreestyleFace.flag */ -enum { - FREESTYLE_FACE_MARK = 1, -}; - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Deprecated Structs - * \{ */ - -#ifdef DNA_DEPRECATED_ALLOW - -/** - * Mesh Edges. - * - * Typically accessed with #Mesh.edges() - */ -typedef struct MEdge { - /** Un-ordered vertex indices (cannot match). */ - unsigned int v1, v2; - /** Deprecated edge crease, now located in `edge_crease`, except for file read and write. */ - char crease_legacy; - /** - * Deprecated bevel weight storage, now located in #CD_BWEIGHT, except for file read and write. - */ - char bweight_legacy; - short flag_legacy; -} MEdge; - -/** #MEdge.flag */ -enum { - /** Deprecated selection status. Now stored in ".select_edge" attribute. */ - /* SELECT = (1 << 0), */ - ME_SEAM = (1 << 2), - /** Deprecated hide status. Now stored in ".hide_edge" attribute. */ - /* ME_HIDE = (1 << 4), */ - /** Deprecated loose edge status. Now stored in #Mesh::loose_edges() runtime cache. */ - ME_LOOSEEDGE = (1 << 7), - /** Deprecated sharp edge status. Now stored in "sharp_edge" attribute. */ - ME_SHARP = (1 << 9), -}; - -/** - * Mesh Faces. - * This only stores the polygon size & flags, the vertex & edge indices are stored in the "corner - * edges" array. - * - * Typically accessed with #Mesh.faces(). - */ -typedef struct MPoly { - /** Offset into loop array and number of loops in the face. */ - int loopstart; - /** Keep signed since we need to subtract when getting the previous loop. */ - int totloop; - /** Deprecated material index. Now stored in the "material_index" attribute, but kept for IO. */ - short mat_nr_legacy; - char flag_legacy, _pad; -} MPoly; - -/** #MPoly.flag */ -enum { - /** Deprecated smooth shading status. Now stored reversed in "sharp_face" attribute. */ - ME_SMOOTH = (1 << 0), - /** Deprecated selection status. Now stored in ".select_poly" attribute. */ - ME_FACE_SEL = (1 << 1), - /** Deprecated hide status. Now stored in ".hide_poly" attribute. */ - /* ME_HIDE = (1 << 4), */ -}; - -/** - * UV coordinate for a polygon face & flag for selection & other options. - * Deprecated, but kept to read old files. UV coordinates are now stored as #CD_PROP_FLOAT2 layers. - */ -typedef struct MLoopUV { - float uv[2]; - int flag; -} MLoopUV; - -/** #MLoopUV.flag */ -enum { - MLOOPUV_EDGESEL = (1 << 0), - MLOOPUV_VERTSEL = (1 << 1), - MLOOPUV_PINNED = (1 << 2), -}; - -/** - * Deprecated mesh vertex data structure. Now stored with generic attributes. - */ -typedef struct MVert { - float co_legacy[3]; - /** - * Deprecated flag for storing hide status and selection, which are now stored in separate - * generic attributes. Kept for file read and write. - */ - char flag_legacy; - /** - * Deprecated bevel weight storage, now located in #CD_BWEIGHT, except for file read and write. - */ - char bweight_legacy; - char _pad[2]; -} MVert; - -/** #MVert.flag */ -enum { - /** Deprecated selection status. Now stored in ".select_vert" attribute. */ - /* SELECT = (1 << 0), */ - /** Deprecated hide status. Now stored in ".hide_vert" attribute. */ - ME_HIDE = (1 << 4), -}; - -/** - * Mesh Face Corners. - * Deprecated storage for the vertex of a face corner and the following edge. - * Replaced by the "corner_verts" and "corner_edges" arrays. - */ -typedef struct MLoop { - /** Vertex index. */ - unsigned int v; - /** Edge index into an #MEdge array. */ - unsigned int e; -} MLoop; - -#endif - -/** - * Used in Blender pre 2.63, See #Mesh::corner_verts(), #Mesh::faces() for face data stored in the - * blend file. Use for reading old files and in a handful of cases which should be removed - * eventually. - */ -typedef struct MFace { - unsigned int v1, v2, v3, v4; - short mat_nr; - /** We keep edcode, for conversion to edges draw flags in old files. */ - char edcode, flag; -} MFace; - -/** #MFace.edcode */ -enum { - ME_V1V2 = (1 << 0), - ME_V2V3 = (1 << 1), - ME_V3V1 = (1 << 2), - ME_V3V4 = ME_V3V1, - ME_V4V1 = (1 << 3), -}; - -/** Tessellation uv face data. */ -typedef struct MTFace { - float uv[4][2]; -} MTFace; - -/** - * Tessellation vertex color data. - * - * \note The red and blue are swapped for historical reasons. - */ -typedef struct MCol { - unsigned char a, r, g, b; -} MCol; - -#ifdef DNA_DEPRECATED_ALLOW - -/** Old game engine recast navigation data, while unused 2.7x files may contain this. */ -typedef struct MRecast { - int i; -} MRecast; - -#endif - -/** \} */ diff --git a/BlenderMalt/CBlenderMalt/blender_dna/DNA_session_uid_types.h b/BlenderMalt/CBlenderMalt/blender_dna/DNA_session_uid_types.h deleted file mode 100644 index 3e3f380f..00000000 --- a/BlenderMalt/CBlenderMalt/blender_dna/DNA_session_uid_types.h +++ /dev/null @@ -1,26 +0,0 @@ -/* SPDX-FileCopyrightText: 2023 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup DNA - */ - -#pragma once - -#include "BLI_sys_types.h" - -/** - * Is a structure because of the following considerations: - * - * - It is not possible to use custom types in DNA members: `makesdna` does not recognize them. - * - It allows to add more bits, more than standard fixed-size types can store. For example, if - * we ever need to go 128 bits, it is as simple as adding extra 64bit field. - */ -typedef struct SessionUID { - /** - * Never access directly, as it might cause a headache when more bits are needed: if the field - * is used directly it will not be easy to find all places where partial access is used. - */ - uint64_t uid_; -} SessionUID; diff --git a/BlenderMalt/CBlenderMalt/mikktspace.c b/BlenderMalt/CBlenderMalt/mikktspace.c new file mode 100644 index 00000000..0342ae01 --- /dev/null +++ b/BlenderMalt/CBlenderMalt/mikktspace.c @@ -0,0 +1,1899 @@ +/** \file mikktspace/mikktspace.c + * \ingroup mikktspace + */ +/** + * Copyright (C) 2011 by Morten S. Mikkelsen + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#include +#include +#include +#include +#include +#include + +#include "mikktspace.h" + +#define TFALSE 0 +#define TTRUE 1 + +#ifndef M_PI +#define M_PI 3.1415926535897932384626433832795 +#endif + +#define INTERNAL_RND_SORT_SEED 39871946 + +// internal structure +typedef struct { + float x, y, z; +} SVec3; + +static tbool veq( const SVec3 v1, const SVec3 v2 ) +{ + return (v1.x == v2.x) && (v1.y == v2.y) && (v1.z == v2.z); +} + +static SVec3 vadd( const SVec3 v1, const SVec3 v2 ) +{ + SVec3 vRes; + + vRes.x = v1.x + v2.x; + vRes.y = v1.y + v2.y; + vRes.z = v1.z + v2.z; + + return vRes; +} + + +static SVec3 vsub( const SVec3 v1, const SVec3 v2 ) +{ + SVec3 vRes; + + vRes.x = v1.x - v2.x; + vRes.y = v1.y - v2.y; + vRes.z = v1.z - v2.z; + + return vRes; +} + +static SVec3 vscale(const float fS, const SVec3 v) +{ + SVec3 vRes; + + vRes.x = fS * v.x; + vRes.y = fS * v.y; + vRes.z = fS * v.z; + + return vRes; +} + +static float LengthSquared( const SVec3 v ) +{ + return v.x*v.x + v.y*v.y + v.z*v.z; +} + +static float Length( const SVec3 v ) +{ + return sqrtf(LengthSquared(v)); +} + +static SVec3 Normalize( const SVec3 v ) +{ + return vscale(1 / Length(v), v); +} + +static float vdot( const SVec3 v1, const SVec3 v2) +{ + return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z; +} + + +static tbool NotZero(const float fX) +{ + // could possibly use FLT_EPSILON instead + return fabsf(fX) > FLT_MIN; +} + +static tbool VNotZero(const SVec3 v) +{ + // might change this to an epsilon based test + return NotZero(v.x) || NotZero(v.y) || NotZero(v.z); +} + + + +typedef struct { + int iNrFaces; + int * pTriMembers; +} SSubGroup; + +typedef struct { + int iNrFaces; + int * pFaceIndices; + int iVertexRepresentitive; + tbool bOrientPreservering; +} SGroup; + +// +#define MARK_DEGENERATE 1 +#define QUAD_ONE_DEGEN_TRI 2 +#define GROUP_WITH_ANY 4 +#define ORIENT_PRESERVING 8 + + + +typedef struct { + int FaceNeighbors[3]; + SGroup * AssignedGroup[3]; + + // normalized first order face derivatives + SVec3 vOs, vOt; + float fMagS, fMagT; // original magnitudes + + // determines if the current and the next triangle are a quad. + int iOrgFaceNumber; + int iFlag, iTSpacesOffs; + unsigned char vert_num[4]; +} STriInfo; + +typedef struct { + SVec3 vOs; + float fMagS; + SVec3 vOt; + float fMagT; + int iCounter; // this is to average back into quads. + tbool bOrient; +} STSpace; + +static int GenerateInitialVerticesIndexList(STriInfo pTriInfos[], int piTriList_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn); +static void GenerateSharedVerticesIndexList(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn); +static void InitTriInfo(STriInfo pTriInfos[], const int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn); +static int Build4RuleGroups(STriInfo pTriInfos[], SGroup pGroups[], int piGroupTrianglesBuffer[], const int piTriListIn[], const int iNrTrianglesIn); +static tbool GenerateTSpaces(STSpace psTspace[], const STriInfo pTriInfos[], const SGroup pGroups[], + const int iNrActiveGroups, const int piTriListIn[], const float fThresCos, + const SMikkTSpaceContext * pContext); + +static int MakeIndex(const int iFace, const int iVert) +{ + assert(iVert>=0 && iVert<4 && iFace>=0); + return (iFace<<2) | (iVert&0x3); +} + +static void IndexToData(int * piFace, int * piVert, const int iIndexIn) +{ + piVert[0] = iIndexIn&0x3; + piFace[0] = iIndexIn>>2; +} + +static STSpace AvgTSpace(const STSpace * pTS0, const STSpace * pTS1) +{ + STSpace ts_res; + + // this if is important. Due to floating point precision + // averaging when ts0==ts1 will cause a slight difference + // which results in tangent space splits later on + if (pTS0->fMagS==pTS1->fMagS && pTS0->fMagT==pTS1->fMagT && + veq(pTS0->vOs,pTS1->vOs) && veq(pTS0->vOt, pTS1->vOt)) + { + ts_res.fMagS = pTS0->fMagS; + ts_res.fMagT = pTS0->fMagT; + ts_res.vOs = pTS0->vOs; + ts_res.vOt = pTS0->vOt; + } + else + { + ts_res.fMagS = 0.5f*(pTS0->fMagS+pTS1->fMagS); + ts_res.fMagT = 0.5f*(pTS0->fMagT+pTS1->fMagT); + ts_res.vOs = vadd(pTS0->vOs,pTS1->vOs); + ts_res.vOt = vadd(pTS0->vOt,pTS1->vOt); + if ( VNotZero(ts_res.vOs) ) ts_res.vOs = Normalize(ts_res.vOs); + if ( VNotZero(ts_res.vOt) ) ts_res.vOt = Normalize(ts_res.vOt); + } + + return ts_res; +} + + + +static SVec3 GetPosition(const SMikkTSpaceContext * pContext, const int index); +static SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index); +static SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index); + + +// degen triangles +static void DegenPrologue(STriInfo pTriInfos[], int piTriList_out[], const int iNrTrianglesIn, const int iTotTris); +static void DegenEpilogue(STSpace psTspace[], STriInfo pTriInfos[], int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn, const int iTotTris); + + +tbool genTangSpaceDefault(const SMikkTSpaceContext * pContext) +{ + return genTangSpace(pContext, 180.0f); +} + +tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThreshold) +{ + // count nr_triangles + int * piTriListIn = NULL, * piGroupTrianglesBuffer = NULL; + STriInfo * pTriInfos = NULL; + SGroup * pGroups = NULL; + STSpace * psTspace = NULL; + int iNrTrianglesIn = 0, f=0, t=0, i=0; + int iNrTSPaces = 0, iTotTris = 0, iDegenTriangles = 0, iNrMaxGroups = 0; + int iNrActiveGroups = 0, index = 0; + const int iNrFaces = pContext->m_pInterface->m_getNumFaces(pContext); + tbool bRes = TFALSE; + const float fThresCos = (float) cos((fAngularThreshold*(float)M_PI)/180.0f); + + // verify all call-backs have been set + if ( pContext->m_pInterface->m_getNumFaces==NULL || + pContext->m_pInterface->m_getNumVerticesOfFace==NULL || + pContext->m_pInterface->m_getPosition==NULL || + pContext->m_pInterface->m_getNormal==NULL || + pContext->m_pInterface->m_getTexCoord==NULL ) + return TFALSE; + + // count triangles on supported faces + for (f=0; fm_pInterface->m_getNumVerticesOfFace(pContext, f); + if (verts==3) ++iNrTrianglesIn; + else if (verts==4) iNrTrianglesIn += 2; + } + if (iNrTrianglesIn<=0) return TFALSE; + + // allocate memory for an index list + piTriListIn = (int *) malloc(sizeof(int)*3*iNrTrianglesIn); + pTriInfos = (STriInfo *) malloc(sizeof(STriInfo)*iNrTrianglesIn); + if (piTriListIn==NULL || pTriInfos==NULL) + { + if (piTriListIn!=NULL) free(piTriListIn); + if (pTriInfos!=NULL) free(pTriInfos); + return TFALSE; + } + + // make an initial triangle --> face index list + iNrTSPaces = GenerateInitialVerticesIndexList(pTriInfos, piTriListIn, pContext, iNrTrianglesIn); + + // make a welded index list of identical positions and attributes (pos, norm, texc) + //printf("gen welded index list begin\n"); + GenerateSharedVerticesIndexList(piTriListIn, pContext, iNrTrianglesIn); + //printf("gen welded index list end\n"); + + // Mark all degenerate triangles + iTotTris = iNrTrianglesIn; + iDegenTriangles = 0; + for (t=0; tm_pInterface->m_getNumVerticesOfFace(pContext, f); + if (verts!=3 && verts!=4) continue; + + + // I've decided to let degenerate triangles and group-with-anythings + // vary between left/right hand coordinate systems at the vertices. + // All healthy triangles on the other hand are built to always be either or. + + /*// force the coordinate system orientation to be uniform for every face. + // (this is already the case for good triangles but not for + // degenerate ones and those with bGroupWithAnything==true) + bool bOrient = psTspace[index].bOrient; + if (psTspace[index].iCounter == 0) // tspace was not derived from a group + { + // look for a space created in GenerateTSpaces() by iCounter>0 + bool bNotFound = true; + int i=1; + while (i 0) bNotFound=false; + else ++i; + } + if (!bNotFound) bOrient = psTspace[index+i].bOrient; + }*/ + + // set data + for (i=0; ivOs.x, pTSpace->vOs.y, pTSpace->vOs.z}; + float bitang[] = {pTSpace->vOt.x, pTSpace->vOt.y, pTSpace->vOt.z}; + if (pContext->m_pInterface->m_setTSpace!=NULL) + pContext->m_pInterface->m_setTSpace(pContext, tang, bitang, pTSpace->fMagS, pTSpace->fMagT, pTSpace->bOrient, f, i); + if (pContext->m_pInterface->m_setTSpaceBasic!=NULL) + pContext->m_pInterface->m_setTSpaceBasic(pContext, tang, pTSpace->bOrient==TTRUE ? 1.0f : (-1.0f), f, i); + + ++index; + } + } + + free(psTspace); + + + return TTRUE; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef struct { + float vert[3]; + int index; +} STmpVert; + +static const int g_iCells = 2048; + +#ifdef _MSC_VER +# define NOINLINE __declspec(noinline) +#else +# define NOINLINE __attribute__ ((noinline)) +#endif + +// it is IMPORTANT that this function is called to evaluate the hash since +// inlining could potentially reorder instructions and generate different +// results for the same effective input value fVal. +static NOINLINE int FindGridCell(const float fMin, const float fMax, const float fVal) +{ + const float fIndex = g_iCells * ((fVal-fMin)/(fMax-fMin)); + const int iIndex = (int)fIndex; + return iIndex < g_iCells ? (iIndex >= 0 ? iIndex : 0) : (g_iCells - 1); +} + +static void MergeVertsFast(int piTriList_in_and_out[], STmpVert pTmpVert[], const SMikkTSpaceContext * pContext, const int iL_in, const int iR_in); +static void MergeVertsSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int pTable[], const int iEntries); +static void GenerateSharedVerticesIndexListSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn); + +static void GenerateSharedVerticesIndexList(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn) +{ + + // Generate bounding box + int * piHashTable=NULL, * piHashCount=NULL, * piHashOffsets=NULL, * piHashCount2=NULL; + STmpVert * pTmpVert = NULL; + int i=0, iChannel=0, k=0, e=0; + int iMaxCount=0; + SVec3 vMin = GetPosition(pContext, 0), vMax = vMin, vDim; + float fMin, fMax; + for (i=1; i<(iNrTrianglesIn*3); i++) + { + const int index = piTriList_in_and_out[i]; + + const SVec3 vP = GetPosition(pContext, index); + if (vMin.x > vP.x) vMin.x = vP.x; + else if (vMax.x < vP.x) vMax.x = vP.x; + if (vMin.y > vP.y) vMin.y = vP.y; + else if (vMax.y < vP.y) vMax.y = vP.y; + if (vMin.z > vP.z) vMin.z = vP.z; + else if (vMax.z < vP.z) vMax.z = vP.z; + } + + vDim = vsub(vMax,vMin); + iChannel = 0; + fMin = vMin.x; fMax=vMax.x; + if (vDim.y>vDim.x && vDim.y>vDim.z) + { + iChannel=1; + fMin = vMin.y; + fMax = vMax.y; + } + else if (vDim.z>vDim.x) + { + iChannel=2; + fMin = vMin.z; + fMax = vMax.z; + } + + // make allocations + piHashTable = (int *) malloc(sizeof(int)*iNrTrianglesIn*3); + piHashCount = (int *) malloc(sizeof(int)*g_iCells); + piHashOffsets = (int *) malloc(sizeof(int)*g_iCells); + piHashCount2 = (int *) malloc(sizeof(int)*g_iCells); + + if (piHashTable==NULL || piHashCount==NULL || piHashOffsets==NULL || piHashCount2==NULL) + { + if (piHashTable!=NULL) free(piHashTable); + if (piHashCount!=NULL) free(piHashCount); + if (piHashOffsets!=NULL) free(piHashOffsets); + if (piHashCount2!=NULL) free(piHashCount2); + GenerateSharedVerticesIndexListSlow(piTriList_in_and_out, pContext, iNrTrianglesIn); + return; + } + memset(piHashCount, 0, sizeof(int)*g_iCells); + memset(piHashCount2, 0, sizeof(int)*g_iCells); + + // count amount of elements in each cell unit + for (i=0; i<(iNrTrianglesIn*3); i++) + { + const int index = piTriList_in_and_out[i]; + const SVec3 vP = GetPosition(pContext, index); + const float fVal = iChannel==0 ? vP.x : (iChannel==1 ? vP.y : vP.z); + const int iCell = FindGridCell(fMin, fMax, fVal); + ++piHashCount[iCell]; + } + + // evaluate start index of each cell. + piHashOffsets[0]=0; + for (k=1; kpTmpVert[l].vert[c]) fvMin[c]=pTmpVert[l].vert[c]; + if (fvMax[c]dx && dy>dz) channel=1; + else if (dz>dx) channel=2; + + fSep = 0.5f*(fvMax[channel]+fvMin[channel]); + + // stop if all vertices are NaNs + if (!isfinite(fSep)) + return; + + // terminate recursion when the separation/average value + // is no longer strictly between fMin and fMax values. + if (fSep>=fvMax[channel] || fSep<=fvMin[channel]) + { + // complete the weld + for (l=iL_in; l<=iR_in; l++) + { + int i = pTmpVert[l].index; + const int index = piTriList_in_and_out[i]; + const SVec3 vP = GetPosition(pContext, index); + const SVec3 vN = GetNormal(pContext, index); + const SVec3 vT = GetTexCoord(pContext, index); + + tbool bNotFound = TTRUE; + int l2=iL_in, i2rec=-1; + while (l20); // at least 2 entries + + // separate (by fSep) all points between iL_in and iR_in in pTmpVert[] + while (iL < iR) + { + tbool bReadyLeftSwap = TFALSE, bReadyRightSwap = TFALSE; + while ((!bReadyLeftSwap) && iL=iL_in && iL<=iR_in); + bReadyLeftSwap = !(pTmpVert[iL].vert[channel]=iL_in && iR<=iR_in); + bReadyRightSwap = pTmpVert[iR].vert[channel]m_pInterface->m_getNumFaces(pContext); f++) + { + const int verts = pContext->m_pInterface->m_getNumVerticesOfFace(pContext, f); + if (verts!=3 && verts!=4) continue; + + pTriInfos[iDstTriIndex].iOrgFaceNumber = f; + pTriInfos[iDstTriIndex].iTSpacesOffs = iTSpacesOffs; + + if (verts==3) + { + unsigned char * pVerts = pTriInfos[iDstTriIndex].vert_num; + pVerts[0]=0; pVerts[1]=1; pVerts[2]=2; + piTriList_out[iDstTriIndex*3+0] = MakeIndex(f, 0); + piTriList_out[iDstTriIndex*3+1] = MakeIndex(f, 1); + piTriList_out[iDstTriIndex*3+2] = MakeIndex(f, 2); + ++iDstTriIndex; // next + } + else + { + { + pTriInfos[iDstTriIndex+1].iOrgFaceNumber = f; + pTriInfos[iDstTriIndex+1].iTSpacesOffs = iTSpacesOffs; + } + + { + // need an order independent way to evaluate + // tspace on quads. This is done by splitting + // along the shortest diagonal. + const int i0 = MakeIndex(f, 0); + const int i1 = MakeIndex(f, 1); + const int i2 = MakeIndex(f, 2); + const int i3 = MakeIndex(f, 3); + const SVec3 T0 = GetTexCoord(pContext, i0); + const SVec3 T1 = GetTexCoord(pContext, i1); + const SVec3 T2 = GetTexCoord(pContext, i2); + const SVec3 T3 = GetTexCoord(pContext, i3); + const float distSQ_02 = LengthSquared(vsub(T2,T0)); + const float distSQ_13 = LengthSquared(vsub(T3,T1)); + tbool bQuadDiagIs_02; + if (distSQ_02m_pInterface->m_getPosition(pContext, pos, iF, iI); + res.x=pos[0]; res.y=pos[1]; res.z=pos[2]; + return res; +} + +static SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index) +{ + int iF, iI; + SVec3 res; float norm[3]; + IndexToData(&iF, &iI, index); + pContext->m_pInterface->m_getNormal(pContext, norm, iF, iI); + res.x=norm[0]; res.y=norm[1]; res.z=norm[2]; + return res; +} + +static SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index) +{ + int iF, iI; + SVec3 res; float texc[2]; + IndexToData(&iF, &iI, index); + pContext->m_pInterface->m_getTexCoord(pContext, texc, iF, iI); + res.x=texc[0]; res.y=texc[1]; res.z=1.0f; + return res; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef union { + struct + { + int i0, i1, f; + }; + int array[3]; +} SEdge; + +static void BuildNeighborsFast(STriInfo pTriInfos[], SEdge * pEdges, const int piTriListIn[], const int iNrTrianglesIn); +static void BuildNeighborsSlow(STriInfo pTriInfos[], const int piTriListIn[], const int iNrTrianglesIn); + +// returns the texture area times 2 +static float CalcTexArea(const SMikkTSpaceContext * pContext, const int indices[]) +{ + const SVec3 t1 = GetTexCoord(pContext, indices[0]); + const SVec3 t2 = GetTexCoord(pContext, indices[1]); + const SVec3 t3 = GetTexCoord(pContext, indices[2]); + + const float t21x = t2.x-t1.x; + const float t21y = t2.y-t1.y; + const float t31x = t3.x-t1.x; + const float t31y = t3.y-t1.y; + + const float fSignedAreaSTx2 = t21x*t31y - t21y*t31x; + + return fSignedAreaSTx2<0 ? (-fSignedAreaSTx2) : fSignedAreaSTx2; +} + +static void InitTriInfo(STriInfo pTriInfos[], const int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn) +{ + int f=0, i=0, t=0; + // pTriInfos[f].iFlag is cleared in GenerateInitialVerticesIndexList() which is called before this function. + + // generate neighbor info list + for (f=0; f0 ? ORIENT_PRESERVING : 0); + + if ( NotZero(fSignedAreaSTx2) ) + { + const float fAbsArea = fabsf(fSignedAreaSTx2); + const float fLenOs = Length(vOs); + const float fLenOt = Length(vOt); + const float fS = (pTriInfos[f].iFlag&ORIENT_PRESERVING)==0 ? (-1.0f) : 1.0f; + if ( NotZero(fLenOs) ) pTriInfos[f].vOs = vscale(fS/fLenOs, vOs); + if ( NotZero(fLenOt) ) pTriInfos[f].vOt = vscale(fS/fLenOt, vOt); + + // evaluate magnitudes prior to normalization of vOs and vOt + pTriInfos[f].fMagS = fLenOs / fAbsArea; + pTriInfos[f].fMagT = fLenOt / fAbsArea; + + // if this is a good triangle + if ( NotZero(pTriInfos[f].fMagS) && NotZero(pTriInfos[f].fMagT)) + pTriInfos[f].iFlag &= (~GROUP_WITH_ANY); + } + } + + // force otherwise healthy quads to a fixed orientation + while (t<(iNrTrianglesIn-1)) + { + const int iFO_a = pTriInfos[t].iOrgFaceNumber; + const int iFO_b = pTriInfos[t+1].iOrgFaceNumber; + if (iFO_a==iFO_b) // this is a quad + { + const tbool bIsDeg_a = (pTriInfos[t].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE; + const tbool bIsDeg_b = (pTriInfos[t+1].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE; + + // bad triangles should already have been removed by + // DegenPrologue(), but just in case check bIsDeg_a and bIsDeg_a are false + if ((bIsDeg_a||bIsDeg_b)==TFALSE) + { + const tbool bOrientA = (pTriInfos[t].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + const tbool bOrientB = (pTriInfos[t+1].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + // if this happens the quad has extremely bad mapping!! + if (bOrientA!=bOrientB) + { + //printf("found quad with bad mapping\n"); + tbool bChooseOrientFirstTri = TFALSE; + if ((pTriInfos[t+1].iFlag&GROUP_WITH_ANY)!=0) bChooseOrientFirstTri = TTRUE; + else if ( CalcTexArea(pContext, &piTriListIn[t*3+0]) >= CalcTexArea(pContext, &piTriListIn[(t+1)*3+0]) ) + bChooseOrientFirstTri = TTRUE; + + // force match + { + const int t0 = bChooseOrientFirstTri ? t : (t+1); + const int t1 = bChooseOrientFirstTri ? (t+1) : t; + pTriInfos[t1].iFlag &= (~ORIENT_PRESERVING); // clear first + pTriInfos[t1].iFlag |= (pTriInfos[t0].iFlag&ORIENT_PRESERVING); // copy bit + } + } + } + t += 2; + } + else + ++t; + } + + // match up edge pairs + { + SEdge * pEdges = (SEdge *) malloc(sizeof(SEdge)*iNrTrianglesIn*3); + if (pEdges==NULL) + BuildNeighborsSlow(pTriInfos, piTriListIn, iNrTrianglesIn); + else + { + BuildNeighborsFast(pTriInfos, pEdges, piTriListIn, iNrTrianglesIn); + + free(pEdges); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + +static tbool AssignRecur(const int piTriListIn[], STriInfo psTriInfos[], const int iMyTriIndex, SGroup * pGroup); +static void AddTriToGroup(SGroup * pGroup, const int iTriIndex); + +static int Build4RuleGroups(STriInfo pTriInfos[], SGroup pGroups[], int piGroupTrianglesBuffer[], const int piTriListIn[], const int iNrTrianglesIn) +{ + const int iNrMaxGroups = iNrTrianglesIn*3; + int iNrActiveGroups = 0; + int iOffset = 0, f=0, i=0; + (void)iNrMaxGroups; /* quiet warnings in non debug mode */ + for (f=0; fiVertexRepresentitive = vert_index; + pTriInfos[f].AssignedGroup[i]->bOrientPreservering = (pTriInfos[f].iFlag&ORIENT_PRESERVING)!=0; + pTriInfos[f].AssignedGroup[i]->iNrFaces = 0; + pTriInfos[f].AssignedGroup[i]->pFaceIndices = &piGroupTrianglesBuffer[iOffset]; + ++iNrActiveGroups; + + AddTriToGroup(pTriInfos[f].AssignedGroup[i], f); + bOrPre = (pTriInfos[f].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + neigh_indexL = pTriInfos[f].FaceNeighbors[i]; + neigh_indexR = pTriInfos[f].FaceNeighbors[i>0?(i-1):2]; + if (neigh_indexL>=0) // neighbor + { + const tbool bAnswer = + AssignRecur(piTriListIn, pTriInfos, neigh_indexL, + pTriInfos[f].AssignedGroup[i] ); + + const tbool bOrPre2 = (pTriInfos[neigh_indexL].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + const tbool bDiff = bOrPre!=bOrPre2 ? TTRUE : TFALSE; + assert(bAnswer || bDiff); + (void)bAnswer, (void)bDiff; /* quiet warnings in non debug mode */ + } + if (neigh_indexR>=0) // neighbor + { + const tbool bAnswer = + AssignRecur(piTriListIn, pTriInfos, neigh_indexR, + pTriInfos[f].AssignedGroup[i] ); + + const tbool bOrPre2 = (pTriInfos[neigh_indexR].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + const tbool bDiff = bOrPre!=bOrPre2 ? TTRUE : TFALSE; + assert(bAnswer || bDiff); + (void)bAnswer, (void)bDiff; /* quiet warnings in non debug mode */ + } + + // update offset + iOffset += pTriInfos[f].AssignedGroup[i]->iNrFaces; + // since the groups are disjoint a triangle can never + // belong to more than 3 groups. Subsequently something + // is completely screwed if this assertion ever hits. + assert(iOffset <= iNrMaxGroups); + } + } + } + + return iNrActiveGroups; +} + +static void AddTriToGroup(SGroup * pGroup, const int iTriIndex) +{ + pGroup->pFaceIndices[pGroup->iNrFaces] = iTriIndex; + ++pGroup->iNrFaces; +} + +static tbool AssignRecur(const int piTriListIn[], STriInfo psTriInfos[], + const int iMyTriIndex, SGroup * pGroup) +{ + STriInfo * pMyTriInfo = &psTriInfos[iMyTriIndex]; + + // track down vertex + const int iVertRep = pGroup->iVertexRepresentitive; + const int * pVerts = &piTriListIn[3*iMyTriIndex+0]; + int i=-1; + if (pVerts[0]==iVertRep) i=0; + else if (pVerts[1]==iVertRep) i=1; + else if (pVerts[2]==iVertRep) i=2; + assert(i>=0 && i<3); + + // early out + if (pMyTriInfo->AssignedGroup[i] == pGroup) return TTRUE; + else if (pMyTriInfo->AssignedGroup[i]!=NULL) return TFALSE; + if ((pMyTriInfo->iFlag&GROUP_WITH_ANY)!=0) + { + // first to group with a group-with-anything triangle + // determines it's orientation. + // This is the only existing order dependency in the code!! + if ( pMyTriInfo->AssignedGroup[0] == NULL && + pMyTriInfo->AssignedGroup[1] == NULL && + pMyTriInfo->AssignedGroup[2] == NULL ) + { + pMyTriInfo->iFlag &= (~ORIENT_PRESERVING); + pMyTriInfo->iFlag |= (pGroup->bOrientPreservering ? ORIENT_PRESERVING : 0); + } + } + { + const tbool bOrient = (pMyTriInfo->iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + if (bOrient != pGroup->bOrientPreservering) return TFALSE; + } + + AddTriToGroup(pGroup, iMyTriIndex); + pMyTriInfo->AssignedGroup[i] = pGroup; + + { + const int neigh_indexL = pMyTriInfo->FaceNeighbors[i]; + const int neigh_indexR = pMyTriInfo->FaceNeighbors[i>0?(i-1):2]; + if (neigh_indexL>=0) + AssignRecur(piTriListIn, psTriInfos, neigh_indexL, pGroup); + if (neigh_indexR>=0) + AssignRecur(piTriListIn, psTriInfos, neigh_indexR, pGroup); + } + + + + return TTRUE; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + +static tbool CompareSubGroups(const SSubGroup * pg1, const SSubGroup * pg2); +static void QuickSort(int* pSortBuffer, int iLeft, int iRight, unsigned int uSeed); +static STSpace EvalTspace(int face_indices[], const int iFaces, const int piTriListIn[], const STriInfo pTriInfos[], const SMikkTSpaceContext * pContext, const int iVertexRepresentitive); + +static tbool GenerateTSpaces(STSpace psTspace[], const STriInfo pTriInfos[], const SGroup pGroups[], + const int iNrActiveGroups, const int piTriListIn[], const float fThresCos, + const SMikkTSpaceContext * pContext) +{ + STSpace * pSubGroupTspace = NULL; + SSubGroup * pUniSubGroups = NULL; + int * pTmpMembers = NULL; + int iMaxNrFaces=0, iUniqueTspaces=0, g=0, i=0; + for (g=0; giNrFaces; i++) // triangles + { + const int f = pGroup->pFaceIndices[i]; // triangle number + int index=-1, iVertIndex=-1, iOF_1=-1, iMembers=0, j=0, l=0; + SSubGroup tmp_group; + tbool bFound; + SVec3 n, vOs, vOt; + if (pTriInfos[f].AssignedGroup[0]==pGroup) index=0; + else if (pTriInfos[f].AssignedGroup[1]==pGroup) index=1; + else if (pTriInfos[f].AssignedGroup[2]==pGroup) index=2; + assert(index>=0 && index<3); + + iVertIndex = piTriListIn[f*3+index]; + assert(iVertIndex==pGroup->iVertexRepresentitive); + + // is normalized already + n = GetNormal(pContext, iVertIndex); + + // project + vOs = vsub(pTriInfos[f].vOs, vscale(vdot(n,pTriInfos[f].vOs), n)); + vOt = vsub(pTriInfos[f].vOt, vscale(vdot(n,pTriInfos[f].vOt), n)); + if ( VNotZero(vOs) ) vOs = Normalize(vOs); + if ( VNotZero(vOt) ) vOt = Normalize(vOt); + + // original face number + iOF_1 = pTriInfos[f].iOrgFaceNumber; + + iMembers = 0; + for (j=0; jiNrFaces; j++) + { + const int t = pGroup->pFaceIndices[j]; // triangle number + const int iOF_2 = pTriInfos[t].iOrgFaceNumber; + + // project + SVec3 vOs2 = vsub(pTriInfos[t].vOs, vscale(vdot(n,pTriInfos[t].vOs), n)); + SVec3 vOt2 = vsub(pTriInfos[t].vOt, vscale(vdot(n,pTriInfos[t].vOt), n)); + if ( VNotZero(vOs2) ) vOs2 = Normalize(vOs2); + if ( VNotZero(vOt2) ) vOt2 = Normalize(vOt2); + + { + const tbool bAny = ( (pTriInfos[f].iFlag | pTriInfos[t].iFlag) & GROUP_WITH_ANY )!=0 ? TTRUE : TFALSE; + // make sure triangles which belong to the same quad are joined. + const tbool bSameOrgFace = iOF_1==iOF_2 ? TTRUE : TFALSE; + + const float fCosS = vdot(vOs,vOs2); + const float fCosT = vdot(vOt,vOt2); + + assert(f!=t || bSameOrgFace); // sanity check + if (bAny || bSameOrgFace || (fCosS>fThresCos && fCosT>fThresCos)) + pTmpMembers[iMembers++] = t; + } + } + + // sort pTmpMembers + tmp_group.iNrFaces = iMembers; + tmp_group.pTriMembers = pTmpMembers; + if (iMembers>1) + { + unsigned int uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed? + QuickSort(pTmpMembers, 0, iMembers-1, uSeed); + } + + // look for an existing match + bFound = TFALSE; + l=0; + while (liVertexRepresentitive); + ++iUniqueSubGroups; + } + + // output tspace + { + const int iOffs = pTriInfos[f].iTSpacesOffs; + const int iVert = pTriInfos[f].vert_num[index]; + STSpace * pTS_out = &psTspace[iOffs+iVert]; + assert(pTS_out->iCounter<2); + assert(((pTriInfos[f].iFlag&ORIENT_PRESERVING)!=0) == pGroup->bOrientPreservering); + if (pTS_out->iCounter==1) + { + *pTS_out = AvgTSpace(pTS_out, &pSubGroupTspace[l]); + pTS_out->iCounter = 2; // update counter + pTS_out->bOrient = pGroup->bOrientPreservering; + } + else + { + assert(pTS_out->iCounter==0); + *pTS_out = pSubGroupTspace[l]; + pTS_out->iCounter = 1; // update counter + pTS_out->bOrient = pGroup->bOrientPreservering; + } + } + } + + // clean up and offset iUniqueTspaces + for (s=0; s=0 && i<3); + + // project + index = piTriListIn[3*f+i]; + n = GetNormal(pContext, index); + vOs = vsub(pTriInfos[f].vOs, vscale(vdot(n,pTriInfos[f].vOs), n)); + vOt = vsub(pTriInfos[f].vOt, vscale(vdot(n,pTriInfos[f].vOt), n)); + if ( VNotZero(vOs) ) vOs = Normalize(vOs); + if ( VNotZero(vOt) ) vOt = Normalize(vOt); + + i2 = piTriListIn[3*f + (i<2?(i+1):0)]; + i1 = piTriListIn[3*f + i]; + i0 = piTriListIn[3*f + (i>0?(i-1):2)]; + + p0 = GetPosition(pContext, i0); + p1 = GetPosition(pContext, i1); + p2 = GetPosition(pContext, i2); + v1 = vsub(p0,p1); + v2 = vsub(p2,p1); + + // project + v1 = vsub(v1, vscale(vdot(n,v1),n)); if ( VNotZero(v1) ) v1 = Normalize(v1); + v2 = vsub(v2, vscale(vdot(n,v2),n)); if ( VNotZero(v2) ) v2 = Normalize(v2); + + // weight contribution by the angle + // between the two edge vectors + fCos = vdot(v1,v2); fCos=fCos>1?1:(fCos<(-1) ? (-1) : fCos); + fAngle = (float) acos(fCos); + fMagS = pTriInfos[f].fMagS; + fMagT = pTriInfos[f].fMagT; + + res.vOs=vadd(res.vOs, vscale(fAngle,vOs)); + res.vOt=vadd(res.vOt,vscale(fAngle,vOt)); + res.fMagS+=(fAngle*fMagS); + res.fMagT+=(fAngle*fMagT); + fAngleSum += fAngle; + } + } + + // normalize + if ( VNotZero(res.vOs) ) res.vOs = Normalize(res.vOs); + if ( VNotZero(res.vOt) ) res.vOt = Normalize(res.vOt); + if (fAngleSum>0) + { + res.fMagS /= fAngleSum; + res.fMagT /= fAngleSum; + } + + return res; +} + +static tbool CompareSubGroups(const SSubGroup * pg1, const SSubGroup * pg2) +{ + tbool bStillSame=TTRUE; + int i=0; + if (pg1->iNrFaces!=pg2->iNrFaces) return TFALSE; + while (iiNrFaces && bStillSame) + { + bStillSame = pg1->pTriMembers[i]==pg2->pTriMembers[i] ? TTRUE : TFALSE; + if (bStillSame) ++i; + } + return bStillSame; +} + +static void QuickSort(int* pSortBuffer, int iLeft, int iRight, unsigned int uSeed) +{ + int iL, iR, n, index, iMid, iTmp; + + // Random + unsigned int t=uSeed&31; + t=(uSeed<>(32-t)); + uSeed=uSeed+t+3; + // Random end + + iL=iLeft; iR=iRight; + n = (iR-iL)+1; + assert(n>=0); + index = (int) (uSeed%n); + + iMid=pSortBuffer[index + iL]; + + + do + { + while (pSortBuffer[iL] < iMid) + ++iL; + while (pSortBuffer[iR] > iMid) + --iR; + + if (iL <= iR) + { + iTmp = pSortBuffer[iL]; + pSortBuffer[iL] = pSortBuffer[iR]; + pSortBuffer[iR] = iTmp; + ++iL; --iR; + } + } + while (iL <= iR); + + if (iLeft < iR) + QuickSort(pSortBuffer, iLeft, iR, uSeed); + if (iL < iRight) + QuickSort(pSortBuffer, iL, iRight, uSeed); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// + +static void QuickSortEdges(SEdge * pSortBuffer, int iLeft, int iRight, const int channel, unsigned int uSeed); +static void GetEdge(int * i0_out, int * i1_out, int * edgenum_out, const int indices[], const int i0_in, const int i1_in); + +static void BuildNeighborsFast(STriInfo pTriInfos[], SEdge * pEdges, const int piTriListIn[], const int iNrTrianglesIn) +{ + // build array of edges + unsigned int uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed? + int iEntries=0, iCurStartIndex=-1, f=0, i=0; + for (f=0; f pSortBuffer[iRight].array[channel]) + { + sTmp = pSortBuffer[iLeft]; + pSortBuffer[iLeft] = pSortBuffer[iRight]; + pSortBuffer[iRight] = sTmp; + } + return; + } + + // Random + t=uSeed&31; + t=(uSeed<>(32-t)); + uSeed=uSeed+t+3; + // Random end + + iL = iLeft; + iR = iRight; + n = (iR-iL)+1; + assert(n>=0); + index = (int) (uSeed%n); + + iMid=pSortBuffer[index + iL].array[channel]; + + do + { + while (pSortBuffer[iL].array[channel] < iMid) + ++iL; + while (pSortBuffer[iR].array[channel] > iMid) + --iR; + + if (iL <= iR) + { + sTmp = pSortBuffer[iL]; + pSortBuffer[iL] = pSortBuffer[iR]; + pSortBuffer[iR] = sTmp; + ++iL; --iR; + } + } + while (iL <= iR); + + if (iLeft < iR) + QuickSortEdges(pSortBuffer, iLeft, iR, channel, uSeed); + if (iL < iRight) + QuickSortEdges(pSortBuffer, iL, iRight, channel, uSeed); +} + +// resolve ordering and edge number +static void GetEdge(int * i0_out, int * i1_out, int * edgenum_out, const int indices[], const int i0_in, const int i1_in) +{ + *edgenum_out = -1; + + // test if first index is on the edge + if (indices[0]==i0_in || indices[0]==i1_in) + { + // test if second index is on the edge + if (indices[1]==i0_in || indices[1]==i1_in) + { + edgenum_out[0]=0; // first edge + i0_out[0]=indices[0]; + i1_out[0]=indices[1]; + } + else + { + edgenum_out[0]=2; // third edge + i0_out[0]=indices[2]; + i1_out[0]=indices[0]; + } + } + else + { + // only second and third index is on the edge + edgenum_out[0]=1; // second edge + i0_out[0]=indices[1]; + i1_out[0]=indices[2]; + } +} + + +///////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////// Degenerate triangles //////////////////////////////////// + +static void DegenPrologue(STriInfo pTriInfos[], int piTriList_out[], const int iNrTrianglesIn, const int iTotTris) +{ + int iNextGoodTriangleSearchIndex=-1; + tbool bStillFindingGoodOnes; + + // locate quads with only one good triangle + int t=0; + while (t<(iTotTris-1)) + { + const int iFO_a = pTriInfos[t].iOrgFaceNumber; + const int iFO_b = pTriInfos[t+1].iOrgFaceNumber; + if (iFO_a==iFO_b) // this is a quad + { + const tbool bIsDeg_a = (pTriInfos[t].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE; + const tbool bIsDeg_b = (pTriInfos[t+1].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE; + if ((bIsDeg_a^bIsDeg_b)!=0) + { + pTriInfos[t].iFlag |= QUAD_ONE_DEGEN_TRI; + pTriInfos[t+1].iFlag |= QUAD_ONE_DEGEN_TRI; + } + t += 2; + } + else + ++t; + } + + // reorder list so all degen triangles are moved to the back + // without reordering the good triangles + iNextGoodTriangleSearchIndex = 1; + t=0; + bStillFindingGoodOnes = TTRUE; + while (t (t+1)); + + // swap triangle t0 and t1 + if (!bJustADegenerate) + { + int i=0; + for (i=0; i<3; i++) + { + const int index = piTriList_out[t0*3+i]; + piTriList_out[t0*3+i] = piTriList_out[t1*3+i]; + piTriList_out[t1*3+i] = index; + } + { + const STriInfo tri_info = pTriInfos[t0]; + pTriInfos[t0] = pTriInfos[t1]; + pTriInfos[t1] = tri_info; + } + } + else + bStillFindingGoodOnes = TFALSE; // this is not supposed to happen + } + + if (bStillFindingGoodOnes) ++t; + } + + assert(bStillFindingGoodOnes); // code will still work. + assert(iNrTrianglesIn == t); +} + +static void DegenEpilogue(STSpace psTspace[], STriInfo pTriInfos[], int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn, const int iTotTris) +{ + int t=0, i=0; + // deal with degenerate triangles + // punishment for degenerate triangles is O(N^2) + for (t=iNrTrianglesIn; t http://image.diku.dk/projects/media/morten.mikkelsen.08.pdf + * Note that though the tangent spaces at the vertices are generated in an order-independent way, + * by this implementation, the interpolated tangent space is still affected by which diagonal is + * chosen to split each quad. A sensible solution is to have your tools pipeline always + * split quads by the shortest diagonal. This choice is order-independent and works with mirroring. + * If these have the same length then compare the diagonals defined by the texture coordinates. + * XNormal which is a tool for baking normal maps allows you to write your own tangent space plugin + * and also quad triangulator plugin. + */ + + +typedef int tbool; +typedef struct SMikkTSpaceContext SMikkTSpaceContext; + +typedef struct { + // Returns the number of faces (triangles/quads) on the mesh to be processed. + int (*m_getNumFaces)(const SMikkTSpaceContext * pContext); + + // Returns the number of vertices on face number iFace + // iFace is a number in the range {0, 1, ..., getNumFaces()-1} + int (*m_getNumVerticesOfFace)(const SMikkTSpaceContext * pContext, const int iFace); + + // returns the position/normal/texcoord of the referenced face of vertex number iVert. + // iVert is in the range {0,1,2} for triangles and {0,1,2,3} for quads. + void (*m_getPosition)(const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert); + void (*m_getNormal)(const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert); + void (*m_getTexCoord)(const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert); + + // either (or both) of the two setTSpace callbacks can be set. + // The call-back m_setTSpaceBasic() is sufficient for basic normal mapping. + + // This function is used to return the tangent and fSign to the application. + // fvTangent is a unit length vector. + // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level. + // bitangent = fSign * cross(vN, tangent); + // Note that the results are returned unindexed. It is possible to generate a new index list + // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results. + // DO NOT! use an already existing index list. + void (*m_setTSpaceBasic)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert); + + // This function is used to return tangent space results to the application. + // fvTangent and fvBiTangent are unit length vectors and fMagS and fMagT are their + // true magnitudes which can be used for relief mapping effects. + // fvBiTangent is the "real" bitangent and thus may not be perpendicular to fvTangent. + // However, both are perpendicular to the vertex normal. + // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level. + // fSign = bIsOrientationPreserving ? 1.0f : (-1.0f); + // bitangent = fSign * cross(vN, tangent); + // Note that the results are returned unindexed. It is possible to generate a new index list + // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results. + // DO NOT! use an already existing index list. + void (*m_setTSpace)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT, + const tbool bIsOrientationPreserving, const int iFace, const int iVert); +} SMikkTSpaceInterface; + +struct SMikkTSpaceContext +{ + SMikkTSpaceInterface * m_pInterface; // initialized with callback functions + void * m_pUserData; // pointer to client side mesh data etc. (passed as the first parameter with every interface call) +}; + +// these are both thread safe! +tbool genTangSpaceDefault(const SMikkTSpaceContext * pContext); // Default (recommended) fAngularThreshold is 180 degrees (which means threshold disabled) +tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThreshold); + + +// To avoid visual errors (distortions/unwanted hard edges in lighting), when using sampled normal maps, the +// normal map sampler must use the exact inverse of the pixel shader transformation. +// The most efficient transformation we can possibly do in the pixel shader is +// achieved by using, directly, the "unnormalized" interpolated tangent, bitangent and vertex normal: vT, vB and vN. +// pixel shader (fast transform out) +// vNout = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); +// where vNt is the tangent space normal. The normal map sampler must likewise use the +// interpolated and "unnormalized" tangent, bitangent and vertex normal to be compliant with the pixel shader. +// sampler does (exact inverse of pixel shader): +// float3 row0 = cross(vB, vN); +// float3 row1 = cross(vN, vT); +// float3 row2 = cross(vT, vB); +// float fSign = dot(vT, row0)<0 ? -1 : 1; +// vNt = normalize( fSign * float3(dot(vNout,row0), dot(vNout,row1), dot(vNout,row2)) ); +// where vNout is the sampled normal in some chosen 3D space. +// +// Should you choose to reconstruct the bitangent in the pixel shader instead +// of the vertex shader, as explained earlier, then be sure to do this in the normal map sampler also. +// Finally, beware of quad triangulations. If the normal map sampler doesn't use the same triangulation of +// quads as your renderer then problems will occur since the interpolated tangent spaces will differ +// eventhough the vertex level tangent spaces match. This can be solved either by triangulating before +// sampling/exporting or by using the order-independent choice of diagonal for splitting quads suggested earlier. +// However, this must be used both by the sampler and your tools/rendering pipeline. + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/BlenderMalt/MaltMeshes.py b/BlenderMalt/MaltMeshes.py index 336c5e4d..ce914501 100644 --- a/BlenderMalt/MaltMeshes.py +++ b/BlenderMalt/MaltMeshes.py @@ -74,11 +74,14 @@ def attribute_ptr(name, ctype): ctypes.memmove(uv_buffer.buffer(), uvs, uv_buffer.size_in_bytes()) uvs_list.append(uv_buffer) if i == 0 and object.original.data.malt_parameters.bools['precomputed_tangents'].boolean: - m.calc_tangents(uvmap=uv_layer.name) - tangents_ptr = CBlenderMalt.mesh_tangents_ptr(ctypes.c_void_p(m.as_pointer())) - tangents = (ctypes.c_float * (loop_count * 4)).from_address(ctypes.addressof(tangents_ptr.contents)) tangents_buffer = get_load_buffer('tangents'+str(i), ctypes.c_float, (loop_count * 4)) - ctypes.memmove(tangents_buffer.buffer(), tangents, tangents_buffer.size_in_bytes()) + CBlenderMalt.mesh_tangents( + to_ptr(m.loop_triangles[0].as_pointer(), ctypes.c_int), + loop_tri_count * 3, + positions.buffer(), + normals.buffer(), + uv_buffer.buffer(), + tangents_buffer.buffer()) colors_list = [None]*4 if object.type == 'MESH': @@ -100,7 +103,6 @@ def attribute_ptr(name, ctype): ctypes.memmove(color_buffer.buffer(), color, color_buffer.size_in_bytes()) colors_list[i] = color_buffer - #TODO: Optimize. Create load buffers from bytearrays and retrieve them later mesh_data = { 'positions': positions, 'indices': indices, diff --git a/BlenderMalt/__init__.py b/BlenderMalt/__init__.py index 2f55671a..1a58a4ca 100644 --- a/BlenderMalt/__init__.py +++ b/BlenderMalt/__init__.py @@ -13,13 +13,6 @@ from os import path import bpy -def version_missmatch(): - return bpy.app.version[:2] != bl_info['blender'][:2] -def version_missmatch_message(): - if version_missmatch(): - v = bl_info['blender'] - return f"Malt loading aborted. The installed Malt version only works with Blender {v[0]}.{v[1]}" - #Add Malt and dependencies to the import path __CURRENT_DIR = path.dirname(path.realpath(__file__)) __MALT_PATH = path.join(__CURRENT_DIR, '.MaltPath') @@ -63,10 +56,6 @@ def update_debug_mode(self, context): def draw(self, context): layout = self.layout - if version_missmatch(): - layout.label(text=version_missmatch_message(), icon='ERROR') - return - if context.scene.render.engine == 'MALT': layout.operator('wm.path_open', text="Open Session Log").filepath=sys.stdout.log_path else: @@ -130,9 +119,12 @@ def do_windows_fixes(): if platform.system() == 'Windows': sys.executable = sys._base_executable # Use python-gpu on windows (patched python with NvOptimusEnablement and AmdPowerXpressRequestHighPerformance) + python_gpu_path = path.join(__MALT_DEPENDENCIES_PATH, 'python-gpu-{}.exe'.format(_PY_VERSION)) + if os.path.exists(python_gpu_path) == False: + print(f"MALT WARNING: python-gpu-{_PY_VERSION}.exe not found. Performance might be affected.") + return python_executable = path.join(sys.exec_prefix, 'bin', 'python-gpu-{}.exe'.format(_PY_VERSION)) if os.path.exists(python_executable) == False: - python_gpu_path = path.join(__MALT_DEPENDENCIES_PATH, 'python-gpu-{}.exe'.format(_PY_VERSION)) try: copy(python_gpu_path, python_executable) except PermissionError as e: @@ -201,10 +193,6 @@ def get_modules(): def register(): for _class in classes: bpy.utils.register_class(_class) - - if version_missmatch(): - print(version_missmatch_message()) - return import importlib for module in get_modules(): diff --git a/LICENSE - DEPENDENCIES b/LICENSE - DEPENDENCIES index 496a00de..422a286b 100644 --- a/LICENSE - DEPENDENCIES +++ b/LICENSE - DEPENDENCIES @@ -72,3 +72,7 @@ GNU GPL https://blender.org https://github.com/blender/blender/blob/master/doc/license/GPL3-license.txt +MikkTSpace +zlib License +http://mikktspace.com/ +https://github.com/mmikk/MikkTSpace/blob/master/mikktspace.h diff --git a/LICENSE - DEPENDENCIES (FULL TEXT) b/LICENSE - DEPENDENCIES (FULL TEXT) index f903b522..ef76d5fb 100644 --- a/LICENSE - DEPENDENCIES (FULL TEXT) +++ b/LICENSE - DEPENDENCIES (FULL TEXT) @@ -1304,5 +1304,28 @@ the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . +******************************************************************************** +MikkTSpace +zlib License +http://mikktspace.com/ + +Copyright (C) 2011 by Morten S. Mikkelsen + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + ******************************************************************************** ********************************************************************************