This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/blenkernel/intern/library.c
Kent Mein d0e346d544 updated .c files to include:
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

Just need to finish cpp files now :)

Kent
--
mein@cs.umn.edu
2002-11-25 12:02:15 +00:00

910 lines
19 KiB
C

/* 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 HAVE_CONFIG_H
#include <config.h>
#endif
#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);
}