diff options
Diffstat (limited to 'source/blender/blenkernel/intern/library.c')
-rw-r--r-- | source/blender/blenkernel/intern/library.c | 905 |
1 files changed, 905 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c new file mode 100644 index 00000000000..97ede69280c --- /dev/null +++ b/source/blender/blenkernel/intern/library.c @@ -0,0 +1,905 @@ + +/* library.c aug 94 MIXED MODEL + * + * jan 95 + * + * afhandeling ID's en libraries + * allocceren en vrijgeven alle library data + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <stdlib.h> + +#ifdef WIN32 +#include "BLI_winstuff.h" +#endif + +#include "MEM_guardedalloc.h" + +/* all types are needed here, in order to do memory operations */ +#include "DNA_ID.h" +#include "DNA_listBase.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_mesh_types.h" +#include "DNA_lattice_types.h" +#include "DNA_curve_types.h" +#include "DNA_meta_types.h" +#include "DNA_material_types.h" +#include "DNA_texture_types.h" +#include "DNA_ika_types.h" +#include "DNA_image_types.h" +#include "DNA_wave_types.h" +#include "DNA_lamp_types.h" +#include "DNA_camera_types.h" +#include "DNA_ipo_types.h" +#include "DNA_key_types.h" +#include "DNA_world_types.h" +#include "DNA_screen_types.h" +#include "DNA_vfont_types.h" +#include "DNA_text_types.h" +#include "DNA_sound_types.h" +#include "DNA_group_types.h" +#include "DNA_armature_types.h" +#include "DNA_action_types.h" + +#include "BLI_blenlib.h" +#include "BLI_dynstr.h" + +#include "BKE_bad_level_calls.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_global.h" +#include "BKE_sound.h" +#include "BKE_object.h" +#include "BKE_screen.h" +#include "BKE_mesh.h" +#include "BKE_material.h" +#include "BKE_curve.h" +#include "BKE_mball.h" + #include "BKE_text.h" +#include "BKE_texture.h" +#include "BKE_scene.h" +#include "BKE_image.h" +#include "BKE_ika.h" +#include "BKE_ipo.h" +#include "BKE_key.h" +#include "BKE_world.h" +#include "BKE_font.h" +#include "BKE_group.h" +#include "BKE_lattice.h" +#include "BKE_armature.h" +#include "BKE_action.h" + +#define MAX_IDPUP 30 /* was 24 */ +#define MAX_LIBARRAY 100 /* was 30 */ + +/* ************* ALGEMEEN ************************ */ + +void id_lib_extern(ID *id) +{ + if(id) { + if(id->flag & LIB_INDIRECT) { + id->flag -= LIB_INDIRECT; + id->flag |= LIB_EXTERN; + } + } +} + +void id_us_plus(ID *id) +{ + if(id) { + id->us++; + if(id->flag & LIB_INDIRECT) { + id->flag -= LIB_INDIRECT; + id->flag |= LIB_EXTERN; + } + } +} + +ListBase *wich_libbase(Main *mainlib, short type) +{ + switch( type ) { + case ID_SCE: + return &(mainlib->scene); + case ID_LI: + return &(mainlib->library); + case ID_OB: + return &(mainlib->object); + case ID_ME: + return &(mainlib->mesh); + case ID_CU: + return &(mainlib->curve); + case ID_MB: + return &(mainlib->mball); + case ID_MA: + return &(mainlib->mat); + case ID_TE: + return &(mainlib->tex); + case ID_IM: + return &(mainlib->image); + case ID_IK: + return &(mainlib->ika); + case ID_WV: + return &(mainlib->wave); + case ID_LT: + return &(mainlib->latt); + case ID_LA: + return &(mainlib->lamp); + case ID_CA: + return &(mainlib->camera); + case ID_IP: + return &(mainlib->ipo); + case ID_KE: + return &(mainlib->key); + case ID_WO: + return &(mainlib->world); + case ID_SCR: + return &(mainlib->screen); + case ID_VF: + return &(mainlib->vfont); + case ID_TXT: + return &(mainlib->text); + case ID_SO: + return &(mainlib->sound); + case ID_SAMPLE: + /* declared as an external in sound.h !!! */ + return (samples); + case ID_GR: + return &(mainlib->group); + case ID_AR: + return &(mainlib->armature); + case ID_AC: + return &(mainlib->action); + } + return 0; +} + +int set_listbasepointers(Main *main, ListBase **lb) +{ + /* BACKWARDS! let op volgorde van vrijgeven! (mesh<->mat) */ + + lb[0]= &(main->ipo); + lb[1]= &(main->key); + lb[2]= &(main->image); + lb[3]= &(main->tex); + lb[4]= &(main->mat); + lb[5]= &(main->vfont); + + /* Important!: When adding a new object type, + * the specific data should be inserted here + */ + + lb[6]= &(main->armature); + lb[7]= &(main->action); + + lb[8]= &(main->mesh); + lb[9]= &(main->curve); + lb[10]= &(main->mball); + lb[11]= &(main->ika); + lb[12]= &(main->wave); + lb[13]= &(main->latt); + lb[14]= &(main->lamp); + lb[15]= &(main->camera); + + lb[16]= &(main->world); + lb[17]= &(main->screen); + lb[18]= &(main->object); + lb[19]= &(main->scene); + lb[20]= &(main->library); + lb[21]= &(main->text); + lb[22]= &(main->sound); + lb[23]= &(main->group); + + lb[24]= samples; + lb[25]= 0; + + return 25; +} + +/* *********** ALLOC EN FREE ***************** + +free_libblock(ListBase *lb, ID *id ) + lijstbasis en datablok geven, alleen ID wordt uitgelezen + +void *alloc_libblock(ListBase *lb, type, name) + hangt in lijst en geeft nieuw ID + + ***************************** */ + +static ID *alloc_libblock_notest(short type) +{ + ID *id= 0; + + switch( type ) { + case ID_SCE: + id= MEM_callocN(sizeof(Scene), "scene"); + break; + case ID_LI: + id= MEM_callocN(sizeof(Library), "library"); + break; + case ID_OB: + id= MEM_callocN(sizeof(Object), "object"); + break; + case ID_ME: + id= MEM_callocN(sizeof(Mesh), "mesh"); + break; + case ID_CU: + id= MEM_callocN(sizeof(Curve), "curve"); + break; + case ID_MB: + id= MEM_callocN(sizeof(MetaBall), "mball"); + break; + case ID_MA: + id= MEM_callocN(sizeof(Material), "mat"); + break; + case ID_TE: + id= MEM_callocN(sizeof(Tex), "tex"); + break; + case ID_IM: + id= MEM_callocN(sizeof(Image), "image"); + break; + case ID_IK: + id= MEM_callocN(sizeof(Ika), "ika"); + break; + case ID_WV: + id= MEM_callocN(sizeof(Wave), "wave"); + break; + case ID_LT: + id= MEM_callocN(sizeof(Lattice), "latt"); + break; + case ID_LA: + id= MEM_callocN(sizeof(Lamp), "lamp"); + break; + case ID_CA: + id= MEM_callocN(sizeof(Camera), "camera"); + break; + case ID_IP: + id= MEM_callocN(sizeof(Ipo), "ipo"); + break; + case ID_KE: + id= MEM_callocN(sizeof(Key), "key"); + break; + case ID_WO: + id= MEM_callocN(sizeof(World), "world"); + break; + case ID_SCR: + id= MEM_callocN(sizeof(bScreen), "screen"); + break; + case ID_VF: + id= MEM_callocN(sizeof(VFont), "vfont"); + break; + case ID_TXT: + id= MEM_callocN(sizeof(Text), "text"); + break; + case ID_SO: + id= MEM_callocN(sizeof(bSound), "sound"); + break; + case ID_SAMPLE: + id = MEM_callocN(sizeof(bSample), "sound"); + break; + case ID_GR: + id= MEM_callocN(sizeof(Group), "sound"); + break; + case ID_AR: + id = MEM_callocN(sizeof(bArmature), "armature"); + break; + case ID_AC: + id = MEM_callocN(sizeof(bAction), "action"); + break; + } + return id; +} + +// used everywhere in blenkernel and text.c +void *alloc_libblock(ListBase *lb, short type, char *name) +{ + ID *id= 0; + + id= alloc_libblock_notest(type); + if(id) { + BLI_addtail(lb, id); + id->us= 1; + *( (short *)id->name )= type; + new_id(lb, id, name); + /* alfabetisch opnieuw invoegen: zit in new_id */ + } + return id; +} + +/* GS reads the memory pointed at in a specific ordering. There are, + * however two definitions for it. I have jotted them down here, both, + * but I think the first one is actually used. The thing is that + * big-endian systems might read this the wrong way round. OTOH, we + * constructed the IDs that are read out with this macro explicitly as + * well. I expect we'll sort it out soon... */ + +/* from blendef: */ +#define GS(a) (*((short *)(a))) + +/* from misc_util: flip the bytes from x */ +/*#define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1]) */ + +// used everywhere in blenkernel and text.c +void *copy_libblock(void *rt) +{ + ID *idn, *id; + ListBase *lb; + char *cp, *cpn; + int idn_len; + + id= rt; + + lb= wich_libbase(G.main, GS(id->name)); + idn= alloc_libblock(lb, GS(id->name), id->name+2); + + idn_len= MEM_allocN_len(idn); + if(idn_len - sizeof(ID) > 0) { + cp= (char *)id; + cpn= (char *)idn; + memcpy(cpn+sizeof(ID), cp+sizeof(ID), idn_len - sizeof(ID)); + } + + id->newid= idn; + idn->flag |= LIB_NEW; + + return idn; +} + +static void free_library(Library *lib) +{ + /* no freeing needed for libraries yet */ +} + +// used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c +void free_libblock(ListBase *lb, void *idv) +{ + ID *id= idv; + + switch( GS(id->name) ) { /* GetShort uit util.h */ + case ID_SCE: + free_scene((Scene *)id); + break; + case ID_LI: + free_library((Library *)id); + break; + case ID_OB: + free_object((Object *)id); + break; + case ID_ME: + free_mesh((Mesh *)id); + break; + case ID_CU: + free_curve((Curve *)id); + break; + case ID_MB: + free_mball((MetaBall *)id); + break; + case ID_MA: + free_material((Material *)id); + break; + case ID_TE: + free_texture((Tex *)id); + break; + case ID_IM: + free_image((Image *)id); + break; + case ID_IK: + free_ika((Ika *)id); + break; + case ID_WV: + /* free_wave(id); */ + break; + case ID_LT: + free_lattice((Lattice *)id); + break; + case ID_LA: + free_lamp((Lamp *)id); + break; + case ID_CA: +/* free_camera(id); */ + /* cast wasn't here before... spooky... */ + free_camera((Camera*) id); + break; + case ID_IP: + free_ipo((Ipo *)id); + break; + case ID_KE: + free_key((Key *)id); + break; + case ID_WO: + free_world((World *)id); + break; + case ID_SCR: + free_screen((bScreen *)id); + break; + case ID_VF: + free_vfont((VFont *)id); + break; + case ID_TXT: + free_text((Text *)id); + break; + case ID_SO: + sound_free_sound((bSound *)id); + break; + case ID_SAMPLE: + sound_free_sample((bSample *)id); + break; + case ID_GR: + free_group((Group *)id); + break; + case ID_AR: + free_armature((bArmature *)id); + break; + case ID_AC: + free_action((bAction *)id); + break; + } + + BLI_remlink(lb, id); + MEM_freeN(id); + + /* should not be here!! this is an interface-thing */ + allspace(OOPS_TEST, 0); +} + +void free_libblock_us(ListBase *lb, void *idv) /* test users */ +{ + ID *id= idv; + + id->us--; + + if(id->us<0) { + if(id->lib) printf("ERROR block %s %s users %d\n", id->lib->name, id->name, id->us); + else printf("ERROR block %s users %d\n", id->name, id->us); + } + if(id->us==0) { + if( GS(id->name)==ID_OB ) unlink_object((Object *)id); + + free_libblock(lb, id); + } +} + + +void free_main(Main *mainvar) +{ + /* ook aanroepen bij file inlezen, erase all, etc */ + ListBase *lbarray[MAX_LIBARRAY]; + int a; + + a= set_listbasepointers(mainvar, lbarray); + while(a--) { + ListBase *lb= lbarray[a]; + ID *id; + + while (id= lb->first) { + free_libblock(lb, id); + } + } + + MEM_freeN(mainvar); +} + +/* ***************** ID ************************ */ + +// only used in exotic.c +ID *find_id(char *type, char *name) /* type: "OB" of "MA" etc */ +{ + ID *id; + ListBase *lb; + + lb= wich_libbase(G.main, GS(type)); + + id= lb->first; + while(id) { + if( strcmp(id->name+2, name)==0 ) return id; + id= id->next; + } + return 0; +} + +static void get_flags_for_id(ID *id, char *buf) { + int isfake= id->flag & LIB_FAKEUSER; + + /* Writeout the flags for the entry, note there + * is a small hack that writes 5 spaces instead + * of 4 if no flags are displayed... this makes + * things usually line up ok - better would be + * to have that explicit, oh well - zr + */ + + if (id->us<0) + sprintf(buf, "-1W "); + else if (!id->lib && !isfake && id->us) + sprintf(buf, " "); + else + sprintf(buf, "%c%c%c ", id->lib?'L':' ', isfake?'F':' ', (id->us==0)?'O':' '); +} + +static void IDnames_to_dyn_pupstring(DynStr *pupds, ListBase *lb, ID *link, short *nr) +{ + int i, nids= BLI_countlist(lb); + + *nr= -1; + + if (nids>MAX_IDPUP) { + BLI_dynstr_append(pupds, "DataBrowse %x-2"); + } else { + ID *id; + + for (i=0, id= lb->first; id; id= id->next, i++) { + char buf[32]; + + if (id==link) + *nr= i+1; + + get_flags_for_id(id, buf); + + BLI_dynstr_append(pupds, buf); + BLI_dynstr_append(pupds, id->name+2); + + if(id->next) + BLI_dynstr_append(pupds, "|"); + } + } +} + + /* Silly routine, the only difference between the one + * above is that it only adds items with a matching + * blocktype... this should be unified somehow... - zr + */ +static void IPOnames_to_dyn_pupstring(DynStr *pupds, ListBase *lb, ID *link, short *nr, int blocktype) +{ + ID *id; + int i, nids; + + for (id= lb->first, nids= 0; id; id= id->next) { + Ipo *ipo= (Ipo*) id; + + if (ipo->blocktype==blocktype) + nids++; + } + + if (nids>MAX_IDPUP) { + BLI_dynstr_append(pupds, "DataBrowse %x-2"); + } else { + for (i=0, id= lb->first; id; id= id->next) { + Ipo *ipo= (Ipo*) id; + + if (ipo->blocktype==blocktype) { + char buf[32]; + + if (id==link) + *nr= i+1; + + get_flags_for_id(id, buf); + + BLI_dynstr_append(pupds, buf); + BLI_dynstr_append(pupds, id->name+2); + + if(id->next) + BLI_dynstr_append(pupds, "|"); + + i++; + } + } + } +} + +// used by headerbuttons.c buttons.c editobject.c editseq.c +void IDnames_to_pupstring(char **str, char *title, char *extraops, ListBase *lb, ID *link, short *nr) +{ + DynStr *pupds= BLI_dynstr_new(); + + if (title) { + BLI_dynstr_append(pupds, title); + BLI_dynstr_append(pupds, "%t|"); + } + + IDnames_to_dyn_pupstring(pupds, lb, link, nr); + + if (extraops) { + if (BLI_dynstr_get_len(pupds)) + BLI_dynstr_append(pupds, "|"); + BLI_dynstr_append(pupds, extraops); + } + + *str= BLI_dynstr_get_cstring(pupds); + BLI_dynstr_free(pupds); +} + +// only used by headerbuttons.c +void IPOnames_to_pupstring(char **str, char *title, char *extraops, ListBase *lb, ID *link, short *nr, int blocktype) +{ + DynStr *pupds= BLI_dynstr_new(); + + if (title) { + BLI_dynstr_append(pupds, title); + BLI_dynstr_append(pupds, "%t|"); + } + + IPOnames_to_dyn_pupstring(pupds, lb, link, nr, blocktype); + + if (extraops) { + if (BLI_dynstr_get_len(pupds)) + BLI_dynstr_append(pupds, "|"); + BLI_dynstr_append(pupds, extraops); + } + + *str= BLI_dynstr_get_cstring(pupds); + BLI_dynstr_free(pupds); +} + +// used by buttons.c library.c mball.c +void splitIDname(char *name, char *left, int *nr) +{ + int a; + + *nr= 0; + strncpy(left, name, 21); + + a= strlen(name); + if(a>1 && name[a-1]=='.') return; + + while(a--) { + if( name[a]=='.' ) { + left[a]= 0; + *nr= atol(name+a+1); + return; + } + if( isdigit(name[a])==0 ) break; + + left[a]= 0; + } + strcpy(left, name); +} + +static void sort_alpha_id(ListBase *lb, ID *id) +{ + ID *idtest; + + /* alfabetisch opnieuw invoegen */ + if(lb->first!=lb->last) { + BLI_remlink(lb, id); + + idtest= lb->first; + while(idtest) { + if(strcasecmp(idtest->name, id->name)>0 || idtest->lib) { + BLI_insertlinkbefore(lb, idtest, id); + break; + } + idtest= idtest->next; + } + /* als laatste */ + if(idtest==0) { + BLI_addtail(lb, id); + } + } + +} + +int new_id(ListBase *lb, ID *id, char *tname) +/* alleen locale blokken: externe en indirekte hebben al een unieke ID */ +/* return 1: nieuwe naam gemaakt */ +{ + ID *idtest; + int nr= 0, nrtest, maxtest=32, a; + char aname[32], *name, left[24], leftest[24], in_use[32]; + + /* - naam splitsen + * - zoeken + */ + + if(id->lib) return 0; + + if(tname==0) name= id->name+2; + else { + /* tname can be const */ + strncpy(aname, tname, 21); + name= aname; + + if( strlen(name) > 21 ) name[21]= 0; + } + + if(lb==0) lb= wich_libbase(G.main, GS(id->name)); + + /* eerste fase: bestaat de id al? */ + idtest= lb->first; + while(idtest) { + + if(id!=idtest && idtest->lib==0) { + + /* niet alphabetic testen! */ + /* optim */ + if( idtest->name[2] == name[0] ) { + if(strcmp(name, idtest->name+2)==0) break; + } + } + + idtest= idtest->next; + } + + /* if there is no double return */ + if(idtest==0) { + strcpy(id->name+2, name); + return 0; + } + + memset(in_use, 0, maxtest); + + splitIDname(name, left, &nr); + if(nr>999 && strlen(left)>16) left[16]= 0; + else if(strlen(left)>17) left[17]= 0; + + + idtest= lb->first; + while(idtest) { + + if(id!=idtest && idtest->lib==0) { + + splitIDname(idtest->name+2, leftest, &nrtest); + if(strcmp(left, leftest)==0) { + + if(nrtest<maxtest) in_use[nrtest]= 1; + if(nr <= nrtest) nr= nrtest+1; + } + } + + idtest= idtest->next; + } + + for(a=0; a<maxtest; a++) { + if(a>=nr) break; + if( in_use[a]==0 ) { + nr= a; + break; + } + } + + if(nr==0) sprintf(id->name+2, "%s", left); + else { + if (nr >= 1000 && strlen(left) > 16) { + // this would overflow name buffer + left[16]= 0; + return (new_id(lb, id, left)); + } + /* this format specifier is fucked... */ + sprintf(id->name+2, "%s.%0.3d", left, nr); + } + + sort_alpha_id(lb, id); + + return 1; +} + +// next to indirect usage in read/writefile also in editobject.c scene.c +void clear_id_newpoins() +{ + ListBase *lbarray[MAX_LIBARRAY]; + ID *id; + int a; + + a= set_listbasepointers(G.main, lbarray); + while(a--) { + id= lbarray[a]->first; + while(id) { + id->newid= 0; + id->flag &= ~LIB_NEW; + id= id->next; + } + } +} + +void all_local(void) +{ + ListBase *lbarray[MAX_LIBARRAY], tempbase={0, 0}; + ID *id, *idn; + int a; + + a= set_listbasepointers(G.main, lbarray); + while(a--) { + id= lbarray[a]->first; + + while(id) { + id->newid= 0; + id->flag &= ~(LIB_EXTERN|LIB_INDIRECT|LIB_NEW); + + idn= id->next; /* id wordt mogelijk opnieuw ingevoegd */ + if(id->lib) { + id->lib= 0; + new_id(lbarray[a], id, 0); /* new_id doet dit alleen bij dubbele namen */ + sort_alpha_id(lbarray[a], id); + } + else { + /* patch: testen of de zaak wel alphabetisch is */ +/* + if(idn) { + if(strcasecmp(id->name, idn->name)>0) { + remlink(lbarray[a], id); + addtail(&tempbase, id); + } + else if(id->prev) { + idp= id->prev; + if(strcasecmp(idp->name, id->name)>0) { + remlink(lbarray[a], id); + addtail(&tempbase, id); + } + } + } +*/ + } + + id= idn; + } + + /* patch2: zorgen dat de zaak wel alphabetisch is */ + while( (id=tempbase.first) ) { + BLI_remlink(&tempbase, id); + BLI_addtail(lbarray[a], id); + new_id(lbarray[a], id, 0); + } + } +} + + +void test_idbutton(char *name) +{ + /* vanuit buttons: als naam al bestaat: new_id aanroepen */ + ListBase *lb; + ID *idtest; + + + lb= wich_libbase(G.main, GS(name-2) ); + if(lb==0) return; + + /* zoek welke id */ + idtest= lb->first; + while(idtest) { + if( strcmp(idtest->name+2, name)==0) break; + idtest= idtest->next; + } + + if(idtest) if( new_id(lb, idtest, name)==0 ) sort_alpha_id(lb, idtest); +} + +void rename_id(ID *id, char *name) +{ + ListBase *lb; + + strncpy(id->name+2, name, 21); + lb= wich_libbase(G.main, GS(id->name) ); + + new_id(lb, id, name); +} + |