diff options
Diffstat (limited to 'source/blender/blenkernel/intern/object.c')
-rw-r--r-- | source/blender/blenkernel/intern/object.c | 1681 |
1 files changed, 1681 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c new file mode 100644 index 00000000000..c6c91d00609 --- /dev/null +++ b/source/blender/blenkernel/intern/object.c @@ -0,0 +1,1681 @@ +/* object.c MIXED MODEL + * + * jan 95 + * + * $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 <string.h> +#include <math.h> +#include <stdio.h> +#ifdef WIN32 +#include "BLI_winstuff.h" +#endif +#include "MEM_guardedalloc.h" + +#include "DNA_action_types.h" +#include "DNA_armature_types.h" +#include "DNA_camera_types.h" +#include "DNA_constraint_types.h" +#include "DNA_curve_types.h" +#include "DNA_group_types.h" +#include "DNA_ika_types.h" +#include "DNA_ipo_types.h" +#include "DNA_lamp_types.h" +#include "DNA_lattice_types.h" +#include "DNA_material_types.h" +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_texture_types.h" +#include "DNA_userdef_types.h" +#include "DNA_view3d_types.h" +#include "DNA_world_types.h" + +#include "BKE_armature.h" +#include "BKE_action.h" +#include "BKE_deform.h" +#include "BKE_nla.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_editVert.h" + +#include "BKE_utildefines.h" +#include "BKE_bad_level_calls.h" + +#include "BKE_main.h" +#include "BKE_global.h" + +#include "BKE_object.h" +#include "BKE_blender.h" +#include "BKE_screen.h" +#include "BKE_ipo.h" +#include "BKE_ika.h" +#include "BKE_library.h" +#include "BKE_mesh.h" +#include "BKE_curve.h" +#include "BKE_mball.h" +#include "BKE_effect.h" +#include "BKE_sca.h" +#include "BPY_extern.h" +#include "BKE_displist.h" +#include "BKE_property.h" +#include "BKE_anim.h" +#include "BKE_group.h" +#include "BKE_lattice.h" +#include "BKE_constraint.h" +#include "BKE_scene.h" + +/* Local function protos */ +static void solve_parenting (Object *ob, Object *par, float slowmat[][4], int simul); + +float originmat[3][3]; /* na where_is_object(), kan her en der gebruikt worden */ +Object workob; + +void clear_workob(void) +{ + memset(&workob, 0, sizeof(Object)); + + workob.size[0]= workob.size[1]= workob.size[2]= 1.0; + +} + +void copy_baseflags() +{ + Base *base= G.scene->base.first; + + while(base) { + base->object->flag= base->flag; + base= base->next; + } +} + +void copy_objectflags() +{ + Base *base= G.scene->base.first; + + while(base) { + base->flag= base->object->flag; + base= base->next; + } +} + +void update_base_layer(Object *ob) +{ + Base *base= G.scene->base.first; + + while (base) { + if (base->object == ob) base->lay= ob->lay; + base= base->next; + } +} + +/* niet object zelf vrijgeven */ +void free_object(Object *ob) +{ + int a; + + /* specifieke data loskoppelen */ + if(ob->data) { + ID *id= ob->data; + id->us--; + if(id->us==0) { + if(ob->type==OB_MESH) unlink_mesh(ob->data); + else if(ob->type==OB_CURVE) unlink_curve(ob->data); + else if(ob->type==OB_MBALL) unlink_mball(ob->data); + } + ob->data= 0; + } + + for(a=0; a<ob->totcol; a++) { + if(ob->mat[a]) ob->mat[a]->id.us--; + } + if(ob->mat) MEM_freeN(ob->mat); + ob->mat= 0; + if(ob->bb) MEM_freeN(ob->bb); + ob->bb= 0; + if(ob->path) free_path(ob->path); + ob->path= 0; + if(ob->ipo) ob->ipo->id.us--; + if(ob->action) ob->action->id.us--; + if(ob->defbase.first) + BLI_freelistN(&ob->defbase); + if(ob->pose) { + clear_pose(ob->pose); + MEM_freeN(ob->pose); + } + free_effects(&ob->effect); + BLI_freelistN(&ob->network); + free_properties(&ob->prop); + + free_sensors(&ob->sensors); + free_controllers(&ob->controllers); + free_actuators(&ob->actuators); + + free_constraints(&ob->constraints); + free_constraint_channels(&ob->constraintChannels); + free_nlastrips(&ob->nlastrips); + + freedisplist(&ob->disp); + + BPY_free_scriptlink(&ob->scriptlink); +} + +void unlink_object(Object *ob) +{ + Object *obt; + Material *mat; + World *wrld; + bScreen *sc; + Scene *sce; + Curve *cu; + Tex *tex; + Group *group; + int a; + + unlink_controllers(&ob->controllers); + unlink_actuators(&ob->actuators); + + /* alle objecten aflopen: parents en bevels */ + obt= G.main->object.first; + while(obt) { + if(obt->id.lib==0) { + if(obt->parent==ob) { + obt->parent= 0; + if(ob->type==OB_LATTICE) freedisplist(&obt->disp); + } + if(obt->track==ob) obt->track= 0; + if ELEM(obt->type, OB_CURVE, OB_FONT) { + cu= obt->data; + if(cu->bevobj==ob) cu->bevobj= 0; + if(cu->textoncurve==ob) cu->textoncurve= 0; + } + if(obt->type==OB_IKA) { + Ika *ika= obt->data; + Deform *def= ika->def; + + if(ika->parent==ob) ika->parent= 0; + a= ika->totdef; + while(a--) { + if(def->ob==ob) { + ika->totdef= 0; + MEM_freeN(ika->def); + ika->def= 0; + break; + } + def++; + } + } + sca_remove_ob_poin(obt, ob); + } + obt= obt->id.next; + } + + /* materialen */ + mat= G.main->mat.first; + while(mat) { + + for(a=0; a<8; a++) { + if(mat->mtex[a] && ob==mat->mtex[a]->object) { + /* eigenlijk testen op lib */ + mat->mtex[a]->object= 0; + } + } + + mat= mat->id.next; + } + + /* textures */ + tex= G.main->tex.first; + while(tex) { + if(tex->env) { + if(tex->env->object == ob) tex->env->object= 0; + } + tex= tex->id.next; + } + + /* mballs */ + if(ob->type==OB_MBALL) { + obt= find_basis_mball(ob); + if(obt) freedisplist(&obt->disp); + } + + /* worlds */ + wrld= G.main->world.first; + while(wrld) { + if(wrld->id.lib==0) { + for(a=0; a<6; a++) { + if(wrld->mtex[a] && ob==wrld->mtex[a]->object) + wrld->mtex[a]->object =0; + } + } + + wrld= wrld->id.next; + } + + /* scene's */ + sce= G.main->scene.first; + while(sce) { + if(sce->id.lib==0) { + if(sce->camera==ob) sce->camera= 0; + } + sce= sce->id.next; + } + /* keys */ + + /* screens */ + sc= G.main->screen.first; + while(sc) { + ScrArea *sa= sc->areabase.first; + while(sa) { + SpaceLink *sl; + + for (sl= sa->spacedata.first; sl; sl= sl->next) { + if(sl->spacetype==SPACE_VIEW3D) { + View3D *v3d= (View3D*) sl; + + if(v3d->camera==ob) { + v3d->camera= 0; + if(v3d->persp>1) v3d->persp= 1; + } + if(v3d->localvd && v3d->localvd->camera==ob ) { + v3d->localvd->camera= 0; + if(v3d->localvd->persp>1) v3d->localvd->persp= 1; + } + } + } + + sa= sa->next; + } + sc= sc->id.next; + } + + /* groups */ + group= G.main->group.first; + while(group) { + rem_from_group(group, ob); + group= group->id.next; + } +} + +int exist_object(Object *obtest) +{ + Object *ob; + + ob= G.main->object.first; + while(ob) { + if(ob==obtest) return 1; + ob= ob->id.next; + } + return 0; +} + +void *add_camera() +{ + Camera *cam; + + cam= alloc_libblock(&G.main->camera, ID_CA, "Camera"); + + cam->lens= 35.0f; + cam->clipsta= 0.1f; + cam->clipend= 100.0f; + cam->drawsize= 0.5f; + cam->netsta= 0.5f; + cam->netend= 10.0f; + cam->hold= 50; + + return cam; +} + +Camera *copy_camera(Camera *cam) +{ + Camera *camn; + + camn= copy_libblock(cam); + id_us_plus((ID *)camn->ipo); + + BPY_copy_scriptlink(&camn->scriptlink); + + return camn; +} + + + +void make_local_camera(Camera *cam) +{ + Object *ob; + Camera *camn; + int local=0, lib=0; + + /* - zijn er alleen lib users: niet doen + * - zijn er alleen locale users: flag zetten + * - mixed: copy + */ + + if(cam->id.lib==0) return; + if(cam->id.us==1) { + cam->id.lib= 0; + cam->id.flag= LIB_LOCAL; + new_id(0, (ID *)cam, 0); + return; + } + + ob= G.main->object.first; + while(ob) { + if(ob->data==cam) { + if(ob->id.lib) lib= 1; + else local= 1; + } + ob= ob->id.next; + } + + if(local && lib==0) { + cam->id.lib= 0; + cam->id.flag= LIB_LOCAL; + new_id(0, (ID *)cam, 0); + } + else if(local && lib) { + camn= copy_camera(cam); + camn->id.us= 0; + + ob= G.main->object.first; + while(ob) { + if(ob->data==cam) { + + if(ob->id.lib==0) { + ob->data= camn; + camn->id.us++; + cam->id.us--; + } + } + ob= ob->id.next; + } + } +} + + + +void *add_lamp(void) +{ + Lamp *la; + + la= alloc_libblock(&G.main->lamp, ID_LA, "Lamp"); + + la->r= la->g= la->b= 1.0; + la->haint= la->energy= 1.0; + la->dist= 20.0f; + la->spotsize= 45.0f; + la->spotblend= 0.15f; + la->att2= 1.0f; + la->mode= LA_SHAD; + la->bufsize= 512; + la->clipsta= 0.5f; + la->clipend= 40.0f; + la->shadspotsize= 45.0f; + la->samp= 3; + la->bias= 1.0f; + la->soft= 3.0f; + + return la; +} + +Lamp *copy_lamp(Lamp *la) +{ + Lamp *lan; + int a; + + lan= copy_libblock(la); + + for(a=0; a<8; a++) { + if(lan->mtex[a]) { + lan->mtex[a]= MEM_mallocN(sizeof(MTex), "copylamptex"); + memcpy(lan->mtex[a], la->mtex[a], sizeof(MTex)); + id_us_plus((ID *)lan->mtex[a]->tex); + } + } + + id_us_plus((ID *)lan->ipo); + + BPY_copy_scriptlink(&la->scriptlink); + + return lan; +} + +void make_local_lamp(Lamp *la) +{ + Object *ob; + Lamp *lan; + int local=0, lib=0; + + /* - zijn er alleen lib users: niet doen + * - zijn er alleen locale users: flag zetten + * - mixed: copy + */ + + if(la->id.lib==0) return; + if(la->id.us==1) { + la->id.lib= 0; + la->id.flag= LIB_LOCAL; + new_id(0, (ID *)la, 0); + return; + } + + ob= G.main->object.first; + while(ob) { + if(ob->data==la) { + if(ob->id.lib) lib= 1; + else local= 1; + } + ob= ob->id.next; + } + + if(local && lib==0) { + la->id.lib= 0; + la->id.flag= LIB_LOCAL; + new_id(0, (ID *)la, 0); + } + else if(local && lib) { + lan= copy_lamp(la); + lan->id.us= 0; + + ob= G.main->object.first; + while(ob) { + if(ob->data==la) { + + if(ob->id.lib==0) { + ob->data= lan; + lan->id.us++; + la->id.us--; + } + } + ob= ob->id.next; + } + } +} + +void free_camera(Camera *ca) +{ + BPY_free_scriptlink(&ca->scriptlink); +} + +void free_lamp(Lamp *la) +{ + MTex *mtex; + int a; + + /* scriptlinks */ + + BPY_free_scriptlink(&la->scriptlink); + + for(a=0; a<8; a++) { + mtex= la->mtex[a]; + if(mtex && mtex->tex) mtex->tex->id.us--; + if(mtex) MEM_freeN(mtex); + } + la->ipo= 0; +} + +void *add_wave() +{ + return 0; +} + + +/* *************************************************** */ + +static void *add_obdata_from_type(int type) +{ + switch (type) { + case OB_MESH: G.totmesh++; return add_mesh(); + case OB_CURVE: G.totcurve++; return add_curve(OB_CURVE); + case OB_SURF: G.totcurve++; return add_curve(OB_SURF); + case OB_FONT: return add_curve(OB_FONT); + case OB_MBALL: return add_mball(); + case OB_CAMERA: return add_camera(); + case OB_LAMP: G.totlamp++; return add_lamp(); + case OB_IKA: return add_ika(); + case OB_LATTICE: return add_lattice(); + case OB_WAVE: return add_wave(); + case OB_ARMATURE: return add_armature(); + case OB_EMPTY: return NULL; + default: + printf("add_obdata_from_type: Internal error, bad type: %d\n", type); + return NULL; + } +} + +static char *get_obdata_defname(int type) +{ + switch (type) { + case OB_MESH: return "Mesh"; + case OB_CURVE: return "Curve"; + case OB_SURF: return "Surf"; + case OB_FONT: return "Font"; + case OB_MBALL: return "Mball"; + case OB_CAMERA: return "Camera"; + case OB_LAMP: return "Lamp"; + case OB_IKA: return "Ika"; + case OB_LATTICE: return "Lattice"; + case OB_WAVE: return "Wave"; + case OB_ARMATURE: return "Armature"; + case OB_EMPTY: return "Empty"; + default: + printf("get_obdata_defname: Internal error, bad type: %d\n", type); + return "Empty"; + } +} + +/* algemene add: in G.scene, met layer uit area en default naam */ +/* maakt alle minimaal nodige datablokken aan, zonder vertices etc. */ +Object *add_object(int type) +{ + Object *ob; + Base *base; + char name[32]; + + if (G.obpose) + exit_posemode(1); + + strcpy(name, get_obdata_defname(type)); + + ob= alloc_libblock(&G.main->object, ID_OB, name); + G.totobj++; + + /* default object vars */ + ob->type= type; + /* ob->transflag= OB_QUAT; */ + + QuatOne(ob->quat); + QuatOne(ob->dquat); + + ob->col[0]= ob->col[1]= ob->col[2]= 0.0; + ob->col[3]= 1.0; + + ob->loc[0]= ob->loc[1]= ob->loc[2]= 0.0; + ob->rot[0]= ob->rot[1]= ob->rot[2]= 0.0; + ob->size[0]= ob->size[1]= ob->size[2]= 1.0; + + Mat4One(ob->parentinv); + Mat4One(ob->obmat); + ob->dt= OB_SHADED; + if(U.flag & MAT_ON_OB) ob->colbits= -1; + + if(type==OB_CAMERA || type==OB_LAMP) { + ob->trackflag= OB_NEGZ; + ob->upflag= OB_POSY; + } + else { + ob->trackflag= OB_POSY; + ob->upflag= OB_POSZ; + } + ob->ipoflag = OB_OFFS_OB+OB_OFFS_PARENT; + + ob->dupon= 1; ob->dupoff= 0; + ob->dupsta= 1; ob->dupend= 100; + + /* Gameengine defaults*/ + ob->mass= ob->inertia= 1.0f; + ob->formfactor= 0.4f; + ob->damping= 0.04f; + ob->rdamping= 0.1f; + ob->anisotropicFriction[0] = 1.0f; + ob->anisotropicFriction[1] = 1.0f; + ob->anisotropicFriction[2] = 1.0f; + ob->gameflag= OB_PROP; + + ob->data= add_obdata_from_type(type); + + ob->lay= G.scene->lay; + + base= scene_add_base(G.scene, ob); + scene_select_base(G.scene, base); + + return ob; +} + +void base_init_from_view3d(Base *base, View3D *v3d) +{ + Object *ob= base->object; + + if (v3d->localview) { + base->lay= ob->lay= v3d->layact + v3d->lay; + VECCOPY(ob->loc, v3d->cursor); + } else { + base->lay= ob->lay= v3d->layact; + VECCOPY(ob->loc, G.scene->cursor); + } + + v3d->viewquat[0]= -v3d->viewquat[0]; + if (ob->transflag & OB_QUAT) { + QUATCOPY(ob->quat, v3d->viewquat); + } else { + QuatToEul(v3d->viewquat, ob->rot); + } + v3d->viewquat[0]= -v3d->viewquat[0]; +} + +Object *copy_object(Object *ob) +{ + Object *obn; + int a; + bConstraintChannel *actcon; + + obn= copy_libblock(ob); + + if(ob->totcol) { + obn->mat= MEM_dupallocN(ob->mat); + } + + if(ob->bb) obn->bb= MEM_dupallocN(ob->bb); + obn->path= 0; + obn->flag &= ~OB_FROMGROUP; + + copy_effects(&obn->effect, &ob->effect); + + obn->network.first= obn->network.last= 0; + + BPY_copy_scriptlink(&ob->scriptlink); + + copy_properties(&obn->prop, &ob->prop); + copy_sensors(&obn->sensors, &ob->sensors); + copy_controllers(&obn->controllers, &ob->controllers); + copy_actuators(&obn->actuators, &ob->actuators); + + copy_pose(&obn->pose, ob->pose, 1); + copy_defgroups(&obn->defbase, &ob->defbase); + copy_nlastrips(&obn->nlastrips, &ob->nlastrips); + copy_constraints (&obn->constraints, &ob->constraints); + + actcon = clone_constraint_channels (&obn->constraintChannels, &ob->constraintChannels, ob->activecon); + /* If the active constraint channel was in this list, update it */ + if (actcon) + obn->activecon = actcon; + + /* usernummers ophogen */ + id_us_plus((ID *)obn->data); + id_us_plus((ID *)obn->ipo); + id_us_plus((ID *)obn->action); + for(a=0; a<obn->totcol; a++) id_us_plus((ID *)obn->mat[a]); + + obn->disp.first= obn->disp.last= 0; + + return obn; +} + +void expand_local_object(Object *ob) +{ + int a; + + id_lib_extern((ID *)ob->action); + id_lib_extern((ID *)ob->ipo); + id_lib_extern((ID *)ob->data); + + for(a=0; a<ob->totcol; a++) { + id_lib_extern((ID *)ob->mat[a]); + } +} + +void make_local_object(Object *ob) +{ + Object *obn; + Scene *sce; + Base *base; + int local=0, lib=0; + + /* - zijn er alleen lib users: niet doen + * - zijn er alleen locale users: flag zetten + * - mixed: copy + */ + + if(ob->id.lib==0) return; + if(ob->id.us==1) { + ob->id.lib= 0; + ob->id.flag= LIB_LOCAL; + new_id(0, (ID *)ob, 0); + + } + else { + sce= G.main->scene.first; + while(sce) { + base= sce->base.first; + while(base) { + if(base->object==ob) { + if(sce->id.lib) lib++; + else local++; + break; + } + base= base->next; + } + sce= sce->id.next; + } + + if(local && lib==0) { + ob->id.lib= 0; + ob->id.flag= LIB_LOCAL; + new_id(0, (ID *)ob, 0); + } + else if(local && lib) { + obn= copy_object(ob); + obn->id.us= 0; + + sce= G.main->scene.first; + while(sce) { + if(sce->id.lib==0) { + base= sce->base.first; + while(base) { + if(base->object==ob) { + base->object= obn; + obn->id.us++; + ob->id.us--; + } + base= base->next; + } + } + sce= sce->id.next; + } + } + } + + expand_local_object(ob); +} + +/* *************** CALC ****************** */ + +/* er zit ook een tijdberekening in de drawobject() */ + +float bluroffs= 0.0; +int no_speed_curve= 0; + +void set_mblur_offs(int blur) +{ + bluroffs= R.r.blurfac*((float)blur); + bluroffs/= (float)R.r.osa; +} + +void disable_speed_curve(int val) +{ + no_speed_curve= val; +} + +float bsystem_time(Object *ob, Object *par, float cfra, float ofs) +{ + /* geeft float terug ( zie ook frame_to_float in ipo.c) */ + + if(no_speed_curve==0) if(ob && ob->ipo) cfra= calc_ipo_time(ob->ipo, cfra); + + /* tweede field */ + if(R.flag & R_SEC_FIELD) { + if(R.r.mode & R_FIELDSTILL); else cfra+= .5; + } + + /* motion blur */ + cfra+= bluroffs; + + /* global time */ + cfra*= G.scene->r.framelen; + + /* ofset frames */ + if(ob && (ob->ipoflag & OB_OFFS_PARENT)) { + if((ob->partype & PARSLOW)==0) cfra-= ob->sf; + } + + cfra-= ofs; + + return cfra; +} + +void object_to_mat3(Object *ob, float mat[][3]) /* no parent */ +{ + float smat[3][3], vec[3]; + float rmat[3][3]; + float q1[4]; + + /* size */ + if(ob->ipo) { + vec[0]= ob->size[0]+ob->dsize[0]; + vec[1]= ob->size[1]+ob->dsize[1]; + vec[2]= ob->size[2]+ob->dsize[2]; + SizeToMat3(vec, smat); + } + else { + SizeToMat3(ob->size, smat); + } + + /* rot */ + if(ob->transflag & OB_QUAT) { + if(ob->ipo) { + QuatMul(q1, ob->quat, ob->dquat); + QuatToMat3(q1, rmat); + } + else { + QuatToMat3(ob->quat, rmat); + } + } + else { + if(ob->ipo) { + vec[0]= ob->rot[0]+ob->drot[0]; + vec[1]= ob->rot[1]+ob->drot[1]; + vec[2]= ob->rot[2]+ob->drot[2]; + EulToMat3(vec, rmat); + } + else { + EulToMat3(ob->rot, rmat); + } + } + Mat3MulMat3(mat, rmat, smat); +} + +void object_to_mat4(Object *ob, float mat[][4]) +{ + float tmat[3][3]; + + object_to_mat3(ob, tmat); + + Mat4CpyMat3(mat, tmat); + + VECCOPY(mat[3], ob->loc); + if(ob->ipo) { + mat[3][0]+= ob->dloc[0]; + mat[3][1]+= ob->dloc[1]; + mat[3][2]+= ob->dloc[2]; + } +} + +int enable_cu_speed= 1; + +void ob_parcurve(Object *ob, Object *par, float mat[][4]) +{ + Curve *cu; + float q[4], vec[4], dir[3], *quat, x1, ctime; + + Mat4One(mat); + + cu= par->data; + if(cu->path==0 || cu->path->data==0) calc_curvepath(par); + if(cu->path==0) return; + + /* uitzondering afvangen: curve paden die als duplicator worden gebruikt */ + if(enable_cu_speed) { + ctime= bsystem_time(ob, par, (float)G.scene->r.cfra, 0.0); + + if(calc_ipo_spec(cu->ipo, CU_SPEED, &ctime)==0) { + ctime /= cu->pathlen; + CLAMP(ctime, 0.0, 1.0); + } + } + else { + ctime= G.scene->r.cfra - ob->sf; + ctime /= cu->pathlen; + + CLAMP(ctime, 0.0, 1.0); + } + + if( where_on_path(par, ctime, vec, dir) ) { + + if(cu->flag & CU_FOLLOW) { + quat= vectoquat(dir, ob->trackflag, ob->upflag); + + Normalise(dir); + q[0]= (float)cos(0.5*vec[3]); + x1= (float)sin(0.5*vec[3]); + q[1]= -x1*dir[0]; + q[2]= -x1*dir[1]; + q[3]= -x1*dir[2]; + QuatMul(quat, q, quat); + + QuatToMat4(quat, mat); + } + + VECCOPY(mat[3], vec); + + } +} + +void ob_parbone(Object *ob, Object *par, float mat[][4]) +{ + Bone *bone; + bArmature *arm; + + Mat4One(mat); + arm=get_armature(par); + if (!arm) + return; + + /* Make sure the bone is still valid */ + bone = get_named_bone(arm, ob->parsubstr); + if (!bone){ + printf ("Lost bone %s\n", ob->parsubstr); + return; + } + + apply_pose_armature(arm, par->pose, 1); /* Hopefully can set doit parameter in the future */ + where_is_bone (par, bone); + + /* Translate by negative bone */ + get_objectspace_bone_matrix(bone, mat, 0, 1); + +} + +void ob_parlimb(Object *ob, Object *par, float mat[][4]) +{ + Ika *ika; + Limb *li; + float ang=0.0; + int cur=0; + + /* in lokale ob space */ + Mat4One(mat); + + ika= par->data; + li= ika->limbbase.first; + while(li) { + ang+= li->alpha; + if(cur==ob->par1 || li->next==0) break; + + cur++; + li= li->next; + } + + mat[0][0]= (float)cos(ang); + mat[1][0]= (float)-sin(ang); + mat[0][1]= (float)sin(ang); + mat[1][1]= (float)cos(ang); + + mat[3][0]= li->eff[0]; + mat[3][1]= li->eff[1]; + +} + +void give_parvert(Object *par, int nr, float *vec) +{ + Mesh *me; + MVert *mvert; + EditVert *eve; +/* extern ListBase editNurb; already in bad lev calls */ + Nurb *nu; + Curve *cu; + BPoint *bp; + DispList *dl; + BezTriple *bezt; + float *fp; + int a, count; + + vec[0]=vec[1]=vec[2]= 0.0; + + if(par->type==OB_MESH) { + if(par==G.obedit) { + if(nr >= G.totvert) nr= 0; + + count= 0; + eve= G.edve.first; + while(eve) { + if(count==nr) { + memcpy(vec, eve->co, 12); + break; + } + eve= eve->next; + count++; + } + } + else { + me= par->data; + if(me->totvert) { + if(nr >= me->totvert) nr= 0; + + /* is er deform */ + dl= find_displist(&par->disp, DL_VERTS); + if(dl) { + fp= dl->verts+3*nr; + VECCOPY(vec, fp); + } + else { + mvert= me->mvert + nr; + VECCOPY(vec, mvert->co); + } + } + } + } + else if ELEM(par->type, OB_CURVE, OB_SURF) { + + cu= par->data; + nu= cu->nurb.first; + if(par==G.obedit) nu= editNurb.first; + + count= 0; + while(nu) { + if((nu->type & 7)==CU_BEZIER) { + bezt= nu->bezt; + a= nu->pntsu; + while(a--) { + if(count==nr) { + VECCOPY(vec, bezt->vec[1]); + break; + } + count++; + bezt++; + } + } + else { + bp= nu->bp; + a= nu->pntsu*nu->pntsv; + while(a--) { + if(count==nr) { + memcpy(vec, bp->vec, 12); + break; + } + count++; + bp++; + } + } + nu= nu->next; + } + + } + else if(par->type==OB_IKA) { + Ika *ika= par->data; + Limb *li= ika->limbbase.first; + int cur= 1; + if(nr) { + while(li) { + if(cur==nr || li->next==0) break; + cur++; + li= li->next; + } + vec[0]= li->eff[0]; + vec[1]= li->eff[1]; + } + } + else return; +} + +void ob_parvert3(Object *ob, Object *par, float mat[][4]) +{ + float cmat[3][3], v1[3], v2[3], v3[3], q[4]; + + /* in lokale ob space */ + Mat4One(mat); + + if ELEM3(par->type, OB_MESH, OB_SURF, OB_CURVE) { + + give_parvert(par, ob->par1, v1); + give_parvert(par, ob->par2, v2); + give_parvert(par, ob->par3, v3); + + triatoquat(v1, v2, v3, q); + QuatToMat3(q, cmat); + Mat4CpyMat3(mat, cmat); + + if(ob->type==OB_CURVE) { + VECCOPY(mat[3], v1); + } + else { + VecAddf(mat[3], v1, v2); + VecAddf(mat[3], mat[3], v3); + VecMulf(mat[3], 0.3333333f); + } + } +} + +static int no_parent_ipo=0; +void set_no_parent_ipo(int val) +{ + no_parent_ipo= val; +} + +static float timefac= 1.0; /* 50 Hz, dtime:2 */ +void set_dtime(int dtime) +{ + timefac= ((float)(dtime-1))/2.0f; +} + +static int during_script_flag=0; +void disable_where_script(short on) +{ + during_script_flag= on; +} + +int during_script(void) { + return during_script_flag; +} + +void where_is_object_time(Object *ob, float ctime) +{ + Object *par; + float *fp1, *fp2, slowmat[4][4] = MAT4_UNITY; + float stime, fac1, fac2; + int a; + int pop; + + /* nieuwe versie: correcte parent+vertexparent en track+parent */ + /* deze berekent alleen de directe relatie met de parent en track */ + /* hij is sneller, maar moet wel de timeoffs in de gaten houden */ + + if(ob==0) return; + + if( ctime != ob->ctime) { + ob->ctime= ctime; + + if(ob->ipo) { + + stime= bsystem_time(ob, 0, ctime, 0.0); + + calc_ipo(ob->ipo, stime); + execute_ipo((ID *)ob, ob->ipo); + } + } + + + if(ob->type==OB_IKA) { + Ika *ika= ob->data; + if(ika->parent) where_is_object_time(ika->parent, ctime); + } + + if(ob->parent) { + par= ob->parent; + + if(ob->ipoflag & OB_OFFS_PARENT) ctime-= ob->sf; + + pop= 0; + if(no_parent_ipo==0 && ctime != par->ctime) { + + // alleen voor ipo systemen? + pushdata(par, sizeof(Object)); + pop= 1; + + where_is_object_time(par, ctime); + } + + solve_parenting(ob, par, slowmat, 0); + + if(pop) { + poplast(par); + } + + if(ob->partype & PARSLOW) { + // framerate meetellen + + fac1= (float)(timefac/(1.0+ fabs(ob->sf))); + if(fac1>=1.0) return; + fac2= 1.0f-fac1; + + fp1= ob->obmat[0]; + fp2= slowmat[0]; + for(a=0; a<16; a++, fp1++, fp2++) { + fp1[0]= fac1*fp1[0] + fac2*fp2[0]; + } + } + + } + else { + object_to_mat4(ob, ob->obmat); + } + + /* Handle tracking */ + if(ob->track) { + if( ctime != ob->track->ctime) where_is_object_time(ob->track, ctime); + solve_tracking (ob, ob->track->obmat); + + } + + solve_constraints (ob, TARGET_OBJECT, NULL, ctime); + + if(ob->scriptlink.totscript && !during_script()) { + BPY_do_pyscript((ID *)ob, SCRIPT_REDRAW); + } +} + +static void solve_parenting (Object *ob, Object *par, float slowmat[][4], int simul) +{ + float totmat[4][4]; + float tmat[4][4]; + float obmat[4][4]; + float vec[3]; + int ok; + + object_to_mat4(ob, obmat); + + if(ob->partype & PARSLOW) Mat4CpyMat4(slowmat, ob->obmat); + + + switch(ob->partype & PARTYPE) { + case PAROBJECT: + ok= 0; + if(par->type==OB_CURVE) { + if( ((Curve *)par->data)->flag & CU_PATH ) { + ob_parcurve(ob, par, tmat); + ok= 1; + } + } + + if(ok) Mat4MulSerie(totmat, par->obmat, tmat, + NULL, NULL, NULL, NULL, NULL, NULL); + else Mat4CpyMat4(totmat, par->obmat); + + break; + case PARBONE: + ob_parbone(ob, par, tmat); + Mat4MulSerie(totmat, par->obmat, tmat, + NULL, NULL, NULL, NULL, NULL, NULL); + break; + case PARLIMB: + ob_parlimb(ob, par, tmat); + Mat4MulSerie(totmat, par->obmat, tmat, + NULL, NULL, NULL, NULL, NULL, NULL); + break; + + case PARVERT1: + Mat4One(totmat); + if (simul){ + VECCOPY(totmat[3], par->obmat[3]); + } + else{ + give_parvert(par, ob->par1, vec); + VecMat4MulVecfl(totmat[3], par->obmat, vec); + } + break; + case PARVERT3: + ob_parvert3(ob, par, tmat); + + Mat4MulSerie(totmat, par->obmat, tmat, + NULL, NULL, NULL, NULL, NULL, NULL); + break; + + case PARSKEL: +#if 0 + if (ob!=G.obedit) + Mat4One(totmat); + else + Mat4CpyMat4(totmat, par->obmat); + break; +#else + Mat4CpyMat4(totmat, par->obmat); +#endif + } + + // totaal + Mat4MulSerie(tmat, totmat, ob->parentinv, + NULL, NULL, NULL, NULL, NULL, NULL); + Mat4MulSerie(ob->obmat, tmat, obmat, + NULL, NULL, NULL, NULL, NULL, NULL); + + if (simul){ + + } + else{ + // >>>>>>>>>>>>>>>>>> + // dit is een extern bruikbare originmat + Mat3CpyMat4(originmat, tmat); + + // origin, voor hulplijntje + if( (ob->partype & 15)==PARSKEL ) { + VECCOPY(ob->orig, par->obmat[3]); + } + else { + VECCOPY(ob->orig, totmat[3]); + } + } + +} +void solve_tracking (Object *ob, float targetmat[][4]) +{ + float *quat; + float vec[3]; + float totmat[3][3]; + float tmat[4][4]; + + VecSubf(vec, ob->obmat[3], targetmat[3]); + quat= vectoquat(vec, ob->trackflag, ob->upflag); + QuatToMat3(quat, totmat); + + if(ob->parent && (ob->transflag & OB_POWERTRACK)) { + /* 'tijdelijk' : parent info wissen */ + object_to_mat4(ob, tmat); + tmat[0][3]= ob->obmat[0][3]; + tmat[1][3]= ob->obmat[1][3]; + tmat[2][3]= ob->obmat[2][3]; + tmat[3][0]= ob->obmat[3][0]; + tmat[3][1]= ob->obmat[3][1]; + tmat[3][2]= ob->obmat[3][2]; + tmat[3][3]= ob->obmat[3][3]; + } + else Mat4CpyMat4(tmat, ob->obmat); + + Mat4MulMat34(ob->obmat, totmat, tmat); + +} + +void where_is_object(Object *ob) +{ + + /* deze zijn gememcopied */ + if(ob->flag & OB_FROMDUPLI) return; + + where_is_object_time(ob, (float)G.scene->r.cfra); +} + + +void where_is_object_simul(Object *ob) +/* It seems that this function is only called +for a lamp that is the child of another object */ +{ + Object *par; + Ipo *ipo; + float *fp1, *fp2; + float slowmat[4][4]; + float fac1, fac2; + int a; + + /* nieuwe versie: correcte parent+vertexparent en track+parent */ + /* deze berekent alleen de directe relatie met de parent en track */ + /* GEEN TIMEOFFS */ + + /* geen ipo! (ivm dloc en realtime-ipos) */ + ipo= ob->ipo; + ob->ipo= NULL; + + if(ob->parent) { + par= ob->parent; + + solve_parenting(ob, par, slowmat, 1); + + if(ob->partype & PARSLOW) { + + fac1= (float)(1.0/(1.0+ fabs(ob->sf))); + fac2= 1.0f-fac1; + fp1= ob->obmat[0]; + fp2= slowmat[0]; + for(a=0; a<16; a++, fp1++, fp2++) { + fp1[0]= fac1*fp1[0] + fac2*fp2[0]; + } + } + + } + else { + object_to_mat4(ob, ob->obmat); + } + + if(ob->track) + solve_tracking(ob, ob->track->obmat); + + solve_constraints(ob, TARGET_OBJECT, NULL, G.scene->r.cfra); + + /* LET OP!!! */ + ob->ipo= ipo; + +} +extern void Mat4BlendMat4(float out[][4], float dst[][4], float src[][4], float srcweight); + +void solve_constraints (Object *ob, short obtype, void *obdata, float ctime) +{ + bConstraint *con; + float tmat[4][4], focusmat[4][4], lastmat[4][4]; + int i, clear=1, tot=0; + float a; + float aquat[4], quat[4]; + float aloc[3], loc[3]; + float asize[3], size[3]; + float oldmat[4][4]; + float smat[3][3], rmat[3][3], mat[3][3]; + float enf; + + for (con = ob->constraints.first; con; con=con->next){ + /* Clear accumulators if necessary*/ + if (clear){ + clear=0; + a=0; + tot=0; + memset(aquat, 0, sizeof(float)*4); + memset(aloc, 0, sizeof(float)*3); + memset(asize, 0, sizeof(float)*3); + } + + /* Check this constraint only if it has some enforcement */ + // if (con->enforce > 0) + if (!(con->flag & CONSTRAINT_DISABLE)) + { + if (con->enforce==0) + enf = 0.001f; + enf = con->enforce; + + /* Get the targetmat */ + get_constraint_target(con, obtype, obdata, tmat, size, ctime); + + Mat4CpyMat4(focusmat, tmat); + + /* Extract the components & accumulate */ + Mat4ToQuat(focusmat, quat); + VECCOPY(loc, focusmat[3]); + + a+=enf; + tot++; + + for(i=0; i<3; i++){ + aquat[i+1]+=(quat[i+1]) * enf; + aloc[i]+=(loc[i]) * enf; + asize[i]+=(size[i]-1.0f) * enf; + } + aquat[0]+=(quat[0])*enf; + Mat4CpyMat4(lastmat, focusmat); + } + + /* If the next constraint is not the same type (or there isn't one), + * then evaluate the accumulator & request a clear */ + if ((!con->next)||(con->next && con->next->type!=con->type)) + { + clear=1; + Mat4CpyMat4(oldmat, ob->obmat); + + /* If we have several inputs, do a blend of them */ + if (tot){ + if (tot>1){ + if (a){ + for (i=0; i<3; i++){ + asize[i]=1.0f + (asize[i]/(a)); + aloc[i]=(aloc[i]/a); + } + + NormalQuat(aquat); + + QuatToMat3(aquat, rmat); + SizeToMat3(asize, smat); + Mat3MulMat3(mat, rmat, smat); + Mat4CpyMat3(focusmat, mat); + VECCOPY(focusmat[3], aloc); + + evaluate_constraint(con, ob, obtype, obdata, focusmat); + } + + } + /* If we only have one, blend with the current obmat */ + else{ + float solution[4][4]; + float delta[4][4]; + float imat[4][4]; + float identity[4][4]; + float worldmat[4][4]; + + if (con->type!=CONSTRAINT_TYPE_KINEMATIC){ + /* If we're not an IK constraint, solve the constraint then blend it to the previous one */ + evaluate_constraint(con, ob, obtype, obdata, lastmat); + + Mat4CpyMat4 (solution, ob->obmat); + + /* Interpolate the enforcement */ + Mat4Invert (imat, oldmat); + Mat4MulMat4 (delta, solution, imat); + + Mat4One(identity); + Mat4BlendMat4(delta, identity, delta, a); + Mat4MulMat4 (ob->obmat, delta, oldmat); + + } + else{ + /* Interpolate the target between the chain's unconstrained endpoint and the effector loc */ + if (obtype==TARGET_BONE){ + get_objectspace_bone_matrix(obdata, oldmat, 1, 1); + + Mat4MulMat4(worldmat, oldmat, ob->parent->obmat); + + Mat4BlendMat4(focusmat, worldmat, lastmat, a); + + evaluate_constraint(con, ob, obtype, obdata, focusmat); + } + } + } + } + } + } +} +void what_does_parent1(Object *par, int partype, int par1, int par2, int par3) +{ + + clear_workob(); + Mat4One(workob.parentinv); + workob.parent= par; + if(par) + workob.track= par->track; /* LET OP: NIET ECHT NETJES */ + workob.partype= partype; + workob.par1= par1; + workob.par2= par2; + workob.par3= par3; + + if (par){ + workob.constraints.first = par->constraints.first; + workob.constraints.last = par->constraints.last; + } + + where_is_object(&workob); +} + + +void what_does_parent(Object *ob) +{ + + clear_workob(); + Mat4One(workob.obmat); + Mat4One(workob.parentinv); + workob.parent= ob->parent; + workob.track= ob->track; + + workob.trackflag= ob->trackflag; + workob.upflag= ob->upflag; + + workob.partype= ob->partype; + workob.par1= ob->par1; + workob.par2= ob->par2; + workob.par3= ob->par3; + + workob.constraints.first = ob->constraints.first; + workob.constraints.last = ob->constraints.last; + + strcpy (workob.parsubstr, ob->parsubstr); + + where_is_object(&workob); +} + +BoundBox *unit_boundbox() +{ + BoundBox *bb; + + bb= MEM_mallocN(sizeof(BoundBox), "bb"); + + bb->vec[0][0]=bb->vec[1][0]=bb->vec[2][0]=bb->vec[3][0]= -1.0; + bb->vec[4][0]=bb->vec[5][0]=bb->vec[6][0]=bb->vec[7][0]= 1.0; + + bb->vec[0][1]=bb->vec[1][1]=bb->vec[4][1]=bb->vec[5][1]= -1.0; + bb->vec[2][1]=bb->vec[3][1]=bb->vec[6][1]=bb->vec[7][1]= 1.0; + + bb->vec[0][2]=bb->vec[3][2]=bb->vec[4][2]=bb->vec[7][2]= -1.0; + bb->vec[1][2]=bb->vec[2][2]=bb->vec[5][2]=bb->vec[6][2]= 1.0; + + return bb; +} + +void minmax_object(Object *ob, float *min, float *max) +{ + BoundBox bb; + Mesh *me; + Curve *cu; + float vec[3]; + int a; + + switch(ob->type) { + + case OB_CURVE: + case OB_FONT: + case OB_SURF: + cu= ob->data; + + if(cu->bb==0) tex_space_curve(cu); + bb= *(cu->bb); + + for(a=0; a<8; a++) { + Mat4MulVecfl(ob->obmat, bb.vec[a]); + DO_MINMAX(bb.vec[a], min, max); + } + break; + + case OB_MESH: + me= get_mesh(ob); + + if(me) { + if(me->bb==0) tex_space_mesh(me); + bb= *(me->bb); + + for(a=0; a<8; a++) { + Mat4MulVecfl(ob->obmat, bb.vec[a]); + DO_MINMAX(bb.vec[a], min, max); + } + } + if(min[0] < max[0] ) break; + + /* else here no break!!!, mesh can be zero sized */ + + default: + DO_MINMAX(ob->obmat[3], min, max); + + VECCOPY(vec, ob->obmat[3]); + VecAddf(vec, vec, ob->size); + DO_MINMAX(vec, min, max); + + VECCOPY(vec, ob->obmat[3]); + VecSubf(vec, vec, ob->size); + DO_MINMAX(vec, min, max); + break; + } +} + + |