This is part of a larger refactoring towards a more extensible architecture in Blender (T75724).
A work in progress implementation of the proposal is in the `blenloader-decentralization` branch.
Steps that can be done now:
[x] Commit API to master.
[x] Update `writefile.c` to use the API (except for very few special cases, search for `writer->wd`).
[x] Update direct linking in `readfile.c` to use the API (except for a few cases, search for `reader->fd`).
[x] Implement `blendRead` and `blendWrite` callbacks for modifiers (the fluid modifier still has some special handling; haven't changed pointcache reading yet, to avoid merge conflicts with another patch of mine).
[x] Update lib linking in `readfile.c` to use the API.
[x] Update expand in `readfile.c` to use the API.
---
#### API
First, there needs to be an API that allows specifying how .blend file I/O works for a particular piece of data (e.g. a data block, a node, a modifier, ...). This API is proposed in `BLO_read_write.h` ([[ https://developer.blender.org/diffusion/B/browse/blenloader-decentralization/source/blender/blenloader/BLO_read_write.h | source code ]]). Please read the documentation in this header to see how the API works.
Partial copy of the documentation:
```
This file contains an API that allows different parts of Blender to define what data is stored
in .blend files.
Four callbacks have to be provided to fully implement .blend I/O for a piece of data. One of
those is related to file writing and three for file reading. Reading requires multiple
callbacks, due to the way linking between files works.
Brief description of the individual callbacks:
- Blend Write: Define which structs and memory buffers are saved.
- Blend Read Data: Loads structs and memory buffers from file and updates pointers them.
- Blend Read Lib: Updates pointers to ID data blocks.
- Blend Expand: Defines which other data blocks should be loaded (possibly from other files).
Each of these callbacks uses a different API functions.
```
#### Using the API
Fortunately, we don't have to start using the API everywhere at the same time. Instead we can gradually move functions from `writefile.c` and `readfile.c` to e.g. `blenkernel`. Furthermore, callbacks can be added to `ModifierTypeInfo` and `IDTypeInfo` (and later `bNodeType`).
**Modifiers**
```
lang=c
/* Is called when the modifier is written to a file. The modifier data struct itself is written
* already.
*
* This method should write any additional arrays and referenced structs that should be
* stored in the file.
*/
void (*blendWrite)(struct BlendWriter *writer, const struct ModifierData *md);
/* Is called when the modifier is read from a file.
*
* It can be used to update pointers to arrays and other structs. Furthermore, fields that have
* not been written (e.g. runtime data) can be reset.
*/
void (*blendRead)(struct BlendDataReader *reader, struct ModifierData *md);
```
In the branch I implemented these callbacks for almost all modifiers (e.g. [[ https://developer.blender.org/diffusion/B/browse/blenloader-decentralization/source/blender/modifiers/intern/MOD_hook.c$128 | hook modifier ]]).
**Data Blocks**
```
lang=c
typedef void (*IDTypeBlendWriteFunction)(struct BlendWriter *writer, struct ID *id, const void *id_address);
typedef void (*IDTypeBlendReadDataFunction)(struct BlendDataReader *reader, struct ID *id);
typedef void (*IDTypeBlendReadLibFunction)(struct BlendLibReader *reader, struct ID *id);
typedef void (*IDTypeBlendExpandFunction)(struct BlendExpander *expander, struct ID *id);
/**
* Write all structs that should be saved in a .blend file.
*/
IDTypeBlendWriteFunction blend_write;
/**
* Update pointers for all structs directly owned by this data block.
*/
IDTypeBlendReadDataFunction blend_read_data;
/**
* Update pointers to other id data blocks.
*/
IDTypeBlendReadLibFunction blend_read_lib;
/**
* Specify which other id data blocks should be loaded when the current one is loaded.
*/
IDTypeBlendExpandFunction blend_expand;
```
In the branch I implemented these callbacks in `action.c`and `key.c` already ([[ https://developer.blender.org/diffusion/B/browse/blenloader-decentralization/source/blender/blenkernel/intern/action.c$159 | action ]], [[ https://developer.blender.org/diffusion/B/browse/blenloader-decentralization/source/blender/blenkernel/intern/key.c$102 | key ]]).
**Misc**
In order to implement the callbacks mentioned above, I also had to move the I/O code of some other structures out of `blenloader`. Namely I already moved `AnimData`, `CurveMapping`, `CurveProfile`, `IDProperty` and some more. It takes quite some time, but it's mostly pattern matching. Usually, I just copy the code from e.g. `readfile.c` and then update the code line by line.