=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.
This commit is contained in:
Joseph Eagar 2006-11-17 04:46:48 +00:00
parent 24f4440d05
commit 8768707610
11 changed files with 1794 additions and 9 deletions

View File

@ -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 */

View File

@ -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);
}
}

View File

@ -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);

View File

@ -131,6 +131,7 @@
#include "BKE_softbody.h" // sbNew()
#include "BKE_texture.h" // for open_plugin_tex
#include "BKE_utildefines.h" // SWITCH_INT DATA ENDB DNA1 O_BINARY GLOB USER TEST REND
#include "BKE_idprop.h"
#include "BIF_butspace.h" // badlevel, for do_versions, patching event codes
#include "BIF_previewrender.h" // bedlelvel, for struct RenderInfo
@ -1233,8 +1234,86 @@ static void test_pointer_array(FileData *fd, void **mat)
}
}
/* ************ READ Brush *************** */
/* ************ READ ID Properties *************** */
void IDP_DirectLinkProperty(IDProperty *prop, int switch_endian, void *fd);
void IDP_LibLinkProperty(IDProperty *prop, int switch_endian, void *fd);
void IDP_DirectLinkArray(IDProperty *prop, int switch_endian, void *fd)
{
/*since we didn't save the extra string buffer, set totallen to len.*/
prop->totallen = prop->len;
prop->data.pointer = newdataadr(fd, prop->data.pointer);
if (switch_endian) {
int i;
if (prop->subtype == IDP_INT) {
for (i=0; i<prop->len; i++) {
if (sizeof(int) == 4) {
SWITCH_INT(((int*)prop->data.pointer)[i]);
} else if (sizeof(int) == 8) {
SWITCH_LONGINT(((int*)prop->data.pointer)[i])
}
}
} else if (prop->subtype == IDP_FLOAT) {
int i;
for (i=0; i<prop->len; i++) {
SWITCH_INT(((int*)prop->data.pointer)[i]);
}
} else printf("Unkown ID property array type! could not do endian switching!!\n");
}
}
void IDP_DirectLinkString(IDProperty *prop, int switch_endian, void *fd)
{
/*since we didn't save the extra string buffer, set totallen to len.*/
prop->totallen = prop->len;
prop->data.pointer = newdataadr(fd, prop->data.pointer);
}
void IDP_DirectLinkGroup(IDProperty *prop, int switch_endian, void *fd)
{
ListBase *lb = &prop->data.group;
IDProperty *loop;
link_list(fd, lb);
/*Link child id properties now*/
for (loop=prop->data.group.first; loop; loop=loop->next) {
IDP_DirectLinkProperty(loop, switch_endian, fd);
}
}
void IDP_DirectLinkProperty(IDProperty *prop, int switch_endian, void *fd)
{
/*we pack floats and ints in an int, this may cause problems where sizeof(int) != sizeof(float)*/
if (sizeof(void*) == 8 && switch_endian != 0 && BLO_test_64bits(fd)) {
if (prop->type == IDP_FLOAT && sizeof(int) == 8) {
/*un-longint switch it (as DNA saw a long int here) then int switch it*/
SWITCH_LONGINT(prop->data.val);
SWITCH_INT(prop->data.val);
}
}
switch (prop->type) {
case IDP_GROUP:
IDP_DirectLinkGroup(prop, switch_endian, fd);
break;
case IDP_STRING:
IDP_DirectLinkString(prop, switch_endian, fd);
break;
case IDP_ARRAY:
IDP_DirectLinkArray(prop, switch_endian, fd);
break;
}
}
/*stub function*/
void IDP_LibLinkProperty(IDProperty *prop, int switch_endian, void *fd)
{
}
/* ************ READ Brush *************** */
/* library brush linking after fileread */
static void lib_link_brush(FileData *fd, Main *main)
{
@ -2198,6 +2277,11 @@ static void lib_link_material(FileData *fd, Main *main)
ma= main->mat.first;
while(ma) {
if(ma->id.flag & LIB_NEEDLINK) {
/*Link ID Properties -- and copy this comment EXACTLY for easy finding
of library blocks that implement this.*/
/*set head id properties type to IDP_GROUP; calloc kindly initilizes
all other needed values :) */
if (ma->id.properties) IDP_LibLinkProperty(ma->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
ma->ipo= newlibadr_us(fd, ma->id.lib, ma->ipo);
ma->group= newlibadr_us(fd, ma->id.lib, ma->group);
@ -2228,6 +2312,11 @@ static void direct_link_material(FileData *fd, Material *ma)
ma->mtex[a]= newdataadr(fd, ma->mtex[a]);
}
if (ma->id.properties) {
ma->id.properties = newdataadr(fd, ma->id.properties);
IDP_DirectLinkProperty(ma->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
ma->ramp_col= newdataadr(fd, ma->ramp_col);
ma->ramp_spec= newdataadr(fd, ma->ramp_spec);
@ -2412,6 +2501,7 @@ static void lib_link_object(FileData *fd, Main *main)
ob= main->object.first;
while(ob) {
if(ob->id.flag & LIB_NEEDLINK) {
if (ob->id.properties) IDP_LibLinkProperty(ob->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
ob->parent= newlibadr(fd, ob->id.lib, ob->parent);
ob->track= newlibadr(fd, ob->id.lib, ob->track);
@ -2635,6 +2725,11 @@ static void direct_link_object(FileData *fd, Object *ob)
ob->pose= newdataadr(fd, ob->pose);
direct_link_pose(fd, ob->pose);
if (ob->id.properties) {
ob->id.properties = newdataadr(fd, ob->id.properties);
IDP_DirectLinkProperty(ob->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
link_list(fd, &ob->defbase);
direct_link_nlastrips(fd, &ob->nlastrips);
link_list(fd, &ob->constraintChannels);
@ -2706,6 +2801,7 @@ static void direct_link_object(FileData *fd, Object *ob)
sb->bpoint= NULL; // init pointers so it gets rebuilt nicely
sb->bspring= NULL;
sb->scratch= NULL;
sb->keys= newdataadr(fd, sb->keys);
test_pointer_array(fd, (void **)&sb->keys);

View File

@ -164,6 +164,7 @@ Important to know is that 'streaming' has been added to files, for Blender Publi
#include "BKE_sound.h" /* ... and for samples */
#include "BKE_utildefines.h" // for defines
#include "BKE_modifier.h"
#include "BKE_idprop.h"
#ifdef WITH_VERSE
#include "BKE_verse.h"
#include "BIF_verse.h"
@ -376,6 +377,54 @@ static void writedata(WriteData *wd, int filecode, int len, void *adr) /* do not
}
/* *************** writing some direct data structs used in more code parts **************** */
/*These functions are used by blender's .blend system for file saving/loading.*/
void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd);
void IDP_WriteProperty(IDProperty *prop, void *wd);
void IDP_WriteArray(IDProperty *prop, void *wd)
{
/*REMEMBER to set totalen to len in the linking code!!*/
if (prop->data.pointer) {
writedata(wd, DATA, MEM_allocN_len(prop->data.pointer), prop->data.pointer);
}
}
void IDP_WriteString(IDProperty *prop, void *wd)
{
/*REMEMBER to set totalen to len in the linking code!!*/
writedata(wd, DATA, prop->len+1, prop->data.pointer);
}
void IDP_WriteGroup(IDProperty *prop, void *wd)
{
IDProperty *loop;
for (loop=prop->data.group.first; loop; loop=loop->next) {
IDP_WriteProperty(loop, wd);
}
}
/* Functions to read/write ID Properties */
void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd)
{
switch (prop->type) {
case IDP_GROUP:
IDP_WriteGroup(prop, wd);
break;
case IDP_STRING:
IDP_WriteString(prop, wd);
break;
case IDP_ARRAY:
IDP_WriteArray(prop, wd);
break;
}
}
void IDP_WriteProperty(IDProperty *prop, void *wd)
{
writestruct(wd, DATA, "IDProperty", 1, prop);
IDP_WriteProperty_OnlyData(prop, wd);
}
static void write_curvemapping(WriteData *wd, CurveMapping *cumap)
{
@ -405,7 +454,7 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree)
write_curvemapping(wd, node->storage);
else if(ntree->type==NTREE_COMPOSIT && (node->type==CMP_NODE_TIME || node->type==CMP_NODE_CURVE_VEC || node->type==CMP_NODE_CURVE_RGB))
write_curvemapping(wd, node->storage);
else
else
writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage);
}
for(sock= node->inputs.first; sock; sock= sock->next)
@ -773,6 +822,12 @@ static void write_objects(WriteData *wd, ListBase *idbase)
if(vnode) ob->vnode = (void*)vnode;
#endif
/*Write ID Properties -- and copy this comment EXACTLY for easy finding
of library blocks that implement this.*/
/*manually set head group property to IDP_GROUP, just in case it hadn't been
set yet :) */
if (ob->id.properties) IDP_WriteProperty(ob->id.properties, wd);
/* direct data */
writedata(wd, DATA, sizeof(void *)*ob->totcol, ob->mat);
write_effects(wd, &ob->effect);
@ -1147,6 +1202,12 @@ static void write_materials(WriteData *wd, ListBase *idbase)
if(ma->id.us>0 || wd->current) {
/* write LibData */
writestruct(wd, ID_MA, "Material", 1, ma);
/*Write ID Properties -- and copy this comment EXACTLY for easy finding
of library blocks that implement this.*/
/*manually set head group property to IDP_GROUP, just in case it hadn't been
set yet :) */
if (ma->id.properties) IDP_WriteProperty(ma->id.properties, wd);
for(a=0; a<MAX_MTEX; a++) {
if(ma->mtex[a]) writestruct(wd, DATA, "MTex", 1, ma->mtex[a]);
@ -1424,7 +1485,7 @@ static void write_screens(WriteData *wd, ListBase *scrbase)
writestruct(wd, DATA, "SpaceImage", 1, sl);
if(sima->cumap)
write_curvemapping(wd, sima->cumap);
write_curvemapping(wd, sima->cumap);
}
else if(sl->spacetype==SPACE_IMASEL) {
writestruct(wd, DATA, "SpaceImaSel", 1, sl);

View File

@ -1,9 +1,9 @@
/**
* blenlib/DNA_ID.h (mar-2001 nzc)
*
* ID and Library types, which are fundamental for sdna,
* ID and Library types, which are fundamental for sdna,
*
* $Id$
* $Id$
*
* ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
*
@ -36,21 +36,70 @@
#ifndef DNA_ID_H
#define DNA_ID_H
#include "DNA_listBase.h"
#ifdef __cplusplus
extern "C" {
#endif
/* There's a nasty circular dependency here.... void* to the rescue! I
* really wonder why this is needed. */
struct Library;
struct FileData;
struct ID;
typedef struct IDPropertyData {
void *pointer;
ListBase group;
int val, pad;
} IDPropertyData;
typedef struct IDProperty {
struct IDProperty *next, *prev;
char name[32];
char type, subtype;
short flag;
IDPropertyData data;
int len; /* array length, also (this is important!) string length + 1.
the idea is to be able to reuse array realloc functions on strings.*/
/*totallen is total length of allocated array/string, including a buffer.
Note that the buffering is mild; the code comes from python's list implementation.*/
int totallen; /*strings and arrays are both buffered, though the buffer isn't
saved. at least it won't be when I write that code. :)*/
int saved; /*saved is used to indicate if this struct has been saved yet.
seemed like a good idea as a pad var was needed anyway :)*/
} IDProperty;
#define MAX_IDPROP_NAME 32
#define DEFAULT_ALLOC_FOR_NULL_STRINGS 64
/*->type*/
#define IDP_STRING 0
#define IDP_INT 1
#define IDP_FLOAT 2
#define IDP_VECTOR 3
#define IDP_MATRIX 4
#define IDP_ARRAY 5
#define IDP_GROUP 6
#define IDP_ID 7
/*special types for vector, matrices and arrays
these arn't quite completely implemented, and
may be removed.*/
#define IDP_MATRIX4X4 9
#define IDP_MATRIX3X3 10
#define IDP_VECTOR2D 11
#define IDP_VECTOR3D 12
#define IDP_VECTOR4D 13
#define IDP_FILE 14
/*add any future new id property types here.*/
/* watch it: Sequence has identical beginning. */
/**
* ID is the first thing included in all serializable types. It
* provides a common handle to place all data in double-linked lists.
* */
/* There's a nasty circular dependency here.... void* to the rescue! I
* really wonder why this is needed. */
typedef struct ID {
void *next, *prev;
struct ID *newid;
@ -63,6 +112,7 @@ typedef struct ID {
*/
short flag;
int icon_id;
IDProperty *properties;
} ID;
/**

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,26 @@
#include <Python.h>
struct ID;
struct IDProperty;
struct BPy_IDGroup_Iter;
typedef struct BPy_IDProperty {
PyObject_VAR_HEAD
struct ID *id;
struct IDProperty *prop;
PyObject *data_wrap;
} BPy_IDProperty;
typedef struct BPy_IDArray {
PyObject_VAR_HEAD
struct ID *id;
struct IDProperty *prop;
} BPy_IDArray;
typedef struct BPy_IDGroup_Iter {
PyObject_VAR_HEAD
BPy_IDProperty *group;
struct IDProperty *cur;
} BPy_IDGroup_Iter;
PyObject *BPy_Wrap_IDProperty(struct ID *id, struct IDProperty *prop);

View File

@ -41,6 +41,7 @@
#include "BKE_library.h"
#include "BKE_material.h"
#include "BKE_texture.h"
#include "BKE_idprop.h"
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "BSE_editipo.h"
@ -52,6 +53,7 @@
#include "Ipo.h"
#include "Group.h"
#include "gen_utils.h"
#include "IDProp.h"
/*****************************************************************************/
/* Python BPy_Material defaults: */
@ -602,6 +604,7 @@ static PyObject *Material_clearScriptLinks(BPy_Material *self, PyObject *args);
static PyObject *Material_insertIpoKey( BPy_Material * self, PyObject * args );
static PyObject *Material_copy( BPy_Material * self );
static PyObject *Material_getProperties( BPy_Material * self );
/*****************************************************************************/
@ -609,6 +612,8 @@ static PyObject *Material_copy( BPy_Material * self );
/*****************************************************************************/
static PyMethodDef BPy_Material_methods[] = {
/* name, method, flags, doc */
{"getProperties", ( PyCFunction) Material_getProperties, METH_NOARGS,
"() Return Material's ID Properties"},
{"getName", ( PyCFunction ) Material_getName, METH_NOARGS,
"() - Return Material's name"},
{"getIpo", ( PyCFunction ) Material_getIpo, METH_NOARGS,
@ -1080,6 +1085,8 @@ static PyGetSetDef BPy_Material_getseters[] = {
(getter)Material_getUsers, (setter)NULL,
"Number of material users",
NULL},
{"properties", (getter) Material_getProperties, (setter)NULL,
"Get material's ID properties"},
{NULL,NULL,NULL,NULL,NULL} /* Sentinel */
};
@ -1280,6 +1287,12 @@ Material *GetMaterialByName( char *name )
/* Python BPy_Material methods: */
/*****************************************************************************/
static PyObject *Material_getProperties( BPy_Material * self )
{
/*sanity check, we set parent property type to Group here*/
return BPy_Wrap_IDProperty((ID*)self->material, IDP_GetProperties((ID*)self->material, 1));
}
static PyObject *Material_getIpo( BPy_Material * self )
{
Ipo *ipo = self->material->ipo;

View File

@ -66,6 +66,7 @@ struct rctf;
#include "BKE_scene.h"
#include "BKE_nla.h"
#include "BKE_material.h"
#include "BKE_idprop.h"
#include "BSE_editipo.h"
#include "BSE_edit.h"
@ -114,6 +115,7 @@ struct rctf;
#include "gen_utils.h"
#include "EXPP_interface.h"
#include "BIF_editkey.h"
#include "IDProp.h"
/* Defines for insertIpoKey */
@ -326,6 +328,7 @@ struct PyMethodDef M_Object_methods[] = {
static int setupSB(Object* ob); /*Make sure Softbody Pointer is initialized */
static int setupPI(Object* ob);
static PyObject *Object_GetProperties(BPy_Object * self);
static PyObject *Object_buildParts( BPy_Object * self );
static PyObject *Object_clearIpo( BPy_Object * self );
static PyObject *Object_clrParent( BPy_Object * self, PyObject * args );
@ -750,6 +753,8 @@ works only if self and the object specified are of the same type."},
"() - Insert a Shape Key in the current object"},
{"__copy__", ( PyCFunction ) Object_copy, METH_NOARGS,
"() - Return a copy of this object."},
{"getProperties", ( PyCFunction ) Object_GetProperties, METH_NOARGS,
"() return a reference to the ID properties associated with this object."},
{NULL, NULL, 0, NULL}
};
@ -982,6 +987,12 @@ static PyObject *M_Object_Duplicate( PyObject * self_unused,
/* Python BPy_Object methods: */
/*****************************************************************************/
static PyObject *Object_GetProperties(BPy_Object * self)
{
return BPy_Wrap_IDProperty((ID*)self->object, IDP_GetProperties((ID*)self->object, 1));
}
static PyObject *Object_buildParts( BPy_Object * self )
{
build_particle_system( self->object );
@ -4983,7 +4994,8 @@ static PyGetSetDef BPy_Object_getseters[] = {
(getter)Object_getType, (setter)NULL,
"String describing Object type",
NULL},
{"properties", (getter)Object_GetProperties, (setter)NULL,
"Get the ID properties associated with this object"},
{NULL,NULL,NULL,NULL,NULL} /* Sentinel */
};

View File

@ -0,0 +1,65 @@
class IDProperty:
"""
The IDProperty wrapper type
===========================
@ivar name: the name of the property
@ivar type: the property type (is read-only)
@ivar data: the property's data.
"""
class IDGroup:
"""
The IDGroup wrapper type
========================
This type supports both iteration and the []
operator to get child ID properties.
You can also add new properties using the [] operator.
For example:
group['a float!'] = 0.0
group['an int!'] = 0
group['a string!'] = "hi!"
group['an array!'] = [0, 0, 1.0, 0] #note that any floats in the list
#makes the whole list a float array.
group['a subgroup!] = {"float": 0.0, "an int": 1.0, "an array": [1, 2], \
"another subgroup": {"a": 0.0, "str": "bleh"}}
you also do del group['item']
"""
def newProperty(type, name, array_type="Float", val=""):
"""
This function creates a new child ID property in the group.
@type type: an int or a string
@param type: The ID property type. Can be:
"String" or Blender.IDPropTypes['String']
"Int" or Blender.IDPropTypes['Int']
"Float" or Blender.IDPropTypes['Float']
"Array" or Blender.IDPropTypes['Array']
"Group" or Blender.IDPropTypes['Group']
"""
def deleteProperty(prop):
"""
deletes a property, takes either a name or a reference
as an argument.
"""
class IDArray:
"""
The IDArray wrapper type
========================
@ivar type: returns the type of the array, can be either IDP_Int or IDP_Float
"""
def __getitem__(self):
pass
def __setitem__(self):
pass
def __len__(self):
pass