soc-2008-mxcurioni: FRS_glBlendEquation files
This commit is contained in:
43
source/blender/blenkernel/BKE_bullet.h
Normal file
43
source/blender/blenkernel/BKE_bullet.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
*
|
||||
* $Id: BKE_bullet.h 16773 2008-09-27 22:01:26Z ben2610 $
|
||||
*
|
||||
* ***** BEGIN GPL 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.
|
||||
*
|
||||
* 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) Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): none yet.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
#ifndef BKE_BULLET_H
|
||||
#define BKE_BULLET_H
|
||||
|
||||
struct BulletSoftBody;
|
||||
|
||||
|
||||
/* allocates and initializes general main data */
|
||||
extern struct BulletSoftBody *bsbNew(void);
|
||||
|
||||
/* frees internal data and softbody itself */
|
||||
extern void bsbFree(struct BulletSoftBody *sb);
|
||||
|
||||
#endif
|
||||
|
||||
55
source/blender/blenkernel/BKE_fluidsim.h
Normal file
55
source/blender/blenkernel/BKE_fluidsim.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* BKE_fluidsim.h
|
||||
*
|
||||
*
|
||||
* ***** BEGIN GPL 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.
|
||||
*
|
||||
* 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) Blender Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): none yet.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_object_fluidsim.h" // N_T
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BKE_DerivedMesh.h"
|
||||
|
||||
/* old interface */
|
||||
FluidsimSettings *fluidsimSettingsNew(Object *srcob);
|
||||
|
||||
void initElbeemMesh(Object *ob, int *numVertices, float **vertices, int *numTriangles, int **triangles, int useGlobalCoords, int modifierIndex);
|
||||
|
||||
|
||||
/* new fluid-modifier interface */
|
||||
void fluidsim_init(FluidsimModifierData *fluidmd);
|
||||
void fluidsim_free(FluidsimModifierData *fluidmd);
|
||||
|
||||
DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm, FluidsimModifierData *fluidmd, int framenr, int useRenderParams);
|
||||
DerivedMesh *fluidsimModifier_do(FluidsimModifierData *fluidmd, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc);
|
||||
|
||||
// get bounding box of mesh
|
||||
void fluid_get_bb(MVert *mvert, int totvert, float obmat[][4],
|
||||
/*RET*/ float start[3], /*RET*/ float size[3] );
|
||||
|
||||
|
||||
|
||||
39
source/blender/blenkernel/BKE_simple_deform.h
Normal file
39
source/blender/blenkernel/BKE_simple_deform.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* BKE_shrinkwrap.h
|
||||
*
|
||||
* ***** BEGIN GPL 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.
|
||||
*
|
||||
* 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) Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): none yet.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
#ifndef BKE_SIMPLE_DEFORM_H
|
||||
#define BKE_SIMPLE_DEFORM_H
|
||||
|
||||
struct Object;
|
||||
struct DerivedMesh;
|
||||
struct SimpleDeformModifierData;
|
||||
|
||||
void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object *ob, struct DerivedMesh *dm, float (*vertexCos)[3], int numVerts);
|
||||
|
||||
#endif
|
||||
|
||||
95
source/blender/blenkernel/intern/bullet.c
Normal file
95
source/blender/blenkernel/intern/bullet.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
*
|
||||
* $Id: bullet.c 16776 2008-09-28 03:07:13Z erwin $
|
||||
*
|
||||
* ***** BEGIN GPL 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.
|
||||
*
|
||||
* 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) Blender Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): none yet.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
/* types */
|
||||
#include "DNA_object_force.h" /* here is the softbody struct */
|
||||
|
||||
#include "BKE_bullet.h"
|
||||
|
||||
|
||||
/* ************ Object level, exported functions *************** */
|
||||
|
||||
/* allocates and initializes general main data */
|
||||
BulletSoftBody *bsbNew(void)
|
||||
{
|
||||
BulletSoftBody *bsb;
|
||||
|
||||
bsb= MEM_callocN(sizeof(BulletSoftBody), "bulletsoftbody");
|
||||
|
||||
bsb->flag = OB_BSB_BENDING_CONSTRAINTS | OB_BSB_SHAPE_MATCHING | OB_BSB_AERO_VPOINT;
|
||||
bsb->linStiff = 0.5f;
|
||||
bsb->angStiff = 1.0f;
|
||||
bsb->volume = 1.0f;
|
||||
|
||||
|
||||
bsb->viterations = 0;
|
||||
bsb->piterations = 2;
|
||||
bsb->diterations = 0;
|
||||
bsb->citerations = 4;
|
||||
|
||||
bsb->kSRHR_CL = 0.1f;
|
||||
bsb->kSKHR_CL = 1.f;
|
||||
bsb->kSSHR_CL = 0.5f;
|
||||
bsb->kSR_SPLT_CL = 0.5f;
|
||||
|
||||
bsb->kSK_SPLT_CL = 0.5f;
|
||||
bsb->kSS_SPLT_CL = 0.5f;
|
||||
bsb->kVCF = 1;
|
||||
bsb->kDP = 0;
|
||||
|
||||
bsb->kDG = 0;
|
||||
bsb->kLF = 0;
|
||||
bsb->kPR = 0;
|
||||
bsb->kVC = 0;
|
||||
|
||||
bsb->kDF = 0.2f;
|
||||
bsb->kMT = 0.05;
|
||||
bsb->kCHR = 1.0f;
|
||||
bsb->kKHR = 0.1f;
|
||||
|
||||
bsb->kSHR = 1.0f;
|
||||
bsb->kAHR = 0.7f;
|
||||
bsb->collisionflags = 0;
|
||||
//bsb->collisionflags = OB_BSB_COL_CL_RS + OB_BSB_COL_CL_SS;
|
||||
bsb->numclusteriterations = 64;
|
||||
|
||||
return bsb;
|
||||
}
|
||||
|
||||
/* frees all */
|
||||
void bsbFree(BulletSoftBody *bsb)
|
||||
{
|
||||
/* no internal data yet */
|
||||
MEM_freeN(bsb);
|
||||
}
|
||||
|
||||
|
||||
642
source/blender/blenkernel/intern/fluidsim.c
Normal file
642
source/blender/blenkernel/intern/fluidsim.c
Normal file
@@ -0,0 +1,642 @@
|
||||
/**
|
||||
* fluidsim.c
|
||||
*
|
||||
*
|
||||
* ***** BEGIN GPL 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.
|
||||
*
|
||||
* 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) Blender Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): none yet.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_object_force.h" // for pointcache
|
||||
#include "DNA_particle_types.h"
|
||||
#include "DNA_scene_types.h" // N_T
|
||||
|
||||
#include "BLI_arithb.h"
|
||||
#include "BLI_blenlib.h"
|
||||
|
||||
#include "BKE_cdderivedmesh.h"
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_DerivedMesh.h"
|
||||
#include "BKE_fluidsim.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_pointcache.h"
|
||||
#include "BKE_utildefines.h"
|
||||
|
||||
// headers for fluidsim bobj meshes
|
||||
#include <stdlib.h>
|
||||
#include "LBM_fluidsim.h"
|
||||
#include "elbeem.h"
|
||||
#include <zlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* ************************* fluidsim bobj file handling **************************** */
|
||||
|
||||
// -----------------------------------------
|
||||
// forward decleration
|
||||
// -----------------------------------------
|
||||
|
||||
// -----------------------------------------
|
||||
|
||||
void fluidsim_init(FluidsimModifierData *fluidmd)
|
||||
{
|
||||
#ifndef DISABLE_ELBEEM
|
||||
if(fluidmd)
|
||||
{
|
||||
FluidsimSettings *fss = MEM_callocN(sizeof(FluidsimSettings), "fluidsimsettings");
|
||||
|
||||
fluidmd->fss = fss;
|
||||
|
||||
if(!fss)
|
||||
return;
|
||||
|
||||
fss->type = 0;
|
||||
fss->show_advancedoptions = 0;
|
||||
|
||||
fss->resolutionxyz = 50;
|
||||
fss->previewresxyz = 25;
|
||||
fss->realsize = 0.03;
|
||||
fss->guiDisplayMode = 2; // preview
|
||||
fss->renderDisplayMode = 3; // render
|
||||
|
||||
fss->viscosityMode = 2; // default to water
|
||||
fss->viscosityValue = 1.0;
|
||||
fss->viscosityExponent = 6;
|
||||
|
||||
// dg TODO: change this to []
|
||||
fss->gravx = 0.0;
|
||||
fss->gravy = 0.0;
|
||||
fss->gravz = -9.81;
|
||||
fss->animStart = 0.0;
|
||||
fss->animEnd = 0.30;
|
||||
fss->gstar = 0.005; // used as normgstar
|
||||
fss->maxRefine = -1;
|
||||
// maxRefine is set according to resolutionxyz during bake
|
||||
|
||||
// fluid/inflow settings
|
||||
// fss->iniVel --> automatically set to 0
|
||||
|
||||
/* elubie: changed this to default to the same dir as the render output
|
||||
to prevent saving to C:\ on Windows */
|
||||
BLI_strncpy(fss->surfdataPath, btempdir, FILE_MAX);
|
||||
|
||||
// first init of bounding box
|
||||
// no bounding box needed
|
||||
|
||||
// todo - reuse default init from elbeem!
|
||||
fss->typeFlags = 0;
|
||||
fss->domainNovecgen = 0;
|
||||
fss->volumeInitType = 1; // volume
|
||||
fss->partSlipValue = 0.0;
|
||||
|
||||
fss->generateTracers = 0;
|
||||
fss->generateParticles = 0.0;
|
||||
fss->surfaceSmoothing = 1.0;
|
||||
fss->surfaceSubdivs = 1.0;
|
||||
fss->particleInfSize = 0.0;
|
||||
fss->particleInfAlpha = 0.0;
|
||||
|
||||
// init fluid control settings
|
||||
fss->attractforceStrength = 0.2;
|
||||
fss->attractforceRadius = 0.75;
|
||||
fss->velocityforceStrength = 0.2;
|
||||
fss->velocityforceRadius = 0.75;
|
||||
fss->cpsTimeStart = fss->animStart;
|
||||
fss->cpsTimeEnd = fss->animEnd;
|
||||
fss->cpsQuality = 10.0; // 1.0 / 10.0 => means 0.1 width
|
||||
|
||||
/*
|
||||
BAD TODO: this is done in buttons_object.c in the moment
|
||||
Mesh *mesh = ob->data;
|
||||
// calculate bounding box
|
||||
fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize);
|
||||
*/
|
||||
|
||||
fss->lastgoodframe = -1;
|
||||
|
||||
fss->flag = 0;
|
||||
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
void fluidsim_free(FluidsimModifierData *fluidmd)
|
||||
{
|
||||
#ifndef DISABLE_ELBEEM
|
||||
if(fluidmd)
|
||||
{
|
||||
MEM_freeN(fluidmd->fss);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
DerivedMesh *fluidsimModifier_do(FluidsimModifierData *fluidmd, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc)
|
||||
{
|
||||
#ifndef DISABLE_ELBEEM
|
||||
DerivedMesh *result = NULL;
|
||||
int framenr;
|
||||
FluidsimSettings *fss = NULL;
|
||||
|
||||
framenr= (int)G.scene->r.cfra;
|
||||
|
||||
// only handle fluidsim domains
|
||||
if(fluidmd && fluidmd->fss && (fluidmd->fss->type != OB_FLUIDSIM_DOMAIN))
|
||||
return dm;
|
||||
|
||||
// sanity check
|
||||
if(!fluidmd || (fluidmd && !fluidmd->fss))
|
||||
return dm;
|
||||
|
||||
fss = fluidmd->fss;
|
||||
|
||||
// timescale not supported yet
|
||||
// clmd->sim_parms->timescale= timescale;
|
||||
|
||||
// support reversing of baked fluid frames here
|
||||
if((fss->flag & OB_FLUIDSIM_REVERSE) && (fss->lastgoodframe >= 0))
|
||||
{
|
||||
framenr = fss->lastgoodframe - framenr + 1;
|
||||
CLAMP(framenr, 1, fss->lastgoodframe);
|
||||
}
|
||||
|
||||
/* try to read from cache */
|
||||
if(((fss->lastgoodframe >= framenr) || (fss->lastgoodframe < 0)) && (result = fluidsim_read_cache(ob, dm, fluidmd, framenr, useRenderParams)))
|
||||
{
|
||||
// fss->lastgoodframe = framenr; // set also in src/fluidsim.c
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
// display last known good frame
|
||||
if(fss->lastgoodframe >= 0)
|
||||
{
|
||||
if((result = fluidsim_read_cache(ob, dm, fluidmd, fss->lastgoodframe, useRenderParams)))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
// it was supposed to be a valid frame but it isn't!
|
||||
fss->lastgoodframe = framenr - 1;
|
||||
|
||||
|
||||
// this could be likely the case when you load an old fluidsim
|
||||
if((result = fluidsim_read_cache(ob, dm, fluidmd, fss->lastgoodframe, useRenderParams)))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
result = CDDM_copy(dm);
|
||||
|
||||
if(result)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return dm;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef DISABLE_ELBEEM
|
||||
/* read .bobj.gz file into a fluidsimDerivedMesh struct */
|
||||
static DerivedMesh *fluidsim_read_obj(char *filename)
|
||||
{
|
||||
int wri,i,j;
|
||||
float wrf;
|
||||
int gotBytes;
|
||||
gzFile gzf;
|
||||
int numverts = 0, numfaces = 0;
|
||||
DerivedMesh *dm = NULL;
|
||||
MFace *mface;
|
||||
MVert *mvert;
|
||||
short *normals;
|
||||
|
||||
// ------------------------------------------------
|
||||
// get numverts + numfaces first
|
||||
// ------------------------------------------------
|
||||
gzf = gzopen(filename, "rb");
|
||||
if (!gzf)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// read numverts
|
||||
gotBytes = gzread(gzf, &wri, sizeof(wri));
|
||||
numverts = wri;
|
||||
|
||||
// skip verts
|
||||
for(i=0; i<numverts*3; i++)
|
||||
{
|
||||
gotBytes = gzread(gzf, &wrf, sizeof( wrf ));
|
||||
}
|
||||
|
||||
// read number of normals
|
||||
gotBytes = gzread(gzf, &wri, sizeof(wri));
|
||||
|
||||
// skip normals
|
||||
for(i=0; i<numverts*3; i++)
|
||||
{
|
||||
gotBytes = gzread(gzf, &wrf, sizeof( wrf ));
|
||||
}
|
||||
|
||||
/* get no. of triangles */
|
||||
gotBytes = gzread(gzf, &wri, sizeof(wri));
|
||||
numfaces = wri;
|
||||
|
||||
gzclose( gzf );
|
||||
// ------------------------------------------------
|
||||
|
||||
if(!numfaces || !numverts)
|
||||
return NULL;
|
||||
|
||||
gzf = gzopen(filename, "rb");
|
||||
if (!gzf)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dm = CDDM_new(numverts, 0, numfaces);
|
||||
|
||||
if(!dm)
|
||||
{
|
||||
gzclose( gzf );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// read numverts
|
||||
gotBytes = gzread(gzf, &wri, sizeof(wri));
|
||||
|
||||
// read vertex position from file
|
||||
mvert = CDDM_get_verts(dm);
|
||||
for(i=0; i<numverts; i++)
|
||||
{
|
||||
MVert *mv = &mvert[i];
|
||||
|
||||
for(j=0; j<3; j++)
|
||||
{
|
||||
gotBytes = gzread(gzf, &wrf, sizeof( wrf ));
|
||||
mv->co[j] = wrf;
|
||||
}
|
||||
}
|
||||
|
||||
// should be the same as numverts
|
||||
gotBytes = gzread(gzf, &wri, sizeof(wri));
|
||||
if(wri != numverts)
|
||||
{
|
||||
if(dm)
|
||||
dm->release(dm);
|
||||
gzclose( gzf );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
normals = MEM_callocN(sizeof(short) * numverts * 3, "fluid_tmp_normals" );
|
||||
if(!normals)
|
||||
{
|
||||
if(dm)
|
||||
dm->release(dm);
|
||||
gzclose( gzf );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// read normals from file (but don't save them yet)
|
||||
for(i=0; i<numverts*3; i++)
|
||||
{
|
||||
gotBytes = gzread(gzf, &wrf, sizeof( wrf ));
|
||||
normals[i] = (short)(wrf*32767.0f);
|
||||
}
|
||||
|
||||
/* read no. of triangles */
|
||||
gotBytes = gzread(gzf, &wri, sizeof(wri));
|
||||
|
||||
if(wri!=numfaces)
|
||||
printf("Fluidsim: error in reading data from file.\n");
|
||||
|
||||
// read triangles from file
|
||||
mface = CDDM_get_faces(dm);
|
||||
for(i=0; i<numfaces; i++)
|
||||
{
|
||||
int face[4];
|
||||
MFace *mf = &mface[i];
|
||||
|
||||
gotBytes = gzread(gzf, &(face[0]), sizeof( face[0] ));
|
||||
gotBytes = gzread(gzf, &(face[1]), sizeof( face[1] ));
|
||||
gotBytes = gzread(gzf, &(face[2]), sizeof( face[2] ));
|
||||
face[3] = 0;
|
||||
|
||||
// check if 3rd vertex has index 0 (not allowed in blender)
|
||||
if(face[2])
|
||||
{
|
||||
mf->v1 = face[0];
|
||||
mf->v2 = face[1];
|
||||
mf->v3 = face[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
mf->v1 = face[1];
|
||||
mf->v2 = face[2];
|
||||
mf->v3 = face[0];
|
||||
}
|
||||
mf->v4 = face[3];
|
||||
|
||||
test_index_face(mf, NULL, 0, 3);
|
||||
}
|
||||
|
||||
gzclose( gzf );
|
||||
|
||||
CDDM_calc_edges(dm);
|
||||
|
||||
CDDM_apply_vert_normals(dm, (short (*)[3])normals);
|
||||
MEM_freeN(normals);
|
||||
|
||||
// CDDM_calc_normals(result);
|
||||
|
||||
return dm;
|
||||
}
|
||||
|
||||
DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm, FluidsimModifierData *fluidmd, int framenr, int useRenderParams)
|
||||
{
|
||||
int displaymode = 0;
|
||||
int curFrame = framenr - 1 /*G.scene->r.sfra*/; /* start with 0 at start frame */
|
||||
char targetDir[FILE_MAXFILE+FILE_MAXDIR], targetFile[FILE_MAXFILE+FILE_MAXDIR];
|
||||
FluidsimSettings *fss = fluidmd->fss;
|
||||
DerivedMesh *dm = NULL;
|
||||
MFace *mface;
|
||||
int numfaces;
|
||||
int mat_nr, flag, i;
|
||||
|
||||
if(!useRenderParams) {
|
||||
displaymode = fss->guiDisplayMode;
|
||||
} else {
|
||||
displaymode = fss->renderDisplayMode;
|
||||
}
|
||||
|
||||
strncpy(targetDir, fss->surfdataPath, FILE_MAXDIR);
|
||||
|
||||
// use preview or final mesh?
|
||||
if(displaymode==1)
|
||||
{
|
||||
// just display original object
|
||||
return NULL;
|
||||
}
|
||||
else if(displaymode==2)
|
||||
{
|
||||
strcat(targetDir,"fluidsurface_preview_####");
|
||||
}
|
||||
else
|
||||
{ // 3
|
||||
strcat(targetDir,"fluidsurface_final_####");
|
||||
}
|
||||
|
||||
BLI_convertstringcode(targetDir, G.sce);
|
||||
BLI_convertstringframe(targetDir, curFrame); // fixed #frame-no
|
||||
|
||||
strcpy(targetFile,targetDir);
|
||||
strcat(targetFile, ".bobj.gz");
|
||||
|
||||
dm = fluidsim_read_obj(targetFile);
|
||||
|
||||
if(!dm)
|
||||
{
|
||||
// switch, abort background rendering when fluidsim mesh is missing
|
||||
const char *strEnvName2 = "BLENDER_ELBEEMBOBJABORT"; // from blendercall.cpp
|
||||
|
||||
if(G.background==1) {
|
||||
if(getenv(strEnvName2)) {
|
||||
int elevel = atoi(getenv(strEnvName2));
|
||||
if(elevel>0) {
|
||||
printf("Env. var %s set, fluid sim mesh '%s' not found, aborting render...\n",strEnvName2, targetFile);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// display org. object upon failure which is in dm
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// assign material + flags to new dm
|
||||
mface = orgdm->getFaceArray(orgdm);
|
||||
mat_nr = mface[0].mat_nr;
|
||||
flag = mface[0].flag;
|
||||
|
||||
mface = dm->getFaceArray(dm);
|
||||
numfaces = dm->getNumFaces(dm);
|
||||
for(i=0; i<numfaces; i++)
|
||||
{
|
||||
mface[i].mat_nr = mat_nr;
|
||||
mface[i].flag = flag;
|
||||
}
|
||||
|
||||
// load vertex velocities, if they exist...
|
||||
// TODO? use generate flag as loading flag as well?
|
||||
// warning, needs original .bobj.gz mesh loading filename
|
||||
/*
|
||||
if(displaymode==3)
|
||||
{
|
||||
readVelgz(targetFile, srcob);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no data for preview, only clear...
|
||||
int i,j;
|
||||
for(i=0; i<mesh->totvert;i++) { for(j=0; j<3; j++) { srcob->fluidsimSettings->meshSurfNormals[i].co[j] = 0.; }}
|
||||
}*/
|
||||
|
||||
return dm;
|
||||
}
|
||||
|
||||
void fluid_get_bb(MVert *mvert, int totvert, float obmat[][4],
|
||||
/*RET*/ float start[3], /*RET*/ float size[3] )
|
||||
{
|
||||
float bbsx=0.0, bbsy=0.0, bbsz=0.0;
|
||||
float bbex=1.0, bbey=1.0, bbez=1.0;
|
||||
int i;
|
||||
float vec[3];
|
||||
|
||||
VECCOPY(vec, mvert[0].co);
|
||||
Mat4MulVecfl(obmat, vec);
|
||||
bbsx = vec[0]; bbsy = vec[1]; bbsz = vec[2];
|
||||
bbex = vec[0]; bbey = vec[1]; bbez = vec[2];
|
||||
|
||||
for(i = 1; i < totvert; i++) {
|
||||
VECCOPY(vec, mvert[i].co);
|
||||
Mat4MulVecfl(obmat, vec);
|
||||
|
||||
if(vec[0] < bbsx){ bbsx= vec[0]; }
|
||||
if(vec[1] < bbsy){ bbsy= vec[1]; }
|
||||
if(vec[2] < bbsz){ bbsz= vec[2]; }
|
||||
if(vec[0] > bbex){ bbex= vec[0]; }
|
||||
if(vec[1] > bbey){ bbey= vec[1]; }
|
||||
if(vec[2] > bbez){ bbez= vec[2]; }
|
||||
}
|
||||
|
||||
// return values...
|
||||
if(start) {
|
||||
start[0] = bbsx;
|
||||
start[1] = bbsy;
|
||||
start[2] = bbsz;
|
||||
}
|
||||
if(size) {
|
||||
size[0] = bbex-bbsx;
|
||||
size[1] = bbey-bbsy;
|
||||
size[2] = bbez-bbsz;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// old interface
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// file handling
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
void initElbeemMesh(struct Object *ob,
|
||||
int *numVertices, float **vertices,
|
||||
int *numTriangles, int **triangles,
|
||||
int useGlobalCoords, int modifierIndex)
|
||||
{
|
||||
DerivedMesh *dm = NULL;
|
||||
MVert *mvert;
|
||||
MFace *mface;
|
||||
int countTris=0, i, totvert, totface;
|
||||
float *verts;
|
||||
int *tris;
|
||||
|
||||
dm = mesh_create_derived_index_render(ob, CD_MASK_BAREMESH, modifierIndex);
|
||||
//dm = mesh_create_derived_no_deform(ob,NULL);
|
||||
|
||||
mvert = dm->getVertArray(dm);
|
||||
mface = dm->getFaceArray(dm);
|
||||
totvert = dm->getNumVerts(dm);
|
||||
totface = dm->getNumFaces(dm);
|
||||
|
||||
*numVertices = totvert;
|
||||
verts = MEM_callocN( totvert*3*sizeof(float), "elbeemmesh_vertices");
|
||||
for(i=0; i<totvert; i++) {
|
||||
VECCOPY( &verts[i*3], mvert[i].co);
|
||||
if(useGlobalCoords) { Mat4MulVecfl(ob->obmat, &verts[i*3]); }
|
||||
}
|
||||
*vertices = verts;
|
||||
|
||||
for(i=0; i<totface; i++) {
|
||||
countTris++;
|
||||
if(mface[i].v4) { countTris++; }
|
||||
}
|
||||
*numTriangles = countTris;
|
||||
tris = MEM_callocN( countTris*3*sizeof(int), "elbeemmesh_triangles");
|
||||
countTris = 0;
|
||||
for(i=0; i<totface; i++) {
|
||||
int face[4];
|
||||
face[0] = mface[i].v1;
|
||||
face[1] = mface[i].v2;
|
||||
face[2] = mface[i].v3;
|
||||
face[3] = mface[i].v4;
|
||||
|
||||
tris[countTris*3+0] = face[0];
|
||||
tris[countTris*3+1] = face[1];
|
||||
tris[countTris*3+2] = face[2];
|
||||
countTris++;
|
||||
if(face[3]) {
|
||||
tris[countTris*3+0] = face[0];
|
||||
tris[countTris*3+1] = face[2];
|
||||
tris[countTris*3+2] = face[3];
|
||||
countTris++;
|
||||
}
|
||||
}
|
||||
*triangles = tris;
|
||||
|
||||
dm->release(dm);
|
||||
}
|
||||
|
||||
/* read zipped fluidsim velocities into the co's of the fluidsimsettings normals struct */
|
||||
void readVelgz(char *filename, Object *srcob)
|
||||
{
|
||||
int wri, i, j;
|
||||
float wrf;
|
||||
gzFile gzf;
|
||||
MVert *vverts = srcob->fluidsimSettings->meshSurfNormals;
|
||||
int len = strlen(filename);
|
||||
Mesh *mesh = srcob->data;
|
||||
// mesh and vverts have to be valid from loading...
|
||||
|
||||
// clean up in any case
|
||||
for(i=0; i<mesh->totvert;i++)
|
||||
{
|
||||
for(j=0; j<3; j++)
|
||||
{
|
||||
vverts[i].co[j] = 0.;
|
||||
}
|
||||
}
|
||||
if(srcob->fluidsimSettings->domainNovecgen>0) return;
|
||||
|
||||
if(len<7)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// .bobj.gz , correct filename
|
||||
// 87654321
|
||||
filename[len-6] = 'v';
|
||||
filename[len-5] = 'e';
|
||||
filename[len-4] = 'l';
|
||||
|
||||
gzf = gzopen(filename, "rb");
|
||||
if (!gzf)
|
||||
return;
|
||||
|
||||
gzread(gzf, &wri, sizeof( wri ));
|
||||
if(wri != mesh->totvert)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for(i=0; i<mesh->totvert;i++)
|
||||
{
|
||||
for(j=0; j<3; j++)
|
||||
{
|
||||
gzread(gzf, &wrf, sizeof( wrf ));
|
||||
vverts[i].co[j] = wrf;
|
||||
}
|
||||
}
|
||||
|
||||
gzclose(gzf);
|
||||
}
|
||||
|
||||
|
||||
#endif // DISABLE_ELBEEM
|
||||
|
||||
248
source/blender/blenkernel/intern/simple_deform.c
Normal file
248
source/blender/blenkernel/intern/simple_deform.c
Normal file
@@ -0,0 +1,248 @@
|
||||
/**
|
||||
* deform_simple.c
|
||||
*
|
||||
* ***** BEGIN GPL 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.
|
||||
*
|
||||
* 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) Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): André Pinto
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
||||
#include "BKE_simple_deform.h"
|
||||
#include "BKE_DerivedMesh.h"
|
||||
#include "BKE_deform.h"
|
||||
#include "BKE_utildefines.h"
|
||||
#include "BLI_arithb.h"
|
||||
#include "BKE_shrinkwrap.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
|
||||
//Clamps/Limits the given coordinate to: limits[0] <= co[axis] <= limits[1]
|
||||
//The ammount of clamp is saved on dcut
|
||||
static void axis_limit(int axis, const float limits[2], float co[3], float dcut[3])
|
||||
{
|
||||
float val = co[axis];
|
||||
if(limits[0] > val) val = limits[0];
|
||||
if(limits[1] < val) val = limits[1];
|
||||
|
||||
dcut[axis] = co[axis] - val;
|
||||
co[axis] = val;
|
||||
}
|
||||
|
||||
static void simpleDeform_taper(const float factor, const float dcut[3], float *co)
|
||||
{
|
||||
float x = co[0], y = co[1], z = co[2];
|
||||
float scale = z*factor;
|
||||
|
||||
co[0] = x + x*scale;
|
||||
co[1] = y + y*scale;
|
||||
co[2] = z;
|
||||
|
||||
if(dcut)
|
||||
{
|
||||
co[0] += dcut[0];
|
||||
co[1] += dcut[1];
|
||||
co[2] += dcut[2];
|
||||
}
|
||||
}
|
||||
|
||||
static void simpleDeform_stretch(const float factor, const float dcut[3], float *co)
|
||||
{
|
||||
float x = co[0], y = co[1], z = co[2];
|
||||
float scale;
|
||||
|
||||
scale = (z*z*factor-factor + 1.0);
|
||||
|
||||
co[0] = x*scale;
|
||||
co[1] = y*scale;
|
||||
co[2] = z*(1.0+factor);
|
||||
|
||||
|
||||
if(dcut)
|
||||
{
|
||||
co[0] += dcut[0];
|
||||
co[1] += dcut[1];
|
||||
co[2] += dcut[2];
|
||||
}
|
||||
}
|
||||
|
||||
static void simpleDeform_twist(const float factor, const float *dcut, float *co)
|
||||
{
|
||||
float x = co[0], y = co[1], z = co[2];
|
||||
float theta, sint, cost;
|
||||
|
||||
theta = z*factor;
|
||||
sint = sin(theta);
|
||||
cost = cos(theta);
|
||||
|
||||
co[0] = x*cost - y*sint;
|
||||
co[1] = x*sint + y*cost;
|
||||
co[2] = z;
|
||||
|
||||
if(dcut)
|
||||
{
|
||||
co[0] += dcut[0];
|
||||
co[1] += dcut[1];
|
||||
co[2] += dcut[2];
|
||||
}
|
||||
}
|
||||
|
||||
static void simpleDeform_bend(const float factor, const float dcut[3], float *co)
|
||||
{
|
||||
float x = co[0], y = co[1], z = co[2];
|
||||
float theta, sint, cost;
|
||||
|
||||
theta = x*factor;
|
||||
sint = sin(theta);
|
||||
cost = cos(theta);
|
||||
|
||||
if(fabs(factor) > 1e-7f)
|
||||
{
|
||||
co[0] = -(y-1.0f/factor)*sint;
|
||||
co[1] = (y-1.0f/factor)*cost + 1.0f/factor;
|
||||
co[2] = z;
|
||||
}
|
||||
|
||||
|
||||
if(dcut)
|
||||
{
|
||||
co[0] += cost*dcut[0];
|
||||
co[1] += sint*dcut[0];
|
||||
co[2] += dcut[2];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* simple deform modifier */
|
||||
void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object *ob, struct DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
|
||||
{
|
||||
static const float lock_axis[2] = {0.0f, 0.0f};
|
||||
|
||||
int i;
|
||||
int limit_axis = 0;
|
||||
float smd_limit[2], smd_factor;
|
||||
SpaceTransform *transf = NULL, tmp_transf;
|
||||
void (*simpleDeform_callback)(const float factor, const float dcut[3], float *co) = NULL; //Mode callback
|
||||
int vgroup = get_named_vertexgroup_num(ob, smd->vgroup_name);
|
||||
MDeformVert *dvert = NULL;
|
||||
|
||||
//Safe-check
|
||||
if(smd->origin == ob) smd->origin = NULL; //No self references
|
||||
|
||||
if(smd->limit[0] < 0.0) smd->limit[0] = 0.0f;
|
||||
if(smd->limit[0] > 1.0) smd->limit[0] = 1.0f;
|
||||
|
||||
smd->limit[0] = MIN2(smd->limit[0], smd->limit[1]); //Upper limit >= than lower limit
|
||||
|
||||
//Calculate matrixs do convert between coordinate spaces
|
||||
if(smd->origin)
|
||||
{
|
||||
transf = &tmp_transf;
|
||||
|
||||
if(smd->originOpts & MOD_SIMPLEDEFORM_ORIGIN_LOCAL)
|
||||
{
|
||||
space_transform_from_matrixs(transf, ob->obmat, smd->origin->obmat);
|
||||
}
|
||||
else
|
||||
{
|
||||
Mat4CpyMat4(transf->local2target, smd->origin->obmat);
|
||||
Mat4Invert(transf->target2local, transf->local2target);
|
||||
}
|
||||
}
|
||||
|
||||
//Setup vars
|
||||
limit_axis = (smd->mode == MOD_SIMPLEDEFORM_MODE_BEND) ? 0 : 2; //Bend limits on X.. all other modes limit on Z
|
||||
|
||||
//Update limits if needed
|
||||
{
|
||||
float lower = FLT_MAX;
|
||||
float upper = -FLT_MAX;
|
||||
|
||||
for(i=0; i<numVerts; i++)
|
||||
{
|
||||
float tmp[3];
|
||||
VECCOPY(tmp, vertexCos[i]);
|
||||
|
||||
if(transf) space_transform_apply(transf, tmp);
|
||||
|
||||
lower = MIN2(lower, tmp[limit_axis]);
|
||||
upper = MAX2(upper, tmp[limit_axis]);
|
||||
}
|
||||
|
||||
|
||||
//SMD values are normalized to the BV, calculate the absolut values
|
||||
smd_limit[1] = lower + (upper-lower)*smd->limit[1];
|
||||
smd_limit[0] = lower + (upper-lower)*smd->limit[0];
|
||||
|
||||
smd_factor = smd->factor / MAX2(FLT_EPSILON, smd_limit[1]-smd_limit[0]);
|
||||
}
|
||||
|
||||
|
||||
if(dm)
|
||||
dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
|
||||
|
||||
|
||||
switch(smd->mode)
|
||||
{
|
||||
case MOD_SIMPLEDEFORM_MODE_TWIST: simpleDeform_callback = simpleDeform_twist; break;
|
||||
case MOD_SIMPLEDEFORM_MODE_BEND: simpleDeform_callback = simpleDeform_bend; break;
|
||||
case MOD_SIMPLEDEFORM_MODE_TAPER: simpleDeform_callback = simpleDeform_taper; break;
|
||||
case MOD_SIMPLEDEFORM_MODE_STRETCH: simpleDeform_callback = simpleDeform_stretch; break;
|
||||
default:
|
||||
return; //No simpledeform mode?
|
||||
}
|
||||
|
||||
for(i=0; i<numVerts; i++)
|
||||
{
|
||||
float weight = vertexgroup_get_vertex_weight(dvert, i, vgroup);
|
||||
|
||||
if(weight != 0.0f)
|
||||
{
|
||||
float co[3], dcut[3] = {0.0f, 0.0f, 0.0f};
|
||||
|
||||
if(transf) space_transform_apply(transf, vertexCos[i]);
|
||||
|
||||
VECCOPY(co, vertexCos[i]);
|
||||
|
||||
//Apply axis limits
|
||||
if(smd->mode != MOD_SIMPLEDEFORM_MODE_BEND) //Bend mode shoulnt have any lock axis
|
||||
{
|
||||
if(smd->axis & MOD_SIMPLEDEFORM_LOCK_AXIS_X) axis_limit(0, lock_axis, co, dcut);
|
||||
if(smd->axis & MOD_SIMPLEDEFORM_LOCK_AXIS_Y) axis_limit(1, lock_axis, co, dcut);
|
||||
}
|
||||
axis_limit(limit_axis, smd_limit, co, dcut);
|
||||
|
||||
simpleDeform_callback(smd_factor, dcut, co); //Apply deform
|
||||
VecLerpf(vertexCos[i], vertexCos[i], co, weight); //Use vertex weight has coef of linear interpolation
|
||||
|
||||
if(transf) space_transform_invert(transf, vertexCos[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "GLBlendEquation.h"
|
||||
|
||||
void FRS_glBlendEquation(GLenum mode) {
|
||||
if( glBlendEquation ) {
|
||||
glBlendEquation(mode);
|
||||
} else if ( glBlendEquationEXT ) {
|
||||
glBlendEquationEXT(mode);
|
||||
}
|
||||
}
|
||||
16
source/blender/freestyle/intern/rendering/GLBlendEquation.h
Normal file
16
source/blender/freestyle/intern/rendering/GLBlendEquation.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef GLBLENDEQUATION_H
|
||||
#define GLBLENDEQUATION_H
|
||||
|
||||
#include <GL/glew.h>
|
||||
#ifdef WIN32
|
||||
# include <windows.h>
|
||||
#endif
|
||||
#ifdef __MACH__
|
||||
# include <OpenGL/gl.h>
|
||||
#else
|
||||
# include <GL/gl.h>
|
||||
#endif
|
||||
|
||||
void FRS_glBlendEquation(GLenum mode);
|
||||
|
||||
#endif // GLBLENDEQUATION_H
|
||||
117
source/blender/include/BIF_keyframing.h
Normal file
117
source/blender/include/BIF_keyframing.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* $Id: BIF_keyframing.h 14444 2008-04-16 22:40:48Z aligorith $
|
||||
*
|
||||
* ***** BEGIN GPL 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.
|
||||
*
|
||||
* 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) 2008, Blender Foundation
|
||||
* This is a new part of Blender (with some old code)
|
||||
*
|
||||
* Contributor(s): Joshua Leung
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef BIF_KEYFRAMING_H
|
||||
#define BIF_KEYFRAMING_H
|
||||
|
||||
struct ListBase;
|
||||
struct ID;
|
||||
|
||||
struct IpoCurve;
|
||||
struct BezTriple;
|
||||
|
||||
/* ************ Keyframing Management **************** */
|
||||
|
||||
/* Lesser Keyframing API call:
|
||||
* Use this when validation of necessary animation data isn't necessary as it already
|
||||
* exists, and there is a beztriple that can be directly copied into the array.
|
||||
*/
|
||||
int insert_bezt_icu(struct IpoCurve *icu, struct BezTriple *bezt);
|
||||
|
||||
/* Main Keyframing API call:
|
||||
* Use this when validation of necessary animation data isn't necessary as it
|
||||
* already exists. It will insert a keyframe using the current value being keyframed.
|
||||
*/
|
||||
void insert_vert_icu(struct IpoCurve *icu, float x, float y, short flag);
|
||||
|
||||
|
||||
/* flags for use in insert_key(), and insert_vert_icu() */
|
||||
enum {
|
||||
INSERTKEY_NEEDED = (1<<0), /* only insert keyframes where they're needed */
|
||||
INSERTKEY_MATRIX = (1<<1), /* insert 'visual' keyframes where possible/needed */
|
||||
INSERTKEY_FAST = (1<<2), /* don't recalculate handles,etc. after adding key */
|
||||
INSERTKEY_FASTR = (1<<3), /* don't realloc mem (or increase count, as array has already been set out) */
|
||||
INSERTKEY_REPLACE = (1<<4), /* only replace an existing keyframe (this overrides INSERTKEY_NEEDED) */
|
||||
} eInsertKeyFlags;
|
||||
|
||||
/* -------- */
|
||||
|
||||
/* Main Keyframing API calls:
|
||||
* Use this to create any necessary animation data,, and then insert a keyframe
|
||||
* using the current value being keyframed, in the relevant place. Returns success.
|
||||
*/
|
||||
// TODO: adapt this for new data-api -> this blocktype, etc. stuff is evil!
|
||||
short insertkey(struct ID *id, int blocktype, char *actname, char *constname, int adrcode, short flag);
|
||||
|
||||
/* Main Keyframing API call:
|
||||
* Use this to delete keyframe on current frame for relevant channel. Will perform checks just in case.
|
||||
*/
|
||||
short deletekey(struct ID *id, int blocktype, char *actname, char *constname, int adrcode, short flag);
|
||||
|
||||
|
||||
/* Main Keyframe Management calls:
|
||||
* These handle keyframes management from various spaces. They will handle the menus
|
||||
* required for each space.
|
||||
*/
|
||||
void common_insertkey(void);
|
||||
void common_deletekey(void);
|
||||
|
||||
/* ************ Auto-Keyframing ********************** */
|
||||
/* Notes:
|
||||
* - All the defines for this (User-Pref settings and Per-Scene settings)
|
||||
* are defined in DNA_userdef_types.h
|
||||
* - Scene settings take presidence over those for userprefs, with old files
|
||||
* inheriting userpref settings for the scene settings
|
||||
* - "On/Off + Mode" are stored per Scene, but "settings" are currently stored
|
||||
* as userprefs
|
||||
*/
|
||||
|
||||
/* Auto-Keying macros for use by various tools */
|
||||
/* check if auto-keyframing is enabled (per scene takes presidence) */
|
||||
#define IS_AUTOKEY_ON ((G.scene) ? (G.scene->autokey_mode & AUTOKEY_ON) : (U.autokey_mode & AUTOKEY_ON))
|
||||
/* check the mode for auto-keyframing (per scene takes presidence) */
|
||||
#define IS_AUTOKEY_MODE(mode) ((G.scene) ? (G.scene->autokey_mode == AUTOKEY_MODE_##mode) : (U.autokey_mode == AUTOKEY_MODE_##mode))
|
||||
/* check if a flag is set for auto-keyframing (as userprefs only!) */
|
||||
#define IS_AUTOKEY_FLAG(flag) (U.autokey_flag & AUTOKEY_FLAG_##flag)
|
||||
|
||||
/* ************ Keyframe Checking ******************** */
|
||||
|
||||
/* Checks whether a keyframe exists for the given ID-block one the given frame */
|
||||
short id_cfra_has_keyframe(struct ID *id, short filter);
|
||||
|
||||
/* filter flags fr id_cfra_has_keyframe */
|
||||
enum {
|
||||
/* general */
|
||||
ANIMFILTER_ALL = 0, /* include all available animation data */
|
||||
ANIMFILTER_LOCAL = (1<<0), /* only include locally available anim data */
|
||||
|
||||
/* object specific */
|
||||
ANIMFILTER_MAT = (1<<1), /* include material keyframes too */
|
||||
ANIMFILTER_SKEY = (1<<2), /* shape keys (for geometry) */
|
||||
} eAnimFilterFlags;
|
||||
|
||||
#endif /* BIF_KEYFRAMING_H */
|
||||
1870
source/blender/src/keyframing.c
Normal file
1870
source/blender/src/keyframing.c
Normal file
@@ -0,0 +1,1870 @@
|
||||
/**
|
||||
* $Id: keyframing.c 14881 2008-05-18 10:41:42Z aligorith $
|
||||
*
|
||||
* ***** BEGIN GPL 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.
|
||||
*
|
||||
* 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) 2008, Blender Foundation
|
||||
* This is a new part of Blender (with some old code)
|
||||
*
|
||||
* Contributor(s): Joshua Leung
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_arithb.h"
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_dynstr.h"
|
||||
|
||||
#include "DNA_listBase.h"
|
||||
#include "DNA_ID.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_ipo_types.h"
|
||||
#include "DNA_lamp_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_space_types.h"
|
||||
#include "DNA_texture_types.h"
|
||||
#include "DNA_userdef_types.h"
|
||||
#include "DNA_vec_types.h"
|
||||
#include "DNA_view3d_types.h"
|
||||
#include "DNA_world_types.h"
|
||||
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_utildefines.h"
|
||||
#include "BKE_blender.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_constraint.h"
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_depsgraph.h"
|
||||
#include "BKE_ipo.h"
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "BIF_keyframing.h"
|
||||
#include "BIF_butspace.h"
|
||||
#include "BIF_editaction.h"
|
||||
#include "BIF_editkey.h"
|
||||
#include "BIF_interface.h"
|
||||
#include "BIF_mywindow.h"
|
||||
#include "BIF_poseobject.h"
|
||||
#include "BIF_screen.h"
|
||||
#include "BIF_space.h"
|
||||
#include "BIF_toolbox.h"
|
||||
#include "BIF_toets.h"
|
||||
|
||||
#include "BSE_editipo.h"
|
||||
#include "BSE_node.h"
|
||||
#include "BSE_time.h"
|
||||
#include "BSE_view.h"
|
||||
|
||||
#include "blendef.h"
|
||||
|
||||
#include "PIL_time.h" /* sleep */
|
||||
#include "mydevice.h"
|
||||
|
||||
/* ************************************************** */
|
||||
/* LOCAL TYPES AND DEFINES */
|
||||
|
||||
/* -------------- Keying Sets ------------------- */
|
||||
|
||||
/* keying set - a set of channels that will be keyframed together */
|
||||
// TODO: move this to a header to allow custom sets someday?
|
||||
typedef struct bKeyingSet {
|
||||
/* callback func to consider if keyingset should be included
|
||||
* (by default, if this is undefined, item will be shown)
|
||||
*/
|
||||
short (*include_cb)(struct bKeyingSet *, const char *);
|
||||
|
||||
char name[48]; /* name of keyingset */
|
||||
int blocktype; /* blocktype that all channels belong to */ // in future, this may be eliminated
|
||||
short flag; /* flags to use when setting keyframes */
|
||||
|
||||
short chan_num; /* number of channels to insert keyframe in */
|
||||
short adrcodes[32]; /* adrcodes for channels to insert keys for (ideally would be variable-len, but limit of 32 will suffice) */
|
||||
} bKeyingSet;
|
||||
|
||||
/* keying set context - an array of keying sets and the number of them */
|
||||
typedef struct bKeyingContext {
|
||||
bKeyingSet *keyingsets; /* array containing the keyingsets of interest */
|
||||
bKeyingSet *lastused; /* item that was chosen last time*/
|
||||
int tot; /* number of keyingsets in */
|
||||
} bKeyingContext;
|
||||
|
||||
|
||||
/* ----------- Common KeyData Sources ------------ */
|
||||
|
||||
/* temporary struct to gather data combos to keyframe */
|
||||
typedef struct bCommonKeySrc {
|
||||
struct bCommonKeySrc *next, *prev;
|
||||
|
||||
/* general data/destination-source settings */
|
||||
ID *id; /* id-block this comes from */
|
||||
char *actname; /* name of action channel */
|
||||
char *constname; /* name of constraint channel */
|
||||
|
||||
/* general destination source settings */
|
||||
Ipo *ipo; /* ipo-block that id-block has (optional) */
|
||||
bAction *act; /* action-block that id-block has (optional) */
|
||||
|
||||
/* pose-level settings */
|
||||
bPoseChannel *pchan; /* pose channel */
|
||||
|
||||
/* buttons-window settings */
|
||||
int map; /* offset to apply to certain adrcodes */
|
||||
} bCommonKeySrc;
|
||||
|
||||
/* ************************************************** */
|
||||
/* KEYFRAME INSERTION */
|
||||
|
||||
/* -------------- BezTriple Insertion -------------------- */
|
||||
|
||||
/* threshold for inserting keyframes - threshold here should be good enough for now, but should become userpref */
|
||||
#define BEZT_INSERT_THRESH 0.00001
|
||||
|
||||
/* Binary search algorithm for finding where to insert BezTriple. (for use by insert_bezt_icu)
|
||||
* Returns the index to insert at (data already at that index will be offset if replace is 0)
|
||||
*/
|
||||
static int binarysearch_bezt_index (BezTriple array[], BezTriple *item, int arraylen, short *replace)
|
||||
{
|
||||
int start=0, end=arraylen;
|
||||
int loopbreaker= 0, maxloop= arraylen * 2;
|
||||
const float frame= (item)? item->vec[1][0] : 0.0f;
|
||||
|
||||
/* initialise replace-flag first */
|
||||
*replace= 0;
|
||||
|
||||
/* sneaky optimisations (don't go through searching process if...):
|
||||
* - keyframe to be added is to be added out of current bounds
|
||||
* - keyframe to be added would replace one of the existing ones on bounds
|
||||
*/
|
||||
if ((arraylen <= 0) || ELEM(NULL, array, item)) {
|
||||
printf("Warning: binarysearch_bezt_index encountered invalid array \n");
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
/* check whether to add before/after/on */
|
||||
float framenum;
|
||||
|
||||
/* 'First' Keyframe (when only one keyframe, this case is used) */
|
||||
framenum= array[0].vec[1][0];
|
||||
if (IS_EQT(frame, framenum, BEZT_INSERT_THRESH)) {
|
||||
*replace = 1;
|
||||
return 0;
|
||||
}
|
||||
else if (frame < framenum)
|
||||
return 0;
|
||||
|
||||
/* 'Last' Keyframe */
|
||||
framenum= array[(arraylen-1)].vec[1][0];
|
||||
if (IS_EQT(frame, framenum, BEZT_INSERT_THRESH)) {
|
||||
*replace= 1;
|
||||
return (arraylen - 1);
|
||||
}
|
||||
else if (frame > framenum)
|
||||
return arraylen;
|
||||
}
|
||||
|
||||
|
||||
/* most of the time, this loop is just to find where to put it
|
||||
* 'loopbreaker' is just here to prevent infinite loops
|
||||
*/
|
||||
for (loopbreaker=0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
|
||||
/* compute and get midpoint */
|
||||
int mid = (start + end) / 2;
|
||||
float midfra= array[mid].vec[1][0];
|
||||
|
||||
/* check if exactly equal to midpoint */
|
||||
if (IS_EQT(frame, midfra, BEZT_INSERT_THRESH)) {
|
||||
*replace = 1;
|
||||
return mid;
|
||||
}
|
||||
|
||||
/* repeat in upper/lower half */
|
||||
if (frame > midfra)
|
||||
start= mid + 1;
|
||||
else if (frame < midfra)
|
||||
end= mid - 1;
|
||||
}
|
||||
|
||||
/* print error if loop-limit exceeded */
|
||||
if (loopbreaker == (maxloop-1)) {
|
||||
printf("Error: binarysearch_bezt_index was taking too long \n");
|
||||
|
||||
// include debug info
|
||||
printf("\tround = %d: start = %d, end = %d, arraylen = %d \n", loopbreaker, start, end, arraylen);
|
||||
}
|
||||
|
||||
/* not found, so return where to place it */
|
||||
return start;
|
||||
}
|
||||
|
||||
/* This function adds a given BezTriple to an IPO-Curve. It will allocate
|
||||
* memory for the array if needed, and will insert the BezTriple into a
|
||||
* suitable place in chronological order.
|
||||
*
|
||||
* NOTE: any recalculate of the IPO-Curve that needs to be done will need to
|
||||
* be done by the caller.
|
||||
*/
|
||||
int insert_bezt_icu (IpoCurve *icu, BezTriple *bezt)
|
||||
{
|
||||
BezTriple *newb;
|
||||
int i= 0;
|
||||
|
||||
if (icu->bezt == NULL) {
|
||||
icu->bezt= MEM_callocN(sizeof(BezTriple), "beztriple");
|
||||
*(icu->bezt)= *bezt;
|
||||
icu->totvert= 1;
|
||||
}
|
||||
else {
|
||||
short replace = -1;
|
||||
i = binarysearch_bezt_index(icu->bezt, bezt, icu->totvert, &replace);
|
||||
|
||||
if (replace) {
|
||||
/* sanity check: 'i' may in rare cases exceed arraylen */
|
||||
if ((i >= 0) && (i < icu->totvert))
|
||||
*(icu->bezt + i) = *bezt;
|
||||
}
|
||||
else {
|
||||
/* add new */
|
||||
newb= MEM_callocN((icu->totvert+1)*sizeof(BezTriple), "beztriple");
|
||||
|
||||
/* add the beztriples that should occur before the beztriple to be pasted (originally in ei->icu) */
|
||||
if (i > 0)
|
||||
memcpy(newb, icu->bezt, i*sizeof(BezTriple));
|
||||
|
||||
/* add beztriple to paste at index i */
|
||||
*(newb + i)= *bezt;
|
||||
|
||||
/* add the beztriples that occur after the beztriple to be pasted (originally in icu) */
|
||||
if (i < icu->totvert)
|
||||
memcpy(newb+i+1, icu->bezt+i, (icu->totvert-i)*sizeof(BezTriple));
|
||||
|
||||
/* replace (+ free) old with new */
|
||||
MEM_freeN(icu->bezt);
|
||||
icu->bezt= newb;
|
||||
|
||||
icu->totvert++;
|
||||
}
|
||||
}
|
||||
|
||||
/* we need to return the index, so that some tools which do post-processing can
|
||||
* detect where we added the BezTriple in the array
|
||||
*/
|
||||
return i;
|
||||
}
|
||||
|
||||
/* This function is a wrapper for insert_bezt_icu, and should be used when
|
||||
* adding a new keyframe to a curve, when the keyframe doesn't exist anywhere
|
||||
* else yet.
|
||||
*
|
||||
* 'fast' - is only for the python API where importing BVH's would take an extreamly long time.
|
||||
*/
|
||||
void insert_vert_icu (IpoCurve *icu, float x, float y, short fast)
|
||||
{
|
||||
BezTriple beztr;
|
||||
int a, h1, h2;
|
||||
|
||||
/* set all three points, for nicer start position */
|
||||
memset(&beztr, 0, sizeof(BezTriple));
|
||||
beztr.vec[0][0]= x;
|
||||
beztr.vec[0][1]= y;
|
||||
beztr.vec[1][0]= x;
|
||||
beztr.vec[1][1]= y;
|
||||
beztr.vec[2][0]= x;
|
||||
beztr.vec[2][1]= y;
|
||||
beztr.hide= IPO_BEZ;
|
||||
beztr.f1= beztr.f2= beztr.f3= SELECT;
|
||||
beztr.h1= beztr.h2= HD_AUTO;
|
||||
|
||||
/* add temp beztriple to keyframes */
|
||||
a= insert_bezt_icu(icu, &beztr);
|
||||
if (!fast) calchandles_ipocurve(icu);
|
||||
|
||||
/* set handletype */
|
||||
if (icu->totvert > 2) {
|
||||
BezTriple *bezt;
|
||||
|
||||
h1= h2= HD_AUTO;
|
||||
bezt= (icu->bezt + a);
|
||||
|
||||
if (a > 0) h1= (bezt-1)->h2;
|
||||
if (a < icu->totvert-1) h2= (bezt+1)->h1;
|
||||
|
||||
bezt->h1= h1;
|
||||
bezt->h2= h2;
|
||||
|
||||
if (!fast) calchandles_ipocurve(icu);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------- Get Data ------------------------ */
|
||||
|
||||
/* Get pointer to use to get values from */
|
||||
// FIXME: this should not be possible with Data-API
|
||||
static void *get_context_ipo_poin(ID *id, int blocktype, char *actname, char *constname, IpoCurve *icu, int *vartype)
|
||||
{
|
||||
switch (blocktype) {
|
||||
case ID_PO: /* posechannel */
|
||||
if (GS(id->name)==ID_OB) {
|
||||
Object *ob= (Object *)id;
|
||||
bPoseChannel *pchan= get_pose_channel(ob->pose, actname);
|
||||
|
||||
if (pchan) {
|
||||
*vartype= IPO_FLOAT;
|
||||
return get_pchan_ipo_poin(pchan, icu->adrcode);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ID_CO: /* constraint */
|
||||
if ((GS(id->name)==ID_OB) && (constname && constname[0])) {
|
||||
Object *ob= (Object *)id;
|
||||
bConstraint *con;
|
||||
|
||||
/* assume that we only want the influence (as only used for Constraint Channels) */
|
||||
if ((ob->ipoflag & OB_ACTION_OB) && !strcmp(actname, "Object")) {
|
||||
for (con= ob->constraints.first; con; con= con->next) {
|
||||
if (strcmp(constname, con->name)==0) {
|
||||
*vartype= IPO_FLOAT;
|
||||
return &con->enforce;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ob->pose) {
|
||||
bPoseChannel *pchan= get_pose_channel(ob->pose, actname);
|
||||
|
||||
if (pchan) {
|
||||
for (con= pchan->constraints.first; con; con= con->next) {
|
||||
if (strcmp(constname, con->name)==0) {
|
||||
*vartype= IPO_FLOAT;
|
||||
return &con->enforce;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ID_OB: /* object */
|
||||
/* hack: layer channels for object need to be keyed WITHOUT localview flag...
|
||||
* tsk... tsk... why must we just dump bitflags upon users :/
|
||||
*/
|
||||
if ((GS(id->name)==ID_OB) && (icu->adrcode==OB_LAY)) {
|
||||
Object *ob= (Object *)id;
|
||||
static int layer = 0;
|
||||
|
||||
/* init layer to be the object's layer var, then remove local view from it */
|
||||
layer = ob->lay;
|
||||
layer &= 0xFFFFFF;
|
||||
*vartype= IPO_INT_BIT;
|
||||
|
||||
/* return pointer to this static var
|
||||
* - assumes that this pointer won't be stored for use later, so may not be threadsafe
|
||||
* if multiple keyframe calls are made, but that is unlikely to happen in the near future
|
||||
*/
|
||||
return (void *)(&layer);
|
||||
}
|
||||
/* no break here for other ob channel-types - as they can be done normally */
|
||||
|
||||
default: /* normal data-source */
|
||||
return get_ipo_poin(id, icu, vartype);
|
||||
}
|
||||
|
||||
/* not valid... */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* -------------- 'Smarter' Keyframing Functions -------------------- */
|
||||
/* return codes for new_key_needed */
|
||||
enum {
|
||||
KEYNEEDED_DONTADD = 0,
|
||||
KEYNEEDED_JUSTADD,
|
||||
KEYNEEDED_DELPREV,
|
||||
KEYNEEDED_DELNEXT
|
||||
} eKeyNeededStatus;
|
||||
|
||||
/* This helper function determines whether a new keyframe is needed */
|
||||
/* Cases where keyframes should not be added:
|
||||
* 1. Keyframe to be added bewteen two keyframes with similar values
|
||||
* 2. Keyframe to be added on frame where two keyframes are already situated
|
||||
* 3. Keyframe lies at point that intersects the linear line between two keyframes
|
||||
*/
|
||||
static short new_key_needed (IpoCurve *icu, float cFrame, float nValue)
|
||||
{
|
||||
BezTriple *bezt=NULL, *prev=NULL;
|
||||
int totCount, i;
|
||||
float valA = 0.0f, valB = 0.0f;
|
||||
|
||||
/* safety checking */
|
||||
if (icu == NULL) return KEYNEEDED_JUSTADD;
|
||||
totCount= icu->totvert;
|
||||
if (totCount == 0) return KEYNEEDED_JUSTADD;
|
||||
|
||||
/* loop through checking if any are the same */
|
||||
bezt= icu->bezt;
|
||||
for (i=0; i<totCount; i++) {
|
||||
float prevPosi=0.0f, prevVal=0.0f;
|
||||
float beztPosi=0.0f, beztVal=0.0f;
|
||||
|
||||
/* get current time+value */
|
||||
beztPosi= bezt->vec[1][0];
|
||||
beztVal= bezt->vec[1][1];
|
||||
|
||||
if (prev) {
|
||||
/* there is a keyframe before the one currently being examined */
|
||||
|
||||
/* get previous time+value */
|
||||
prevPosi= prev->vec[1][0];
|
||||
prevVal= prev->vec[1][1];
|
||||
|
||||
/* keyframe to be added at point where there are already two similar points? */
|
||||
if (IS_EQ(prevPosi, cFrame) && IS_EQ(beztPosi, cFrame) && IS_EQ(beztPosi, prevPosi)) {
|
||||
return KEYNEEDED_DONTADD;
|
||||
}
|
||||
|
||||
/* keyframe between prev+current points ? */
|
||||
if ((prevPosi <= cFrame) && (cFrame <= beztPosi)) {
|
||||
/* is the value of keyframe to be added the same as keyframes on either side ? */
|
||||
if (IS_EQ(prevVal, nValue) && IS_EQ(beztVal, nValue) && IS_EQ(prevVal, beztVal)) {
|
||||
return KEYNEEDED_DONTADD;
|
||||
}
|
||||
else {
|
||||
float realVal;
|
||||
|
||||
/* get real value of curve at that point */
|
||||
realVal= eval_icu(icu, cFrame);
|
||||
|
||||
/* compare whether it's the same as proposed */
|
||||
if (IS_EQ(realVal, nValue))
|
||||
return KEYNEEDED_DONTADD;
|
||||
else
|
||||
return KEYNEEDED_JUSTADD;
|
||||
}
|
||||
}
|
||||
|
||||
/* new keyframe before prev beztriple? */
|
||||
if (cFrame < prevPosi) {
|
||||
/* A new keyframe will be added. However, whether the previous beztriple
|
||||
* stays around or not depends on whether the values of previous/current
|
||||
* beztriples and new keyframe are the same.
|
||||
*/
|
||||
if (IS_EQ(prevVal, nValue) && IS_EQ(beztVal, nValue) && IS_EQ(prevVal, beztVal))
|
||||
return KEYNEEDED_DELNEXT;
|
||||
else
|
||||
return KEYNEEDED_JUSTADD;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* just add a keyframe if there's only one keyframe
|
||||
* and the new one occurs before the exisiting one does.
|
||||
*/
|
||||
if ((cFrame < beztPosi) && (totCount==1))
|
||||
return KEYNEEDED_JUSTADD;
|
||||
}
|
||||
|
||||
/* continue. frame to do not yet passed (or other conditions not met) */
|
||||
if (i < (totCount-1)) {
|
||||
prev= bezt;
|
||||
bezt++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* Frame in which to add a new-keyframe occurs after all other keys
|
||||
* -> If there are at least two existing keyframes, then if the values of the
|
||||
* last two keyframes and the new-keyframe match, the last existing keyframe
|
||||
* gets deleted as it is no longer required.
|
||||
* -> Otherwise, a keyframe is just added. 1.0 is added so that fake-2nd-to-last
|
||||
* keyframe is not equal to last keyframe.
|
||||
*/
|
||||
bezt= (icu->bezt + (icu->totvert - 1));
|
||||
valA= bezt->vec[1][1];
|
||||
|
||||
if (prev)
|
||||
valB= prev->vec[1][1];
|
||||
else
|
||||
valB= bezt->vec[1][1] + 1.0f;
|
||||
|
||||
if (IS_EQ(valA, nValue) && IS_EQ(valA, valB))
|
||||
return KEYNEEDED_DELPREV;
|
||||
else
|
||||
return KEYNEEDED_JUSTADD;
|
||||
}
|
||||
|
||||
/* ------------------ 'Visual' Keyframing Functions ------------------ */
|
||||
|
||||
/* internal status codes for visualkey_can_use */
|
||||
enum {
|
||||
VISUALKEY_NONE = 0,
|
||||
VISUALKEY_LOC,
|
||||
VISUALKEY_ROT
|
||||
};
|
||||
|
||||
/* This helper function determines if visual-keyframing should be used when
|
||||
* inserting keyframes for the given channel. As visual-keyframing only works
|
||||
* on Object and Pose-Channel blocks, this should only get called for those
|
||||
* blocktypes, when using "standard" keying but 'Visual Keying' option in Auto-Keying
|
||||
* settings is on.
|
||||
*/
|
||||
static short visualkey_can_use (ID *id, int blocktype, char *actname, char *constname, int adrcode)
|
||||
{
|
||||
Object *ob= NULL;
|
||||
bConstraint *con= NULL;
|
||||
short searchtype= VISUALKEY_NONE;
|
||||
|
||||
/* validate data */
|
||||
if ((id == NULL) || (GS(id->name)!=ID_OB) || !(ELEM(blocktype, ID_OB, ID_PO)))
|
||||
return 0;
|
||||
|
||||
/* get first constraint and determine type of keyframe constraints to check for*/
|
||||
ob= (Object *)id;
|
||||
|
||||
if (blocktype == ID_OB) {
|
||||
con= ob->constraints.first;
|
||||
|
||||
if (ELEM3(adrcode, OB_LOC_X, OB_LOC_Y, OB_LOC_Z))
|
||||
searchtype= VISUALKEY_LOC;
|
||||
else if (ELEM3(adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z))
|
||||
searchtype= VISUALKEY_ROT;
|
||||
}
|
||||
else if (blocktype == ID_PO) {
|
||||
bPoseChannel *pchan= get_pose_channel(ob->pose, actname);
|
||||
con= pchan->constraints.first;
|
||||
|
||||
if (ELEM3(adrcode, AC_LOC_X, AC_LOC_Y, AC_LOC_Z))
|
||||
searchtype= VISUALKEY_LOC;
|
||||
else if (ELEM4(adrcode, AC_QUAT_W, AC_QUAT_X, AC_QUAT_Y, AC_QUAT_Z))
|
||||
searchtype= VISUALKEY_ROT;
|
||||
}
|
||||
|
||||
/* only search if a searchtype and initial constraint are available */
|
||||
if (searchtype && con) {
|
||||
for (; con; con= con->next) {
|
||||
/* only consider constraint if it is not disabled, and has influence */
|
||||
if (con->flag & CONSTRAINT_DISABLE) continue;
|
||||
if (con->enforce == 0.0f) continue;
|
||||
|
||||
/* some constraints may alter these transforms */
|
||||
switch (con->type) {
|
||||
/* multi-transform constraints */
|
||||
case CONSTRAINT_TYPE_CHILDOF:
|
||||
return 1;
|
||||
case CONSTRAINT_TYPE_TRANSFORM:
|
||||
return 1;
|
||||
case CONSTRAINT_TYPE_FOLLOWPATH:
|
||||
return 1;
|
||||
|
||||
/* single-transform constraits */
|
||||
case CONSTRAINT_TYPE_TRACKTO:
|
||||
if (searchtype==VISUALKEY_ROT) return 1;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_ROTLIMIT:
|
||||
if (searchtype==VISUALKEY_ROT) return 1;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_LOCLIMIT:
|
||||
if (searchtype==VISUALKEY_LOC) return 1;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_ROTLIKE:
|
||||
if (searchtype==VISUALKEY_ROT) return 1;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_DISTLIMIT:
|
||||
if (searchtype==VISUALKEY_LOC) return 1;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_LOCLIKE:
|
||||
if (searchtype==VISUALKEY_LOC) return 1;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_LOCKTRACK:
|
||||
if (searchtype==VISUALKEY_ROT) return 1;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_MINMAX:
|
||||
if (searchtype==VISUALKEY_LOC) return 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* when some condition is met, this function returns, so here it can be 0 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This helper function extracts the value to use for visual-keyframing
|
||||
* In the event that it is not possible to perform visual keying, try to fall-back
|
||||
* to using the poin method. Assumes that all data it has been passed is valid.
|
||||
*/
|
||||
static float visualkey_get_value (ID *id, int blocktype, char *actname, char *constname, int adrcode, IpoCurve *icu)
|
||||
{
|
||||
Object *ob;
|
||||
void *poin = NULL;
|
||||
int index, vartype;
|
||||
|
||||
/* validate situtation */
|
||||
if ((id==NULL) || (GS(id->name)!=ID_OB) || (ELEM(blocktype, ID_OB, ID_PO)==0))
|
||||
return 0.0f;
|
||||
|
||||
/* get object */
|
||||
ob= (Object *)id;
|
||||
|
||||
/* only valid for objects or posechannels */
|
||||
if (blocktype == ID_OB) {
|
||||
/* parented objects are not supported, as the effects of the parent
|
||||
* are included in the matrix, which kindof beats the point
|
||||
*/
|
||||
if (ob->parent == NULL) {
|
||||
/* only Location or Rotation keyframes are supported now */
|
||||
if (ELEM3(adrcode, OB_LOC_X, OB_LOC_Y, OB_LOC_Z)) {
|
||||
/* assumes that OB_LOC_Z > OB_LOC_Y > OB_LOC_X */
|
||||
index= adrcode - OB_LOC_X;
|
||||
|
||||
return ob->obmat[3][index];
|
||||
}
|
||||
else if (ELEM3(adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z)) {
|
||||
float eul[3];
|
||||
|
||||
/* assumes that OB_ROT_Z > OB_ROT_Y > OB_ROT_X */
|
||||
index= adrcode - OB_ROT_X;
|
||||
|
||||
Mat4ToEul(ob->obmat, eul);
|
||||
return eul[index]*(5.72958);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (blocktype == ID_PO) {
|
||||
bPoseChannel *pchan;
|
||||
float tmat[4][4];
|
||||
|
||||
/* get data to use */
|
||||
pchan= get_pose_channel(ob->pose, actname);
|
||||
|
||||
/* Although it is not strictly required for this particular space conversion,
|
||||
* arg1 must not be null, as there is a null check for the other conversions to
|
||||
* be safe. Therefore, the active object is passed here, and in many cases, this
|
||||
* will be what owns the pose-channel that is getting this anyway.
|
||||
*/
|
||||
Mat4CpyMat4(tmat, pchan->pose_mat);
|
||||
constraint_mat_convertspace(ob, pchan, tmat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL);
|
||||
|
||||
/* Loc, Rot/Quat keyframes are supported... */
|
||||
if (ELEM3(adrcode, AC_LOC_X, AC_LOC_Y, AC_LOC_Z)) {
|
||||
/* assumes that AC_LOC_Z > AC_LOC_Y > AC_LOC_X */
|
||||
index= adrcode - AC_LOC_X;
|
||||
|
||||
/* only use for non-connected bones */
|
||||
if ((pchan->bone->parent) && !(pchan->bone->flag & BONE_CONNECTED))
|
||||
return tmat[3][index];
|
||||
else if (pchan->bone->parent == NULL)
|
||||
return tmat[3][index];
|
||||
}
|
||||
else if (ELEM4(adrcode, AC_QUAT_W, AC_QUAT_X, AC_QUAT_Y, AC_QUAT_Z)) {
|
||||
float trimat[3][3], quat[4];
|
||||
|
||||
/* assumes that AC_QUAT_Z > AC_QUAT_Y > AC_QUAT_X > AC_QUAT_W */
|
||||
index= adrcode - AC_QUAT_W;
|
||||
|
||||
Mat3CpyMat4(trimat, tmat);
|
||||
Mat3ToQuat_is_ok(trimat, quat);
|
||||
|
||||
return quat[index];
|
||||
}
|
||||
}
|
||||
|
||||
/* as the function hasn't returned yet, try reading from poin */
|
||||
poin= get_context_ipo_poin(id, blocktype, actname, constname, icu, &vartype);
|
||||
if (poin)
|
||||
return read_ipo_poin(poin, vartype);
|
||||
else
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------- Insert Key API ------------------------- */
|
||||
|
||||
/* Main Keyframing API call:
|
||||
* Use this when validation of necessary animation data isn't necessary as it
|
||||
* already exists. It will insert a keyframe using the current value being keyframed.
|
||||
*
|
||||
* The flag argument is used for special settings that alter the behaviour of
|
||||
* the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
|
||||
* and extra keyframe filtering.
|
||||
*/
|
||||
short insertkey (ID *id, int blocktype, char *actname, char *constname, int adrcode, short flag)
|
||||
{
|
||||
IpoCurve *icu;
|
||||
|
||||
/* get ipo-curve */
|
||||
icu= verify_ipocurve(id, blocktype, actname, constname, NULL, adrcode, 1);
|
||||
|
||||
/* only continue if we have an ipo-curve to add keyframe to */
|
||||
if (icu) {
|
||||
float cfra = frame_to_float(CFRA);
|
||||
float curval= 0.0f;
|
||||
void *poin = NULL;
|
||||
int vartype;
|
||||
|
||||
/* apply special time tweaking */
|
||||
if (GS(id->name) == ID_OB) {
|
||||
Object *ob= (Object *)id;
|
||||
|
||||
/* apply NLA-scaling (if applicable) */
|
||||
if (actname && actname[0])
|
||||
cfra= get_action_frame(ob, cfra);
|
||||
|
||||
/* ancient time-offset cruft */
|
||||
if ( (ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)) ) {
|
||||
/* actually frametofloat calc again! */
|
||||
cfra-= give_timeoffset(ob)*G.scene->r.framelen;
|
||||
}
|
||||
}
|
||||
|
||||
/* get pointer to data to read from */
|
||||
poin= get_context_ipo_poin(id, blocktype, actname, constname, icu, &vartype);
|
||||
if (poin == NULL) return 0;
|
||||
|
||||
/* obtain value to give keyframe */
|
||||
if ( (flag & INSERTKEY_MATRIX) &&
|
||||
(visualkey_can_use(id, blocktype, actname, constname, adrcode)) )
|
||||
{
|
||||
/* visual-keying is only available for object and pchan datablocks, as
|
||||
* it works by keyframing using a value extracted from the final matrix
|
||||
* instead of using the kt system to extract a value.
|
||||
*/
|
||||
curval= visualkey_get_value(id, blocktype, actname, constname, adrcode, icu);
|
||||
}
|
||||
else {
|
||||
/* use kt's read_poin function to extract value (kt->read_poin should
|
||||
* exist in all cases, but it never hurts to check)
|
||||
*/
|
||||
curval= read_ipo_poin(poin, vartype);
|
||||
}
|
||||
|
||||
/* only insert keyframes where they are needed */
|
||||
if (flag & INSERTKEY_NEEDED) {
|
||||
short insert_mode;
|
||||
|
||||
/* check whether this curve really needs a new keyframe */
|
||||
insert_mode= new_key_needed(icu, cfra, curval);
|
||||
|
||||
/* insert new keyframe at current frame */
|
||||
if (insert_mode)
|
||||
insert_vert_icu(icu, cfra, curval, (flag & INSERTKEY_FAST));
|
||||
|
||||
/* delete keyframe immediately before/after newly added */
|
||||
switch (insert_mode) {
|
||||
case KEYNEEDED_DELPREV:
|
||||
delete_icu_key(icu, icu->totvert-2, 1);
|
||||
break;
|
||||
case KEYNEEDED_DELNEXT:
|
||||
delete_icu_key(icu, 1, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* just insert keyframe */
|
||||
insert_vert_icu(icu, cfra, curval, (flag & INSERTKEY_FAST));
|
||||
}
|
||||
|
||||
/* return success */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* return failure */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ************************************************** */
|
||||
/* KEYFRAME DELETION */
|
||||
|
||||
/* Main Keyframing API call:
|
||||
* Use this when validation of necessary animation data isn't necessary as it
|
||||
* already exists. It will delete a keyframe at the current frame.
|
||||
*
|
||||
* The flag argument is used for special settings that alter the behaviour of
|
||||
* the keyframe deletion. These include the quick refresh options.
|
||||
*/
|
||||
short deletekey (ID *id, int blocktype, char *actname, char *constname, int adrcode, short flag)
|
||||
{
|
||||
Ipo *ipo;
|
||||
IpoCurve *icu;
|
||||
|
||||
/* get ipo-curve
|
||||
* Note: here is one of the places where we don't want new ipo + ipo-curve added!
|
||||
* so 'add' var must be 0
|
||||
*/
|
||||
ipo= verify_ipo(id, blocktype, actname, constname, NULL, 0);
|
||||
icu= verify_ipocurve(id, blocktype, actname, constname, NULL, adrcode, 0);
|
||||
|
||||
/* only continue if we have an ipo-curve to remove keyframes from */
|
||||
if (icu) {
|
||||
BezTriple bezt;
|
||||
float cfra = frame_to_float(CFRA);
|
||||
short found = -1;
|
||||
int i;
|
||||
|
||||
/* apply special time tweaking */
|
||||
if (GS(id->name) == ID_OB) {
|
||||
Object *ob= (Object *)id;
|
||||
|
||||
/* apply NLA-scaling (if applicable) */
|
||||
if (actname && actname[0])
|
||||
cfra= get_action_frame(ob, cfra);
|
||||
|
||||
/* ancient time-offset cruft */
|
||||
if ( (ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)) ) {
|
||||
/* actually frametofloat calc again! */
|
||||
cfra-= give_timeoffset(ob)*G.scene->r.framelen;
|
||||
}
|
||||
}
|
||||
|
||||
/* only need to set bezt->vec[1][0], as that's all binarysearch uses */
|
||||
memset(&bezt, 0, sizeof(BezTriple));
|
||||
bezt.vec[1][0]= cfra;
|
||||
|
||||
/* try to find index of beztriple to get rid of */
|
||||
i = binarysearch_bezt_index(icu->bezt, &bezt, icu->totvert, &found);
|
||||
if (found) {
|
||||
/* delete the key at the index (will sanity check + do recalc afterwards ) */
|
||||
delete_icu_key(icu, i, 1);
|
||||
|
||||
/* Only delete curve too if there isn't an ipo-driver still hanging around on an empty curve */
|
||||
if (icu->totvert==0 && icu->driver==NULL) {
|
||||
BLI_remlink(&ipo->curve, icu);
|
||||
free_ipo_curve(icu);
|
||||
}
|
||||
|
||||
/* return success */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* return failure */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ************************************************** */
|
||||
/* COMMON KEYFRAME MANAGEMENT (common_insertkey/deletekey) */
|
||||
|
||||
|
||||
/* ------------- KeyingSet Defines ------------ */
|
||||
/* Note: these must all be named with the defks_* prefix, otherwise the template macro will not work! */
|
||||
|
||||
/* macro for defining keyingset contexts */
|
||||
#define KSC_TEMPLATE(ctx_name) {&defks_##ctx_name[0], NULL, sizeof(defks_##ctx_name)/sizeof(bKeyingSet)}
|
||||
|
||||
/* --- */
|
||||
|
||||
/* check if option not available for deleting keys */
|
||||
static short incl_non_del_keys (bKeyingSet *ks, const char mode[])
|
||||
{
|
||||
/* as optimisation, assume that it is sufficient to check only first letter
|
||||
* of mode (int comparison should be faster than string!)
|
||||
*/
|
||||
//if (strcmp(mode, "Delete")==0)
|
||||
if (mode && mode[0]=='D')
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Object KeyingSets ------ */
|
||||
|
||||
/* check if include shapekey entry */
|
||||
static short incl_v3d_ob_shapekey (bKeyingSet *ks, const char mode[])
|
||||
{
|
||||
Object *ob= (G.obedit)? (G.obedit) : (OBACT);
|
||||
char *newname= NULL;
|
||||
|
||||
/* not available for delete mode */
|
||||
if (strcmp(mode, "Delete")==0)
|
||||
return 0;
|
||||
|
||||
/* check if is geom object that can get shapekeys */
|
||||
switch (ob->type) {
|
||||
/* geometry? */
|
||||
case OB_MESH: newname= "Mesh"; break;
|
||||
case OB_CURVE: newname= "Curve"; break;
|
||||
case OB_SURF: newname= "Surface"; break;
|
||||
case OB_LATTICE: newname= "Lattice"; break;
|
||||
|
||||
/* not geometry! */
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if ks is shapekey entry (this could be callled for separator before too!) */
|
||||
if (ks->flag == -3)
|
||||
sprintf(ks->name, newname);
|
||||
|
||||
/* if it gets here, it's ok */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* array for object keyingset defines */
|
||||
bKeyingSet defks_v3d_object[] =
|
||||
{
|
||||
/* include_cb, name, blocktype, flag, chan_num, adrcodes */
|
||||
{NULL, "Loc", ID_OB, 0, 3, {OB_LOC_X,OB_LOC_Y,OB_LOC_Z}},
|
||||
{NULL, "Rot", ID_OB, 0, 3, {OB_ROT_X,OB_ROT_Y,OB_ROT_Z}},
|
||||
{NULL, "Scale", ID_OB, 0, 3, {OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}},
|
||||
|
||||
{NULL, "%l", 0, -1, 0, {0}}, // separator
|
||||
|
||||
{NULL, "LocRot", ID_OB, 0, 6,
|
||||
{OB_LOC_X,OB_LOC_Y,OB_LOC_Z,
|
||||
OB_ROT_X,OB_ROT_Y,OB_ROT_Z}},
|
||||
|
||||
{NULL, "LocScale", ID_OB, 0, 6,
|
||||
{OB_LOC_X,OB_LOC_Y,OB_LOC_Z,
|
||||
OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}},
|
||||
|
||||
{NULL, "LocRotScale", ID_OB, 0, 9,
|
||||
{OB_LOC_X,OB_LOC_Y,OB_LOC_Z,
|
||||
OB_ROT_X,OB_ROT_Y,OB_ROT_Z,
|
||||
OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}},
|
||||
|
||||
{NULL, "RotScale", ID_OB, 0, 6,
|
||||
{OB_ROT_X,OB_ROT_Y,OB_ROT_Z,
|
||||
OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}},
|
||||
|
||||
{incl_non_del_keys, "%l", 0, -1, 0, {0}}, // separator
|
||||
|
||||
{incl_non_del_keys, "VisualLoc", ID_OB, INSERTKEY_MATRIX, 3, {OB_LOC_X,OB_LOC_Y,OB_LOC_Z}},
|
||||
{incl_non_del_keys, "VisualRot", ID_OB, INSERTKEY_MATRIX, 3, {OB_ROT_X,OB_ROT_Y,OB_ROT_Z}},
|
||||
|
||||
{incl_non_del_keys, "VisualLocRot", ID_OB, INSERTKEY_MATRIX, 6,
|
||||
{OB_LOC_X,OB_LOC_Y,OB_LOC_Z,
|
||||
OB_ROT_X,OB_ROT_Y,OB_ROT_Z}},
|
||||
|
||||
{NULL, "%l", 0, -1, 0, {0}}, // separator
|
||||
|
||||
{NULL, "Layer", ID_OB, 0, 1, {OB_LAY}}, // icky option...
|
||||
{NULL, "Available", ID_OB, -2, 0, {0}},
|
||||
|
||||
{incl_v3d_ob_shapekey, "%l%l", 0, -1, 0, {0}}, // separator (linked to shapekey entry)
|
||||
{incl_v3d_ob_shapekey, "<ShapeKey>", ID_OB, -3, 0, {0}}
|
||||
};
|
||||
|
||||
/* PoseChannel KeyingSets ------ */
|
||||
|
||||
/* array for posechannel keyingset defines */
|
||||
bKeyingSet defks_v3d_pchan[] =
|
||||
{
|
||||
/* include_cb, name, blocktype, flag, chan_num, adrcodes */
|
||||
{NULL, "Loc", ID_PO, 0, 3, {AC_LOC_X,AC_LOC_Y,AC_LOC_Z}},
|
||||
{NULL, "Rot", ID_PO, 0, 4, {AC_QUAT_W,AC_QUAT_X,AC_QUAT_Y,AC_QUAT_Z}},
|
||||
{NULL, "Scale", ID_PO, 0, 3, {AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z}},
|
||||
|
||||
{NULL, "%l", 0, -1, 0, {0}}, // separator
|
||||
|
||||
{NULL, "LocRot", ID_PO, 0, 7,
|
||||
{AC_LOC_X,AC_LOC_Y,AC_LOC_Z,AC_QUAT_W,
|
||||
AC_QUAT_X,AC_QUAT_Y,AC_QUAT_Z}},
|
||||
|
||||
{NULL, "LocScale", ID_PO, 0, 6,
|
||||
{AC_LOC_X,AC_LOC_Y,AC_LOC_Z,
|
||||
AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z}},
|
||||
|
||||
{NULL, "LocRotScale", ID_PO, 0, 10,
|
||||
{AC_LOC_X,AC_LOC_Y,AC_LOC_Z,AC_QUAT_W,AC_QUAT_X,
|
||||
AC_QUAT_Y,AC_QUAT_Z,AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z}},
|
||||
|
||||
{NULL, "RotScale", ID_PO, 0, 7,
|
||||
{AC_QUAT_W,AC_QUAT_X,AC_QUAT_Y,AC_QUAT_Z,
|
||||
AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z}},
|
||||
|
||||
{incl_non_del_keys, "%l", 0, -1, 0, {0}}, // separator
|
||||
|
||||
{incl_non_del_keys, "VisualLoc", ID_PO, INSERTKEY_MATRIX, 3, {AC_LOC_X,AC_LOC_Y,AC_LOC_Z}},
|
||||
{incl_non_del_keys, "VisualRot", ID_PO, INSERTKEY_MATRIX, 4, {AC_QUAT_W,AC_QUAT_X,AC_QUAT_Y,AC_QUAT_Z}},
|
||||
|
||||
{incl_non_del_keys, "VisualLocRot", ID_PO, INSERTKEY_MATRIX, 7,
|
||||
{AC_LOC_X,AC_LOC_Y,AC_LOC_Z,AC_QUAT_W,
|
||||
AC_QUAT_X,AC_QUAT_Y,AC_QUAT_Z}},
|
||||
|
||||
{NULL, "%l", 0, -1, 0, {0}}, // separator
|
||||
|
||||
{NULL, "Available", ID_PO, -2, 0, {0}}
|
||||
};
|
||||
|
||||
/* Material KeyingSets ------ */
|
||||
|
||||
/* array for material keyingset defines */
|
||||
bKeyingSet defks_buts_shading_mat[] =
|
||||
{
|
||||
/* include_cb, name, blocktype, flag, chan_num, adrcodes */
|
||||
{NULL, "RGB", ID_MA, 0, 3, {MA_COL_R,MA_COL_G,MA_COL_B}},
|
||||
{NULL, "Alpha", ID_MA, 0, 1, {MA_ALPHA}},
|
||||
{NULL, "Halo Size", ID_MA, 0, 1, {MA_HASIZE}},
|
||||
{NULL, "Mode", ID_MA, 0, 1, {MA_MODE}}, // evil bitflags
|
||||
|
||||
{NULL, "%l", 0, -1, 0, {0}}, // separator
|
||||
|
||||
{NULL, "All Color", ID_MA, 0, 18,
|
||||
{MA_COL_R,MA_COL_G,MA_COL_B,
|
||||
MA_ALPHA,MA_HASIZE, MA_MODE,
|
||||
MA_SPEC_R,MA_SPEC_G,MA_SPEC_B,
|
||||
MA_REF,MA_EMIT,MA_AMB,MA_SPEC,MA_HARD,
|
||||
MA_MODE,MA_TRANSLU,MA_ADD}},
|
||||
|
||||
{NULL, "All Mirror", ID_MA, 0, 5,
|
||||
{MA_RAYM,MA_FRESMIR,MA_FRESMIRI,
|
||||
MA_FRESTRA,MA_FRESTRAI}},
|
||||
|
||||
{NULL, "%l", 0, -1, 0, {0}}, // separator
|
||||
|
||||
{NULL, "Ofs", ID_MA, 0, 3, {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z}},
|
||||
{NULL, "Size", ID_MA, 0, 3, {MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z}},
|
||||
|
||||
{NULL, "All Mapping", ID_MA, 0, 14,
|
||||
{MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z,
|
||||
MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z,
|
||||
MAP_R,MAP_G,MAP_B,MAP_DVAR,
|
||||
MAP_COLF,MAP_NORF,MAP_VARF,MAP_DISP}},
|
||||
|
||||
{NULL, "%l", 0, -1, 0, {0}}, // separator
|
||||
|
||||
{NULL, "Available", ID_MA, -2, 0, {0}}
|
||||
};
|
||||
|
||||
/* World KeyingSets ------ */
|
||||
|
||||
/* array for world keyingset defines */
|
||||
bKeyingSet defks_buts_shading_wo[] =
|
||||
{
|
||||
/* include_cb, name, blocktype, flag, chan_num, adrcodes */
|
||||
{NULL, "Zenith RGB", ID_WO, 0, 3, {WO_ZEN_R,WO_ZEN_G,WO_ZEN_B}},
|
||||
{NULL, "Horizon RGB", ID_WO, 0, 3, {WO_HOR_R,WO_HOR_G,WO_HOR_B}},
|
||||
|
||||
{NULL, "%l", 0, -1, 0, {0}}, // separator
|
||||
|
||||
{NULL, "Mist", ID_WO, 0, 4, {WO_MISI,WO_MISTDI,WO_MISTSTA,WO_MISTHI}},
|
||||
{NULL, "Stars", ID_WO, 0, 5, {WO_STAR_R,WO_STAR_G,WO_STAR_B,WO_STARDIST,WO_STARSIZE}},
|
||||
|
||||
|
||||
{NULL, "%l", 0, -1, 0, {0}}, // separator
|
||||
|
||||
{NULL, "Ofs", ID_WO, 0, 3, {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z}},
|
||||
{NULL, "Size", ID_WO, 0, 3, {MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z}},
|
||||
|
||||
{NULL, "All Mapping", ID_WO, 0, 14,
|
||||
{MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z,
|
||||
MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z,
|
||||
MAP_R,MAP_G,MAP_B,MAP_DVAR,
|
||||
MAP_COLF,MAP_NORF,MAP_VARF,MAP_DISP}},
|
||||
|
||||
{NULL, "%l", 0, -1, 0, {0}}, // separator
|
||||
|
||||
{NULL, "Available", ID_WO, -2, 0, {0}}
|
||||
};
|
||||
|
||||
/* Lamp KeyingSets ------ */
|
||||
|
||||
/* array for lamp keyingset defines */
|
||||
bKeyingSet defks_buts_shading_la[] =
|
||||
{
|
||||
/* include_cb, name, blocktype, flag, chan_num, adrcodes */
|
||||
{NULL, "RGB", ID_LA, 0, 3, {LA_COL_R,LA_COL_G,LA_COL_B}},
|
||||
{NULL, "Energy", ID_LA, 0, 1, {LA_ENERGY}},
|
||||
{NULL, "Spot Size", ID_LA, 0, 1, {LA_SPOTSI}},
|
||||
|
||||
{NULL, "%l", 0, -1, 0, {0}}, // separator
|
||||
|
||||
{NULL, "Ofs", ID_LA, 0, 3, {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z}},
|
||||
{NULL, "Size", ID_LA, 0, 3, {MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z}},
|
||||
|
||||
{NULL, "All Mapping", ID_LA, 0, 14,
|
||||
{MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z,
|
||||
MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z,
|
||||
MAP_R,MAP_G,MAP_B,MAP_DVAR,
|
||||
MAP_COLF,MAP_NORF,MAP_VARF,MAP_DISP}},
|
||||
|
||||
{NULL, "%l", 0, -1, 0, {0}}, // separator
|
||||
|
||||
{NULL, "Available", ID_LA, -2, 0, {0}}
|
||||
};
|
||||
|
||||
/* Texture KeyingSets ------ */
|
||||
|
||||
/* array for texture keyingset defines */
|
||||
bKeyingSet defks_buts_shading_tex[] =
|
||||
{
|
||||
/* include_cb, name, blocktype, flag, chan_num, adrcodes */
|
||||
{NULL, "Clouds", ID_TE, 0, 5,
|
||||
{TE_NSIZE,TE_NDEPTH,TE_NTYPE,
|
||||
TE_MG_TYP,TE_N_BAS1}},
|
||||
|
||||
{NULL, "Marble", ID_TE, 0, 7,
|
||||
{TE_NSIZE,TE_NDEPTH,TE_NTYPE,
|
||||
TE_TURB,TE_MG_TYP,TE_N_BAS1,TE_N_BAS2}},
|
||||
|
||||
{NULL, "Stucci", ID_TE, 0, 5,
|
||||
{TE_NSIZE,TE_NTYPE,TE_TURB,
|
||||
TE_MG_TYP,TE_N_BAS1}},
|
||||
|
||||
{NULL, "Wood", ID_TE, 0, 6,
|
||||
{TE_NSIZE,TE_NTYPE,TE_TURB,
|
||||
TE_MG_TYP,TE_N_BAS1,TE_N_BAS2}},
|
||||
|
||||
{NULL, "Magic", ID_TE, 0, 2, {TE_NDEPTH,TE_TURB}},
|
||||
|
||||
{NULL, "Blend", ID_TE, 0, 1, {TE_MG_TYP}},
|
||||
|
||||
{NULL, "Musgrave", ID_TE, 0, 6,
|
||||
{TE_MG_TYP,TE_MGH,TE_MG_LAC,
|
||||
TE_MG_OCT,TE_MG_OFF,TE_MG_GAIN}},
|
||||
|
||||
{NULL, "Voronoi", ID_TE, 0, 9,
|
||||
{TE_VNW1,TE_VNW2,TE_VNW3,TE_VNW4,
|
||||
TE_VNMEXP,TE_VN_DISTM,TE_VN_COLT,
|
||||
TE_ISCA,TE_NSIZE}},
|
||||
|
||||
{NULL, "Distorted Noise", ID_TE, 0, 4,
|
||||
{TE_MG_OCT,TE_MG_OFF,TE_MG_GAIN,TE_DISTA}},
|
||||
|
||||
{NULL, "Color Filter", ID_TE, 0, 5,
|
||||
{TE_COL_R,TE_COL_G,TE_COL_B,TE_BRIGHT,TE_CONTRA}},
|
||||
|
||||
{NULL, "%l", 0, -1, 0, {0}}, // separator
|
||||
|
||||
{NULL, "Available", ID_TE, -2, 0, {0}}
|
||||
};
|
||||
|
||||
/* Object Buttons KeyingSets ------ */
|
||||
|
||||
/* check if include particles entry */
|
||||
static short incl_buts_ob (bKeyingSet *ks, const char mode[])
|
||||
{
|
||||
Object *ob= OBACT;
|
||||
/* only if object is mesh type */
|
||||
return (ob->type == OB_MESH);
|
||||
}
|
||||
|
||||
/* array for texture keyingset defines */
|
||||
bKeyingSet defks_buts_object[] =
|
||||
{
|
||||
/* include_cb, name, blocktype, flag, chan_num, adrcodes */
|
||||
{incl_buts_ob, "Surface Damping", ID_OB, 0, 1, {OB_PD_SDAMP}},
|
||||
{incl_buts_ob, "Random Damping", ID_OB, 0, 1, {OB_PD_RDAMP}},
|
||||
{incl_buts_ob, "Permeability", ID_OB, 0, 1, {OB_PD_PERM}},
|
||||
|
||||
{NULL, "%l", 0, -1, 0, {0}}, // separator
|
||||
|
||||
{NULL, "Force Strength", ID_OB, 0, 1, {OB_PD_FSTR}},
|
||||
{NULL, "Force Falloff", ID_OB, 0, 1, {OB_PD_FFALL}},
|
||||
|
||||
{NULL, "%l", 0, -1, 0, {0}}, // separator
|
||||
|
||||
{NULL, "Available", ID_OB, -2, 0, {0}} // this will include ob-transforms too!
|
||||
};
|
||||
|
||||
/* Camera Buttons KeyingSets ------ */
|
||||
|
||||
/* check if include internal-renderer entry */
|
||||
static short incl_buts_cam1 (bKeyingSet *ks, const char mode[])
|
||||
{
|
||||
/* only if renderer is internal renderer */
|
||||
return (G.scene->r.renderer==R_INTERN);
|
||||
}
|
||||
|
||||
/* check if include external-renderer entry */
|
||||
static short incl_buts_cam2 (bKeyingSet *ks, const char mode[])
|
||||
{
|
||||
/* only if renderer is internal renderer */
|
||||
return (G.scene->r.renderer!=R_INTERN);
|
||||
}
|
||||
|
||||
/* array for camera keyingset defines */
|
||||
bKeyingSet defks_buts_cam[] =
|
||||
{
|
||||
/* include_cb, name, blocktype, flag, chan_num, adrcodes */
|
||||
{NULL, "Lens", ID_CA, 0, 1, {CAM_LENS}},
|
||||
{NULL, "Clipping", ID_CA, 0, 2, {CAM_STA,CAM_END}},
|
||||
{NULL, "Focal Distance", ID_CA, 0, 1, {CAM_YF_FDIST}},
|
||||
|
||||
{NULL, "%l", 0, -1, 0, {0}}, // separator
|
||||
|
||||
|
||||
{incl_buts_cam2, "Aperture", ID_CA, 0, 1, {CAM_YF_APERT}},
|
||||
{incl_buts_cam1, "Viewplane Shift", ID_CA, 0, 2, {CAM_SHIFT_X,CAM_SHIFT_Y}},
|
||||
|
||||
{NULL, "%l", 0, -1, 0, {0}}, // separator
|
||||
|
||||
{NULL, "Available", ID_CA, -2, 0, {0}}
|
||||
};
|
||||
|
||||
/* --- */
|
||||
|
||||
/* Keying Context Defines - Must keep in sync with enumeration (eKS_Contexts) */
|
||||
bKeyingContext ks_contexts[] =
|
||||
{
|
||||
KSC_TEMPLATE(v3d_object),
|
||||
KSC_TEMPLATE(v3d_pchan),
|
||||
|
||||
KSC_TEMPLATE(buts_shading_mat),
|
||||
KSC_TEMPLATE(buts_shading_wo),
|
||||
KSC_TEMPLATE(buts_shading_la),
|
||||
KSC_TEMPLATE(buts_shading_tex),
|
||||
|
||||
KSC_TEMPLATE(buts_object),
|
||||
KSC_TEMPLATE(buts_cam)
|
||||
};
|
||||
|
||||
/* Keying Context Enumeration - Must keep in sync with definitions*/
|
||||
typedef enum eKS_Contexts {
|
||||
KSC_V3D_OBJECT = 0,
|
||||
KSC_V3D_PCHAN,
|
||||
|
||||
KSC_BUTS_MAT,
|
||||
KSC_BUTS_WO,
|
||||
KSC_BUTS_LA,
|
||||
KSC_BUTS_TEX,
|
||||
|
||||
KSC_BUTS_OB,
|
||||
KSC_BUTS_CAM,
|
||||
|
||||
/* make sure this last one remains untouched! */
|
||||
KSC_TOT_TYPES
|
||||
} eKS_Contexts;
|
||||
|
||||
|
||||
/* ---------------- KeyingSet Tools ------------------- */
|
||||
|
||||
/* helper for commonkey_context_get() - get keyingsets for 3d-view */
|
||||
static void commonkey_context_getv3d (ListBase *sources, bKeyingContext **ksc)
|
||||
{
|
||||
Object *ob;
|
||||
IpoCurve *icu;
|
||||
|
||||
if ((OBACT) && (OBACT->flag & OB_POSEMODE)) {
|
||||
bPoseChannel *pchan;
|
||||
|
||||
/* pose-level */
|
||||
ob= OBACT;
|
||||
*ksc= &ks_contexts[KSC_V3D_PCHAN];
|
||||
set_pose_keys(ob); /* sets pchan->flag to POSE_KEY if bone selected, and clears if not */
|
||||
|
||||
/* loop through posechannels */
|
||||
for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) {
|
||||
if (pchan->flag & POSE_KEY) {
|
||||
bCommonKeySrc *cks;
|
||||
|
||||
/* add new keyframing destination */
|
||||
cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
|
||||
BLI_addtail(sources, cks);
|
||||
|
||||
/* set id-block to key to, and action */
|
||||
cks->id= (ID *)ob;
|
||||
cks->act= ob->action;
|
||||
|
||||
/* set pchan */
|
||||
cks->pchan= pchan;
|
||||
cks->actname= pchan->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Base *base;
|
||||
|
||||
/* object-level */
|
||||
*ksc= &ks_contexts[KSC_V3D_OBJECT];
|
||||
|
||||
/* loop through bases */
|
||||
for (base= FIRSTBASE; base; base= base->next) {
|
||||
if (TESTBASELIB(base)) {
|
||||
bCommonKeySrc *cks;
|
||||
|
||||
/* add new keyframing destination */
|
||||
cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
|
||||
BLI_addtail(sources, cks);
|
||||
|
||||
/* set id-block to key to */
|
||||
ob= base->object;
|
||||
cks->id= (ID *)ob;
|
||||
|
||||
/* when ob's keyframes are in an action, default to using 'Object' as achan name */
|
||||
if (ob->ipoflag & OB_ACTION_OB)
|
||||
cks->actname= "Object";
|
||||
|
||||
/* set ipo-flags */
|
||||
// TODO: add checks for lib-linked data
|
||||
if ((ob->ipo) || (ob->action)) {
|
||||
if (ob->ipo) {
|
||||
cks->ipo= ob->ipo;
|
||||
}
|
||||
else {
|
||||
bActionChannel *achan;
|
||||
|
||||
cks->act= ob->action;
|
||||
achan= get_action_channel(ob->action, cks->actname);
|
||||
|
||||
if (achan && achan->ipo)
|
||||
cks->ipo= achan->ipo;
|
||||
}
|
||||
|
||||
/* deselect all ipo-curves */
|
||||
for (icu= cks->ipo->curve.first; icu; icu= icu->next) {
|
||||
icu->flag &= ~IPO_SELECT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* helper for commonkey_context_get() - get keyingsets for buttons window */
|
||||
static void commonkey_context_getsbuts (ListBase *sources, bKeyingContext **ksc)
|
||||
{
|
||||
bCommonKeySrc *cks;
|
||||
|
||||
/* check on tab-type */
|
||||
switch (G.buts->mainb) {
|
||||
case CONTEXT_SHADING: /* ------------- Shading buttons ---------------- */
|
||||
/* subtabs include "Material", "Texture", "Lamp", "World"*/
|
||||
switch (G.buts->tab[CONTEXT_SHADING]) {
|
||||
case TAB_SHADING_MAT: /* >------------- Material Tab -------------< */
|
||||
{
|
||||
Material *ma= editnode_get_active_material(G.buts->lockpoin);
|
||||
|
||||
/* add new keyframing destination */
|
||||
cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
|
||||
BLI_addtail(sources, cks);
|
||||
|
||||
/* set data */
|
||||
cks->id= (ID *)ma;
|
||||
cks->ipo= ma->ipo;
|
||||
cks->map= texchannel_to_adrcode(ma->texact);
|
||||
|
||||
/* set keyingsets */
|
||||
*ksc= &ks_contexts[KSC_BUTS_MAT];
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case TAB_SHADING_WORLD: /* >------------- World Tab -------------< */
|
||||
{
|
||||
World *wo= G.buts->lockpoin;
|
||||
|
||||
/* add new keyframing destination */
|
||||
cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
|
||||
BLI_addtail(sources, cks);
|
||||
|
||||
/* set data */
|
||||
cks->id= (ID *)wo;
|
||||
cks->ipo= wo->ipo;
|
||||
cks->map= texchannel_to_adrcode(wo->texact);
|
||||
|
||||
/* set keyingsets */
|
||||
*ksc= &ks_contexts[KSC_BUTS_WO];
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case TAB_SHADING_LAMP: /* >------------- Lamp Tab -------------< */
|
||||
{
|
||||
Lamp *la= G.buts->lockpoin;
|
||||
|
||||
/* add new keyframing destination */
|
||||
cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
|
||||
BLI_addtail(sources, cks);
|
||||
|
||||
/* set data */
|
||||
cks->id= (ID *)la;
|
||||
cks->ipo= la->ipo;
|
||||
cks->map= texchannel_to_adrcode(la->texact);
|
||||
|
||||
/* set keyingsets */
|
||||
*ksc= &ks_contexts[KSC_BUTS_LA];
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case TAB_SHADING_TEX: /* >------------- Texture Tab -------------< */
|
||||
{
|
||||
Tex *tex= G.buts->lockpoin;
|
||||
|
||||
/* add new keyframing destination */
|
||||
cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
|
||||
BLI_addtail(sources, cks);
|
||||
|
||||
/* set data */
|
||||
cks->id= (ID *)tex;
|
||||
cks->ipo= tex->ipo;
|
||||
|
||||
/* set keyingsets */
|
||||
*ksc= &ks_contexts[KSC_BUTS_TEX];
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case CONTEXT_OBJECT: /* ------------- Object buttons ---------------- */
|
||||
{
|
||||
Object *ob= OBACT;
|
||||
|
||||
if (ob) {
|
||||
/* add new keyframing destination */
|
||||
cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
|
||||
BLI_addtail(sources, cks);
|
||||
|
||||
/* set id-block to key to */
|
||||
cks->id= (ID *)ob;
|
||||
cks->ipo= ob->ipo;
|
||||
|
||||
/* set keyingsets */
|
||||
*ksc= &ks_contexts[KSC_BUTS_OB];
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CONTEXT_EDITING: /* ------------- Editing buttons ---------------- */
|
||||
{
|
||||
Object *ob= OBACT;
|
||||
|
||||
if ((ob) && (ob->type==OB_CAMERA) && (G.buts->lockpoin)) { /* >---------------- camera buttons ---------------< */
|
||||
Camera *ca= G.buts->lockpoin;
|
||||
|
||||
/* add new keyframing destination */
|
||||
cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
|
||||
BLI_addtail(sources, cks);
|
||||
|
||||
/* set id-block to key to */
|
||||
cks->id= (ID *)ca;
|
||||
cks->ipo= ca->ipo;
|
||||
|
||||
/* set keyingsets */
|
||||
*ksc= &ks_contexts[KSC_BUTS_CAM];
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* if nothing happened... */
|
||||
*ksc= NULL;
|
||||
}
|
||||
|
||||
|
||||
/* get keyingsets for appropriate context */
|
||||
static void commonkey_context_get (ScrArea *sa, ListBase *sources, bKeyingContext **ksc)
|
||||
{
|
||||
/* check view type */
|
||||
switch (sa->spacetype) {
|
||||
/* 3d view - first one tested as most often used */
|
||||
case SPACE_VIEW3D:
|
||||
{
|
||||
commonkey_context_getv3d(sources, ksc);
|
||||
}
|
||||
break;
|
||||
|
||||
/* buttons view */
|
||||
case SPACE_BUTS:
|
||||
{
|
||||
commonkey_context_getsbuts(sources, ksc);
|
||||
}
|
||||
break;
|
||||
|
||||
/* timeline view - keyframe buttons */
|
||||
case SPACE_TIME:
|
||||
{
|
||||
ScrArea *sab;
|
||||
|
||||
/* try to find largest 3d-view available
|
||||
* (mostly of the time, this is what when user will want this,
|
||||
* as it's a standard feature in all other apps)
|
||||
*/
|
||||
sab= find_biggest_area_of_type(SPACE_VIEW3D);
|
||||
if (sab) {
|
||||
commonkey_context_getv3d(sources, ksc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* otherwise, try to find the biggest area
|
||||
* WARNING: must check if that area is another timeline, as that would cause infinite loop
|
||||
*/
|
||||
sab= closest_bigger_area();
|
||||
if ((sab) && (sab->spacetype != SPACE_TIME))
|
||||
commonkey_context_get(sab, sources, ksc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* flush updates after all operations */
|
||||
static void commonkey_context_finish (ListBase *sources)
|
||||
{
|
||||
/* check view type */
|
||||
switch (curarea->spacetype) {
|
||||
/* 3d view - first one tested as most often used */
|
||||
case SPACE_VIEW3D:
|
||||
{
|
||||
/* either pose or object level */
|
||||
if (OBACT && (OBACT->pose)) {
|
||||
Object *ob= OBACT;
|
||||
|
||||
/* recalculate ipo handles, etc. */
|
||||
if (ob->action)
|
||||
remake_action_ipos(ob->action);
|
||||
|
||||
/* recalculate bone-paths on adding new keyframe? */
|
||||
// TODO: currently, there is no setting to turn this on/off globally
|
||||
if (ob->pose->flag & POSE_RECALCPATHS)
|
||||
pose_recalculate_paths(ob);
|
||||
}
|
||||
else {
|
||||
bCommonKeySrc *cks;
|
||||
|
||||
/* loop over bases (as seen in sources) */
|
||||
for (cks= sources->first; cks; cks= cks->next) {
|
||||
Object *ob= (Object *)cks->id;
|
||||
|
||||
/* simply set recalc flag */
|
||||
ob->recalc |= OB_RECALC_OB;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* flush refreshes after undo */
|
||||
static void commonkey_context_refresh (void)
|
||||
{
|
||||
/* check view type */
|
||||
switch (curarea->spacetype) {
|
||||
/* 3d view - first one tested as most often used */
|
||||
case SPACE_VIEW3D:
|
||||
{
|
||||
/* do refreshes */
|
||||
DAG_scene_flush_update(G.scene, screen_view3d_layers(), 0);
|
||||
|
||||
allspace(REMAKEIPO, 0);
|
||||
allqueue(REDRAWVIEW3D, 0);
|
||||
allqueue(REDRAWMARKER, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* --- */
|
||||
|
||||
/* Build menu-string of available keying-sets (allocates memory for string)
|
||||
* NOTE: mode must not be longer than 64 chars
|
||||
*/
|
||||
static char *build_keyingsets_menu (bKeyingContext *ksc, const char mode[48])
|
||||
{
|
||||
DynStr *pupds= BLI_dynstr_new();
|
||||
bKeyingSet *ks;
|
||||
char buf[64];
|
||||
char *str;
|
||||
int i, n;
|
||||
|
||||
/* add title first */
|
||||
BLI_snprintf(buf, 64, "%s Key %%t|", mode);
|
||||
BLI_dynstr_append(pupds, buf);
|
||||
|
||||
/* loop through keyingsets, adding them */
|
||||
for (ks=ksc->keyingsets, i=0, n=1; i < ksc->tot; ks++, i++, n++) {
|
||||
/* check if keyingset can be used */
|
||||
if (ks->flag == -1) {
|
||||
/* optional separator? */
|
||||
if (ks->include_cb) {
|
||||
if (ks->include_cb(ks, mode)) {
|
||||
BLI_snprintf( buf, 64, "%s%s", ks->name, ((n < ksc->tot)?"|":"") );
|
||||
BLI_dynstr_append(pupds, buf);
|
||||
}
|
||||
}
|
||||
else {
|
||||
BLI_snprintf( buf, 64, "%%l%s", ((n < ksc->tot)?"|":"") );
|
||||
BLI_dynstr_append(pupds, buf);
|
||||
}
|
||||
}
|
||||
else if ( (ks->include_cb==NULL) || (ks->include_cb(ks, mode)) ) {
|
||||
/* entry can be included */
|
||||
BLI_dynstr_append(pupds, ks->name);
|
||||
|
||||
/* check if special "shapekey" entry */
|
||||
if (ks->flag == -3)
|
||||
BLI_snprintf( buf, 64, "%%x0%s", ((n < ksc->tot)?"|":"") );
|
||||
else
|
||||
BLI_snprintf( buf, 64, "%%x%d%s", n, ((n < ksc->tot)?"|":"") );
|
||||
BLI_dynstr_append(pupds, buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* convert to normal MEM_malloc'd string */
|
||||
str= BLI_dynstr_get_cstring(pupds);
|
||||
BLI_dynstr_free(pupds);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/* Get the keying set that was chosen by the user from the menu */
|
||||
static bKeyingSet *get_keyingset_fromcontext (bKeyingContext *ksc, short index)
|
||||
{
|
||||
/* check if index is valid */
|
||||
if (ELEM(NULL, ksc, ksc->keyingsets))
|
||||
return NULL;
|
||||
if ((index < 1) || (index > ksc->tot))
|
||||
return NULL;
|
||||
|
||||
/* index starts from 1, and should directly correspond to keyingset in array */
|
||||
return (bKeyingSet *)(ksc->keyingsets + (index - 1));
|
||||
}
|
||||
|
||||
/* ---------------- Keyframe Management API -------------------- */
|
||||
|
||||
/* mode for common_modifykey */
|
||||
enum {
|
||||
COMMONKEY_MODE_INSERT = 0,
|
||||
COMMONKEY_MODE_DELETE,
|
||||
} eCommonModifyKey_Modes;
|
||||
|
||||
/* Display a menu for handling the insertion of keyframes based on the active view */
|
||||
// TODO: add back an option for repeating last keytype
|
||||
void common_modifykey (short mode)
|
||||
{
|
||||
ListBase dsources = {NULL, NULL};
|
||||
bKeyingContext *ksc= NULL;
|
||||
bCommonKeySrc *cks;
|
||||
bKeyingSet *ks = NULL;
|
||||
char *menustr, buf[64];
|
||||
short menu_nr;
|
||||
|
||||
/* check if mode is valid */
|
||||
if (ELEM(mode, COMMONKEY_MODE_INSERT, COMMONKEY_MODE_DELETE)==0)
|
||||
return;
|
||||
|
||||
/* delegate to other functions or get keyingsets to use */
|
||||
switch (curarea->spacetype) {
|
||||
/* spaces with their own methods */
|
||||
case SPACE_IPO:
|
||||
if (mode == COMMONKEY_MODE_INSERT)
|
||||
insertkey_editipo();
|
||||
return;
|
||||
case SPACE_ACTION:
|
||||
if (mode == COMMONKEY_MODE_INSERT)
|
||||
insertkey_action();
|
||||
return;
|
||||
|
||||
/* TODO: based on UI elements? will that even be handled here??? */
|
||||
|
||||
/* default - check per view */
|
||||
default:
|
||||
/* get the keyingsets and the data to add keyframes to */
|
||||
commonkey_context_get(curarea, &dsources, &ksc);
|
||||
break;
|
||||
}
|
||||
|
||||
/* check that there is data to operate on */
|
||||
if (ELEM(NULL, dsources.first, ksc)) {
|
||||
BLI_freelistN(&dsources);
|
||||
return;
|
||||
}
|
||||
|
||||
/* get menu and process it */
|
||||
if (mode == COMMONKEY_MODE_DELETE)
|
||||
menustr= build_keyingsets_menu(ksc, "Delete");
|
||||
else
|
||||
menustr= build_keyingsets_menu(ksc, "Insert");
|
||||
menu_nr= pupmenu(menustr);
|
||||
if (menustr) MEM_freeN(menustr);
|
||||
|
||||
/* no item selected or shapekey entry? */
|
||||
if (menu_nr < 1) {
|
||||
/* free temp sources */
|
||||
BLI_freelistN(&dsources);
|
||||
|
||||
/* check if insert new shapekey */
|
||||
if ((menu_nr == 0) && (mode == COMMONKEY_MODE_INSERT))
|
||||
insert_shapekey(OBACT);
|
||||
else
|
||||
ksc->lastused= NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
else {
|
||||
/* try to get keyingset */
|
||||
ks= get_keyingset_fromcontext(ksc, menu_nr);
|
||||
|
||||
if (ks == NULL) {
|
||||
BLI_freelistN(&dsources);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* loop over each destination, applying the keying set */
|
||||
for (cks= dsources.first; cks; cks= cks->next) {
|
||||
short success= 0;
|
||||
|
||||
/* special hacks for 'available' option */
|
||||
if (ks->flag == -2) {
|
||||
IpoCurve *icu= NULL, *icn= NULL;
|
||||
|
||||
/* get first IPO-curve */
|
||||
if (cks->act && cks->actname) {
|
||||
bActionChannel *achan= get_action_channel(cks->act, cks->actname);
|
||||
|
||||
// FIXME: what about constraint channels?
|
||||
if (achan && achan->ipo)
|
||||
icu= achan->ipo->curve.first;
|
||||
}
|
||||
else
|
||||
icu= cks->ipo->curve.first;
|
||||
|
||||
/* we get adrcodes directly from IPO curves (see method below...) */
|
||||
for (; icu; icu= icn) {
|
||||
short flag;
|
||||
|
||||
/* get next ipo-curve in case current is deleted */
|
||||
icn= icu->next;
|
||||
|
||||
/* insert mode or delete mode */
|
||||
if (mode == COMMONKEY_MODE_DELETE) {
|
||||
/* local flags only add on to global flags */
|
||||
flag = 0;
|
||||
|
||||
/* delete keyframe */
|
||||
success += deletekey(cks->id, ks->blocktype, cks->actname, cks->constname, icu->adrcode, flag);
|
||||
}
|
||||
else {
|
||||
/* local flags only add on to global flags */
|
||||
flag = ks->flag;
|
||||
if (IS_AUTOKEY_FLAG(AUTOMATKEY)) flag |= INSERTKEY_MATRIX;
|
||||
if (IS_AUTOKEY_FLAG(INSERTNEEDED)) flag |= INSERTKEY_NEEDED;
|
||||
// if (IS_AUTOKEY_MODE(EDITKEYS)) flag |= INSERTKEY_REPLACE;
|
||||
|
||||
/* insert keyframe */
|
||||
success += insertkey(cks->id, ks->blocktype, cks->actname, cks->constname, icu->adrcode, flag);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
int i;
|
||||
|
||||
/* loop over channels available in keyingset */
|
||||
for (i=0; i < ks->chan_num; i++) {
|
||||
short flag, adrcode;
|
||||
|
||||
/* get adrcode
|
||||
* - certain adrcodes (for MTEX channels need special offsets) // BAD CRUFT!!!
|
||||
*/
|
||||
adrcode= ks->adrcodes[i];
|
||||
if (ELEM3(ks->blocktype, ID_MA, ID_LA, ID_WO)) {
|
||||
switch (adrcode) {
|
||||
case MAP_OFS_X: case MAP_OFS_Y: case MAP_OFS_Z:
|
||||
case MAP_SIZE_X: case MAP_SIZE_Y: case MAP_SIZE_Z:
|
||||
case MAP_R: case MAP_G: case MAP_B: case MAP_DVAR:
|
||||
case MAP_COLF: case MAP_NORF: case MAP_VARF: case MAP_DISP:
|
||||
adrcode += cks->map;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* insert mode or delete mode */
|
||||
if (mode == COMMONKEY_MODE_DELETE) {
|
||||
/* local flags only add on to global flags */
|
||||
flag = 0;
|
||||
|
||||
/* delete keyframe */
|
||||
success += deletekey(cks->id, ks->blocktype, cks->actname, cks->constname, adrcode, flag);
|
||||
}
|
||||
else {
|
||||
/* local flags only add on to global flags */
|
||||
flag = ks->flag;
|
||||
if (IS_AUTOKEY_FLAG(AUTOMATKEY)) flag |= INSERTKEY_MATRIX;
|
||||
if (IS_AUTOKEY_FLAG(INSERTNEEDED)) flag |= INSERTKEY_NEEDED;
|
||||
// if (IS_AUTOKEY_MODE(EDITKEYS)) flag |= INSERTKEY_REPLACE;
|
||||
|
||||
/* insert keyframe */
|
||||
success += insertkey(cks->id, ks->blocktype, cks->actname, cks->constname, adrcode, flag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* special handling for some key-sources */
|
||||
if (success) {
|
||||
/* set pose recalc-paths flag */
|
||||
if (cks->pchan) {
|
||||
Object *ob= (Object *)cks->id;
|
||||
bPoseChannel *pchan= cks->pchan;
|
||||
|
||||
/* set flag to trigger path recalc */
|
||||
if (pchan->path)
|
||||
ob->pose->flag |= POSE_RECALCPATHS;
|
||||
|
||||
/* clear unkeyed flag (it doesn't matter if it's set or not) */
|
||||
if (pchan->bone)
|
||||
pchan->bone->flag &= ~BONE_UNKEYED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* apply post-keying flushes for this data sources */
|
||||
commonkey_context_finish(&dsources);
|
||||
ksc->lastused= ks;
|
||||
|
||||
/* free temp data */
|
||||
BLI_freelistN(&dsources);
|
||||
|
||||
/* undo pushes */
|
||||
if (mode == COMMONKEY_MODE_DELETE)
|
||||
BLI_snprintf(buf, 64, "Delete %s Key", ks->name);
|
||||
else
|
||||
BLI_snprintf(buf, 64, "Insert %s Key", ks->name);
|
||||
BIF_undo_push(buf);
|
||||
|
||||
/* queue updates for contexts */
|
||||
commonkey_context_refresh();
|
||||
}
|
||||
|
||||
/* ---- */
|
||||
|
||||
/* used to insert keyframes from any view */
|
||||
void common_insertkey (void)
|
||||
{
|
||||
common_modifykey(COMMONKEY_MODE_INSERT);
|
||||
}
|
||||
|
||||
/* used to insert keyframes from any view */
|
||||
void common_deletekey (void)
|
||||
{
|
||||
common_modifykey(COMMONKEY_MODE_DELETE);
|
||||
}
|
||||
|
||||
/* ************************************************** */
|
||||
Reference in New Issue
Block a user