| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | /** Interfacing with Blender
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * ***** 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 ***** | 
					
						
							|  |  |  |   * | 
					
						
							|  |  |  |   *  $Id$ | 
					
						
							|  |  |  |   * | 
					
						
							|  |  |  |   * This code is currently messy and an attempt to restructure | 
					
						
							|  |  |  |   * some Blender kernel level code. | 
					
						
							|  |  |  |   * Hopefully a template for a future C-API... | 
					
						
							|  |  |  |   * | 
					
						
							|  |  |  |   * | 
					
						
							|  |  |  |   */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BLI_blenlib.h" // mallocs
 | 
					
						
							|  |  |  | #include "BLI_arithb.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BKE_library.h" 
 | 
					
						
							|  |  |  | #include "BKE_global.h"
 | 
					
						
							|  |  |  | #include "BKE_main.h"
 | 
					
						
							|  |  |  | #include "BKE_object.h"
 | 
					
						
							|  |  |  | #include "BKE_mesh.h"
 | 
					
						
							|  |  |  | #include "BKE_ipo.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "MEM_guardedalloc.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "Python.h" 
 | 
					
						
							|  |  |  | #include "BPY_macros.h" 
 | 
					
						
							|  |  |  | #include "structmember.h" 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BDR_editobject.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "b_interface.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-25 12:02:15 +00:00
										 |  |  | #ifdef HAVE_CONFIG_H
 | 
					
						
							|  |  |  | #include <config.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | /************************************************************************
 | 
					
						
							|  |  |  |  * Generic low level routines | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** This just returns a pointer to the global struct.
 | 
					
						
							|  |  |  |   * | 
					
						
							|  |  |  |   * Mainly introduced for debugging purposes.. | 
					
						
							|  |  |  |   * | 
					
						
							|  |  |  |   */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Global *getGlobal(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return &G; | 
					
						
							|  |  |  | }	 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** define list getters:
 | 
					
						
							|  |  |  | 	These functions return a linked list pointer (ListBase *) from the global | 
					
						
							|  |  |  | 	Blender-object list. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Example: | 
					
						
							|  |  |  | 		oblist = getObjectList(); | 
					
						
							|  |  |  | 		firstobject = oblist->first; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | DEF_GETLIST(Scene, scene) | 
					
						
							|  |  |  | DEF_GETLIST(Object, object) | 
					
						
							|  |  |  | DEF_GETLIST(Mesh, mesh) | 
					
						
							|  |  |  | DEF_GETLIST(Camera, camera) | 
					
						
							|  |  |  | DEF_GETLIST(Material, mat) | 
					
						
							|  |  |  | DEF_GETLIST(Lamp, lamp) | 
					
						
							|  |  |  | DEF_GETLIST(World, world) | 
					
						
							|  |  |  | DEF_GETLIST(Ipo, ipo) | 
					
						
							|  |  |  | DEF_GETLIST(Image, image) | 
					
						
							|  |  |  | DEF_GETLIST(Texture, tex) | 
					
						
							|  |  |  | DEF_GETLIST(Text, text) | 
					
						
							|  |  |  | DEF_GETLIST(Key, key) | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* gets a datablock object from the ID list by name */ | 
					
						
							|  |  |  | ID *getFromList(ListBase *list, char *name)  | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	ID *id = list->first; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (id) { | 
					
						
							|  |  |  | 		if(STREQ(name, getIDName(id))) break; | 
					
						
							|  |  |  | 			id= id->next; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return id; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void printList(ListBase *list) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	ID *walk = list->first; | 
					
						
							|  |  |  | 	ID *lastwalk = 0; | 
					
						
							|  |  |  | 	printf("List: %s\n", walk->name); | 
					
						
							|  |  |  | 	while (walk) { | 
					
						
							|  |  |  | 		printf("   %s\n", walk->name); | 
					
						
							|  |  |  | 		lastwalk = walk; | 
					
						
							|  |  |  | 		walk= walk->next; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (list->last != lastwalk) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		printf("****: listbase->last pointing to wrong end!\n"); | 
					
						
							|  |  |  | 		// list->last = lastwalk;
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** (future) garbage collector subroutine */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int gc_mainlist(ListBase *lb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	ID *id = (ID *) lb->first; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (id) { | 
					
						
							|  |  |  | 		if (getIDUsers(id) == 0) { | 
					
						
							|  |  |  | 			switch(GET_ID_TYPE(id)) { | 
					
						
							|  |  |  | 			case ID_OB: | 
					
						
							|  |  |  | 				BPY_debug(("free [Object %s]\n", getIDName(id))); | 
					
						
							|  |  |  | 				unlink_object((Object *) id); | 
					
						
							|  |  |  | 				free_libblock(lb, id); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			default: break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		id = id->next; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** Garbage collection function.  EXPERIMENTAL!
 | 
					
						
							|  |  |  | 	 *  This should free Blender from all unreferenced Objects (i.e.  | 
					
						
							|  |  |  | 	 *  user count == 0).  | 
					
						
							|  |  |  | 	 *  Don't expect too much yet -- User counting isn't done | 
					
						
							|  |  |  | 	 *  consequently in Blender. Neither parenting or bevelcurves | 
					
						
							|  |  |  | 	 *  etc. respect user counts...therefore, no circular references | 
					
						
							|  |  |  | 	 *  show up -- which are in fact possible; example: | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 *  A BevelCurve is parenting its BevelObject: so there is a  | 
					
						
							|  |  |  | 	 *  reference from the BevelObject to the BevelCurve, and a | 
					
						
							|  |  |  | 	 *  reference back from the Bevelcurve to the BevelObject. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 *  There are a lot of cleanup functions in Blender taking care | 
					
						
							|  |  |  | 	 *  of updating (invalidating) references to deleted objects. | 
					
						
							|  |  |  | 	 *  See unlink_object() for more details. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 *  This function must not be called inside a script, so don't go | 
					
						
							|  |  |  | 	 *  and create a wrapper for it :-) | 
					
						
							|  |  |  | 	 *  In a hopefully later implementation, the Python garbage collection | 
					
						
							|  |  |  | 	 *  might be used. For the moment, this is better than 'Save and Reload' | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int garbage_collect(Main *m) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		/* Remember, all descriptor objects must BOB_DECUSER on their raw 
 | 
					
						
							|  |  |  | 		Blender Datablock in their __del__ method (C-API: dealloc function) */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		gc_mainlist(&m->object); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* TODO proper kernel level functions for safely freeing these objects
 | 
					
						
							|  |  |  | 		 * must first be implemented...  | 
					
						
							|  |  |  | 		gc_mainlist(&m->mesh); | 
					
						
							|  |  |  | 	gc_mainlist(&m->mat); | 
					
						
							|  |  |  | 	gc_mainlist(&m->lamp); | 
					
						
							|  |  |  | 	gc_mainlist(&m->camera); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.. and this list is far from being complete. | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** expands pointer array of length 'oldsize' to length 'newsize'.
 | 
					
						
							|  |  |  |   * A pointer to the (void *) array must be passed as first argument  | 
					
						
							|  |  |  |   * The array pointer content can be NULL, in this case a new array of length | 
					
						
							|  |  |  |   * 'newsize' is created. | 
					
						
							|  |  |  |   */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int expandPtrArray(void **p, int oldsize, int newsize) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	void *newarray; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (newsize < oldsize) { | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	}	 | 
					
						
							|  |  |  | 	newarray = MEM_callocN(newsize * sizeof(void *), "PtrArray"); | 
					
						
							|  |  |  | 	if (*p) { | 
					
						
							|  |  |  | 		memcpy(newarray, *p, oldsize); | 
					
						
							|  |  |  | 		MEM_freeN(*p); | 
					
						
							|  |  |  | 	}	 | 
					
						
							|  |  |  | 	*p = newarray; | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /************************************************************************
 | 
					
						
							|  |  |  |  * Material object low level routines | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* MAXMAT = maximum number of materials per object/ object data */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define MATINDEX_CHECK(x) \
 | 
					
						
							|  |  |  | 	if ((x) < 0 || (x) >= MAXMAT) { printf("illegal matindex!\n"); return 0; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** Returns a new material list (material pointer array) of length 'len'
 | 
					
						
							|  |  |  |   * | 
					
						
							|  |  |  |   */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Material **newMaterialList(int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	Material **matlist =  | 
					
						
							|  |  |  | 		(Material **) MEM_mallocN(len * sizeof(Material *), "MaterialList"); | 
					
						
							|  |  |  | 	return matlist; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** releases material list and decrements user count on materials */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int releaseMaterialList(Material **matlist, int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	Material *m; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	MATINDEX_CHECK(len); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i= 0; i < len; i++) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		m = matlist[i]; | 
					
						
							|  |  |  | 		BOB_XDECUSER((ID *) m); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	MEM_freeN(matlist);  | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** Synchronizes Object <-> data material lists. Blender just wants it. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int synchronizeMaterialLists(Object *object, void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	// get pointer to data's material array:
 | 
					
						
							|  |  |  | 	// and            number of data materials
 | 
					
						
							|  |  |  | 	// ... because they will need modification.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Material ***p_dataMaterials = give_matarar(object);  | 
					
						
							|  |  |  | 	short *nmaterials = give_totcolp(object); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (object->totcol > *nmaterials){ // more object mats than data mats
 | 
					
						
							|  |  |  | 		*nmaterials = object->totcol; | 
					
						
							|  |  |  | 		return expandPtrArray((void *) p_dataMaterials, *nmaterials, object->totcol); | 
					
						
							|  |  |  | 	} else if (object->totcol < *nmaterials) { | 
					
						
							|  |  |  | 		object->totcol = *nmaterials; | 
					
						
							|  |  |  | 		return expandPtrArray((void *) &object->mat, object->totcol, *nmaterials); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 1; // in this case, no synchronization needed; they're of equal
 | 
					
						
							|  |  |  | 	          // length
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /************************************************************************
 | 
					
						
							|  |  |  |  * Object low level routines | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** creates a new empty object of type OB_ (TODO: should be enum)
 | 
					
						
							|  |  |  |   * | 
					
						
							|  |  |  |   */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Object *object_new(int type) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	Object *object; | 
					
						
							|  |  |  | 	char name[32]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Global *g = getGlobal(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch(type) { | 
					
						
							|  |  |  | 		case OB_MESH: strcpy(name, "Mesh"); break; | 
					
						
							|  |  |  | 		case OB_CURVE: strcpy(name, "Curve"); break; | 
					
						
							|  |  |  | 		case OB_SURF: strcpy(name, "Surf"); break; | 
					
						
							|  |  |  | 		case OB_FONT: strcpy(name, "Text"); break; | 
					
						
							|  |  |  | 		case OB_MBALL: strcpy(name, "Mball"); break; | 
					
						
							|  |  |  | 		case OB_CAMERA: strcpy(name, "Camera"); break; | 
					
						
							|  |  |  | 		case OB_LAMP: strcpy(name, "Lamp"); break; | 
					
						
							|  |  |  | 		case OB_IKA: strcpy(name, "Ika"); break; | 
					
						
							|  |  |  | 		case OB_LATTICE: strcpy(name, "Lattice"); break; | 
					
						
							|  |  |  | 		case OB_WAVE: strcpy(name, "Wave"); break; | 
					
						
							|  |  |  | 		case OB_ARMATURE: strcpy(name,"Armature");break; | 
					
						
							|  |  |  | 		default:  strcpy(name, "Empty"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	object = alloc_libblock(getObjectList(), ID_OB, name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* user count is set to 1 by alloc_libblock, we just reset it to 0... */ | 
					
						
							|  |  |  | 	BOB_USERCOUNT((ID*) object) = 0; // it's a new object, so no user yet
 | 
					
						
							|  |  |  | 	object->flag = 0; | 
					
						
							|  |  |  | 	object->type = type; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* transforms */ | 
					
						
							|  |  |  | 	QuatOne(object->quat); | 
					
						
							|  |  |  | 	QuatOne(object->dquat); | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  |     object->col[3]= 1.0;    // alpha 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	object->size[0] = object->size[1] = object->size[2] = 1.0; | 
					
						
							|  |  |  | 	object->loc[0] = object->loc[1] = object->loc[2] = 0.0; | 
					
						
							|  |  |  | 	Mat4One(object->parentinv); | 
					
						
							|  |  |  | 	Mat4One(object->obmat); | 
					
						
							|  |  |  | 	object->dt = OB_SHADED; // drawtype
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	object_setdefaults(object); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	object->lay = 1; // Layer, by default visible
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch(type) { | 
					
						
							|  |  |  | 		case OB_MESH: object->data= add_mesh(); g->totmesh++; break; | 
					
						
							|  |  |  | 		case OB_CAMERA: object->data= add_camera(); break; | 
					
						
							|  |  |  | 		case OB_LAMP: object->data= add_lamp(); g->totlamp++; break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// TODO the following types will be supported later
 | 
					
						
							|  |  |  | 	//	case OB_CURVE: object->data= add_curve(OB_CURVE); g->totcurve++; break;
 | 
					
						
							|  |  |  | 	//	case OB_SURF: object->data= add_curve(OB_SURF); g->totcurve++; break;
 | 
					
						
							|  |  |  | 	//	case OB_FONT: object->data= add_curve(OB_FONT); break;
 | 
					
						
							|  |  |  | 	//	case OB_MBALL: object->data= add_mball(); break;
 | 
					
						
							|  |  |  | 	//	case OB_IKA: object->data= add_ika(); object->dt= OB_WIRE; break;
 | 
					
						
							|  |  |  | 	//	case OB_LATTICE: object->data= (void *)add_lattice(); object->dt= OB_WIRE; break;
 | 
					
						
							|  |  |  | 	//	case OB_WAVE: object->data= add_wave(); break;
 | 
					
						
							|  |  |  | 	//	case OB_ARMATURE: object->data=add_armature();break;
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	g->totobj++; // gee, I *hate* G
 | 
					
						
							|  |  |  | 	return object; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* returns new Base */ | 
					
						
							|  |  |  | Base *object_newBase(Object *object) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	Base *base; | 
					
						
							|  |  |  | 	base = MEM_callocN(sizeof(Base), "newbase"); | 
					
						
							|  |  |  | 	if (!base) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	base->object = object; | 
					
						
							|  |  |  | 	base->lay = object->lay; | 
					
						
							|  |  |  | 	base->flag = object->flag; | 
					
						
							|  |  |  | 	return base; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Object *object_copy(Object *object) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	Object *new; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	new = copy_object(object); | 
					
						
							|  |  |  | 	BOB_USERCOUNT((ID*) new) = 0; // it's a new object, so no user yet
 | 
					
						
							|  |  |  | 	return new; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Set draw mode of object */ | 
					
						
							|  |  |  | void object_setDrawMode(Object *object, int modebits) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	object->dt = (modebits & 0xff); | 
					
						
							|  |  |  | 	object->dtx = (modebits >> 8); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int object_getDrawMode(Object *object) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return (((int) object->dtx) << 8 ) + object->dt; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* link data to Object object */ | 
					
						
							|  |  |  | int object_linkdata(Object *object, void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	ID *oldid, *id; | 
					
						
							|  |  |  | 	int valid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!data) return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	oldid = (ID*) object->data;  | 
					
						
							|  |  |  | 	id = (ID*) data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	valid = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define _CASE(objtype, idtype) \
 | 
					
						
							|  |  |  | 	case objtype:\ | 
					
						
							|  |  |  | 		if (GET_ID_TYPE(id) == idtype) \ | 
					
						
							|  |  |  | 			valid = 1; \ | 
					
						
							|  |  |  | 		break;	 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (object->type) { | 
					
						
							|  |  |  | 	_CASE(OB_MESH, ID_ME) | 
					
						
							|  |  |  | 	_CASE(OB_CAMERA, ID_CA) | 
					
						
							|  |  |  | 	_CASE(OB_LAMP, ID_LA) | 
					
						
							|  |  |  | 	default: // not supported
 | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (valid) { | 
					
						
							|  |  |  | 		object->data = data; | 
					
						
							|  |  |  | 		BOB_INCUSER(id); | 
					
						
							|  |  |  | 		if (oldid) | 
					
						
							|  |  |  | 			BOB_DECUSER(oldid); // dec users
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// extra check for multi materials on meshes:
 | 
					
						
							|  |  |  | 		// This is a hack to check whether object material lists are of same
 | 
					
						
							|  |  |  | 		// length as their data material lists..
 | 
					
						
							|  |  |  | 		//if (GET_ID_TYPE(id) == ID_ME) {
 | 
					
						
							|  |  |  | 			//test_object_materials(id);
 | 
					
						
							|  |  |  | 		//}	
 | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* release data from object object */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int object_unlinkdata(Object *object) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	ID *id = object->data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	BOB_XDECUSER(id); | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** set Object materials:
 | 
					
						
							|  |  |  |   * takes a list of Material pointers of maximum length MAXMAT | 
					
						
							|  |  |  |   */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int object_setMaterials(Object *object, Material **matlist, int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	MATINDEX_CHECK(len) | 
					
						
							|  |  |  | 	if (object->mat) { | 
					
						
							|  |  |  | 		releaseMaterialList(object->mat, len); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// inc user count on all materials
 | 
					
						
							|  |  |  | 	for (i = 0; i < len; i++) { | 
					
						
							|  |  |  | 		BOB_XINCUSER( (ID *) matlist[i]); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	object->mat = matlist; | 
					
						
							|  |  |  | 	object->totcol = len; | 
					
						
							|  |  |  | 	object->actcol = len - 1; // XXX
 | 
					
						
							|  |  |  | 	// workaround: blender wants the object's data material list
 | 
					
						
							|  |  |  | 	// to be of the same length, otherwise colourful fun happens.
 | 
					
						
							|  |  |  | 	// so, we synchronize this here:
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (object->type) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		case OB_MESH: | 
					
						
							|  |  |  | 		case OB_CURVE: | 
					
						
							|  |  |  | 		case OB_FONT: | 
					
						
							|  |  |  | 		case OB_SURF: | 
					
						
							|  |  |  | 		case OB_MBALL: | 
					
						
							|  |  |  | 			synchronizeMaterialLists(object, object->data); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** make 'object' the parent of the object 'child' 
 | 
					
						
							|  |  |  |   * | 
					
						
							|  |  |  |   * mode = 1: set parent inverse matrix to _1_ ('clear inverse') | 
					
						
							|  |  |  |   * fast = 1: Don't update scene base (hierarchy). In this case, | 
					
						
							|  |  |  |   *           sort_baselist() needs to be called explicitely before redraw. | 
					
						
							|  |  |  |   */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int object_makeParent(Object *parent, Object *child, int mode, int fast)  | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (test_parent_loop(parent, child)) { | 
					
						
							|  |  |  | 		PyErr_SetString(PyExc_RuntimeError, "parenting loop detected!"); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	child->partype = PAROBJECT; | 
					
						
							|  |  |  | 	child->parent = parent; | 
					
						
							|  |  |  | 	if (mode == 1) { | 
					
						
							|  |  |  | 		Mat4One(child->parentinv); // parent inverse = unity
 | 
					
						
							|  |  |  | 		child->loc[0] = 0.0; child->loc[1] = 0.0; child->loc[2] = 0.0;  | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		what_does_parent(child); | 
					
						
							|  |  |  | 		Mat4Invert(child->parentinv, parent->obmat); // save inverse
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* This is some bad global thing again -- we should determine 
 | 
					
						
							|  |  |  | 	   the current scene | 
					
						
							|  |  |  | 	   another way. Later. */ | 
					
						
							|  |  |  | 	if (!fast)  | 
					
						
							|  |  |  | 		sort_baselist(getGlobal()->scene); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** Unlink parenting hierarchy:
 | 
					
						
							|  |  |  |   * | 
					
						
							|  |  |  |   * mode = 2: keep transform | 
					
						
							|  |  |  |   * fast = 1: don't update scene bases. see makeParent() | 
					
						
							|  |  |  |   */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int object_clrParent(Object *child, int mode, int fast)  | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	Object *par; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	par = child->parent; | 
					
						
							|  |  |  | 	child->parent = 0; | 
					
						
							|  |  |  | 	if (mode == 2) { // keep transform
 | 
					
						
							|  |  |  | 		apply_obmat(child); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (!fast)  | 
					
						
							|  |  |  | 		sort_baselist(getGlobal()->scene); | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** Set object's defaults */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int object_setdefaults(Object *ob) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if(U.flag & MAT_ON_OB) ob->colbits= -1; | 
					
						
							|  |  |  | 	switch(ob->type) { | 
					
						
							|  |  |  | 		case OB_CAMERA: | 
					
						
							|  |  |  | 		case OB_LAMP: | 
					
						
							|  |  |  | 			ob->trackflag = OB_NEGZ; | 
					
						
							|  |  |  | 			ob->upflag = OB_POSY; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			ob->trackflag = OB_POSY; | 
					
						
							|  |  |  | 			ob->upflag = OB_POSZ; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ob->ipoflag = OB_OFFS_OB + OB_OFFS_PARENT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* duplivert settings */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ob->dupon = 1; ob->dupoff = 0; | 
					
						
							|  |  |  | 	ob->dupsta = 1; ob->dupend = 100; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Gameengine defaults*/ | 
					
						
							|  |  |  | 	ob->mass= ob->inertia= 1.0; | 
					
						
							|  |  |  | 	ob->formfactor= 0.4; | 
					
						
							|  |  |  | 	ob->damping= 0.04; | 
					
						
							|  |  |  | 	ob->rdamping= 0.1; | 
					
						
							|  |  |  | 	ob->anisotropicFriction[0] = 1.0; | 
					
						
							|  |  |  | 	ob->anisotropicFriction[1] = 1.0; | 
					
						
							|  |  |  | 	ob->anisotropicFriction[2] = 1.0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* default to not use fh in new system */ | 
					
						
							|  |  |  | 	ob->gameflag= OB_PROP;	/*|OB_DO_FH; */ | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /************************************************************************
 | 
					
						
							|  |  |  |  * Creation of new data blocks | 
					
						
							|  |  |  |  *  | 
					
						
							|  |  |  |  * We [ab|re]use the blender kernel functions, but set the user count to 0, | 
					
						
							|  |  |  |  * because the object does not have users yet. | 
					
						
							|  |  |  |  * Currently, the user count is abused as reference count which should be | 
					
						
							|  |  |  |  * separate in future | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Material *material_new(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	Material *m = add_material("Material"); | 
					
						
							|  |  |  | 	BOB_USERCOUNT((ID*) m) = 0; // set 'refcount' to 0, because 
 | 
					
						
							|  |  |  | 	                            // it's a free material
 | 
					
						
							|  |  |  | 	return m; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Lamp *lamp_new() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	Lamp *la; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	la = add_lamp(); | 
					
						
							|  |  |  | 	BOB_USERCOUNT((ID*) la) = 0;  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return la; | 
					
						
							|  |  |  | }	 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Camera *camera_new() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	Camera *cam; | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |  	cam = add_camera(); | 
					
						
							|  |  |  | 	BOB_USERCOUNT((ID*) cam) = 0;  | 
					
						
							|  |  |  | 	return cam; | 
					
						
							|  |  |  | }	 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Ipo *ipo_new(int type, char *name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	Ipo *ipo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ipo = add_ipo(name, type); | 
					
						
							|  |  |  | 	BOB_USERCOUNT((ID*) ipo) = 0;  | 
					
						
							|  |  |  | 	return ipo; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Finds the ipo curve with channel code 'code' in the datablock 'ipo' 
 | 
					
						
							|  |  |  |    and returns it, if found (NULL otherwise) */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | IpoCurve *ipo_findcurve(Ipo *ipo, int code)  | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	IpoCurve *ipocurve; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ipocurve = ipo->curve.first; | 
					
						
							|  |  |  | 	while(ipocurve) { | 
					
						
							|  |  |  | 		if (ipocurve->adrcode == code) break; | 
					
						
							|  |  |  | 		ipocurve = ipocurve->next; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ipocurve; | 
					
						
							|  |  |  | }	 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** Returns a new Ipo curve */ | 
					
						
							|  |  |  | IpoCurve *ipocurve_new() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	IpoCurve *curve; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	curve = MEM_callocN(sizeof(IpoCurve), "new_ipocurve"); | 
					
						
							|  |  |  | 	curve->flag = IPO_VISIBLE; | 
					
						
							|  |  |  | 	return curve; | 
					
						
							|  |  |  | }	 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | IpoCurve *ipocurve_copy(IpoCurve *curve) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	IpoCurve *newcurve; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	newcurve = MEM_callocN(sizeof(IpoCurve), "new_ipocurve"); | 
					
						
							|  |  |  | 	memcpy(newcurve, curve, sizeof(IpoCurve)); | 
					
						
							|  |  |  | 	// copy bez triples:
 | 
					
						
							|  |  |  | 	newcurve->bezt= MEM_mallocN(curve->totvert*sizeof(BezTriple), "ipocurve_copy"); | 
					
						
							|  |  |  | 	memcpy(newcurve->bezt, curve->bezt, curve->totvert*sizeof(BezTriple));  | 
					
						
							|  |  |  | 	return newcurve; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** Assign ipo to object object */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* macros, see b_interface.h */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | DEF_ASSIGN_IPO(object, Object)  // defines object_assignIpo()
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | DEF_ASSIGN_IPO(camera, Camera)   | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | DEF_ASSIGN_IPO(lamp, Lamp)   | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | DEF_ASSIGN_IPO(material, Material)   | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /************************************************************************
 | 
					
						
							|  |  |  |  * Mesh object low level routines | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** Returns a new, free (non owned) mesh.
 | 
					
						
							|  |  |  |   * add_mesh() automatically returns a mesh object with users = 1, | 
					
						
							|  |  |  |   * so we set it to 0. Hack, hack. | 
					
						
							|  |  |  |   */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Mesh *mesh_new(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	Mesh *me = add_mesh(); | 
					
						
							|  |  |  | 	((ID *) me)->us = 0; | 
					
						
							|  |  |  | 	return me; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** updates drawing properties etc. of mesh */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void mesh_update(Mesh *mesh) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	edge_drawflags_mesh(mesh); | 
					
						
							|  |  |  | 	tex_space_mesh(mesh); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /************************************************************************
 | 
					
						
							|  |  |  |  * Scene object low level routines | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** Returns current Scene */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Scene *scene_getCurrent(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return getGlobal()->scene; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* returns base of object 'object' in Scene 'scene', 0 if nonexistant 
 | 
					
						
							|  |  |  |  * A base is basically an visual instantiation of an 3D object (Object) | 
					
						
							|  |  |  |  * in a Scene. See scene_linkObject() | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Base *scene_getObjectBase(Scene *scene, Object *object) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	Base *base; | 
					
						
							|  |  |  | 	base = scene->base.first; | 
					
						
							|  |  |  | 	while (base) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if (object == base->object) // it exists
 | 
					
						
							|  |  |  | 			return base; | 
					
						
							|  |  |  | 		base = base->next; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* links an object into a scene */ | 
					
						
							|  |  |  | int scene_linkObject(Scene *scene, Object *object) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	Base *base, *b; | 
					
						
							|  |  |  | 	b = scene_getObjectBase(scene, object); | 
					
						
							|  |  |  | 	if (b) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	base = object_newBase(object);  | 
					
						
							|  |  |  | 	if (!base) {  | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	}	 | 
					
						
							|  |  |  | 	BOB_INCUSER((ID *) object); // incref the object 
 | 
					
						
							|  |  |  | 	BLI_addhead(&scene->base, base); | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* unlinks an object from a scene */ | 
					
						
							|  |  |  | int scene_unlinkObject(Scene *scene, Object *object) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	Base *base; | 
					
						
							|  |  |  | 	base = scene_getObjectBase(scene, object); | 
					
						
							|  |  |  | 	if (base) { | 
					
						
							|  |  |  | 		BLI_remlink(&scene->base, base); | 
					
						
							|  |  |  | 		BOB_DECUSER((ID *) object); | 
					
						
							|  |  |  | 		MEM_freeN(base); | 
					
						
							|  |  |  | 		scene->basact = 0; // make sure the just deleted object has no longer an 
 | 
					
						
							|  |  |  | 		                   // active base (which happens if it was selected
 | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 |