[Bf-committers] SDNA do's and don'ts

Ton Roosendaal bf-committers@blender.org
Sat, 1 Feb 2003 17:35:18 +0100

Hi all,

Everyone who wants to add features to the blender core, will be  
confronted with this weirdo system. I called it 'Struct DNA' or SDNA in  
the code. This is essential information that should have been  
documented long ago... but it's never too late to make docs, er!

The system was divised to support Blender's file format, and internal  
library/database system. It allows Blender to do a runtime checking of  
the contents of the Structure data. This enables a few nice features:
- you can just add or remove variables from structures, or add/remove  
complete new structures, without damaging backward *and* forward  
compatiblity of files
- you can use this for Python or smart buttons in Blender, to check  
run-time which variable or structure is being provided

All of Blender's structures that can be saved to a file, are described  
with the SDNA. This is basically a long string of codes, with the  
structure and variable names and types. The 'makesdna' utility takes  
care of this, it has a built-in list of .h header files, that are read  
and converted to the SDNA file.
When a file is saved, the functions that write structs look up the  
structure code and write that in the chunk header (struct BHead,  
writefile.c). At the end of the file, the full SDNA description file is  
appended to the .blend file, to make the file backward/upward  
Each compiled Blender has an SDNA description as well. When a file is  
read, the SDNA of the file is compared with the SDNA of the Blender  
executable. Structures that differ get flagged, and converted while  

Allowed conversions (changes) are:
- if a name is identical, but the type differs it tries to convert.  
Only conversions that make sense happen (e.g. short->int, or  
int->float, etc). Otherwise it is set at zero.
- a new variable is always initialized zero
- dimensions of arrays get fixed (e.g. [3][3] to [4][4])
- pointer sizes corrected (32 bits, 64 bits)
- char to float: divided by 255 automatically
- changes in structures within structures (within structures etc) work  

At the time, I didn't include automatic 'padding' in the system... it's  
the platform dependent habit of compilers to include empty spaces in  
structures, to conform alignment of data. For example, at SGI an 'int'  
should always start at an address that can be divided by 4. When you  
design a struct like this:

struct XYZ {
	char x_flag;
	float x;
	char y_flag;
	float y;
	char z_flag;
	float z;

The actual  length of the structure will be 6x4=24 bytes. Even worse, a  
struct like this:

struct ABC {
	char a;

is 8 bytes at an Alpha, and 4 bytes at 32 bits OS's.

Therefore, for correct SDNA structures in Blender, you have to design  
the structures padding-less, for all supported systems. These are the  

- structures are always multiples of 8 bytes in size
- structs within structs start at an 8-dividable location
- pointers start at an 8-dividable location, unless the previous  
variable is a pointer!
- ints/floats start at a 4-dividable location
- shorts start at a 2-dividable location

If you can't manage this, just instert 'pad' variables in structures.  
You'll find them in Blender more, it's meant to be free space that can  
be used for later. Do not use 'pad' variables in Blender!!!


Ton Roosendaal  Blender Foundation ton@blender.org