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/object.c

1768 lines
35 KiB
C
Raw Normal View History

/* object.c
*
2002-10-12 11:37:38 +00:00
*
* $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 HAVE_CONFIG_H
#include <config.h>
#endif
2002-10-12 11:37:38 +00:00
#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_meshdata_types.h"
2002-10-12 11:37:38 +00:00
#include "DNA_object_types.h"
#include "DNA_oops_types.h"
2002-10-12 11:37:38 +00:00
#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 "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"
OK. Here's the long awaited first step (V0.01!) of SoftBody. It is called from within mesh_modifiers (kernel deform.c). It copies vertices to a temporal particle system (struct SoftBody with BodyPoint structs) to do physics tricks with it. For each frame change the delta movements (based on standard ipo anim or even other deforms (later) are applied to the physics system. How to apply and calculate satisfying results is not my thing... so here I'll commu- nicate with others for. Since it's in the modifier stack, the SoftBody code can run entirely on original data (no displists!). Right now I've implemented 2 things; - "Goal" which is a per vertex value for how much the current position should take into account (goal=1 is without physics). This is a powerful method for artists to get control over what moves and not. Right now i read the vertex color for it. - And some spring stuff, which now only works based on force moving it to the originial location. This doesnt work with 'goal'... erhm. - You can re-use physics vars from engine, used right now is (in Object) - damping - springf (spring factor) - softflag (to set types, or activate softbody for it - The SoftBody pointer in struct Object is only runtime, nothing saved in file To prevent all users going to complain it doesn't work, I've hidden the functionality. :) The buttons to set softbody 'on' only show now (psst psst) when the object has name "soft" as first 4 characters. You can find the buttons in the F7 Particle Interaction Panel (which should be renamed 'physics properties' later or so. Demo file: http://www.blender.org/bf/softbody.blend
2004-10-01 14:04:17 +00:00
#include "BKE_softbody.h"
2002-10-12 11:37:38 +00:00
#include "BPY_extern.h"
2002-10-12 11:37:38 +00:00
/* Local function protos */
static void solve_parenting (Object *ob, Object *par, float slowmat[][4], int simul);
float originmat[3][3]; /* after where_is_object(), can be used in other functions (bad!) */
2002-10-12 11:37:38 +00:00
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;
}
}
static void free_hooks(ListBase *lb)
{
while(lb->first) {
ObHook *hook= lb->first;
if(hook->indexar) MEM_freeN(hook->indexar);
BLI_remlink(lb, hook);
MEM_freeN(hook);
}
}
static void copy_hooks(ListBase *new, ListBase *old)
{
ObHook *hook, *hookn;
new->first= new->last= NULL;
for(hook= old->first; hook; hook= hook->next) {
hookn= MEM_dupallocN(hook);
hookn->indexar= MEM_dupallocN(hookn->indexar);
BLI_addtail(new, hookn);
}
}
/* do not free object itself */
2002-10-12 11:37:38 +00:00
void free_object(Object *ob)
{
int a;
/* disconnect specific data */
2002-10-12 11:37:38 +00:00
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);
free_hooks(&ob->hooks);
2002-10-12 11:37:38 +00:00
freedisplist(&ob->disp);
BPY_free_scriptlink(&ob->scriptlink);
if(ob->pd) MEM_freeN(ob->pd);
OK. Here's the long awaited first step (V0.01!) of SoftBody. It is called from within mesh_modifiers (kernel deform.c). It copies vertices to a temporal particle system (struct SoftBody with BodyPoint structs) to do physics tricks with it. For each frame change the delta movements (based on standard ipo anim or even other deforms (later) are applied to the physics system. How to apply and calculate satisfying results is not my thing... so here I'll commu- nicate with others for. Since it's in the modifier stack, the SoftBody code can run entirely on original data (no displists!). Right now I've implemented 2 things; - "Goal" which is a per vertex value for how much the current position should take into account (goal=1 is without physics). This is a powerful method for artists to get control over what moves and not. Right now i read the vertex color for it. - And some spring stuff, which now only works based on force moving it to the originial location. This doesnt work with 'goal'... erhm. - You can re-use physics vars from engine, used right now is (in Object) - damping - springf (spring factor) - softflag (to set types, or activate softbody for it - The SoftBody pointer in struct Object is only runtime, nothing saved in file To prevent all users going to complain it doesn't work, I've hidden the functionality. :) The buttons to set softbody 'on' only show now (psst psst) when the object has name "soft" as first 4 characters. You can find the buttons in the F7 Particle Interaction Panel (which should be renamed 'physics properties' later or so. Demo file: http://www.blender.org/bf/softbody.blend
2004-10-01 14:04:17 +00:00
if(ob->soft) free_softbody(ob->soft);
2002-10-12 11:37:38 +00:00
}
void unlink_object(Object *ob)
{
Object *obt;
Material *mat;
World *wrld;
bScreen *sc;
Scene *sce;
Curve *cu;
Tex *tex;
ObHook *hook;
2002-10-12 11:37:38 +00:00
Group *group;
int a;
unlink_controllers(&ob->controllers);
unlink_actuators(&ob->actuators);
/* check all objects: parents en bevels */
2002-10-12 11:37:38 +00:00
obt= G.main->object.first;
while(obt) {
if(obt->id.lib==NULL) {
2002-10-12 11:37:38 +00:00
if(obt->parent==ob) {
obt->parent= NULL;
2002-10-12 11:37:38 +00:00
if(ob->type==OB_LATTICE) freedisplist(&obt->disp);
}
if(obt->track==ob) obt->track= NULL;
for(hook=obt->hooks.first; hook; hook= hook->next) {
if(hook->parent==ob) hook->parent= NULL;
}
2002-10-12 11:37:38 +00:00
if ELEM(obt->type, OB_CURVE, OB_FONT) {
cu= obt->data;
if(cu->bevobj==ob) cu->bevobj= NULL;
if(cu->taperobj==ob) cu->taperobj= NULL;
if(cu->textoncurve==ob) cu->textoncurve= NULL;
2002-10-12 11:37:38 +00:00
}
if(obt->type==OB_IKA) {
Ika *ika= obt->data;
Deform *def= ika->def;
if(ika->parent==ob) ika->parent= NULL;
2002-10-12 11:37:38 +00:00
a= ika->totdef;
while(a--) {
if(def->ob==ob) {
ika->totdef= 0;
MEM_freeN(ika->def);
ika->def= NULL;
2002-10-12 11:37:38 +00:00
break;
}
def++;
}
}
sca_remove_ob_poin(obt, ob);
}
obt= obt->id.next;
}
/* materials */
2002-10-12 11:37:38 +00:00
mat= G.main->mat.first;
while(mat) {
for(a=0; a<MAX_MTEX; a++) {
2002-10-12 11:37:38 +00:00
if(mat->mtex[a] && ob==mat->mtex[a]->object) {
/* actually, test for lib here... to do */
2002-10-12 11:37:38 +00:00
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<MAX_MTEX; a++) {
2002-10-12 11:37:38 +00:00
if(wrld->mtex[a] && ob==wrld->mtex[a]->object)
wrld->mtex[a]->object =0;
}
}
wrld= wrld->id.next;
}
/* scenes */
2002-10-12 11:37:38 +00:00
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;
}
}
else if(sl->spacetype==SPACE_IPO) {
SpaceIpo *sipo= (SpaceIpo *)sl;
if(sipo->from == (ID *)ob) sipo->from= NULL;
}
else if(sl->spacetype==SPACE_OOPS) {
SpaceOops *so= (SpaceOops *)sl;
Oops *oops;
oops= so->oops.first;
while(oops) {
if(oops->id==(ID *)ob) oops->id= NULL;
oops= oops->next;
}
if(so->treestore) {
TreeStoreElem *tselem= so->treestore->data;
int a;
for(a=0; a<so->treestore->usedelem; a++, tselem++) {
if(tselem->id==(ID *)ob) tselem->id= NULL;
}
}
so->lockpoin= NULL;
}
2002-10-12 11:37:38 +00:00
}
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;
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;
/* - only lib users: do nothing
* - only local users: set flag
* - mixed: make copy
*/
2002-10-12 11:37:38 +00:00
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");
Area lights and more... - New lamp type added "Area". This uses the radiosity formula (Stoke) to calculate the amount of energy which is received from a plane. Result is very nice local light, which nicely spreads out. - Area lamps have a 'gamma' option to control the light spread - Area lamp builtin sizes: square, rect, cube & box. Only first 2 are implemented. Set a type, and define area size - Button area size won't affect the amount of energy. But scaling the lamp in 3d window will do. This is to cover the case when you scale an entire scene, the light then will remain identical If you just want to change area lamp size, use buttons when you dont want to make the scene too bright or too dark - Since area lights realistically are sensitive for distance (quadratic), the effect it has is quickly too much, or too less. For this the "Dist" value in Lamp can be used. Set it at Dist=10 to have reasonable light on distance 10 Blender units (assumed you didnt scale lamp object). - I tried square sized specularity, but this looked totally weird. Not committed - Plan is to extend area light with 3d dimensions, boxes and cubes. - Note that area light is one-sided, towards negative Z. I need to design a nice drawing method for it. Area Shadow - Since there are a lot of variables associated with soft shadow, they now only are available for Area lights. Allowing spot & normal lamp to have soft shadow is possible though, but will require a reorganisation of the Lamp buttons. Is a point of research & feedback still. - Apart from area size, you now can individually set amount of samples in X and Y direction (for area lamp type 'Rect'). For box type area lamp, this will become 3 dimensions - Area shadows have four options: "Clip circle" : only uses a circular shape of samples, gives smoother results "Dither" : use a 2x2 dither mask "Jitter" : applys a pseudo-random offset to samples "Umbra" : extra emphasis on area that's fully in shadow. Raytrace speedup - improved filling in faces in Octree. Large faces occupied too many nodes - added a coherence check; rays fired sequentially that begin and end in same octree nodes, and that don't intersect, are quickly rejected - rendering shadow scenes benefits from this 20-40%. My statue test monkey file now renders in 19 seconds (was 30). Plus: - adjusted specular max to 511, and made sure Blinn spec has again this incredible small spec size - for UI rounded theme: the color "button" displayed RGB color too dark - fixed countall() function, to also include Subsurf totals - removed setting the 'near' clipping for pressing dot-key numpad - when you press the buttons-window icon for 'Shading Context' the context automaticilly switches as with F5 hotkey Please be warned that this is not a release... settings in files might not work as it did, nor guaranteed to work when we do a release. :)
2003-12-29 16:52:51 +00:00
la->r= la->g= la->b= la->k= 1.0;
2002-10-12 11:37:38 +00:00
la->haint= la->energy= 1.0;
Area lights and more... - New lamp type added "Area". This uses the radiosity formula (Stoke) to calculate the amount of energy which is received from a plane. Result is very nice local light, which nicely spreads out. - Area lamps have a 'gamma' option to control the light spread - Area lamp builtin sizes: square, rect, cube & box. Only first 2 are implemented. Set a type, and define area size - Button area size won't affect the amount of energy. But scaling the lamp in 3d window will do. This is to cover the case when you scale an entire scene, the light then will remain identical If you just want to change area lamp size, use buttons when you dont want to make the scene too bright or too dark - Since area lights realistically are sensitive for distance (quadratic), the effect it has is quickly too much, or too less. For this the "Dist" value in Lamp can be used. Set it at Dist=10 to have reasonable light on distance 10 Blender units (assumed you didnt scale lamp object). - I tried square sized specularity, but this looked totally weird. Not committed - Plan is to extend area light with 3d dimensions, boxes and cubes. - Note that area light is one-sided, towards negative Z. I need to design a nice drawing method for it. Area Shadow - Since there are a lot of variables associated with soft shadow, they now only are available for Area lights. Allowing spot & normal lamp to have soft shadow is possible though, but will require a reorganisation of the Lamp buttons. Is a point of research & feedback still. - Apart from area size, you now can individually set amount of samples in X and Y direction (for area lamp type 'Rect'). For box type area lamp, this will become 3 dimensions - Area shadows have four options: "Clip circle" : only uses a circular shape of samples, gives smoother results "Dither" : use a 2x2 dither mask "Jitter" : applys a pseudo-random offset to samples "Umbra" : extra emphasis on area that's fully in shadow. Raytrace speedup - improved filling in faces in Octree. Large faces occupied too many nodes - added a coherence check; rays fired sequentially that begin and end in same octree nodes, and that don't intersect, are quickly rejected - rendering shadow scenes benefits from this 20-40%. My statue test monkey file now renders in 19 seconds (was 30). Plus: - adjusted specular max to 511, and made sure Blinn spec has again this incredible small spec size - for UI rounded theme: the color "button" displayed RGB color too dark - fixed countall() function, to also include Subsurf totals - removed setting the 'near' clipping for pressing dot-key numpad - when you press the buttons-window icon for 'Shading Context' the context automaticilly switches as with F5 hotkey Please be warned that this is not a release... settings in files might not work as it did, nor guaranteed to work when we do a release. :)
2003-12-29 16:52:51 +00:00
la->dist= 20.0;
la->spotsize= 45.0;
la->spotblend= 0.15;
la->att2= 1.0;
2002-10-12 11:37:38 +00:00
la->mode= LA_SHAD;
la->bufsize= 512;
Area lights and more... - New lamp type added "Area". This uses the radiosity formula (Stoke) to calculate the amount of energy which is received from a plane. Result is very nice local light, which nicely spreads out. - Area lamps have a 'gamma' option to control the light spread - Area lamp builtin sizes: square, rect, cube & box. Only first 2 are implemented. Set a type, and define area size - Button area size won't affect the amount of energy. But scaling the lamp in 3d window will do. This is to cover the case when you scale an entire scene, the light then will remain identical If you just want to change area lamp size, use buttons when you dont want to make the scene too bright or too dark - Since area lights realistically are sensitive for distance (quadratic), the effect it has is quickly too much, or too less. For this the "Dist" value in Lamp can be used. Set it at Dist=10 to have reasonable light on distance 10 Blender units (assumed you didnt scale lamp object). - I tried square sized specularity, but this looked totally weird. Not committed - Plan is to extend area light with 3d dimensions, boxes and cubes. - Note that area light is one-sided, towards negative Z. I need to design a nice drawing method for it. Area Shadow - Since there are a lot of variables associated with soft shadow, they now only are available for Area lights. Allowing spot & normal lamp to have soft shadow is possible though, but will require a reorganisation of the Lamp buttons. Is a point of research & feedback still. - Apart from area size, you now can individually set amount of samples in X and Y direction (for area lamp type 'Rect'). For box type area lamp, this will become 3 dimensions - Area shadows have four options: "Clip circle" : only uses a circular shape of samples, gives smoother results "Dither" : use a 2x2 dither mask "Jitter" : applys a pseudo-random offset to samples "Umbra" : extra emphasis on area that's fully in shadow. Raytrace speedup - improved filling in faces in Octree. Large faces occupied too many nodes - added a coherence check; rays fired sequentially that begin and end in same octree nodes, and that don't intersect, are quickly rejected - rendering shadow scenes benefits from this 20-40%. My statue test monkey file now renders in 19 seconds (was 30). Plus: - adjusted specular max to 511, and made sure Blinn spec has again this incredible small spec size - for UI rounded theme: the color "button" displayed RGB color too dark - fixed countall() function, to also include Subsurf totals - removed setting the 'near' clipping for pressing dot-key numpad - when you press the buttons-window icon for 'Shading Context' the context automaticilly switches as with F5 hotkey Please be warned that this is not a release... settings in files might not work as it did, nor guaranteed to work when we do a release. :)
2003-12-29 16:52:51 +00:00
la->clipsta= 0.5;
la->clipend= 40.0;
la->shadspotsize= 45.0;
2002-10-12 11:37:38 +00:00
la->samp= 3;
Area lights and more... - New lamp type added "Area". This uses the radiosity formula (Stoke) to calculate the amount of energy which is received from a plane. Result is very nice local light, which nicely spreads out. - Area lamps have a 'gamma' option to control the light spread - Area lamp builtin sizes: square, rect, cube & box. Only first 2 are implemented. Set a type, and define area size - Button area size won't affect the amount of energy. But scaling the lamp in 3d window will do. This is to cover the case when you scale an entire scene, the light then will remain identical If you just want to change area lamp size, use buttons when you dont want to make the scene too bright or too dark - Since area lights realistically are sensitive for distance (quadratic), the effect it has is quickly too much, or too less. For this the "Dist" value in Lamp can be used. Set it at Dist=10 to have reasonable light on distance 10 Blender units (assumed you didnt scale lamp object). - I tried square sized specularity, but this looked totally weird. Not committed - Plan is to extend area light with 3d dimensions, boxes and cubes. - Note that area light is one-sided, towards negative Z. I need to design a nice drawing method for it. Area Shadow - Since there are a lot of variables associated with soft shadow, they now only are available for Area lights. Allowing spot & normal lamp to have soft shadow is possible though, but will require a reorganisation of the Lamp buttons. Is a point of research & feedback still. - Apart from area size, you now can individually set amount of samples in X and Y direction (for area lamp type 'Rect'). For box type area lamp, this will become 3 dimensions - Area shadows have four options: "Clip circle" : only uses a circular shape of samples, gives smoother results "Dither" : use a 2x2 dither mask "Jitter" : applys a pseudo-random offset to samples "Umbra" : extra emphasis on area that's fully in shadow. Raytrace speedup - improved filling in faces in Octree. Large faces occupied too many nodes - added a coherence check; rays fired sequentially that begin and end in same octree nodes, and that don't intersect, are quickly rejected - rendering shadow scenes benefits from this 20-40%. My statue test monkey file now renders in 19 seconds (was 30). Plus: - adjusted specular max to 511, and made sure Blinn spec has again this incredible small spec size - for UI rounded theme: the color "button" displayed RGB color too dark - fixed countall() function, to also include Subsurf totals - removed setting the 'near' clipping for pressing dot-key numpad - when you press the buttons-window icon for 'Shading Context' the context automaticilly switches as with F5 hotkey Please be warned that this is not a release... settings in files might not work as it did, nor guaranteed to work when we do a release. :)
2003-12-29 16:52:51 +00:00
la->bias= 1.0;
la->soft= 3.0;
la->ray_samp= la->ray_sampy= la->ray_sampz= 1;
la->area_size=la->area_sizey=la->area_sizez= 1.0;
2002-10-12 11:37:38 +00:00
return la;
}
Lamp *copy_lamp(Lamp *la)
{
Lamp *lan;
int a;
lan= copy_libblock(la);
for(a=0; a<MAX_MTEX; a++) {
2002-10-12 11:37:38 +00:00
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;
/* - only lib users: do nothing
* - only local users: set flag
* - mixed: make copy
*/
2002-10-12 11:37:38 +00:00
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<MAX_MTEX; a++) {
2002-10-12 11:37:38 +00:00
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";
}
}
/* general add: to G.scene, with layer from area and default name */
/* creates minimum required data, but without vertices etc. */
2002-10-12 11:37:38 +00:00
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 & USER_MAT_ON_OB) ob->colbits= -1;
2002-10-12 11:37:38 +00:00
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->ipowin= ID_OB; /* the ipowin shown */
2002-10-12 11:37:38 +00:00
ob->dupon= 1; ob->dupoff= 0;
ob->dupsta= 1; ob->dupend= 100;
/* Game engine defaults*/
2002-10-12 11:37:38 +00:00
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];
}
2002-10-12 11:37:38 +00:00
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);
copy_hooks( &obn->hooks, &ob->hooks);
2002-10-12 11:37:38 +00:00
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;
if(ob->pd) obn->pd= MEM_dupallocN(ob->pd);
/* increase user numbers */
2002-10-12 11:37:38 +00:00
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= NULL;
OK. Here's the long awaited first step (V0.01!) of SoftBody. It is called from within mesh_modifiers (kernel deform.c). It copies vertices to a temporal particle system (struct SoftBody with BodyPoint structs) to do physics tricks with it. For each frame change the delta movements (based on standard ipo anim or even other deforms (later) are applied to the physics system. How to apply and calculate satisfying results is not my thing... so here I'll commu- nicate with others for. Since it's in the modifier stack, the SoftBody code can run entirely on original data (no displists!). Right now I've implemented 2 things; - "Goal" which is a per vertex value for how much the current position should take into account (goal=1 is without physics). This is a powerful method for artists to get control over what moves and not. Right now i read the vertex color for it. - And some spring stuff, which now only works based on force moving it to the originial location. This doesnt work with 'goal'... erhm. - You can re-use physics vars from engine, used right now is (in Object) - damping - springf (spring factor) - softflag (to set types, or activate softbody for it - The SoftBody pointer in struct Object is only runtime, nothing saved in file To prevent all users going to complain it doesn't work, I've hidden the functionality. :) The buttons to set softbody 'on' only show now (psst psst) when the object has name "soft" as first 4 characters. You can find the buttons in the F7 Particle Interaction Panel (which should be renamed 'physics properties' later or so. Demo file: http://www.blender.org/bf/softbody.blend
2004-10-01 14:04:17 +00:00
obn->soft= NULL;
2002-10-12 11:37:38 +00:00
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;
/* - only lib users: do nothing
* - only local users: set flag
* - mixed: make copy
*/
2002-10-12 11:37:38 +00:00
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 ****************** */
/* there is also a timing calculation in drawobject() */
2002-10-12 11:37:38 +00:00
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)
{
/* returns float ( see frame_to_float in ipo.c) */
2002-10-12 11:37:38 +00:00
if(no_speed_curve==0) if(ob && ob->ipo) cfra= calc_ipo_time(ob->ipo, cfra);
/* 2nd field */
2002-10-12 11:37:38 +00:00
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;
/* catch exceptions: curve paths used as a duplicator */
2002-10-12 11:37:38 +00:00
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);
}
/* vec: 4 items! */
2002-10-12 11:37:38 +00:00
if( where_on_path(par, ctime, vec, dir) ) {
if(cu->flag & CU_FOLLOW) {
quat= vectoquat(dir, ob->trackflag, ob->upflag);
/* the tilt */
2002-10-12 11:37:38 +00:00
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 local ob space */
2002-10-12 11:37:38 +00:00
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)
{
EditMesh *em = G.editMesh;
2002-10-12 11:37:38 +00:00
Mesh *me;
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= em->verts.first;
2002-10-12 11:37:38 +00:00
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 there a deform */
2002-10-12 11:37:38 +00:00
dl= find_displist(&par->disp, DL_VERTS);
if(dl) {
fp= dl->verts+3*nr;
VECCOPY(vec, fp);
}
else {
MVert *mvert= me->mvert + nr;
2002-10-12 11:37:38 +00:00
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 local ob space */
2002-10-12 11:37:38 +00:00
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;
2002-10-12 11:37:38 +00:00
}
int during_script(void) {
return during_script_flag;
}
static int during_scriptlink_flag=0;
void disable_where_scriptlink(short on)
{
during_scriptlink_flag= on;
}
int during_scriptlink(void) {
return during_scriptlink_flag;
}
2002-10-12 11:37:38 +00:00
void where_is_object_time(Object *ob, float ctime)
{
Object *par;
float *fp1, *fp2, slowmat[4][4] = MAT4_UNITY;
float stime, fac1, fac2, vec[3];
2002-10-12 11:37:38 +00:00
int a;
int pop;
/* new version: correct parent+vertexparent and track+parent */
/* this one only calculates direct attached parent and track */
2002-10-12 11:37:38 +00:00
/* 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);
}
/* set negative scale flag in object */
Crossf(vec, ob->obmat[0], ob->obmat[1]);
if( Inpf(vec, ob->obmat[2]) < 0.0 ) ob->transflag |= OB_NEG_SCALE;
else ob->transflag &= ~OB_NEG_SCALE;
2002-10-12 11:37:38 +00:00
}
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)) {
/* 'temporal' : clear parent info */
2002-10-12 11:37:38 +00:00
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);
2002-10-12 11:37:38 +00:00
}
void where_is_object(Object *ob)
{
/* these have been mem copied */
2002-10-12 11:37:38 +00:00
if(ob->flag & OB_FROMDUPLI) return;
where_is_object_time(ob, (float)G.scene->r.cfra);
}
void where_is_object_simul(Object *ob)
/* was written for the old game engine (until 2.04) */
2002-10-12 11:37:38 +00:00
/* 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;
/* NO TIMEOFFS */
2002-10-12 11:37:38 +00:00
/* no ipo! (because of dloc and realtime-ipos) */
2002-10-12 11:37:38 +00:00
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);
/* WATCH IT!!! */
2002-10-12 11:37:38 +00:00
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=0;
2002-10-12 11:37:38 +00:00
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->flag & CONSTRAINT_DISABLE))
{
if (con->enforce==0)
enf = 0.001f;
enf = con->enforce;
/* Get the targetmat */
get_constraint_target_matrix(con, obtype, obdata, tmat, size, ctime);
2002-10-12 11:37:38 +00:00
Mat4CpyMat4(focusmat, tmat);
/* Extract the components & accumulate */
Mat4ToQuat(focusmat, quat);
VECCOPY(loc, focusmat[3]);
Mat3CpyMat4(mat, focusmat);
Mat3ToSize(mat, size);
2002-10-12 11:37:38 +00:00
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);
2002-10-12 11:37:38 +00:00
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);
2002-10-12 11:37:38 +00:00
/* Interpolate the enforcement */
Mat4Invert (imat, oldmat);
Mat4MulMat4 (delta, solution, imat);
2002-10-12 11:37:38 +00:00
if (a<1.0) {
Mat4One(identity);
Mat4BlendMat4(delta, identity, delta, a);
}
Mat4MulMat4 (ob->obmat, delta, oldmat);
2002-10-12 11:37:38 +00:00
}
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);
}
}
}
}
}
}
}
2002-10-12 11:37:38 +00:00
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; /* WATCH IT: THATS NOT NICE CODE */
2002-10-12 11:37:38 +00:00
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;
}
}