diff options
author | Joseph Eagar <joeedh@gmail.com> | 2006-11-17 07:46:48 +0300 |
---|---|---|
committer | Joseph Eagar <joeedh@gmail.com> | 2006-11-17 07:46:48 +0300 |
commit | 8768707610fbc1cea2bde069cdfd6d3f3e2fc522 (patch) | |
tree | fb8347ad36f60dede2883b587688184c3631cbcc /source/blender/blenkernel | |
parent | 24f4440d05aa626f35c27758698af396ea94ff76 (diff) |
=ID Properties=
This commit adds supports for per-ID properties to blender.
See http://mediawiki.blender.org/index.php/BlenderDev/ID_Property
for more information on how it all works.
ID properties are accesable by python; but note that
bindings have only been added to Object and Material thus
far. However adding more bindings is easy and I plan
on adding several more hopefully within an hour of this inital
commit.
A generic UI panel is also planned, that will go wherever its
needed; for example in the material buttons, editing buttons, etc.
I'll likely submit the initial code for that as a patch, though,
so matt and ton and others can go over it and make sure it's
all good. :)
VERY important, if you intend to use ID properties please
go to http://mediawiki.blender.org/index.php/BlenderDev/PropertyStandards
and start writing the appropriate standards for it.
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r-- | source/blender/blenkernel/BKE_idprop.h | 112 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/idprop.c | 338 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/library.c | 5 |
3 files changed, 455 insertions, 0 deletions
diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h new file mode 100644 index 00000000000..d61d274dd36 --- /dev/null +++ b/source/blender/blenkernel/BKE_idprop.h @@ -0,0 +1,112 @@ +#ifndef _BKE_IDPROP_H +#define _BKE_IDPROP_H + +#include "DNA_ID.h" + +/* +these two are included for their (new :P )function +pointers. +*/ +#include "BLO_readfile.h" +#include "BLO_writefile.h" + +struct WriteData; +struct FileData; + +struct IDProperty; +struct ID; + +typedef union { + int i; + float f; + char *str; + struct ID *id; + struct { + short type; + short len; + } array; + struct { + int matvec_size; + float *example; + } matrix_or_vector; +} IDPropertyTemplate; + +/* ----------- Array Type ----------- */ +/*this function works for strings too!*/ +void IDP_ResizeArray(struct IDProperty *prop, int newlen); +void IDP_FreeArray(struct IDProperty *prop); +void IDP_UnlinkArray(struct IDProperty *prop); + +/* ---------- String Type ------------ */ +void IDP_AssignString(struct IDProperty *prop, char *st); +void IDP_ConcatStringC(struct IDProperty *prop, char *st); +void IDP_ConcatString(struct IDProperty *str1, struct IDProperty *append); +void IDP_FreeString(struct IDProperty *prop); + +/*-------- ID Type -------*/ +void IDP_LinkID(struct IDProperty *prop, ID *id); +void IDP_UnlinkID(struct IDProperty *prop); + +/*-------- Group Functions -------*/ +void IDP_AddToGroup(struct IDProperty *group, struct IDProperty *prop); +void IDP_RemFromGroup(struct IDProperty *group, struct IDProperty *prop); +IDProperty *IDP_GetPropertyFromGroup(struct IDProperty *prop, char *name); + +/*Get an iterator to iterate over the members of an id property group. + Note that this will automatically free the iterator once iteration is complete; + if you stop the iteration before hitting the end, make sure to call + IDP_FreeIterBeforeEnd().*/ +void *IDP_GetGroupIterator(struct IDProperty *prop); + +/*Returns the next item in the iteration. To use, simple for a loop like the following: + while (IDP_GroupIterNext(iter) != NULL) { + . . . + }*/ +void *IDP_GroupIterNext(void *vself); + +/*Frees the iterator pointed to at vself, only use this if iteration is stopped early; + when the iterator hits the end of the list it'll automatially free itself.*/ +void IDP_FreeIterBeforeEnd(void *vself); + +/*-------- Main Functions --------*/ +/*Get the Group property that contains the id properties for ID id. Set create_if_needed + to create the Group property and attach it to id if it doesn't exist; otherwise + the function will return NULL if there's no Group property attached to the ID.*/ +struct IDProperty *IDP_GetProperties(struct ID *id, int create_if_needed); + +/* +Allocate a new ID. + +This function takes three arguments: the ID property type, a union which defines +it's initial value, and a name. + +The union is simple to use; see the top of this header file for its definition. +An example of using this function: + + IDPropertyTemplate val; + IDProperty *group, *idgroup, *color; + group = IDP_New(IDP_GROUP, val, "group1"); //groups don't need a template. + + val.array.len = 4 + val.array.type = IDP_FLOAT; + color = IDP_New(IDP_ARRAY, val, "color1"); + + idgroup = IDP_GetProperties(some_id, 1); + IDP_AddToGroup(idgroup, color); + IDP_AddToGroup(idgroup, group); + +Note that you MUST either attach the id property to an id property group with +IDP_AddToGroup or MEM_freeN the property, doing anything else might result in +a memory leak. +*/ +struct IDProperty *IDP_New(int type, IDPropertyTemplate val, char *name); +\ +/*NOTE: this will free all child properties of list arrays and groups! + Also, note that this does NOT unlink anything! Plus it doesn't free + the actual struct IDProperty struct either.*/ +void IDP_FreeProperty(struct IDProperty *prop); + +/*Unlinks any struct IDProperty<->ID linkage that might be going on.*/ +void IDP_UnlinkProperty(struct IDProperty *prop); + +#endif /* _BKE_IDPROP_H */ diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c new file mode 100644 index 00000000000..ade4176eeac --- /dev/null +++ b/source/blender/blenkernel/intern/idprop.c @@ -0,0 +1,338 @@ +#include "DNA_listBase.h" +#include "DNA_ID.h" + +#include "BKE_idprop.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_utildefines.h" + +#include "BLI_blenlib.h" + +#include "MEM_guardedalloc.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* IDPropertyTemplate is a union in DNA_ID.h */ +static char idp_size_table[] = { + 0, /*strings don't have fixed sizes :)*/ + sizeof(int), + sizeof(float), + sizeof(float)*3, /*Vector type*/ + sizeof(float)*16, /*Matrix type, we allocate max 4x4 even if in 3x3 mode*/ + 0, /*arrays don't have a fixed size either :)*/ + sizeof(ListBase), /*Group type*/ + sizeof(void*) +}; + + +/* ----------- Array Type ----------- */ + +/*this function works for strings too!*/ +void IDP_ResizeArray(IDProperty *prop, int newlen) +{ + void *newarr; + int newsize=newlen; + + /*first check if the array buffer size has room*/ + /*if newlen is 200 chars less then totallen, reallocate anyway*/ + if (newlen <= prop->totallen && prop->totallen - newlen < 200) { + prop->len = newlen; + return; + } + + /* - Note: This code comes from python, here's the corrusponding comment. - */ + /* This over-allocates proportional to the list size, making room + * for additional growth. The over-allocation is mild, but is + * enough to give linear-time amortized behavior over a long + * sequence of appends() in the presence of a poorly-performing + * system realloc(). + * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... + */ + newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize; + + newarr = MEM_callocN(idp_size_table[prop->type]*newsize, "idproperty array resized"); + /*newlen is bigger*/ + if (newlen >= prop->len) memcpy(newarr, prop->data.pointer, prop->len*idp_size_table[prop->type]); + /*newlen is smaller*/ + else memcpy(newarr, prop->data.pointer, newlen*prop->len*idp_size_table[prop->type]); + + MEM_freeN(prop->data.pointer); + prop->data.pointer = newarr; + prop->len = newlen; + prop->totallen = newsize; +} + +/*does NOT unlink anything!*/ +/*Ok, the way things work, Groups and List Arrays free the ID Property structs of their children. + + This is because all ID Property freeing functions free only direct data (not the ID Property + struct itself), but for Groups and List Arrays their child properties *are* considered + direct data. +*/ + void IDP_FreeArray(IDProperty *prop) +{ + if (prop->data.pointer) + MEM_freeN(prop->data.pointer); +} + +/*taken from readfile.c*/ +#define SWITCH_LONGINT(a) { \ + char s_i, *p_i; \ + p_i= (char *)&(a); \ + s_i=p_i[0]; p_i[0]=p_i[7]; p_i[7]=s_i; \ + s_i=p_i[1]; p_i[1]=p_i[6]; p_i[6]=s_i; \ + s_i=p_i[2]; p_i[2]=p_i[5]; p_i[5]=s_i; \ + s_i=p_i[3]; p_i[3]=p_i[4]; p_i[4]=s_i; } + + + +/* ---------- String Type ------------ */ +void IDP_AssignString(IDProperty *prop, char *st) +{ + int stlen; + + stlen = strlen(st); + + IDP_ResizeArray(prop, stlen+1); /*make room for null byte :) */ + strcpy(prop->data.pointer, st); +} + +void IDP_ConcatStringC(IDProperty *prop, char *st) +{ + int newlen; + + newlen = prop->len + strlen(st); + /*we have to remember that prop->len includes the null byte for strings. + so there's no need to add +1 to the resize function.*/ + IDP_ResizeArray(prop, newlen); + strcat(prop->data.pointer, st); +} + +void IDP_ConcatString(IDProperty *str1, IDProperty *append) +{ + int newlen; + + /*since ->len for strings includes the NULL byte, we have to subtract one or + we'll get an extra null byte after each concatination operation.*/ + newlen = str1->len + append->len - 1; + IDP_ResizeArray(str1, newlen); + strcat(str1->data.pointer, append->data.pointer); +} + +void IDP_FreeString(IDProperty *prop) +{ + MEM_freeN(prop->data.pointer); +} + + +/*-------- ID Type -------*/ + +void IDP_LinkID(IDProperty *prop, ID *id) +{ + if (prop->data.pointer) ((ID*)prop->data.pointer)->us--; + prop->data.pointer = id; + id_us_plus(id); +} + +void IDP_UnlinkID(IDProperty *prop) +{ + ((ID*)prop->data.pointer)->us--; +} + +/*-------- Group Functions -------*/ +void IDP_AddToGroup(IDProperty *group, IDProperty *prop) +{ + group->len++; + BLI_addtail(&group->data.group, prop); +} + +void IDP_RemFromGroup(IDProperty *group, IDProperty *prop) +{ + group->len--; + BLI_remlink(&group->data.group, prop); +} + +IDProperty *IDP_GetPropertyFromGroup(IDProperty *prop, char *name) +{ + IDProperty *loop; + for (loop=prop->data.group.first; loop; loop=loop->next) { + if (strcmp(prop->name, name)==0) return prop; + } + return NULL; +} + +typedef struct IDPIter { + void *next; + IDProperty *parent; +} IDPIter; + +void *IDP_GetGroupIterator(IDProperty *prop) +{ + IDPIter *iter = MEM_callocN(sizeof(IDPIter), "IDPIter"); + iter->next = prop->data.group.first; + iter->parent = prop; + return (void*) iter; +} + +void *IDP_GroupIterNext(void *vself) +{ + IDPIter *self = (IDPIter*) vself; + Link *next = (Link*) self->next; + if (self->next == NULL) { + MEM_freeN(self); + return NULL; + } + + self->next = next->next; + return (void*) next; +} + +void IDP_FreeIterBeforeEnd(void *vself) +{ + MEM_freeN(vself); +} + +/*Ok, the way things work, Groups and List Arrays free the ID Property structs of their children. + This is because all ID Property freeing functions free only direct data (not the ID Property + struct itself), but for Groups and List Arrays their child properties *are* considered + direct data.*/ +void IDP_FreeGroup(IDProperty *prop) +{ + IDProperty *loop, *next; + for (loop=prop->data.group.first; loop; loop=next) + { + next = loop->next; + IDP_FreeProperty(loop); + MEM_freeN(loop); + } +} + + +/*-------- Main Functions --------*/ + +IDProperty *IDP_GetProperties(ID *id, int create_if_needed) +{ + if (id->properties) return id->properties; + else { + if (create_if_needed) { + id->properties = MEM_callocN(sizeof(IDProperty), "IDProperty"); + id->properties->type = IDP_GROUP; + } + return id->properties; + } +} + +IDProperty *IDP_New(int type, IDPropertyTemplate val, char *name) +{ + IDProperty *prop=NULL; + + switch (type) { + case IDP_INT: + prop = MEM_callocN(sizeof(IDProperty), "IDProperty int"); + prop->data.val = val.i; + break; + case IDP_FLOAT: + prop = MEM_callocN(sizeof(IDProperty), "IDProperty float"); + *(float*)&prop->data.val = val.f; + break; + case IDP_ARRAY: + { + /*for now, we only support float and int arrays*/ + if (val.array.type == IDP_FLOAT || val.array.type == IDP_INT) { + prop = MEM_callocN(sizeof(IDProperty), "IDProperty array"); + prop->len = prop->totallen = val.array.len; + prop->subtype = val.array.type; + prop->data.pointer = MEM_callocN(idp_size_table[val.array.type]*val.array.len, "id property array"); + break; + } else { + return NULL; + } + } + case IDP_STRING: + { + char *st = val.str; + int stlen; + + prop = MEM_callocN(sizeof(IDProperty), "IDProperty string"); + if (st == NULL) { + prop->data.pointer = MEM_callocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1"); + prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS; + prop->len = 1; /*NULL string, has len of 1 to account for null byte.*/ + } else { + stlen = strlen(st) + 1; + prop->data.pointer = MEM_callocN(stlen, "id property string 2"); + prop->len = prop->totallen = stlen; + strcpy(prop->data.pointer, st); + } + break; + } + case IDP_GROUP: + { + prop = MEM_callocN(sizeof(IDProperty), "IDProperty group"); + /* heh I think all needed values are set properly by calloc anyway :) */ + break; + } + case IDP_MATRIX: + prop = MEM_callocN(sizeof(IDProperty), "IDProperty array"); + if (val.matrix_or_vector.matvec_size == IDP_MATRIX4X4) + prop->data.pointer = MEM_callocN(sizeof(float)*4*4, "matrix 4x4 idproperty"); + else + prop->data.pointer = MEM_callocN(sizeof(float)*3*3, "matrix 3x3 idproperty"); + case IDP_VECTOR: + prop = MEM_callocN(sizeof(IDProperty), "IDProperty array"); + switch (val.matrix_or_vector.matvec_size) { + case IDP_VECTOR4D: + prop->data.pointer = MEM_callocN(sizeof(float)*4, "vector 4d idproperty"); + break; + case IDP_VECTOR3D: + prop->data.pointer = MEM_callocN(sizeof(float)*3, "vector 3d idproperty"); + break; + case IDP_VECTOR2D: + prop->data.pointer = MEM_callocN(sizeof(float)*2, "vector 2d idproperty"); + break; + + } + default: + { + prop = MEM_callocN(sizeof(IDProperty), "IDProperty array"); + break; + } + } + + prop->type = type; + strncpy(prop->name, name, MAX_IDPROP_NAME); + return prop; +} + +/*NOTE: this will free all child properties of list arrays and groups! + Also, note that this does NOT unlink anything! Plus it doesn't free + the actual IDProperty struct either.*/ +void IDP_FreeProperty(IDProperty *prop) +{ + switch (prop->type) { + case IDP_ARRAY: + IDP_FreeArray(prop); + break; + case IDP_STRING: + IDP_FreeString(prop); + break; + case IDP_GROUP: + IDP_FreeGroup(prop); + break; + case IDP_VECTOR: + case IDP_MATRIX: + MEM_freeN(prop->data.pointer); + break; + } +} + +/*Unlinks any IDProperty<->ID linkage that might be going on.*/ +void IDP_UnlinkProperty(IDProperty *prop) +{ + switch (prop->type) { + case IDP_ID: + IDP_UnlinkID(prop); + } +} diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 2917853b72d..e6aa0208a5e 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -110,6 +110,7 @@ #include "BKE_node.h" #include "BKE_effect.h" #include "BKE_brush.h" +#include "BKE_idprop.h" #include "BPI_script.h" @@ -490,6 +491,10 @@ void free_libblock(ListBase *lb, void *idv) break; } + if (id->properties) { + IDP_FreeProperty(id->properties); + MEM_freeN(id->properties); + } BLI_remlink(lb, id); MEM_freeN(id); |