Core: Make ID::runtime an allocated pointer.

Will avoid having to reshuffle all ID types' DNA alignement when
modifying runtime data, avoid writing garbage data in blendfile, allow
usage of non-trivial C++ data in that runtime struct, etc.

NOTE: Trigger for this refactor was this commit in the upcoming packed
data PR (!133801):
https://projects.blender.org/blender/blender/commit/34a2ad81fbdcf7f

Co-authored-by: Brecht Van Lommel <brecht@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/146046
This commit is contained in:
Bastien Montagne
2025-09-22 18:02:32 +02:00
parent fdc9412b9d
commit 849aba1ccf
20 changed files with 168 additions and 100 deletions

View File

@@ -18,6 +18,7 @@
#include "DNA_action_defaults.h"
#include "DNA_action_types.h"
#include "BKE_lib_id.hh"
#include "BKE_main.hh"
#include "BKE_node.hh"
#include "BKE_report.hh"
@@ -138,7 +139,7 @@ void convert_legacy_animato_action(bAction &dna_action)
void tag_action_user_for_slotted_actions_conversion(ID &animated_id)
{
animated_id.runtime.readfile_data->tags.action_assignment_needs_slot = true;
animated_id.runtime->readfile_data->tags.action_assignment_needs_slot = true;
}
void tag_action_users_for_slotted_actions_conversion(Main &bmain)

View File

@@ -42,8 +42,10 @@
#include "DNA_userdef_enums.h"
struct BlendWriter;
struct Depsgraph;
struct GHash;
struct ID;
struct ID_Readfile_Data;
struct Library;
struct ListBase;
struct Main;
@@ -51,6 +53,41 @@ struct PointerRNA;
struct PropertyRNA;
struct bContext;
namespace blender::bke::id {
/** Status used and counters created during id-remapping. */
struct ID_Runtime_Remap {
/** Status during ID remapping. */
int status = 0;
/** During ID remapping the number of skipped use cases that refcount the data-block. */
int skipped_refcounted = 0;
/**
* During ID remapping the number of direct use cases that could be remapped
* (e.g. obdata when in edit mode).
*/
int skipped_direct = 0;
/** During ID remapping, the number of indirect use cases that could not be remapped. */
int skipped_indirect = 0;
};
struct ID_Runtime {
ID_Runtime_Remap remap = {};
/**
* The depsgraph that owns this data block. This is only set on data-blocks which are
* copied-on-eval by the depsgraph. Additional data-blocks created during depsgraph evaluation
* are not owned by any specific depsgraph and thus this pointer is null for those.
*/
Depsgraph *depsgraph = nullptr;
/**
* This data is only allocated & used during the readfile process. After that, the memory is
* freed and the pointer set to `nullptr`.
*/
ID_Readfile_Data *readfile_data = nullptr;
};
} // namespace blender::bke::id
/**
* Get allocation size of a given data-block type and optionally allocation `r_name`.
*/
@@ -58,6 +95,9 @@ size_t BKE_libblock_get_alloc_info(short type, const char **r_name);
/**
* Allocates and returns memory of the right size for the specified block type,
* initialized to zero.
*
* \note: Typically, caller also needs to immediately call #BKE_libblock_runtime_ensure on the
* allocated ID data.
*/
ID *BKE_libblock_alloc_notest(short type) ATTR_WARN_UNUSED_RESULT;
/**
@@ -90,6 +130,14 @@ void *BKE_libblock_alloc_in_lib(Main *bmain,
*/
void BKE_libblock_init_empty(ID *id) ATTR_NONNULL(1);
/**
* Ensure that the given ID does have a valid runtime data.
*
* Low-level API, should not be needed in typical ID usages, where ID::runtime can always be
* assumed valid.
*/
void BKE_libblock_runtime_ensure(ID &id);
/**
* Reset the runtime counters used by ID remapping.
*/
@@ -445,20 +493,35 @@ enum {
/**
* Low-level ID freeing functions.
*
* \note These functions do NOT cover embedded IDs. Those are managed by the
* \note These `BKE_libblock_free_` functions do NOT cover embedded IDs. Those are managed by the
* owning ID, and are typically allocated/freed from the IDType callbacks.
*/
void BKE_libblock_free_datablock(ID *id, int flag) ATTR_NONNULL();
void BKE_libblock_free_data(ID *id, bool do_id_user) ATTR_NONNULL();
void BKE_libblock_free_runtime_data(ID *id) ATTR_NONNULL();
/**
* Only free generic Python instance data (ID::py_instance).
*
* In most cases #BKE_id_free_ex handles this, when lower level functions are called directly
* this function will need to be called too, if Python has access to the data.
*
* ID data-blocks such as #Material.nodetree are not stored in #Main.
*/
void BKE_libblock_free_data_py(ID *id);
/**
* Only free generic runtime data (ID::runtime).
*
* In most cases #BKE_libblock_free_data handles this, but in rare cases (currently in readfile,
* when freeing linked ID placeholders), it is necessary.
*/
void BKE_libblock_free_runtime_data(ID *id);
/** Free generic ID data, including the runtime and animation data, but not the python data. */
void BKE_libblock_free_data(ID *id, bool do_id_user) ATTR_NONNULL();
/**
* Free IDtype-specific data (does _not_ free generic ID data, use
* #BKE_libblock_free_data for that).
*/
void BKE_libblock_free_datablock(ID *id, int flag) ATTR_NONNULL();
/**
* Complete ID freeing, extended version for corner cases.

View File

@@ -1300,6 +1300,13 @@ void BKE_main_lib_objects_recalc_all(Main *bmain)
*
* **************************** */
void BKE_libblock_runtime_ensure(ID &id)
{
if (!id.runtime) {
id.runtime = MEM_new<blender::bke::id::ID_Runtime>(__func__);
}
}
size_t BKE_libblock_get_alloc_info(short type, const char **r_name)
{
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(type);
@@ -1322,7 +1329,8 @@ ID *BKE_libblock_alloc_notest(short type)
const char *name;
size_t size = BKE_libblock_get_alloc_info(type, &name);
if (size != 0) {
return static_cast<ID *>(MEM_callocN(size, name));
ID *id = static_cast<ID *>(MEM_callocN(size, name));
return id;
}
BLI_assert_msg(0, "Request to allocate unknown data type");
return nullptr;
@@ -1339,6 +1347,7 @@ void *BKE_libblock_alloc_in_lib(Main *bmain,
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || (flag & LIB_ID_CREATE_LOCAL) == 0);
ID *id = BKE_libblock_alloc_notest(type);
BKE_libblock_runtime_ensure(*id);
if (id) {
if ((flag & LIB_ID_CREATE_NO_MAIN) != 0) {
@@ -1443,10 +1452,10 @@ void BKE_libblock_init_empty(ID *id)
void BKE_libblock_runtime_reset_remapping_status(ID *id)
{
id->runtime.remap.status = 0;
id->runtime.remap.skipped_refcounted = 0;
id->runtime.remap.skipped_direct = 0;
id->runtime.remap.skipped_indirect = 0;
id->runtime->remap.status = 0;
id->runtime->remap.skipped_refcounted = 0;
id->runtime->remap.skipped_direct = 0;
id->runtime->remap.skipped_indirect = 0;
}
/* ********** ID session-wise UID management. ********** */
@@ -1550,6 +1559,7 @@ void BKE_libblock_copy_in_lib(Main *bmain,
* Clear and initialize it similar to BKE_libblock_alloc_in_lib. */
const size_t size = BKE_libblock_get_alloc_info(GS(id->name), nullptr);
memset(new_id, 0, size);
BKE_libblock_runtime_ensure(*new_id);
STRNCPY(new_id->name, id->name);
new_id->us = 0;
new_id->tag |= ID_TAG_NOT_ALLOCATED | ID_TAG_NO_MAIN | ID_TAG_NO_USER_REFCOUNT;

View File

@@ -71,9 +71,9 @@ void BKE_libblock_free_data(ID *id, const bool do_id_user)
MEM_freeN(id->library_weak_reference);
}
BKE_libblock_free_runtime_data(id);
BKE_animdata_free(id, do_id_user);
BKE_libblock_free_runtime_data(id);
}
void BKE_libblock_free_datablock(ID *id, const int /*flag*/)
@@ -92,11 +92,15 @@ void BKE_libblock_free_datablock(ID *id, const int /*flag*/)
void BKE_libblock_free_runtime_data(ID *id)
{
/* During "normal" file loading this data is released when versioning ends. Some versioning code
* also deletes IDs, though. For example, in the startup blend file, brushes that were replaced
* by assets are deleted. This means that the regular "delete this ID" flow (aka this code here)
* also needs to free this data. */
BLO_readfile_id_runtime_data_free(*id);
if (id->runtime) {
/* During "normal" file loading this data is released when versioning ends. Some versioning
* code also deletes IDs, though. For example, in the startup blend file, brushes that were
* replaced by assets are deleted. This means that the regular "delete this ID" flow (aka this
* code here) also needs to free this data. */
BLO_readfile_id_runtime_data_free(*id);
MEM_SAFE_DELETE(id->runtime);
}
}
static int id_free(Main *bmain, void *idv, int flag, const bool use_flag_from_idtag)

View File

@@ -82,21 +82,21 @@ static void foreach_libblock_remap_callback_skip(const ID * /*id_owner*/,
BLI_assert(id != nullptr);
if (is_indirect) {
id->runtime.remap.skipped_indirect++;
id->runtime->remap.skipped_indirect++;
}
else if (violates_never_null || is_obj_editmode || is_reference) {
id->runtime.remap.skipped_direct++;
id->runtime->remap.skipped_direct++;
}
else {
BLI_assert_unreachable();
}
if (cb_flag & IDWALK_CB_USER) {
id->runtime.remap.skipped_refcounted++;
id->runtime->remap.skipped_refcounted++;
}
else if (cb_flag & IDWALK_CB_USER_ONE) {
/* No need to count number of times this happens, just a flag is enough. */
id->runtime.remap.status |= ID_REMAP_IS_USER_ONE_SKIPPED;
id->runtime->remap.status |= ID_REMAP_IS_USER_ONE_SKIPPED;
}
}
@@ -141,7 +141,7 @@ static void foreach_libblock_remap_callback_apply(ID *id_owner,
ID *new_id = violates_never_null ? nullptr : *id_ptr;
if (!is_indirect && new_id) {
new_id->runtime.remap.status |= ID_REMAP_IS_LINKED_DIRECT;
new_id->runtime->remap.status |= ID_REMAP_IS_LINKED_DIRECT;
}
if (skip_user_refcount) {
@@ -444,7 +444,7 @@ static void libblock_remap_data_update_tags(ID *old_id, ID *new_id, IDRemap *id_
}
if (new_id != nullptr && (new_id->tag & ID_TAG_INDIRECT) &&
(new_id->runtime.remap.status & ID_REMAP_IS_LINKED_DIRECT))
(new_id->runtime->remap.status & ID_REMAP_IS_LINKED_DIRECT))
{
new_id->tag &= ~ID_TAG_INDIRECT;
new_id->flag &= ~ID_FLAG_INDIRECT_WEAK_LINK;
@@ -569,13 +569,13 @@ static void libblock_remap_foreach_idpair(ID *old_id, ID *new_id, Main *bmain, i
* count has actually been incremented for that, we have to decrease once more its user
* count... unless we had to skip some 'user_one' cases. */
if ((old_id->tag & ID_TAG_EXTRAUSER_SET) &&
!(old_id->runtime.remap.status & ID_REMAP_IS_USER_ONE_SKIPPED))
!(old_id->runtime->remap.status & ID_REMAP_IS_USER_ONE_SKIPPED))
{
id_us_clear_real(old_id);
}
}
const int skipped_refcounted = old_id->runtime.remap.skipped_refcounted;
const int skipped_refcounted = old_id->runtime->remap.skipped_refcounted;
if (old_id->us - skipped_refcounted < 0) {
CLOG_ERROR(&LOG,
"Error in remapping process from '%s' (%p) to '%s' (%p): "
@@ -587,7 +587,7 @@ static void libblock_remap_foreach_idpair(ID *old_id, ID *new_id, Main *bmain, i
old_id->us - skipped_refcounted);
}
const int skipped_direct = old_id->runtime.remap.skipped_direct;
const int skipped_direct = old_id->runtime->remap.skipped_direct;
if (skipped_direct == 0) {
/* old_id is assumed to not be used directly anymore... */
if (old_id->lib && (old_id->tag & ID_TAG_EXTERN)) {

View File

@@ -2191,29 +2191,29 @@ static int direct_link_id_restore_recalc(const FileData *fd,
static void readfile_id_runtime_data_ensure(ID &id)
{
if (id.runtime.readfile_data) {
if (id.runtime->readfile_data) {
return;
}
id.runtime.readfile_data = MEM_callocN<ID_Readfile_Data>(__func__);
id.runtime->readfile_data = MEM_callocN<ID_Readfile_Data>(__func__);
}
ID_Readfile_Data::Tags BLO_readfile_id_runtime_tags(ID &id)
{
if (!id.runtime.readfile_data) {
if (!id.runtime->readfile_data) {
return ID_Readfile_Data::Tags{};
}
return id.runtime.readfile_data->tags;
return id.runtime->readfile_data->tags;
}
ID_Readfile_Data::Tags &BLO_readfile_id_runtime_tags_for_write(ID &id)
{
readfile_id_runtime_data_ensure(id);
return id.runtime.readfile_data->tags;
return id.runtime->readfile_data->tags;
}
void BLO_readfile_id_runtime_data_free(ID &id)
{
MEM_SAFE_FREE(id.runtime.readfile_data);
MEM_SAFE_FREE(id.runtime->readfile_data);
}
void BLO_readfile_id_runtime_data_free_all(Main &bmain)
@@ -2246,6 +2246,9 @@ static void direct_link_id_common(BlendDataReader *reader,
const int id_tag,
const ID_Readfile_Data::Tags id_read_tags)
{
BLI_assert(id->runtime == nullptr);
BKE_libblock_runtime_ensure(*id);
if (!BLO_read_data_is_undo(reader)) {
/* When actually reading a file, we do want to reset/re-generate session UIDS.
* In undo case, we want to re-use existing ones. */
@@ -2271,13 +2274,8 @@ static void direct_link_id_common(BlendDataReader *reader,
id->tag = id_tag;
}
if (!BLO_read_data_is_undo(reader)) {
/* Reset the runtime data, as there were versions of Blender that did not do
* this before writing to disk. */
id->runtime = ID_Runtime{};
}
readfile_id_runtime_data_ensure(*id);
id->runtime.readfile_data->tags = id_read_tags;
id->runtime->readfile_data->tags = id_read_tags;
if ((id_tag & ID_TAG_TEMP_MAIN) == 0) {
BKE_lib_libblock_session_uid_ensure(id);
@@ -2561,6 +2559,7 @@ static ID *create_placeholder(Main *mainvar,
{
ListBase *lb = which_libbase(mainvar, idcode);
ID *ph_id = BKE_libblock_alloc_notest(idcode);
BKE_libblock_runtime_ensure(*ph_id);
*((short *)ph_id->name) = idcode;
BLI_strncpy(ph_id->name + 2, idname, sizeof(ph_id->name) - 2);
@@ -4953,15 +4952,19 @@ static void read_library_linked_ids(FileData *basefd, FileData *fd, Main *mainva
/* Transfer the readfile data from the placeholder to the real ID, but
* only if the real ID has no readfile data yet. The same realid may be
* referred to by multiple placeholders. */
if (realid && !realid->runtime.readfile_data) {
realid->runtime.readfile_data = id->runtime.readfile_data;
id->runtime.readfile_data = nullptr;
if (realid && !realid->runtime->readfile_data) {
realid->runtime->readfile_data = id->runtime->readfile_data;
id->runtime->readfile_data = nullptr;
}
/* The 'readfile' runtime data needs to be freed here, as this ID placeholder does not go
* through versioning (the usual place where this data is freed). Since `id` is not a real
* ID, this shouldn't follow any pointers to embedded IDs. */
BLO_readfile_id_runtime_data_free(*id);
/* Ensure that the runtime pointer, and its 'readfile' sub-data, are properly freed, as
* this ID placeholder does not go through versioning (the usual place where this data is
* freed). Since `id` is not a real ID, this shouldn't follow any pointers to embedded IDs.
*
* WARNING! This placeholder ID is only an ID struct, with a very small subset of regular
* ID common data actually valid and needing to be freed. Therefore, calling
* #BKE_libblock_free_data on it would not work. */
BKE_libblock_free_runtime_data(id);
MEM_freeN(id);
}

View File

@@ -1336,6 +1336,7 @@ BLO_Write_IDBuffer::BLO_Write_IDBuffer(ID &id, const bool is_undo, const bool is
}
temp_id->us = 0;
temp_id->icon_id = 0;
temp_id->runtime = nullptr;
/* Those listbase data change every time we add/remove an ID, and also often when
* renaming one (due to re-sorting). This avoids generating a lot of false 'is changed'
* detections between undo steps. */
@@ -1349,8 +1350,6 @@ BLO_Write_IDBuffer::BLO_Write_IDBuffer(ID &id, const bool is_undo, const bool is
* when we need to re-read the ID into its original address, this is currently cleared in
* #direct_link_id_common in `readfile.cc` anyway. */
temp_id->py_instance = nullptr;
/* Clear runtime data struct. */
temp_id->runtime = ID_Runtime{};
}
BLO_Write_IDBuffer::BLO_Write_IDBuffer(ID &id, BlendWriter *writer)

View File

@@ -14,6 +14,7 @@
#include "BKE_action.hh" /* XXX: BKE_pose_channel_find_name */
#include "BKE_idtype.hh"
#include "BKE_lib_id.hh"
#include "BKE_main.hh"
#include "DNA_object_types.h"
@@ -283,7 +284,7 @@ const ID *DEG_get_original_id(const ID *id)
Depsgraph *DEG_get_depsgraph_by_id(const ID &id)
{
return id.runtime.depsgraph;
return id.runtime->depsgraph;
}
bool DEG_is_original_id(const ID *id)

View File

@@ -753,9 +753,15 @@ ID *deg_expand_eval_copy_datablock(const Depsgraph *depsgraph, const IDNode *id_
DEG_COW_PRINT(
"Expanding datablock for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow);
/* Sanity checks. */
/* Sanity checks.
*
* At this point, `id_cow` is essentially considered as a (partially dirty) allocated buffer (it
* has been freed, but not fully cleared, as a result of calling #deg_free_eval_copy_datablock on
* it). It is not expected to have any valid sub-data, not even a valid `ID::runtime` pointer.
*/
BLI_assert(check_datablock_expanded(id_cow) == false);
BLI_assert(id_cow->py_instance == nullptr);
BLI_assert(id_cow->runtime == nullptr);
/* Copy data from original ID to a copied version. */
/* TODO(sergey): Avoid doing full ID copy somehow, make Mesh to reference
@@ -1022,7 +1028,7 @@ void deg_tag_eval_copy_id(deg::Depsgraph &depsgraph, ID *id_cow, const ID *id_or
/* This ID is no longer localized, is a self-sustaining copy now. */
id_cow->tag &= ~ID_TAG_LOCALIZED;
id_cow->orig_id = (ID *)id_orig;
id_cow->runtime.depsgraph = &reinterpret_cast<::Depsgraph &>(depsgraph);
id_cow->runtime->depsgraph = &reinterpret_cast<::Depsgraph &>(depsgraph);
}
bool deg_eval_copy_is_expanded(const ID *id_cow)

View File

@@ -13,6 +13,7 @@
#include "DNA_ID.h"
struct ID;
struct Depsgraph;
/* Uncomment this to have verbose log about original and evaluated pointers
* logged, with detailed information when they are allocated, expanded

View File

@@ -81,6 +81,8 @@ void IDNode::init_copy_on_write(ID *id_cow_hint)
}
else if (deg_eval_copy_is_needed(id_orig)) {
id_cow = BKE_libblock_alloc_notest(GS(id_orig->name));
/* No need to call #BKE_libblock_runtime_ensure here, this will be done by
* #BKE_libblock_copy_in_lib when #deg_expand_eval_copy_datablock is executed. */
DEG_COW_PRINT(
"Allocate memory for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow);
}

View File

@@ -31,6 +31,7 @@
struct ARegion;
struct AutoComplete;
struct Depsgraph;
struct EnumPropertyItem;
struct FileSelectParams;
struct ID;

View File

@@ -20,6 +20,9 @@
#ifdef __cplusplus
# include <type_traits>
namespace blender::bke::id {
struct ID_Runtime;
}
namespace blender::bke {
struct PreviewImageRuntime;
}
@@ -29,6 +32,7 @@ struct IDPropertyGroupChildrenSet;
namespace blender::bke::library {
struct LibraryRuntime;
}
using ID_RuntimeHandle = blender::bke::id::ID_Runtime;
using PreviewImageRuntimeHandle = blender::bke::PreviewImageRuntime;
using LibraryRuntimeHandle = blender::bke::library::LibraryRuntime;
using IDPropertyGroupChildrenSet = blender::bke::idprop::IDPropertyGroupChildrenSet;
@@ -36,6 +40,7 @@ using IDPropertyGroupChildrenSet = blender::bke::idprop::IDPropertyGroupChildren
typedef struct PreviewImageRuntimeHandle PreviewImageRuntimeHandle;
typedef struct LibraryRuntimeHandle LibraryRuntimeHandle;
typedef struct IDPropertyGroupChildrenSet IDPropertyGroupChildrenSet;
typedef struct ID_RuntimeHandle ID_RuntimeHandle;
#endif
#ifdef __cplusplus
@@ -45,11 +50,9 @@ extern "C" {
struct FileData;
struct GHash;
struct ID;
struct ID_Readfile_Data;
struct Library;
struct PackedFile;
struct UniqueName_Map;
struct Depsgraph;
typedef struct IDPropertyUIData {
/** Tool-tip / property description pointer. Owned by the #IDProperty. */
@@ -380,37 +383,6 @@ enum {
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;
/**
* The depsgraph that owns this data block. This is only set on data-blocks which are
* copied-on-eval by the depsgraph. Additional data-blocks created during depsgraph evaluation
* are not owned by any specific depsgraph and thus this pointer is null for those.
*/
struct Depsgraph *depsgraph;
/**
* This data is only allocated & used during the readfile process. After that, the memory is
* freed and the pointer set to `nullptr`.
*/
struct ID_Readfile_Data *readfile_data;
} ID_Runtime;
typedef struct ID {
/* There's a nasty circular dependency here.... 'void *' to the rescue! I
* really wonder why this is needed. */
@@ -513,7 +485,17 @@ typedef struct ID {
*/
struct LibraryWeakReference *library_weak_reference;
struct ID_Runtime runtime;
/**
* Allocated runtime data, never written on disk or in undo steps.
*
* _Always_ valid for code handling IDs managed by the `BKE_lib_id` API.
*
* Internal low-level implementation of ID creation/copying/deletion, and code handling IDs
* themselves in non-standard ways (mainly the CoW IDs in depsgraph, and some temporary IDs in
* readfile) may have to manage this pointer themselves (see also #BKE_libblock_runtime_ensure
* and #BKE_libblock_free_runtime_data).
*/
ID_RuntimeHandle *runtime;
} ID;
/**

View File

@@ -43,8 +43,6 @@ typedef struct Mask {
int flag;
char _pad[4];
void *_pad1;
Mask_Runtime runtime;
} Mask;

View File

@@ -90,8 +90,6 @@ typedef struct MovieClip {
/** Grease pencil data. */
struct bGPdata *gpd;
void *_pad1;
/** Data for SfM tracking. */
struct MovieTracking tracking;
/**

View File

@@ -2113,7 +2113,6 @@ typedef struct Scene {
ListBase base DNA_DEPRECATED;
/** Active base. */
struct Base *basact DNA_DEPRECATED;
void *_pad1;
/** 3d cursor location. */
View3DCursor cursor;
@@ -2138,7 +2137,6 @@ typedef struct Scene {
/** Default allocated now. */
struct ToolSettings *toolsettings;
void *_pad4;
struct DisplaySafeAreas safe_areas;
/* Migrate or replace? depends on some internal things... */
@@ -2186,7 +2184,6 @@ typedef struct Scene {
/** Physics simulation settings. */
struct PhysicsSettings physics_settings;
void *_pad8;
/**
* XXX: runtime flag for drawing, actually belongs in the window,
* only used by #BKE_object_handle_update()

View File

@@ -20,6 +20,8 @@ typedef struct bSound {
ID id;
void *_pad1;
/**
* The path to the sound file.
*/

View File

@@ -31,6 +31,8 @@ typedef struct Text {
ID id;
void *_pad1;
/**
* Optional file path, when NULL text is considered internal.
* Otherwise this path will be used when saving/reloading.

View File

@@ -81,10 +81,11 @@ typedef struct Tex {
/** Animation data (must be immediately after id for utilities to use it). */
struct AnimData *adt;
void *_pad3;
float noisesize, turbul;
float bright, contrast, saturation, rfac, gfac, bfac;
float filtersize;
char _pad2[4];
/* newnoise: musgrave parameters */
float mg_H, mg_lacunarity, mg_octaves, mg_offset, mg_gain;
@@ -122,7 +123,6 @@ typedef struct Tex {
int sfra DNA_DEPRECATED;
float checkerdist, nabla;
char _pad1[4];
struct ImageUser iuser;

View File

@@ -49,17 +49,15 @@ typedef struct World {
* bit 0: Do mist
*/
short mode;
char _pad2[6];
/** Assorted settings. */
short flag;
float misi, miststa, mistdist, misthi;
/** Ambient occlusion. */
float aodist, aoenergy;
/** Assorted settings. */
short flag;
char _pad3[2];
/** Eevee settings. */
/**
* Resolution of the world probe when baked to a texture. Contains `eLightProbeResolution`.
@@ -73,11 +71,9 @@ typedef struct World {
float sun_shadow_maximum_resolution;
float sun_shadow_jitter_overblur;
float sun_shadow_filter_radius;
char _pad4[4];
short pr_texture;
short use_nodes DNA_DEPRECATED;
char _pad[4];
/* previews */
struct PreviewImage *preview;
@@ -88,6 +84,8 @@ typedef struct World {
/** Light-group membership information. */
struct LightgroupMembership *lightgroup;
void *_pad1;
/** Runtime. */
ListBase gpumaterial;
/* The Depsgraph::update_count when this World was last updated. */