From BlenderWiki

Jump to: navigation, search

Defining Properties in Blender

This is a high level overview of how to add a properties to Blender 2.50 internally. It's a work in progress because 2.50 is still under heavy development and subject to many changes.

We need to do the following these steps:

  • Add a struct member in the DNA header files.
  • Ensure the property is saved and loaded.
  • Ensure it is initialized with the correct defaults for new and existing objects.
  • Define information about the property in the RNA files.
  • Add a button to the user interface.
  • Use the property.

DNA

Blender's data that is saved to file is contained in C structs defined in the header files with a DNA prefix in the makesdna module. It is simply a matter of adding a member to the C struct, and the value of the member will be automatically saved and loaded from .Blend files, though there are some caveats.

More later about saving and loading, what we have to be careful about in the DNA files is alignment. For compatibility between different compilers and platforms, all members must be aligned correctly. The general rule is that if the size of some member variable is n, it must be defined starting at a location in the struct that is a multiple of n. For example ints must be defined at locations that are a multiple of 4. Structs must be created at locations that are a multiple of 8. If for some reason this does not work out, padding variables can be added in between (usually named pad, pad1, ..). Alignment errors in DNA structs will be printed during compilation.

More Information

http://www.blender.org/development/architecture/notes-on-sdna/ http://www.blender.org/development/architecture/

source/blender/makesdna/intern/dna_genfile.c

Relevant files

source/blender/makesdna/DNA_*_types.h

Loading and Saving

The blenloader module has two relevant files here: readfile.c and writefile.c. If the property has a basic type, like int, float, char, or an array of those, this will go automatic. In case of a pointer it needs to be ensured that what the pointer is pointing to is also saved. If it is an ID struct it will be saved already, if it is some custom array or struct it needs to be saved separately, see similar existing properties for how this done.

For loading pointers there are again two cases. If it is a pointer to an ID struct the newlibadr_(us) function should be used, which will look up the new pointer. Otherwise a DATA block must be read, again, look for similar properties.

Relevant files

source/blender/blenloader/readfile.c
source/blender/blenloader/writefile.c

Defaults

We must ensure that the property gets its correct default value in two cases. First when the struct is created, the place where the struct is created depends, but is usually in blenkernel.

The other case that needs to be checked is when loading existing struct from files. By default the DNA system will set the value to zero, which in many cases is ok, and then no further action needs to be taken. If not, in readfile.c in blenloader, there is a long function do_versions which for each consecutive version initializes properties or makes changes for backward compatibility.

There are various ways to check when the property must be initialized, the main thing is that we need to ensure that we set the defaults only on exactly the correct older versions. Files already saved with this new property should never get their overwritten with the defaults, and old files need to be properly initialized. One trick which is often used is when a property is added that cannot be zero, in check if initialization is needed is easy (but still within the correct if(versionfile < XXX) check for performance). If multiple properties are added at the same time only a single property needs to be checked to have a zero value when this is not allowed, and all the properties can then be set to their defaults.

The other possibility is to increase the subversion, but the former solution is preferred if possible. In that case the subversion needs to be incremented in BKE_blender.h, and then a test if(versionfile < XXX || (versionfile == XXX && subversionfile < YYY)) can be used to see if it must be initialized.

Relevant files

source/blender/blenkernel/*.c
source/blender/blenloader/readfile.c

RNA

The RNA files define extra information about properties like minimum/maximum value or tooltip description. These will then be used by user interface code to generate buttons or by the python API to access properties. It is not necessarily require to define an RNA property, for example when the property should not be exposed to the user, but in most cases it should be done. The correct file with rna prefix can be looked up there and modified.

How to define information about the property can be inferred from existing properties mostly, and the API in RNA_define.h gives the functions that can be used. If possible the property can get automatic get/set functions based on the DNA struct information, otherwise manually get/set functions will need to be written.

More information

RNA documentation

Relevant files

source/blender/makesrna/intern/rna_*.c
source/blender/makesrna/RNA_define.h

User Interface

For properties with RNA it should be easy to create a button. Most of the UI code is in python scripts now. In these scripts for panels, headers and menus, the property can be added as a button into a UI layout. For many properties this is simple a matter of calling one function with the data and the property name, RNA itself should have enough information to do any necessary updates when the value changes.

layout.prop(ob, "location")


Relevant files:

release/scripts/ui/*.py

Use the Property

If all these steps were taken, you now should be ready to use the property in the area of the code you are working on.