Cleanup: remove unused files
This commit is contained in:
@@ -1,391 +0,0 @@
|
||||
/*
|
||||
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "AnimationCurveCache.h"
|
||||
|
||||
extern "C" {
|
||||
#include "BKE_action.h"
|
||||
#include "BLI_listbase.h"
|
||||
}
|
||||
|
||||
AnimationCurveCache::AnimationCurveCache(bContext *C):
|
||||
mContext(C)
|
||||
{
|
||||
}
|
||||
|
||||
AnimationCurveCache::~AnimationCurveCache()
|
||||
{
|
||||
clear_cache();
|
||||
}
|
||||
|
||||
void AnimationCurveCache::clear_cache()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AnimationCurveCache::clear_cache(Object *ob)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AnimationCurveCache::create_curves(Object *ob)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AnimationCurveCache::addObject(Object *ob)
|
||||
{
|
||||
cached_objects.push_back(ob);
|
||||
}
|
||||
|
||||
bool AnimationCurveCache::bone_matrix_local_get(Object *ob, Bone *bone, float(&mat)[4][4], bool for_opensim)
|
||||
{
|
||||
|
||||
/* Ok, lets be super cautious and check if the bone exists */
|
||||
bPose *pose = ob->pose;
|
||||
bPoseChannel *pchan = BKE_pose_channel_find_name(pose, bone->name);
|
||||
if (!pchan) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bAction *action = bc_getSceneObjectAction(ob);
|
||||
bPoseChannel *parchan = pchan->parent;
|
||||
enable_fcurves(action, bone->name);
|
||||
float ipar[4][4];
|
||||
|
||||
if (bone->parent) {
|
||||
invert_m4_m4(ipar, parchan->pose_mat);
|
||||
mul_m4_m4m4(mat, ipar, pchan->pose_mat);
|
||||
}
|
||||
else
|
||||
copy_m4_m4(mat, pchan->pose_mat);
|
||||
|
||||
/* OPEN_SIM_COMPATIBILITY
|
||||
* AFAIK animation to second life is via BVH, but no
|
||||
* reason to not have the collada-animation be correct
|
||||
*/
|
||||
if (for_opensim) {
|
||||
float temp[4][4];
|
||||
copy_m4_m4(temp, bone->arm_mat);
|
||||
temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
|
||||
invert_m4(temp);
|
||||
|
||||
mul_m4_m4m4(mat, mat, temp);
|
||||
|
||||
if (bone->parent) {
|
||||
copy_m4_m4(temp, bone->parent->arm_mat);
|
||||
temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
|
||||
|
||||
mul_m4_m4m4(mat, temp, mat);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AnimationCurveCache::sampleMain(Scene *scene, BC_export_transformation_type atm_type, bool for_opensim)
|
||||
{
|
||||
std::map<int, std::vector<SamplePoint>>::iterator frame;
|
||||
for (frame = sample_frames.begin(); frame != sample_frames.end(); frame++) {
|
||||
int frame_index = frame->first;
|
||||
std::vector<SamplePoint> sample_points = frame->second;
|
||||
|
||||
bc_update_scene(mContext, scene, frame_index);
|
||||
|
||||
for (int spi = 0; spi < sample_points.size(); spi++) {
|
||||
SamplePoint &point = sample_points[spi];
|
||||
Object *ob = point.get_object();
|
||||
float mat[4][4];
|
||||
|
||||
if (ob->type == OB_ARMATURE) {
|
||||
/* For Armatures we need to check if this maybe is a pose sample point*/
|
||||
Bone *bone = point.get_bone();
|
||||
if (bone) {
|
||||
if (bone_matrix_local_get(ob, bone, mat, for_opensim)) {
|
||||
point.set_matrix(mat);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* When this SamplePoint is not for a Bone,
|
||||
* then we just store the Object local matrix here
|
||||
*/
|
||||
|
||||
BKE_object_matrix_local_get(ob, mat);
|
||||
point.set_matrix(mat);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* enable fcurves driving a specific bone, disable all the rest
|
||||
* if bone_name = NULL enable all fcurves
|
||||
*/
|
||||
void AnimationCurveCache::enable_fcurves(bAction *act, char *bone_name)
|
||||
{
|
||||
FCurve *fcu;
|
||||
char prefix[200];
|
||||
|
||||
if (bone_name)
|
||||
BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name);
|
||||
|
||||
for (fcu = (FCurve *)act->curves.first; fcu; fcu = fcu->next) {
|
||||
if (bone_name) {
|
||||
if (STREQLEN(fcu->rna_path, prefix, strlen(prefix)))
|
||||
fcu->flag &= ~FCURVE_DISABLED;
|
||||
else
|
||||
fcu->flag |= FCURVE_DISABLED;
|
||||
}
|
||||
else {
|
||||
fcu->flag &= ~FCURVE_DISABLED;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Sample the scene at frames where object fcurves
|
||||
* have defined keys.
|
||||
*/
|
||||
void AnimationCurveCache::sampleScene(Scene *scene, BC_export_transformation_type atm_type, bool for_opensim, bool keyframe_at_end)
|
||||
{
|
||||
create_sample_frames_from_keyframes();
|
||||
sampleMain(scene, atm_type, for_opensim);
|
||||
}
|
||||
|
||||
void AnimationCurveCache::sampleScene(Scene *scene, BC_export_transformation_type atm_type, int sampling_rate, bool for_opensim, bool keyframe_at_end)
|
||||
{
|
||||
create_sample_frames_generated(scene->r.sfra, scene->r.efra, sampling_rate, keyframe_at_end);
|
||||
sampleMain(scene, atm_type, for_opensim);
|
||||
}
|
||||
|
||||
std::vector<FCurve *> *AnimationCurveCache::getSampledCurves(Object *ob)
|
||||
{
|
||||
std::map<Object *, std::vector<FCurve *>>::iterator fcurves;
|
||||
fcurves = cached_curves.find(ob);
|
||||
return (fcurves == cached_curves.end()) ? NULL : &fcurves->second;
|
||||
}
|
||||
|
||||
std::vector<SamplePoint> &AnimationCurveCache::getFrameInfos(int frame_index)
|
||||
{
|
||||
std::map<int, std::vector<SamplePoint>>::iterator frames = sample_frames.find(frame_index);
|
||||
if (frames == sample_frames.end()) {
|
||||
std::vector<SamplePoint> sample_points;
|
||||
sample_frames[frame_index] = sample_points;
|
||||
}
|
||||
return sample_frames[frame_index];
|
||||
}
|
||||
|
||||
|
||||
void AnimationCurveCache::add_sample_point(SamplePoint &point)
|
||||
{
|
||||
int frame_index = point.get_frame();
|
||||
std::vector<SamplePoint> &frame_infos = getFrameInfos(frame_index);
|
||||
frame_infos.push_back(point);
|
||||
}
|
||||
|
||||
/*
|
||||
* loop over all cached objects
|
||||
* loop over all fcurves
|
||||
* record all keyframes
|
||||
*
|
||||
* The vector sample_frames finally contains a list of vectors
|
||||
* where each vector contains a list of SamplePoints which
|
||||
* need to be processed when evaluating the animation.
|
||||
*/
|
||||
void AnimationCurveCache::create_sample_frames_from_keyframes()
|
||||
{
|
||||
sample_frames.clear();
|
||||
for (int i = 0; i < cached_objects.size(); i++) {
|
||||
Object *ob = cached_objects[i];
|
||||
bAction *action = bc_getSceneObjectAction(ob);
|
||||
FCurve *fcu = (FCurve *)action->curves.first;
|
||||
|
||||
for (; fcu; fcu = fcu->next) {
|
||||
for (unsigned int i = 0; i < fcu->totvert; i++) {
|
||||
float f = fcu->bezt[i].vec[1][0];
|
||||
int frame_index = int(f);
|
||||
SamplePoint sample_point(frame_index, ob, fcu, i);
|
||||
add_sample_point(sample_point);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* loop over all cached objects
|
||||
* loop over active action using a stesize of sampling_rate
|
||||
* record all frames
|
||||
*
|
||||
* The vector sample_frames finally contains a list of vectors
|
||||
* where each vector contains a list of SamplePoints which
|
||||
* need to be processed when evaluating the animation.
|
||||
* Note: The FCurves of the objects will not be used here.
|
||||
*/
|
||||
void AnimationCurveCache::create_sample_frames_generated(float sfra, float efra, int sampling_rate, int keyframe_at_end)
|
||||
{
|
||||
sample_frames.clear();
|
||||
|
||||
for (int i = 0; i < cached_objects.size(); i++) {
|
||||
|
||||
Object *ob = cached_objects[i];
|
||||
float f = sfra;
|
||||
|
||||
do {
|
||||
int frame_index = int(f);
|
||||
SamplePoint sample_point(frame_index, ob);
|
||||
add_sample_point(sample_point);
|
||||
|
||||
/* Depending on the Object type add more sample points here
|
||||
*/
|
||||
|
||||
if (ob && ob->type == OB_ARMATURE) {
|
||||
LISTBASE_FOREACH(bPoseChannel *, pchan, &ob->pose->chanbase) {
|
||||
SamplePoint point(frame_index, ob, pchan->bone);
|
||||
add_sample_point(sample_point);
|
||||
}
|
||||
}
|
||||
|
||||
if (f == efra)
|
||||
break;
|
||||
f += sampling_rate;
|
||||
if (f > efra)
|
||||
if (keyframe_at_end)
|
||||
f = efra; // make sure the last frame is always exported
|
||||
else
|
||||
break;
|
||||
} while (true);
|
||||
}
|
||||
}
|
||||
|
||||
Matrix::Matrix()
|
||||
{
|
||||
unit_m4(matrix);
|
||||
}
|
||||
|
||||
Matrix::Matrix(float (&mat)[4][4])
|
||||
{
|
||||
set_matrix(mat);
|
||||
}
|
||||
|
||||
void Matrix::set_matrix(float(&mat)[4][4])
|
||||
{
|
||||
copy_m4_m4(matrix, mat);
|
||||
}
|
||||
|
||||
void Matrix::set_matrix(Matrix &mat)
|
||||
{
|
||||
copy_m4_m4(matrix, mat.matrix);
|
||||
}
|
||||
|
||||
void Matrix::get_matrix(float(&mat)[4][4])
|
||||
{
|
||||
copy_m4_m4(mat, matrix);
|
||||
}
|
||||
|
||||
SamplePoint::SamplePoint(int frame, Object *ob)
|
||||
{
|
||||
this->frame = frame;
|
||||
this->fcu = NULL;
|
||||
this->ob = ob;
|
||||
this->pose_bone = NULL;
|
||||
this->index = -1;
|
||||
}
|
||||
|
||||
SamplePoint::SamplePoint(int frame, Object *ob, FCurve *fcu, int index)
|
||||
{
|
||||
this->frame = frame;
|
||||
this->fcu = fcu;
|
||||
this->ob = ob;
|
||||
this->pose_bone = NULL;
|
||||
this->index = index;
|
||||
this->path = std::string(fcu->rna_path);
|
||||
|
||||
/* Further elaborate on what this Fcurve is doing by checking
|
||||
* its rna_path
|
||||
*/
|
||||
|
||||
if (ob && ob->type == OB_ARMATURE) {
|
||||
char *boneName = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
|
||||
bPose *pose = ob->pose;
|
||||
if (boneName) {
|
||||
bPoseChannel *pchan = BKE_pose_channel_find_name(pose, boneName);
|
||||
this->pose_bone = pchan->bone;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SamplePoint::SamplePoint(int frame, Object *ob, Bone *bone)
|
||||
{
|
||||
this->frame = frame;
|
||||
this->fcu = NULL;
|
||||
this->ob = ob;
|
||||
this->pose_bone = bone;
|
||||
this->index = -1;
|
||||
this->path = "pose.bones[\"" + id_name(bone) + "\"].matrix";
|
||||
}
|
||||
|
||||
Matrix &SamplePoint::get_matrix()
|
||||
{
|
||||
return matrix;
|
||||
}
|
||||
|
||||
void SamplePoint::set_matrix(Matrix &mat)
|
||||
{
|
||||
this->matrix.set_matrix(mat);
|
||||
}
|
||||
|
||||
void SamplePoint::set_matrix(float(&mat)[4][4])
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Object *SamplePoint::get_object()
|
||||
{
|
||||
return this->ob;
|
||||
}
|
||||
|
||||
Bone *SamplePoint::get_bone()
|
||||
{
|
||||
return this->pose_bone;
|
||||
}
|
||||
|
||||
FCurve *SamplePoint::get_fcurve()
|
||||
{
|
||||
return this->fcu;
|
||||
}
|
||||
|
||||
int SamplePoint::get_frame()
|
||||
{
|
||||
return this->frame;
|
||||
}
|
||||
|
||||
int SamplePoint::get_fcurve_index()
|
||||
{
|
||||
return this->index;
|
||||
}
|
||||
|
||||
std::string &SamplePoint::get_path()
|
||||
{
|
||||
return path;
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __ANIMATION_CURVE_CACHE_H__
|
||||
#define __ANIMATION_CURVE_CACHE_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <algorithm> // std::find
|
||||
|
||||
#include "exportSettings.h"
|
||||
#include "collada_utils.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_anim_types.h"
|
||||
}
|
||||
|
||||
class Matrix {
|
||||
private:
|
||||
float matrix[4][4];
|
||||
public:
|
||||
Matrix();
|
||||
Matrix(float (&mat)[4][4]);
|
||||
void set_matrix(float (&mat)[4][4]);
|
||||
void set_matrix(Matrix &mat);
|
||||
void get_matrix(float (&mat)[4][4]);
|
||||
};
|
||||
|
||||
class SamplePoint {
|
||||
|
||||
private:
|
||||
|
||||
Object * ob;
|
||||
Bone *pose_bone;
|
||||
FCurve *fcu;
|
||||
int frame; /* frame in timeline (not sure if we actually should store a float here) */
|
||||
int index; /* Keyframe index in fcurve (makes sense only when fcu is also set) */
|
||||
std::string path; /* Do not mixup with rna_path. It is used for different purposes! */
|
||||
|
||||
Matrix matrix; /* Local matrix, by default unit matrix, will be set when sampling */
|
||||
|
||||
public:
|
||||
|
||||
SamplePoint(int frame, Object *ob);
|
||||
SamplePoint(int frame, Object *ob, FCurve *fcu, int index);
|
||||
SamplePoint(int frame, Object *ob, Bone *bone);
|
||||
|
||||
Object *get_object();
|
||||
Bone *get_bone();
|
||||
FCurve *get_fcurve();
|
||||
int get_frame();
|
||||
int get_fcurve_index();
|
||||
Matrix &get_matrix();
|
||||
std::string &get_path();
|
||||
|
||||
void set_matrix(Matrix &matrix);
|
||||
void set_matrix(float(&mat)[4][4]);
|
||||
};
|
||||
|
||||
|
||||
class AnimationCurveCache {
|
||||
private:
|
||||
void clear_cache(); // remove all sampled FCurves
|
||||
void clear_cache(Object *ob); //remove sampled FCurves for single object
|
||||
void create_curves(Object *ob);
|
||||
|
||||
std::vector<Object *> cached_objects; // list of objects for caching
|
||||
std::map<Object *, std::vector<FCurve *>> cached_curves; //map of cached FCurves
|
||||
std::map<int, std::vector<SamplePoint>> sample_frames; // list of frames where objects need to be sampled
|
||||
|
||||
std::vector<SamplePoint> &getFrameInfos(int frame_index);
|
||||
void add_sample_point(SamplePoint &point);
|
||||
void enable_fcurves(bAction *act, char *bone_name);
|
||||
bool bone_matrix_local_get(Object *ob, Bone *bone, float (&mat)[4][4], bool for_opensim);
|
||||
|
||||
bContext *mContext;
|
||||
|
||||
public:
|
||||
|
||||
AnimationCurveCache(bContext *C);
|
||||
~AnimationCurveCache();
|
||||
|
||||
void addObject(Object *obj);
|
||||
|
||||
void sampleMain(Scene *scene,
|
||||
BC_export_transformation_type atm_type,
|
||||
bool for_opensim);
|
||||
|
||||
void sampleScene(Scene *scene,
|
||||
BC_export_transformation_type atm_type,
|
||||
bool for_opensim,
|
||||
bool keyframe_at_end = true); // use keys from FCurves, use timeline boundaries
|
||||
|
||||
void sampleScene(Scene *scene,
|
||||
BC_export_transformation_type atm_type,
|
||||
int sampling_rate, bool for_opensim,
|
||||
bool keyframe_at_end = true ); // generate keyframes for frames use timeline boundaries
|
||||
|
||||
std::vector<FCurve *> *getSampledCurves(Object *ob);
|
||||
|
||||
void create_sample_frames_from_keyframes();
|
||||
void create_sample_frames_generated(float sfra, float efra, int sampling_rate, int keyframe_at_end);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,2644 +0,0 @@
|
||||
/*
|
||||
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contributor(s): Martin Poirier
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
* autoarmature.c: Interface for automagically manipulating armature (retarget, created, ...)
|
||||
*/
|
||||
|
||||
/** \file blender/editors/armature/editarmature_retarget.c
|
||||
* \ingroup edarmature
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "PIL_time.h"
|
||||
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_math.h"
|
||||
|
||||
#include "BKE_constraint.h"
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_main.h"
|
||||
|
||||
#include "ED_armature.h"
|
||||
#include "ED_undo.h"
|
||||
|
||||
#include "BIF_retarget.h"
|
||||
|
||||
#include "armature_intern.h"
|
||||
|
||||
/************ RIG RETARGET DATA STRUCTURES ***************/
|
||||
|
||||
typedef struct MemoNode {
|
||||
float weight;
|
||||
int next;
|
||||
} MemoNode;
|
||||
|
||||
typedef struct RetargetParam {
|
||||
RigGraph *rigg;
|
||||
RigArc *iarc;
|
||||
RigNode *inode_start;
|
||||
bContext *context;
|
||||
} RetargetParam;
|
||||
|
||||
typedef enum {
|
||||
RETARGET_LENGTH,
|
||||
RETARGET_AGGRESSIVE
|
||||
} RetargetMode;
|
||||
|
||||
typedef enum {
|
||||
METHOD_BRUTE_FORCE = 0,
|
||||
METHOD_MEMOIZE = 1
|
||||
} RetargetMethod;
|
||||
|
||||
typedef enum {
|
||||
ARC_FREE = 0,
|
||||
ARC_TAKEN = 1,
|
||||
ARC_USED = 2
|
||||
} ArcUsageFlags;
|
||||
|
||||
static RigGraph *GLOBAL_RIGG = NULL;
|
||||
|
||||
/*******************************************************************************************************/
|
||||
|
||||
void exec_retargetArctoArc(TaskPool * __restrict pool, void *taskdata, int threadid);
|
||||
|
||||
static void RIG_calculateEdgeAngles(RigEdge *edge_first, RigEdge *edge_second);
|
||||
float rollBoneByQuat(EditBone *bone, float old_up_axis[3], float qrot[4]);
|
||||
|
||||
/* two levels */
|
||||
#define SHAPE_LEVELS (SHAPE_RADIX * SHAPE_RADIX)
|
||||
|
||||
/*********************************** EDITBONE UTILS ****************************************************/
|
||||
|
||||
static int countEditBoneChildren(ListBase *list, EditBone *parent)
|
||||
{
|
||||
EditBone *ebone;
|
||||
int count = 0;
|
||||
|
||||
for (ebone = list->first; ebone; ebone = ebone->next) {
|
||||
if (ebone->parent == parent) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static EditBone *nextEditBoneChild(ListBase *list, EditBone *parent, int n)
|
||||
{
|
||||
EditBone *ebone;
|
||||
|
||||
for (ebone = list->first; ebone; ebone = ebone->next) {
|
||||
if (ebone->parent == parent) {
|
||||
if (n == 0) {
|
||||
return ebone;
|
||||
}
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void getEditBoneRollUpAxis(EditBone *bone, float roll, float up_axis[3])
|
||||
{
|
||||
float mat[3][3], nor[3];
|
||||
|
||||
sub_v3_v3v3(nor, bone->tail, bone->head);
|
||||
|
||||
vec_roll_to_mat3(nor, roll, mat);
|
||||
copy_v3_v3(up_axis, mat[2]);
|
||||
}
|
||||
|
||||
static float rollBoneByQuatAligned(EditBone *bone, float old_up_axis[3], float qrot[4], float qroll[4], float aligned_axis[3])
|
||||
{
|
||||
float nor[3], new_up_axis[3], x_axis[3], z_axis[3];
|
||||
|
||||
copy_v3_v3(new_up_axis, old_up_axis);
|
||||
mul_qt_v3(qrot, new_up_axis);
|
||||
|
||||
sub_v3_v3v3(nor, bone->tail, bone->head);
|
||||
|
||||
cross_v3_v3v3(x_axis, nor, aligned_axis);
|
||||
cross_v3_v3v3(z_axis, x_axis, nor);
|
||||
|
||||
normalize_v3(new_up_axis);
|
||||
normalize_v3(x_axis);
|
||||
normalize_v3(z_axis);
|
||||
|
||||
if (dot_v3v3(new_up_axis, x_axis) < 0) {
|
||||
negate_v3(x_axis);
|
||||
}
|
||||
|
||||
if (dot_v3v3(new_up_axis, z_axis) < 0) {
|
||||
negate_v3(z_axis);
|
||||
}
|
||||
|
||||
if (angle_normalized_v3v3(x_axis, new_up_axis) < angle_normalized_v3v3(z_axis, new_up_axis)) {
|
||||
rotation_between_vecs_to_quat(qroll, new_up_axis, x_axis); /* set roll rotation quat */
|
||||
return ED_armature_ebone_roll_to_vector(bone, x_axis, false);
|
||||
}
|
||||
else {
|
||||
rotation_between_vecs_to_quat(qroll, new_up_axis, z_axis); /* set roll rotation quat */
|
||||
return ED_armature_ebone_roll_to_vector(bone, z_axis, false);
|
||||
}
|
||||
}
|
||||
|
||||
static float rollBoneByQuatJoint(RigEdge *edge, RigEdge *previous, float qrot[4], float qroll[4], float up_axis[3])
|
||||
{
|
||||
if (previous == NULL) {
|
||||
/* default to up_axis if no previous */
|
||||
return rollBoneByQuatAligned(edge->bone, edge->up_axis, qrot, qroll, up_axis);
|
||||
}
|
||||
else {
|
||||
float new_up_axis[3];
|
||||
float vec_first[3], vec_second[3], normal[3];
|
||||
|
||||
if (previous->bone) {
|
||||
sub_v3_v3v3(vec_first, previous->bone->tail, previous->bone->head);
|
||||
}
|
||||
else if (previous->prev->bone) {
|
||||
sub_v3_v3v3(vec_first, edge->bone->head, previous->prev->bone->tail);
|
||||
}
|
||||
else {
|
||||
/* default to up_axis if first bone in the chain is an offset */
|
||||
return rollBoneByQuatAligned(edge->bone, edge->up_axis, qrot, qroll, up_axis);
|
||||
}
|
||||
|
||||
sub_v3_v3v3(vec_second, edge->bone->tail, edge->bone->head);
|
||||
|
||||
normalize_v3(vec_first);
|
||||
normalize_v3(vec_second);
|
||||
|
||||
cross_v3_v3v3(normal, vec_first, vec_second);
|
||||
normalize_v3(normal);
|
||||
|
||||
axis_angle_to_quat(qroll, vec_second, edge->up_angle);
|
||||
|
||||
mul_qt_v3(qroll, normal);
|
||||
|
||||
copy_v3_v3(new_up_axis, edge->up_axis);
|
||||
mul_qt_v3(qrot, new_up_axis);
|
||||
|
||||
normalize_v3(new_up_axis);
|
||||
|
||||
/* real qroll between normal and up_axis */
|
||||
rotation_between_vecs_to_quat(qroll, new_up_axis, normal);
|
||||
|
||||
return ED_armature_ebone_roll_to_vector(edge->bone, normal, false);
|
||||
}
|
||||
}
|
||||
|
||||
float rollBoneByQuat(EditBone *bone, float old_up_axis[3], float qrot[4])
|
||||
{
|
||||
float new_up_axis[3];
|
||||
|
||||
copy_v3_v3(new_up_axis, old_up_axis);
|
||||
mul_qt_v3(qrot, new_up_axis);
|
||||
|
||||
return ED_armature_ebone_roll_to_vector(bone, new_up_axis, false);
|
||||
}
|
||||
|
||||
/************************************ DESTRUCTORS ******************************************************/
|
||||
|
||||
static void RIG_freeRigArc(BArc *arc)
|
||||
{
|
||||
BLI_freelistN(&((RigArc *)arc)->edges);
|
||||
}
|
||||
|
||||
void RIG_freeRigGraph(BGraph *rg)
|
||||
{
|
||||
RigGraph *rigg = (RigGraph *)rg;
|
||||
BNode *node;
|
||||
BArc *arc;
|
||||
|
||||
BLI_task_pool_free(rigg->task_pool);
|
||||
BLI_task_scheduler_free(rigg->task_scheduler);
|
||||
|
||||
if (rigg->link_mesh) {
|
||||
REEB_freeGraph(rigg->link_mesh);
|
||||
}
|
||||
|
||||
for (arc = rg->arcs.first; arc; arc = arc->next) {
|
||||
RIG_freeRigArc(arc);
|
||||
}
|
||||
BLI_freelistN(&rg->arcs);
|
||||
|
||||
for (node = rg->nodes.first; node; node = node->next) {
|
||||
BLI_freeNode(rg, (BNode *)node);
|
||||
}
|
||||
BLI_freelistN(&rg->nodes);
|
||||
|
||||
BLI_freelistN(&rigg->controls);
|
||||
|
||||
BLI_ghash_free(rigg->bones_map, NULL, NULL);
|
||||
BLI_ghash_free(rigg->controls_map, NULL, NULL);
|
||||
|
||||
if (rigg->flag & RIG_FREE_BONELIST) {
|
||||
BLI_freelistN(rigg->editbones);
|
||||
MEM_freeN(rigg->editbones);
|
||||
}
|
||||
|
||||
MEM_freeN(rg);
|
||||
}
|
||||
|
||||
/************************************* ALLOCATORS ******************************************************/
|
||||
|
||||
static RigGraph *newRigGraph(void)
|
||||
{
|
||||
RigGraph *rg;
|
||||
int totthread;
|
||||
|
||||
rg = MEM_callocN(sizeof(RigGraph), "rig graph");
|
||||
|
||||
rg->head = NULL;
|
||||
|
||||
rg->bones_map = BLI_ghash_str_new("newRigGraph bones gh");
|
||||
rg->controls_map = BLI_ghash_str_new("newRigGraph cont gh");
|
||||
|
||||
rg->free_arc = RIG_freeRigArc;
|
||||
rg->free_node = NULL;
|
||||
|
||||
#ifdef USE_THREADS
|
||||
totthread = TASK_SCHEDULER_AUTO_THREADS;
|
||||
#else
|
||||
totthread = TASK_SCHEDULER_SINGLE_THREAD;
|
||||
#endif
|
||||
|
||||
rg->task_scheduler = BLI_task_scheduler_create(totthread);
|
||||
rg->task_pool = BLI_task_pool_create(rg->task_scheduler, NULL);
|
||||
|
||||
return rg;
|
||||
}
|
||||
|
||||
static RigArc *newRigArc(RigGraph *rg)
|
||||
{
|
||||
RigArc *arc;
|
||||
|
||||
arc = MEM_callocN(sizeof(RigArc), "rig arc");
|
||||
arc->count = 0;
|
||||
BLI_addtail(&rg->arcs, arc);
|
||||
|
||||
return arc;
|
||||
}
|
||||
|
||||
static RigControl *newRigControl(RigGraph *rg)
|
||||
{
|
||||
RigControl *ctrl;
|
||||
|
||||
ctrl = MEM_callocN(sizeof(RigControl), "rig control");
|
||||
|
||||
BLI_addtail(&rg->controls, ctrl);
|
||||
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
static RigNode *newRigNodeHead(RigGraph *rg, RigArc *arc, float p[3])
|
||||
{
|
||||
RigNode *node;
|
||||
node = MEM_callocN(sizeof(RigNode), "rig node");
|
||||
BLI_addtail(&rg->nodes, node);
|
||||
|
||||
copy_v3_v3(node->p, p);
|
||||
node->degree = 1;
|
||||
node->arcs = NULL;
|
||||
|
||||
arc->head = node;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static void addRigNodeHead(RigGraph *UNUSED(rg), RigArc *arc, RigNode *node)
|
||||
{
|
||||
node->degree++;
|
||||
|
||||
arc->head = node;
|
||||
}
|
||||
|
||||
static RigNode *newRigNode(RigGraph *rg, float p[3])
|
||||
{
|
||||
RigNode *node;
|
||||
node = MEM_callocN(sizeof(RigNode), "rig node");
|
||||
BLI_addtail(&rg->nodes, node);
|
||||
|
||||
copy_v3_v3(node->p, p);
|
||||
node->degree = 0;
|
||||
node->arcs = NULL;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static RigNode *newRigNodeTail(RigGraph *rg, RigArc *arc, float p[3])
|
||||
{
|
||||
RigNode *node = newRigNode(rg, p);
|
||||
|
||||
node->degree = 1;
|
||||
arc->tail = node;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static void RIG_appendEdgeToArc(RigArc *arc, RigEdge *edge)
|
||||
{
|
||||
BLI_addtail(&arc->edges, edge);
|
||||
|
||||
if (edge->prev == NULL) {
|
||||
copy_v3_v3(edge->head, arc->head->p);
|
||||
}
|
||||
else {
|
||||
RigEdge *last_edge = edge->prev;
|
||||
copy_v3_v3(edge->head, last_edge->tail);
|
||||
RIG_calculateEdgeAngles(last_edge, edge);
|
||||
}
|
||||
|
||||
edge->length = len_v3v3(edge->head, edge->tail);
|
||||
|
||||
arc->length += edge->length;
|
||||
|
||||
arc->count += 1;
|
||||
}
|
||||
|
||||
static void RIG_addEdgeToArc(RigArc *arc, float tail[3], EditBone *bone)
|
||||
{
|
||||
RigEdge *edge;
|
||||
|
||||
edge = MEM_callocN(sizeof(RigEdge), "rig edge");
|
||||
|
||||
copy_v3_v3(edge->tail, tail);
|
||||
edge->bone = bone;
|
||||
|
||||
if (bone) {
|
||||
getEditBoneRollUpAxis(bone, bone->roll, edge->up_axis);
|
||||
}
|
||||
|
||||
RIG_appendEdgeToArc(arc, edge);
|
||||
}
|
||||
/************************************** CLONING TEMPLATES **********************************************/
|
||||
|
||||
static void renameTemplateBone(char *name, char *template_name, ListBase *editbones, char *side_string, char *num_string)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0, j = 0; i < (MAXBONENAME - 1) && j < (MAXBONENAME - 1) && template_name[i] != '\0'; i++) {
|
||||
if (template_name[i] == '&') {
|
||||
if (template_name[i + 1] == 'S' || template_name[i + 1] == 's') {
|
||||
j += BLI_strncpy_rlen(name + j, side_string, MAXBONENAME);
|
||||
i++;
|
||||
}
|
||||
else if (template_name[i + 1] == 'N' || template_name[i + 1] == 'n') {
|
||||
j += BLI_strncpy_rlen(name + j, num_string, MAXBONENAME);
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
name[j] = template_name[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
name[j] = template_name[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
name[j] = '\0';
|
||||
|
||||
ED_armature_ebone_unique_name(editbones, name, NULL);
|
||||
}
|
||||
|
||||
static RigControl *cloneControl(RigGraph *rg, RigGraph *src_rg, RigControl *src_ctrl, GHash *ptr_hash, char *side_string, char *num_string)
|
||||
{
|
||||
RigControl *ctrl;
|
||||
char name[MAXBONENAME];
|
||||
|
||||
ctrl = newRigControl(rg);
|
||||
|
||||
copy_v3_v3(ctrl->head, src_ctrl->head);
|
||||
copy_v3_v3(ctrl->tail, src_ctrl->tail);
|
||||
copy_v3_v3(ctrl->up_axis, src_ctrl->up_axis);
|
||||
copy_v3_v3(ctrl->offset, src_ctrl->offset);
|
||||
|
||||
ctrl->tail_mode = src_ctrl->tail_mode;
|
||||
ctrl->flag = src_ctrl->flag;
|
||||
|
||||
renameTemplateBone(name, src_ctrl->bone->name, rg->editbones, side_string, num_string);
|
||||
ctrl->bone = duplicateEditBoneObjects(src_ctrl->bone, name, rg->editbones, src_rg->ob, rg->ob);
|
||||
ctrl->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
|
||||
BLI_ghash_insert(ptr_hash, src_ctrl->bone, ctrl->bone);
|
||||
|
||||
ctrl->link = src_ctrl->link;
|
||||
ctrl->link_tail = src_ctrl->link_tail;
|
||||
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
static RigArc *cloneArc(RigGraph *rg, RigGraph *src_rg, RigArc *src_arc, GHash *ptr_hash, char *side_string, char *num_string)
|
||||
{
|
||||
RigEdge *src_edge;
|
||||
RigArc *arc;
|
||||
|
||||
arc = newRigArc(rg);
|
||||
|
||||
arc->head = BLI_ghash_lookup(ptr_hash, src_arc->head);
|
||||
arc->tail = BLI_ghash_lookup(ptr_hash, src_arc->tail);
|
||||
|
||||
arc->head->degree++;
|
||||
arc->tail->degree++;
|
||||
|
||||
arc->length = src_arc->length;
|
||||
|
||||
arc->count = src_arc->count;
|
||||
|
||||
for (src_edge = src_arc->edges.first; src_edge; src_edge = src_edge->next) {
|
||||
RigEdge *edge;
|
||||
|
||||
edge = MEM_callocN(sizeof(RigEdge), "rig edge");
|
||||
|
||||
copy_v3_v3(edge->head, src_edge->head);
|
||||
copy_v3_v3(edge->tail, src_edge->tail);
|
||||
copy_v3_v3(edge->up_axis, src_edge->up_axis);
|
||||
|
||||
edge->length = src_edge->length;
|
||||
edge->angle = src_edge->angle;
|
||||
edge->up_angle = src_edge->up_angle;
|
||||
|
||||
if (src_edge->bone != NULL) {
|
||||
char name[MAXBONENAME];
|
||||
renameTemplateBone(name, src_edge->bone->name, rg->editbones, side_string, num_string);
|
||||
edge->bone = duplicateEditBoneObjects(src_edge->bone, name, rg->editbones, src_rg->ob, rg->ob);
|
||||
edge->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
|
||||
BLI_ghash_insert(ptr_hash, src_edge->bone, edge->bone);
|
||||
}
|
||||
|
||||
BLI_addtail(&arc->edges, edge);
|
||||
}
|
||||
|
||||
return arc;
|
||||
}
|
||||
|
||||
static RigGraph *cloneRigGraph(RigGraph *src, ListBase *editbones, Object *ob, char *side_string, char *num_string)
|
||||
{
|
||||
GHash *ptr_hash;
|
||||
RigNode *node;
|
||||
RigArc *arc;
|
||||
RigControl *ctrl;
|
||||
RigGraph *rg;
|
||||
|
||||
ptr_hash = BLI_ghash_ptr_new("cloneRigGraph gh");
|
||||
|
||||
rg = newRigGraph();
|
||||
|
||||
rg->ob = ob;
|
||||
rg->editbones = editbones;
|
||||
|
||||
preEditBoneDuplicate(rg->editbones); /* prime bones for duplication */
|
||||
preEditBoneDuplicate(src->editbones); /* prime bones for duplication */
|
||||
|
||||
/* Clone nodes */
|
||||
for (node = src->nodes.first; node; node = node->next) {
|
||||
RigNode *cloned_node = newRigNode(rg, node->p);
|
||||
BLI_ghash_insert(ptr_hash, node, cloned_node);
|
||||
}
|
||||
|
||||
rg->head = BLI_ghash_lookup(ptr_hash, src->head);
|
||||
|
||||
/* Clone arcs */
|
||||
for (arc = src->arcs.first; arc; arc = arc->next) {
|
||||
cloneArc(rg, src, arc, ptr_hash, side_string, num_string);
|
||||
}
|
||||
|
||||
/* Clone controls */
|
||||
for (ctrl = src->controls.first; ctrl; ctrl = ctrl->next) {
|
||||
cloneControl(rg, src, ctrl, ptr_hash, side_string, num_string);
|
||||
}
|
||||
|
||||
/* Relink bones properly */
|
||||
for (arc = rg->arcs.first; arc; arc = arc->next) {
|
||||
RigEdge *edge;
|
||||
|
||||
for (edge = arc->edges.first; edge; edge = edge->next) {
|
||||
if (edge->bone != NULL) {
|
||||
EditBone *bone;
|
||||
|
||||
updateDuplicateSubtargetObjects(edge->bone, src->editbones, src->ob, rg->ob);
|
||||
|
||||
if (edge->bone->parent) {
|
||||
bone = BLI_ghash_lookup(ptr_hash, edge->bone->parent);
|
||||
|
||||
if (bone != NULL) {
|
||||
edge->bone->parent = bone;
|
||||
}
|
||||
else {
|
||||
/* disconnect since parent isn't cloned
|
||||
* this will only happen when cloning from selected bones
|
||||
* */
|
||||
edge->bone->flag &= ~BONE_CONNECTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) {
|
||||
EditBone *bone;
|
||||
|
||||
updateDuplicateSubtargetObjects(ctrl->bone, src->editbones, src->ob, rg->ob);
|
||||
|
||||
if (ctrl->bone->parent) {
|
||||
bone = BLI_ghash_lookup(ptr_hash, ctrl->bone->parent);
|
||||
|
||||
if (bone != NULL) {
|
||||
ctrl->bone->parent = bone;
|
||||
}
|
||||
else {
|
||||
/* disconnect since parent isn't cloned
|
||||
* this will only happen when cloning from selected bones
|
||||
* */
|
||||
ctrl->bone->flag &= ~BONE_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
ctrl->link = BLI_ghash_lookup(ptr_hash, ctrl->link);
|
||||
ctrl->link_tail = BLI_ghash_lookup(ptr_hash, ctrl->link_tail);
|
||||
}
|
||||
|
||||
BLI_ghash_free(ptr_hash, NULL, NULL);
|
||||
|
||||
return rg;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************************************/
|
||||
|
||||
static void RIG_calculateEdgeAngles(RigEdge *edge_first, RigEdge *edge_second)
|
||||
{
|
||||
float vec_first[3], vec_second[3];
|
||||
|
||||
sub_v3_v3v3(vec_first, edge_first->tail, edge_first->head);
|
||||
sub_v3_v3v3(vec_second, edge_second->tail, edge_second->head);
|
||||
|
||||
normalize_v3(vec_first);
|
||||
normalize_v3(vec_second);
|
||||
|
||||
edge_first->angle = angle_normalized_v3v3(vec_first, vec_second);
|
||||
|
||||
if (edge_second->bone != NULL) {
|
||||
float normal[3];
|
||||
|
||||
cross_v3_v3v3(normal, vec_first, vec_second);
|
||||
normalize_v3(normal);
|
||||
|
||||
edge_second->up_angle = angle_normalized_v3v3(normal, edge_second->up_axis);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************ CONTROL BONES ****************************************************/
|
||||
|
||||
static void RIG_addControlBone(RigGraph *rg, EditBone *bone)
|
||||
{
|
||||
RigControl *ctrl = newRigControl(rg);
|
||||
ctrl->bone = bone;
|
||||
copy_v3_v3(ctrl->head, bone->head);
|
||||
copy_v3_v3(ctrl->tail, bone->tail);
|
||||
getEditBoneRollUpAxis(bone, bone->roll, ctrl->up_axis);
|
||||
ctrl->tail_mode = TL_NONE;
|
||||
|
||||
BLI_ghash_insert(rg->controls_map, bone->name, ctrl);
|
||||
}
|
||||
|
||||
static int RIG_parentControl(RigControl *ctrl, EditBone *link)
|
||||
{
|
||||
if (link) {
|
||||
float offset[3];
|
||||
int flag = 0;
|
||||
|
||||
sub_v3_v3v3(offset, ctrl->bone->head, link->head);
|
||||
|
||||
/* if root matches, check for direction too */
|
||||
if (dot_v3v3(offset, offset) < 0.0001f) {
|
||||
float vbone[3], vparent[3];
|
||||
|
||||
flag |= RIG_CTRL_FIT_ROOT;
|
||||
|
||||
sub_v3_v3v3(vbone, ctrl->bone->tail, ctrl->bone->head);
|
||||
sub_v3_v3v3(vparent, link->tail, link->head);
|
||||
|
||||
/* test for opposite direction */
|
||||
if (dot_v3v3(vbone, vparent) > 0) {
|
||||
float nor[3];
|
||||
float len;
|
||||
|
||||
cross_v3_v3v3(nor, vbone, vparent);
|
||||
|
||||
len = dot_v3v3(nor, nor);
|
||||
if (len < 0.0001f) {
|
||||
flag |= RIG_CTRL_FIT_BONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Bail out if old one is automatically better */
|
||||
if (flag < ctrl->flag) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if there's already a link
|
||||
* overwrite only if new link is higher in the chain */
|
||||
if (ctrl->link && flag == ctrl->flag) {
|
||||
EditBone *bone = NULL;
|
||||
|
||||
for (bone = ctrl->link; bone; bone = bone->parent) {
|
||||
/* if link is in the chain, break and use that one */
|
||||
if (bone == link) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* not in chain, don't update link */
|
||||
if (bone == NULL) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ctrl->link = link;
|
||||
ctrl->flag = flag;
|
||||
|
||||
copy_v3_v3(ctrl->offset, offset);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void RIG_reconnectControlBones(RigGraph *rg)
|
||||
{
|
||||
RigControl *ctrl;
|
||||
bool changed = true;
|
||||
|
||||
/* first pass, link to deform bones */
|
||||
for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) {
|
||||
bPoseChannel *pchan;
|
||||
bConstraint *con;
|
||||
int found = 0;
|
||||
|
||||
/* DO SOME MAGIC HERE */
|
||||
for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) {
|
||||
for (con = pchan->constraints.first; con; con = con->next) {
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
||||
ListBase targets = {NULL, NULL};
|
||||
bConstraintTarget *ct;
|
||||
|
||||
/* constraint targets */
|
||||
if (cti && cti->get_constraint_targets) {
|
||||
int target_index;
|
||||
|
||||
cti->get_constraint_targets(con, &targets);
|
||||
|
||||
for (target_index = 0, ct = targets.first; ct; target_index++, ct = ct->next) {
|
||||
if ((ct->tar == rg->ob) && STREQ(ct->subtarget, ctrl->bone->name)) {
|
||||
/* SET bone link to bone corresponding to pchan */
|
||||
EditBone *link = BLI_ghash_lookup(rg->bones_map, pchan->name);
|
||||
|
||||
/* Making sure bone is in this armature */
|
||||
if (link != NULL) {
|
||||
/* for pole targets, link to parent bone instead, if possible */
|
||||
if (con->type == CONSTRAINT_TYPE_KINEMATIC && target_index == 1) {
|
||||
if (link->parent && BLI_ghash_haskey(rg->bones_map, link->parent->name)) {
|
||||
link = link->parent;
|
||||
}
|
||||
}
|
||||
|
||||
found = RIG_parentControl(ctrl, link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cti->flush_constraint_targets)
|
||||
cti->flush_constraint_targets(con, &targets, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if not found yet, check parent */
|
||||
if (found == 0) {
|
||||
if (ctrl->bone->parent) {
|
||||
/* make sure parent is a deforming bone
|
||||
* NULL if not
|
||||
* */
|
||||
EditBone *link = BLI_ghash_lookup(rg->bones_map, ctrl->bone->parent->name);
|
||||
|
||||
found = RIG_parentControl(ctrl, link);
|
||||
}
|
||||
|
||||
/* check if bone is not superposed on another one */
|
||||
{
|
||||
RigArc *arc;
|
||||
RigArc *best_arc = NULL;
|
||||
EditBone *link = NULL;
|
||||
|
||||
for (arc = rg->arcs.first; arc; arc = arc->next) {
|
||||
RigEdge *edge;
|
||||
for (edge = arc->edges.first; edge; edge = edge->next) {
|
||||
if (edge->bone) {
|
||||
int fit = 0;
|
||||
|
||||
fit = len_v3v3(ctrl->bone->head, edge->bone->head) < 0.0001f;
|
||||
fit = fit || len_v3v3(ctrl->bone->tail, edge->bone->tail) < 0.0001f;
|
||||
|
||||
if (fit) {
|
||||
/* pick the bone on the arc with the lowest symmetry level
|
||||
* means you connect control to the trunk of the skeleton */
|
||||
if (best_arc == NULL || arc->symmetry_level < best_arc->symmetry_level) {
|
||||
best_arc = arc;
|
||||
link = edge->bone;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
found = RIG_parentControl(ctrl, link);
|
||||
}
|
||||
}
|
||||
|
||||
/* if not found yet, check child */
|
||||
if (found == 0) {
|
||||
RigArc *arc;
|
||||
RigArc *best_arc = NULL;
|
||||
EditBone *link = NULL;
|
||||
|
||||
for (arc = rg->arcs.first; arc; arc = arc->next) {
|
||||
RigEdge *edge;
|
||||
for (edge = arc->edges.first; edge; edge = edge->next) {
|
||||
if (edge->bone && edge->bone->parent == ctrl->bone) {
|
||||
/* pick the bone on the arc with the lowest symmetry level
|
||||
* means you connect control to the trunk of the skeleton */
|
||||
if (best_arc == NULL || arc->symmetry_level < best_arc->symmetry_level) {
|
||||
best_arc = arc;
|
||||
link = edge->bone;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
found = RIG_parentControl(ctrl, link);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* second pass, make chains in control bones */
|
||||
while (changed) {
|
||||
changed = false;
|
||||
|
||||
for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) {
|
||||
/* if control is not linked yet */
|
||||
if (ctrl->link == NULL) {
|
||||
bPoseChannel *pchan;
|
||||
bConstraint *con;
|
||||
RigControl *ctrl_parent = NULL;
|
||||
RigControl *ctrl_child;
|
||||
int found = 0;
|
||||
|
||||
if (ctrl->bone->parent) {
|
||||
ctrl_parent = BLI_ghash_lookup(rg->controls_map, ctrl->bone->parent->name);
|
||||
}
|
||||
|
||||
/* check constraints first */
|
||||
|
||||
/* DO SOME MAGIC HERE */
|
||||
for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) {
|
||||
for (con = pchan->constraints.first; con; con = con->next) {
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
||||
ListBase targets = {NULL, NULL};
|
||||
bConstraintTarget *ct;
|
||||
|
||||
/* constraint targets */
|
||||
if (cti && cti->get_constraint_targets) {
|
||||
cti->get_constraint_targets(con, &targets);
|
||||
|
||||
for (ct = targets.first; ct; ct = ct->next) {
|
||||
if ((ct->tar == rg->ob) && STREQ(ct->subtarget, ctrl->bone->name)) {
|
||||
/* SET bone link to ctrl corresponding to pchan */
|
||||
RigControl *link = BLI_ghash_lookup(rg->controls_map, pchan->name);
|
||||
|
||||
/* if owner is a control bone, link with it */
|
||||
if (link && link->link) {
|
||||
RIG_parentControl(ctrl, link->bone);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cti->flush_constraint_targets)
|
||||
cti->flush_constraint_targets(con, &targets, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found == 0) {
|
||||
/* check if parent is already linked */
|
||||
if (ctrl_parent && ctrl_parent->link) {
|
||||
RIG_parentControl(ctrl, ctrl_parent->bone);
|
||||
changed = true;
|
||||
}
|
||||
else {
|
||||
/* check childs */
|
||||
for (ctrl_child = rg->controls.first; ctrl_child; ctrl_child = ctrl_child->next) {
|
||||
/* if a child is linked, link to that one */
|
||||
if (ctrl_child->link && ctrl_child->bone->parent == ctrl->bone) {
|
||||
RIG_parentControl(ctrl, ctrl_child->bone);
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* third pass, link control tails */
|
||||
for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) {
|
||||
/* fit bone already means full match, so skip those */
|
||||
if ((ctrl->flag & RIG_CTRL_FIT_BONE) == 0) {
|
||||
GHashIterator ghi;
|
||||
|
||||
/* look on deform bones first */
|
||||
BLI_ghashIterator_init(&ghi, rg->bones_map);
|
||||
|
||||
for (; !BLI_ghashIterator_done(&ghi); BLI_ghashIterator_step(&ghi)) {
|
||||
EditBone *bone = (EditBone *)BLI_ghashIterator_getValue(&ghi);
|
||||
|
||||
/* don't link with parent */
|
||||
if (bone->parent != ctrl->bone) {
|
||||
if (len_v3v3(ctrl->bone->tail, bone->head) < 0.01f) {
|
||||
ctrl->tail_mode = TL_HEAD;
|
||||
ctrl->link_tail = bone;
|
||||
break;
|
||||
}
|
||||
else if (len_v3v3(ctrl->bone->tail, bone->tail) < 0.01f) {
|
||||
ctrl->tail_mode = TL_TAIL;
|
||||
ctrl->link_tail = bone;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if we haven't found one yet, look in control bones */
|
||||
if (ctrl->tail_mode == TL_NONE) {
|
||||
/* pass */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*******************************************************************************************************/
|
||||
|
||||
static void RIG_joinArcs(RigGraph *rg, RigNode *node, RigArc *joined_arc1, RigArc *joined_arc2)
|
||||
{
|
||||
RigEdge *edge, *next_edge;
|
||||
|
||||
/* ignore cases where joint is at start or end */
|
||||
if (joined_arc1->head == joined_arc2->head || joined_arc1->tail == joined_arc2->tail) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* swap arcs to make sure arc1 is before arc2 */
|
||||
if (joined_arc1->head == joined_arc2->tail) {
|
||||
RigArc *tmp = joined_arc1;
|
||||
joined_arc1 = joined_arc2;
|
||||
joined_arc2 = tmp;
|
||||
}
|
||||
|
||||
for (edge = joined_arc2->edges.first; edge; edge = next_edge) {
|
||||
next_edge = edge->next;
|
||||
|
||||
RIG_appendEdgeToArc(joined_arc1, edge);
|
||||
}
|
||||
|
||||
joined_arc1->tail = joined_arc2->tail;
|
||||
|
||||
BLI_listbase_clear(&joined_arc2->edges);
|
||||
|
||||
BLI_removeArc((BGraph *)rg, (BArc *)joined_arc2);
|
||||
|
||||
BLI_removeNode((BGraph *)rg, (BNode *)node);
|
||||
}
|
||||
|
||||
static void RIG_removeNormalNodes(RigGraph *rg)
|
||||
{
|
||||
RigNode *node, *next_node;
|
||||
|
||||
for (node = rg->nodes.first; node; node = next_node) {
|
||||
next_node = node->next;
|
||||
|
||||
if (node->degree == 2) {
|
||||
RigArc *arc, *joined_arc1 = NULL, *joined_arc2 = NULL;
|
||||
|
||||
for (arc = rg->arcs.first; arc; arc = arc->next) {
|
||||
if (arc->head == node || arc->tail == node) {
|
||||
if (joined_arc1 == NULL) {
|
||||
joined_arc1 = arc;
|
||||
}
|
||||
else {
|
||||
joined_arc2 = arc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RIG_joinArcs(rg, node, joined_arc1, joined_arc2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void RIG_removeUneededOffsets(RigGraph *rg)
|
||||
{
|
||||
RigArc *arc;
|
||||
|
||||
for (arc = rg->arcs.first; arc; arc = arc->next) {
|
||||
RigEdge *first_edge, *last_edge;
|
||||
|
||||
first_edge = arc->edges.first;
|
||||
last_edge = arc->edges.last;
|
||||
|
||||
if (first_edge->bone == NULL) {
|
||||
if (first_edge->bone == NULL && len_v3v3(first_edge->tail, arc->head->p) <= 0.001f) {
|
||||
BLI_remlink(&arc->edges, first_edge);
|
||||
MEM_freeN(first_edge);
|
||||
}
|
||||
else if (arc->head->degree == 1) {
|
||||
RigNode *new_node = (RigNode *)BLI_FindNodeByPosition((BGraph *)rg, first_edge->tail, 0.001f);
|
||||
|
||||
if (new_node) {
|
||||
BLI_remlink(&arc->edges, first_edge);
|
||||
MEM_freeN(first_edge);
|
||||
BLI_replaceNodeInArc((BGraph *)rg, (BArc *)arc, (BNode *)new_node, (BNode *)arc->head);
|
||||
}
|
||||
else {
|
||||
RigEdge *next_edge = first_edge->next;
|
||||
|
||||
if (next_edge) {
|
||||
BLI_remlink(&arc->edges, first_edge);
|
||||
MEM_freeN(first_edge);
|
||||
|
||||
copy_v3_v3(arc->head->p, next_edge->head);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* check if all arc connected start with a null edge */
|
||||
RigArc *other_arc;
|
||||
for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) {
|
||||
if (other_arc != arc) {
|
||||
RigEdge *test_edge;
|
||||
if (other_arc->head == arc->head) {
|
||||
test_edge = other_arc->edges.first;
|
||||
|
||||
if (test_edge->bone != NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (other_arc->tail == arc->head) {
|
||||
test_edge = other_arc->edges.last;
|
||||
|
||||
if (test_edge->bone != NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (other_arc == NULL) {
|
||||
RigNode *new_node = (RigNode *)BLI_FindNodeByPosition((BGraph *)rg, first_edge->tail, 0.001);
|
||||
|
||||
if (new_node) {
|
||||
/* remove null edge in other arcs too */
|
||||
for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) {
|
||||
if (other_arc != arc) {
|
||||
RigEdge *test_edge;
|
||||
if (other_arc->head == arc->head) {
|
||||
BLI_replaceNodeInArc((BGraph *)rg, (BArc *)other_arc, (BNode *)new_node, (BNode *)other_arc->head);
|
||||
test_edge = other_arc->edges.first;
|
||||
BLI_remlink(&other_arc->edges, test_edge);
|
||||
MEM_freeN(test_edge);
|
||||
}
|
||||
else if (other_arc->tail == arc->head) {
|
||||
BLI_replaceNodeInArc((BGraph *)rg, (BArc *)other_arc, (BNode *)new_node, (BNode *)other_arc->tail);
|
||||
test_edge = other_arc->edges.last;
|
||||
BLI_remlink(&other_arc->edges, test_edge);
|
||||
MEM_freeN(test_edge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_remlink(&arc->edges, first_edge);
|
||||
MEM_freeN(first_edge);
|
||||
BLI_replaceNodeInArc((BGraph *)rg, (BArc *)arc, (BNode *)new_node, (BNode *)arc->head);
|
||||
}
|
||||
else {
|
||||
RigEdge *next_edge = first_edge->next;
|
||||
|
||||
if (next_edge) {
|
||||
BLI_remlink(&arc->edges, first_edge);
|
||||
MEM_freeN(first_edge);
|
||||
|
||||
copy_v3_v3(arc->head->p, next_edge->head);
|
||||
|
||||
/* remove null edge in other arcs too */
|
||||
for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) {
|
||||
if (other_arc != arc) {
|
||||
RigEdge *test_edge;
|
||||
if (other_arc->head == arc->head) {
|
||||
test_edge = other_arc->edges.first;
|
||||
BLI_remlink(&other_arc->edges, test_edge);
|
||||
MEM_freeN(test_edge);
|
||||
}
|
||||
else if (other_arc->tail == arc->head) {
|
||||
test_edge = other_arc->edges.last;
|
||||
BLI_remlink(&other_arc->edges, test_edge);
|
||||
MEM_freeN(test_edge);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (last_edge->bone == NULL) {
|
||||
if (len_v3v3(last_edge->head, arc->tail->p) <= 0.001f) {
|
||||
BLI_remlink(&arc->edges, last_edge);
|
||||
MEM_freeN(last_edge);
|
||||
}
|
||||
else if (arc->tail->degree == 1) {
|
||||
RigNode *new_node = (RigNode *)BLI_FindNodeByPosition((BGraph *)rg, last_edge->head, 0.001f);
|
||||
|
||||
if (new_node) {
|
||||
RigEdge *previous_edge = last_edge->prev;
|
||||
|
||||
BLI_remlink(&arc->edges, last_edge);
|
||||
MEM_freeN(last_edge);
|
||||
BLI_replaceNodeInArc((BGraph *)rg, (BArc *)arc, (BNode *)new_node, (BNode *)arc->tail);
|
||||
|
||||
/* set previous angle to 0, since there's no following edges */
|
||||
if (previous_edge) {
|
||||
previous_edge->angle = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
RigEdge *previous_edge = last_edge->prev;
|
||||
|
||||
if (previous_edge) {
|
||||
BLI_remlink(&arc->edges, last_edge);
|
||||
MEM_freeN(last_edge);
|
||||
|
||||
copy_v3_v3(arc->tail->p, previous_edge->tail);
|
||||
previous_edge->angle = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bone, RigNode *starting_node, bool selected)
|
||||
{
|
||||
EditBone *bone, *last_bone = root_bone;
|
||||
RigArc *arc = NULL;
|
||||
int contain_head = 0;
|
||||
|
||||
for (bone = root_bone; bone; bone = nextEditBoneChild(list, bone, 0)) {
|
||||
int nb_children;
|
||||
|
||||
if (selected == 0 || (bone->flag & BONE_SELECTED)) {
|
||||
if ((bone->flag & BONE_NO_DEFORM) == 0) {
|
||||
BLI_ghash_insert(rg->bones_map, bone->name, bone);
|
||||
|
||||
if (arc == NULL) {
|
||||
arc = newRigArc(rg);
|
||||
|
||||
if (starting_node == NULL) {
|
||||
starting_node = newRigNodeHead(rg, arc, root_bone->head);
|
||||
}
|
||||
else {
|
||||
addRigNodeHead(rg, arc, starting_node);
|
||||
}
|
||||
}
|
||||
|
||||
if (bone->parent && (bone->flag & BONE_CONNECTED) == 0) {
|
||||
RIG_addEdgeToArc(arc, bone->head, NULL);
|
||||
}
|
||||
|
||||
RIG_addEdgeToArc(arc, bone->tail, bone);
|
||||
|
||||
last_bone = bone;
|
||||
|
||||
if (STREQ(bone->name, "head")) {
|
||||
contain_head = 1;
|
||||
}
|
||||
}
|
||||
else if ((bone->flag & BONE_EDITMODE_LOCKED) == 0) { /* ignore locked bones */
|
||||
RIG_addControlBone(rg, bone);
|
||||
}
|
||||
}
|
||||
|
||||
nb_children = countEditBoneChildren(list, bone);
|
||||
if (nb_children > 1) {
|
||||
RigNode *end_node = NULL;
|
||||
int i;
|
||||
|
||||
if (arc != NULL) {
|
||||
end_node = newRigNodeTail(rg, arc, bone->tail);
|
||||
}
|
||||
else {
|
||||
end_node = newRigNode(rg, bone->tail);
|
||||
}
|
||||
|
||||
for (i = 0; i < nb_children; i++) {
|
||||
root_bone = nextEditBoneChild(list, bone, i);
|
||||
RIG_arcFromBoneChain(rg, list, root_bone, end_node, selected);
|
||||
}
|
||||
|
||||
/* arc ends here, break */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the loop exited without forking */
|
||||
if (arc != NULL && bone == NULL) {
|
||||
newRigNodeTail(rg, arc, last_bone->tail);
|
||||
}
|
||||
|
||||
if (contain_head) {
|
||||
rg->head = arc->tail;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************************************/
|
||||
static void RIG_findHead(RigGraph *rg)
|
||||
{
|
||||
if (rg->head == NULL) {
|
||||
if (BLI_listbase_is_single(&rg->arcs)) {
|
||||
RigArc *arc = rg->arcs.first;
|
||||
|
||||
rg->head = (RigNode *)arc->head;
|
||||
}
|
||||
else {
|
||||
RigArc *arc;
|
||||
|
||||
for (arc = rg->arcs.first; arc; arc = arc->next) {
|
||||
RigEdge *edge = arc->edges.last;
|
||||
|
||||
if (edge->bone->flag & (BONE_TIPSEL | BONE_SELECTED)) {
|
||||
rg->head = arc->tail;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rg->head == NULL) {
|
||||
rg->head = rg->nodes.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************************************/
|
||||
|
||||
static void RIG_printNode(RigNode *node, const char name[])
|
||||
{
|
||||
printf("%s %p %i <%0.3f, %0.3f, %0.3f>\n", name, (void *)node, node->degree, node->p[0], node->p[1], node->p[2]);
|
||||
|
||||
if (node->symmetry_flag & SYM_TOPOLOGICAL) {
|
||||
if (node->symmetry_flag & SYM_AXIAL)
|
||||
printf("Symmetry AXIAL\n");
|
||||
else if (node->symmetry_flag & SYM_RADIAL)
|
||||
printf("Symmetry RADIAL\n");
|
||||
|
||||
print_v3("symmetry axis", node->symmetry_axis);
|
||||
}
|
||||
}
|
||||
|
||||
void RIG_printArcBones(RigArc *arc)
|
||||
{
|
||||
RigEdge *edge;
|
||||
|
||||
for (edge = arc->edges.first; edge; edge = edge->next) {
|
||||
if (edge->bone)
|
||||
printf("%s ", edge->bone->name);
|
||||
else
|
||||
printf("---- ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void RIG_printCtrl(RigControl *ctrl, char *indent)
|
||||
{
|
||||
char text[128];
|
||||
|
||||
printf("%sBone: %s\n", indent, ctrl->bone->name);
|
||||
printf("%sLink: %s\n", indent, ctrl->link ? ctrl->link->name : "!NONE!");
|
||||
|
||||
BLI_snprintf(text, sizeof(text), "%soffset", indent);
|
||||
print_v3(text, ctrl->offset);
|
||||
|
||||
printf("%sFlag: %i\n", indent, ctrl->flag);
|
||||
}
|
||||
|
||||
static void RIG_printLinkedCtrl(RigGraph *rg, EditBone *bone, int tabs)
|
||||
{
|
||||
RigControl *ctrl;
|
||||
char indent[64];
|
||||
char *s = indent;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < tabs; i++) {
|
||||
s[0] = '\t';
|
||||
s++;
|
||||
}
|
||||
s[0] = 0;
|
||||
|
||||
for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) {
|
||||
if (ctrl->link == bone) {
|
||||
RIG_printCtrl(ctrl, indent);
|
||||
RIG_printLinkedCtrl(rg, ctrl->bone, tabs + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RIG_printArc(RigGraph *rg, RigArc *arc)
|
||||
{
|
||||
RigEdge *edge;
|
||||
|
||||
RIG_printNode((RigNode *)arc->head, "head");
|
||||
|
||||
for (edge = arc->edges.first; edge; edge = edge->next) {
|
||||
printf("\tinner joints %0.3f %0.3f %0.3f\n", edge->tail[0], edge->tail[1], edge->tail[2]);
|
||||
printf("\t\tlength %f\n", edge->length);
|
||||
printf("\t\tangle %f\n", edge->angle * (float)(180 / M_PI));
|
||||
if (edge->bone) {
|
||||
printf("\t\t%s\n", edge->bone->name);
|
||||
RIG_printLinkedCtrl(rg, edge->bone, 3);
|
||||
}
|
||||
}
|
||||
printf("symmetry level: %i flag: %i group %i\n", arc->symmetry_level, arc->symmetry_flag, arc->symmetry_group);
|
||||
|
||||
RIG_printNode((RigNode *)arc->tail, "tail");
|
||||
}
|
||||
|
||||
void RIG_printGraph(RigGraph *rg)
|
||||
{
|
||||
RigArc *arc;
|
||||
|
||||
printf("---- ARCS ----\n");
|
||||
for (arc = rg->arcs.first; arc; arc = arc->next) {
|
||||
RIG_printArc(rg, arc);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (rg->head) {
|
||||
RIG_printNode(rg->head, "HEAD NODE:");
|
||||
}
|
||||
else {
|
||||
printf("HEAD NODE: NONE\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************************************/
|
||||
|
||||
RigGraph *RIG_graphFromArmature(const bContext *C, Object *ob, bArmature *arm)
|
||||
{
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
EditBone *ebone;
|
||||
RigGraph *rg;
|
||||
|
||||
rg = newRigGraph();
|
||||
|
||||
if (obedit == ob) {
|
||||
rg->editbones = ((bArmature *)obedit->data)->edbo;
|
||||
}
|
||||
else {
|
||||
rg->editbones = MEM_callocN(sizeof(ListBase), "EditBones");
|
||||
make_boneList(rg->editbones, &arm->bonebase, NULL);
|
||||
rg->flag |= RIG_FREE_BONELIST;
|
||||
}
|
||||
|
||||
rg->ob = ob;
|
||||
|
||||
/* Do the rotations */
|
||||
for (ebone = rg->editbones->first; ebone; ebone = ebone->next) {
|
||||
if (ebone->parent == NULL) {
|
||||
RIG_arcFromBoneChain(rg, rg->editbones, ebone, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
BLI_removeDoubleNodes((BGraph *)rg, 0.001);
|
||||
|
||||
RIG_removeNormalNodes(rg);
|
||||
|
||||
RIG_removeUneededOffsets(rg);
|
||||
|
||||
BLI_buildAdjacencyList((BGraph *)rg);
|
||||
|
||||
RIG_findHead(rg);
|
||||
|
||||
BLI_markdownSymmetry((BGraph *)rg, (BNode *)rg->head, scene->toolsettings->skgen_symmetry_limit);
|
||||
|
||||
RIG_reconnectControlBones(rg); /* after symmetry, because we use levels to find best match */
|
||||
|
||||
if (BLI_isGraphCyclic((BGraph *)rg)) {
|
||||
printf("armature cyclic\n");
|
||||
}
|
||||
|
||||
return rg;
|
||||
}
|
||||
|
||||
static RigGraph *armatureSelectedToGraph(bContext *C, Object *ob, bArmature *arm)
|
||||
{
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
EditBone *ebone;
|
||||
RigGraph *rg;
|
||||
|
||||
rg = newRigGraph();
|
||||
|
||||
if (obedit == ob) {
|
||||
rg->editbones = arm->edbo;
|
||||
}
|
||||
else {
|
||||
rg->editbones = MEM_callocN(sizeof(ListBase), "EditBones");
|
||||
make_boneList(rg->editbones, &arm->bonebase, NULL);
|
||||
rg->flag |= RIG_FREE_BONELIST;
|
||||
}
|
||||
|
||||
rg->ob = ob;
|
||||
|
||||
/* Do the rotations */
|
||||
for (ebone = rg->editbones->first; ebone; ebone = ebone->next) {
|
||||
if (ebone->parent == NULL) {
|
||||
RIG_arcFromBoneChain(rg, rg->editbones, ebone, NULL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
BLI_removeDoubleNodes((BGraph *)rg, 0.001);
|
||||
|
||||
RIG_removeNormalNodes(rg);
|
||||
|
||||
RIG_removeUneededOffsets(rg);
|
||||
|
||||
BLI_buildAdjacencyList((BGraph *)rg);
|
||||
|
||||
RIG_findHead(rg);
|
||||
|
||||
BLI_markdownSymmetry((BGraph *)rg, (BNode *)rg->head, scene->toolsettings->skgen_symmetry_limit);
|
||||
|
||||
RIG_reconnectControlBones(rg); /* after symmetry, because we use levels to find best match */
|
||||
|
||||
if (BLI_isGraphCyclic((BGraph *)rg)) {
|
||||
printf("armature cyclic\n");
|
||||
}
|
||||
|
||||
return rg;
|
||||
}
|
||||
/************************************ GENERATING *****************************************************/
|
||||
|
||||
#if 0
|
||||
static EditBone *add_editbonetolist(char *name, ListBase *list)
|
||||
{
|
||||
EditBone *bone = MEM_callocN(sizeof(EditBone), "eBone");
|
||||
|
||||
BLI_strncpy(bone->name, name, sizeof(bone->name));
|
||||
ED_armature_ebone_unique_name(list, bone->name, NULL);
|
||||
|
||||
BLI_addtail(list, bone);
|
||||
|
||||
bone->flag |= BONE_TIPSEL;
|
||||
bone->weight = 1.0F;
|
||||
bone->dist = 0.25F;
|
||||
bone->xwidth = 0.1;
|
||||
bone->zwidth = 0.1;
|
||||
bone->rad_head = 0.10;
|
||||
bone->rad_tail = 0.05;
|
||||
bone->segments = 1;
|
||||
bone->layer = 1; //arm->layer;
|
||||
|
||||
/* Bendy-Bone parameters */
|
||||
bone->roll1 = 0.0f;
|
||||
bone->roll2 = 0.0f;
|
||||
bone->curveInX = 0.0f;
|
||||
bone->curveInY = 0.0f;
|
||||
bone->curveOutX = 0.0f;
|
||||
bone->curveOutY = 0.0f;
|
||||
bone->ease1 = 1.0f;
|
||||
bone->ease2 = 1.0f;
|
||||
bone->scaleIn = 1.0f;
|
||||
bone->scaleOut = 1.0f;
|
||||
|
||||
return bone;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0 /* UNUSED */
|
||||
static void generateMissingArcsFromNode(RigGraph *rigg, ReebNode *node, int multi_level_limit)
|
||||
{
|
||||
while (node->multi_level > multi_level_limit && node->link_up)
|
||||
{
|
||||
node = node->link_up;
|
||||
}
|
||||
|
||||
while (node->multi_level < multi_level_limit && node->link_down)
|
||||
{
|
||||
node = node->link_down;
|
||||
}
|
||||
|
||||
if (node->multi_level == multi_level_limit)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < node->degree; i++)
|
||||
{
|
||||
ReebArc *earc = node->arcs[i];
|
||||
|
||||
if (earc->flag == ARC_FREE && earc->head == node)
|
||||
{
|
||||
ReebNode *other = BIF_otherNodeFromIndex(earc, node);
|
||||
|
||||
earc->flag = ARC_USED;
|
||||
|
||||
//generateBonesForArc(rigg, earc, node, other);
|
||||
generateMissingArcsFromNode(rigg, other, multi_level_limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void generateMissingArcs(RigGraph *rigg)
|
||||
{
|
||||
ReebGraph *reebg;
|
||||
int multi_level_limit = 5;
|
||||
|
||||
for (reebg = rigg->link_mesh; reebg; reebg = reebg->link_up)
|
||||
{
|
||||
ReebArc *earc;
|
||||
|
||||
for (earc = reebg->arcs.first; earc; earc = earc->next)
|
||||
{
|
||||
if (earc->flag == ARC_USED)
|
||||
{
|
||||
generateMissingArcsFromNode(rigg, earc->head, multi_level_limit);
|
||||
generateMissingArcsFromNode(rigg, earc->tail, multi_level_limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/************************************ RETARGETTING *****************************************************/
|
||||
|
||||
static void repositionControl(RigGraph *rigg, RigControl *ctrl, float head[3], float tail[3], float qrot[4], float resize);
|
||||
|
||||
static void repositionTailControl(RigGraph *rigg, RigControl *ctrl);
|
||||
|
||||
static void finalizeControl(RigGraph *rigg, RigControl *ctrl, float resize)
|
||||
{
|
||||
if ((ctrl->flag & RIG_CTRL_DONE) == RIG_CTRL_DONE) {
|
||||
RigControl *ctrl_child;
|
||||
|
||||
#if 0
|
||||
printf("CTRL: %s LINK: %s", ctrl->bone->name, ctrl->link->name);
|
||||
|
||||
if (ctrl->link_tail)
|
||||
{
|
||||
printf(" TAIL: %s", ctrl->link_tail->name);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
/* if there was a tail link: apply link, recalc resize factor and qrot */
|
||||
if (ctrl->tail_mode != TL_NONE) {
|
||||
float *tail_vec = NULL;
|
||||
float v1[3], v2[3], qtail[4];
|
||||
|
||||
if (ctrl->tail_mode == TL_TAIL) {
|
||||
tail_vec = ctrl->link_tail->tail;
|
||||
}
|
||||
else if (ctrl->tail_mode == TL_HEAD) {
|
||||
tail_vec = ctrl->link_tail->head;
|
||||
}
|
||||
|
||||
sub_v3_v3v3(v1, ctrl->bone->tail, ctrl->bone->head);
|
||||
sub_v3_v3v3(v2, tail_vec, ctrl->bone->head);
|
||||
|
||||
copy_v3_v3(ctrl->bone->tail, tail_vec);
|
||||
|
||||
rotation_between_vecs_to_quat(qtail, v1, v2);
|
||||
mul_qt_qtqt(ctrl->qrot, qtail, ctrl->qrot);
|
||||
|
||||
resize = len_v3(v2) / len_v3v3(ctrl->head, ctrl->tail);
|
||||
}
|
||||
|
||||
ctrl->bone->roll = rollBoneByQuat(ctrl->bone, ctrl->up_axis, ctrl->qrot);
|
||||
|
||||
/* Cascade to connected control bones */
|
||||
for (ctrl_child = rigg->controls.first; ctrl_child; ctrl_child = ctrl_child->next) {
|
||||
if (ctrl_child->link == ctrl->bone) {
|
||||
repositionControl(rigg, ctrl_child, ctrl->bone->head, ctrl->bone->tail, ctrl->qrot, resize);
|
||||
}
|
||||
if (ctrl_child->link_tail == ctrl->bone) {
|
||||
repositionTailControl(rigg, ctrl_child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void repositionTailControl(RigGraph *rigg, RigControl *ctrl)
|
||||
{
|
||||
ctrl->flag |= RIG_CTRL_TAIL_DONE;
|
||||
|
||||
finalizeControl(rigg, ctrl, 1); /* resize will be recalculated anyway so we don't need it */
|
||||
}
|
||||
|
||||
static void repositionControl(RigGraph *rigg, RigControl *ctrl, float head[3], float UNUSED(tail[3]), float qrot[4], float resize)
|
||||
{
|
||||
float parent_offset[3], tail_offset[3];
|
||||
|
||||
copy_v3_v3(parent_offset, ctrl->offset);
|
||||
mul_v3_fl(parent_offset, resize);
|
||||
mul_qt_v3(qrot, parent_offset);
|
||||
|
||||
add_v3_v3v3(ctrl->bone->head, head, parent_offset);
|
||||
|
||||
ctrl->flag |= RIG_CTRL_HEAD_DONE;
|
||||
|
||||
copy_qt_qt(ctrl->qrot, qrot);
|
||||
|
||||
if (ctrl->tail_mode == TL_NONE) {
|
||||
sub_v3_v3v3(tail_offset, ctrl->tail, ctrl->head);
|
||||
mul_v3_fl(tail_offset, resize);
|
||||
mul_qt_v3(qrot, tail_offset);
|
||||
|
||||
add_v3_v3v3(ctrl->bone->tail, ctrl->bone->head, tail_offset);
|
||||
|
||||
ctrl->flag |= RIG_CTRL_TAIL_DONE;
|
||||
}
|
||||
|
||||
finalizeControl(rigg, ctrl, resize);
|
||||
}
|
||||
|
||||
static void repositionBone(bContext *C, RigGraph *rigg, RigEdge *edge, float vec0[3], float vec1[3], float up_axis[3])
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
EditBone *bone;
|
||||
RigControl *ctrl;
|
||||
float qrot[4], resize;
|
||||
float v1[3], v2[3];
|
||||
float l1, l2;
|
||||
|
||||
bone = edge->bone;
|
||||
|
||||
sub_v3_v3v3(v1, edge->tail, edge->head);
|
||||
sub_v3_v3v3(v2, vec1, vec0);
|
||||
|
||||
l1 = normalize_v3(v1);
|
||||
l2 = normalize_v3(v2);
|
||||
|
||||
resize = l2 / l1;
|
||||
|
||||
rotation_between_vecs_to_quat(qrot, v1, v2);
|
||||
|
||||
copy_v3_v3(bone->head, vec0);
|
||||
copy_v3_v3(bone->tail, vec1);
|
||||
|
||||
if (!is_zero_v3(up_axis)) {
|
||||
float qroll[4];
|
||||
|
||||
if (scene->toolsettings->skgen_retarget_roll == SK_RETARGET_ROLL_VIEW) {
|
||||
bone->roll = rollBoneByQuatAligned(bone, edge->up_axis, qrot, qroll, up_axis);
|
||||
}
|
||||
else if (scene->toolsettings->skgen_retarget_roll == SK_RETARGET_ROLL_JOINT) {
|
||||
bone->roll = rollBoneByQuatJoint(edge, edge->prev, qrot, qroll, up_axis);
|
||||
}
|
||||
else {
|
||||
unit_qt(qroll);
|
||||
}
|
||||
|
||||
mul_qt_qtqt(qrot, qroll, qrot);
|
||||
}
|
||||
else {
|
||||
bone->roll = rollBoneByQuat(bone, edge->up_axis, qrot);
|
||||
}
|
||||
|
||||
for (ctrl = rigg->controls.first; ctrl; ctrl = ctrl->next) {
|
||||
if (ctrl->link == bone) {
|
||||
repositionControl(rigg, ctrl, vec0, vec1, qrot, resize);
|
||||
}
|
||||
if (ctrl->link_tail == bone) {
|
||||
repositionTailControl(rigg, ctrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static RetargetMode detectArcRetargetMode(RigArc *arc);
|
||||
static void retargetArctoArcLength(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start);
|
||||
|
||||
|
||||
static RetargetMode detectArcRetargetMode(RigArc *iarc)
|
||||
{
|
||||
RetargetMode mode = RETARGET_AGGRESSIVE;
|
||||
ReebArc *earc = iarc->link_mesh;
|
||||
RigEdge *edge;
|
||||
int large_angle = 0;
|
||||
float avg_angle = 0;
|
||||
/* float avg_length = 0; */ /* UNUSED */
|
||||
int nb_edges = 0;
|
||||
|
||||
|
||||
for (edge = iarc->edges.first; edge; edge = edge->next) {
|
||||
avg_angle += edge->angle;
|
||||
nb_edges++;
|
||||
}
|
||||
|
||||
avg_angle /= nb_edges - 1; /* -1 because last edge doesn't have an angle */
|
||||
|
||||
/* avg_length = iarc->length / nb_edges; */ /* UNUSED */
|
||||
|
||||
|
||||
if (nb_edges > 2) {
|
||||
for (edge = iarc->edges.first; edge; edge = edge->next) {
|
||||
if (fabsf(edge->angle - avg_angle) > (float)(M_PI / 6)) {
|
||||
large_angle = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (nb_edges == 2 && avg_angle > 0) {
|
||||
large_angle = 1;
|
||||
}
|
||||
|
||||
|
||||
if (large_angle == 0) {
|
||||
mode = RETARGET_LENGTH;
|
||||
}
|
||||
|
||||
if (earc->bcount <= (iarc->count - 1)) {
|
||||
mode = RETARGET_LENGTH;
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
#ifndef USE_THREADS
|
||||
static void printMovesNeeded(int *positions, int nb_positions)
|
||||
{
|
||||
int moves = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nb_positions; i++) {
|
||||
moves += positions[i] - (i + 1);
|
||||
}
|
||||
|
||||
printf("%i moves needed\n", moves);
|
||||
}
|
||||
|
||||
static void printPositions(int *positions, int nb_positions)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nb_positions; i++) {
|
||||
printf("%i ", positions[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#define MAX_COST FLT_MAX /* FIX ME */
|
||||
|
||||
static float costDistance(BArcIterator *iter, float *vec0, float *vec1, int i0, int i1, float distance_weight)
|
||||
{
|
||||
EmbedBucket *bucket = NULL;
|
||||
float max_dist = 0;
|
||||
float v1[3], v2[3], c[3];
|
||||
float v1_inpf;
|
||||
|
||||
if (distance_weight > 0) {
|
||||
sub_v3_v3v3(v1, vec0, vec1);
|
||||
|
||||
v1_inpf = dot_v3v3(v1, v1);
|
||||
|
||||
if (v1_inpf > 0) {
|
||||
int j;
|
||||
for (j = i0 + 1; j < i1 - 1; j++) {
|
||||
float dist;
|
||||
|
||||
bucket = IT_peek(iter, j);
|
||||
|
||||
sub_v3_v3v3(v2, bucket->p, vec1);
|
||||
|
||||
cross_v3_v3v3(c, v1, v2);
|
||||
|
||||
dist = dot_v3v3(c, c) / v1_inpf;
|
||||
|
||||
max_dist = dist > max_dist ? dist : max_dist;
|
||||
}
|
||||
|
||||
return distance_weight * max_dist;
|
||||
}
|
||||
else {
|
||||
return MAX_COST;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static float costAngle(float original_angle, float vec_first[3], float vec_second[3], float angle_weight)
|
||||
{
|
||||
if (angle_weight > 0) {
|
||||
float current_angle;
|
||||
|
||||
if (!is_zero_v3(vec_first) && !is_zero_v3(vec_second)) {
|
||||
current_angle = saacos(dot_v3v3(vec_first, vec_second));
|
||||
|
||||
return angle_weight * fabsf(current_angle - original_angle);
|
||||
}
|
||||
else {
|
||||
return angle_weight * (float)M_PI;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static float costLength(float original_length, float current_length, float length_weight)
|
||||
{
|
||||
if (current_length == 0) {
|
||||
return MAX_COST;
|
||||
}
|
||||
else {
|
||||
float length_ratio = fabsf((current_length - original_length) / original_length);
|
||||
return length_weight * length_ratio * length_ratio;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static float calcCostLengthDistance(BArcIterator *iter, float **vec_cache, RigEdge *edge, float *vec1, float *vec2, int i1, int i2)
|
||||
{
|
||||
float vec[3];
|
||||
float length;
|
||||
|
||||
sub_v3_v3v3(vec, vec2, vec1);
|
||||
length = normalize_v3(vec);
|
||||
|
||||
return costLength(edge->length, length) + costDistance(iter, vec1, vec2, i1, i2);
|
||||
}
|
||||
#endif
|
||||
|
||||
static float calcCostAngleLengthDistance(BArcIterator *iter, float **UNUSED(vec_cache), RigEdge *edge,
|
||||
float *vec0, float *vec1, float *vec2, int i1, int i2,
|
||||
float angle_weight, float length_weight, float distance_weight)
|
||||
{
|
||||
float vec_second[3], vec_first[3];
|
||||
float length2;
|
||||
float new_cost = 0;
|
||||
|
||||
sub_v3_v3v3(vec_second, vec2, vec1);
|
||||
length2 = normalize_v3(vec_second);
|
||||
|
||||
|
||||
/* Angle cost */
|
||||
if (edge->prev) {
|
||||
sub_v3_v3v3(vec_first, vec1, vec0);
|
||||
normalize_v3(vec_first);
|
||||
|
||||
new_cost += costAngle(edge->prev->angle, vec_first, vec_second, angle_weight);
|
||||
}
|
||||
|
||||
/* Length cost */
|
||||
new_cost += costLength(edge->length, length2, length_weight);
|
||||
|
||||
/* Distance cost */
|
||||
new_cost += costDistance(iter, vec1, vec2, i1, i2, distance_weight);
|
||||
|
||||
return new_cost;
|
||||
}
|
||||
|
||||
static int indexMemoNode(int nb_positions, int previous, int current, int joints_left)
|
||||
{
|
||||
return joints_left * nb_positions * nb_positions + current * nb_positions + previous;
|
||||
}
|
||||
|
||||
static void copyMemoPositions(int *positions, MemoNode *table, int nb_positions, int joints_left)
|
||||
{
|
||||
int previous = 0, current = 0;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; joints_left > 0; joints_left--, i++) {
|
||||
MemoNode *node;
|
||||
node = table + indexMemoNode(nb_positions, previous, current, joints_left);
|
||||
|
||||
positions[i] = node->next;
|
||||
|
||||
previous = current;
|
||||
current = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
static MemoNode *solveJoints(MemoNode *table, BArcIterator *iter, float **vec_cache,
|
||||
int nb_joints, int nb_positions, int previous, int current, RigEdge *edge,
|
||||
int joints_left, float angle_weight, float length_weight, float distance_weight)
|
||||
{
|
||||
MemoNode *node;
|
||||
int index = indexMemoNode(nb_positions, previous, current, joints_left);
|
||||
|
||||
node = table + index;
|
||||
|
||||
if (node->weight != 0) {
|
||||
return node;
|
||||
}
|
||||
else if (joints_left == 0) {
|
||||
float *vec0 = vec_cache[previous];
|
||||
float *vec1 = vec_cache[current];
|
||||
float *vec2 = vec_cache[nb_positions + 1];
|
||||
|
||||
node->weight = calcCostAngleLengthDistance(iter, vec_cache, edge, vec0, vec1, vec2, current, iter->length, angle_weight, length_weight, distance_weight);
|
||||
|
||||
return node;
|
||||
}
|
||||
else {
|
||||
MemoNode *min_node = NULL;
|
||||
float *vec0 = vec_cache[previous];
|
||||
float *vec1 = vec_cache[current];
|
||||
float min_weight = 0.0f;
|
||||
int min_next = 0;
|
||||
int next;
|
||||
|
||||
for (next = current + 1; next <= nb_positions - (joints_left - 1); next++) {
|
||||
MemoNode *next_node;
|
||||
float *vec2 = vec_cache[next];
|
||||
float weight = 0.0f;
|
||||
|
||||
/* ADD WEIGHT OF PREVIOUS - CURRENT - NEXT triple */
|
||||
weight = calcCostAngleLengthDistance(iter, vec_cache, edge, vec0, vec1, vec2, current, next, angle_weight, length_weight, distance_weight);
|
||||
|
||||
if (weight >= MAX_COST) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* add node weight */
|
||||
next_node = solveJoints(table, iter, vec_cache, nb_joints, nb_positions, current, next, edge->next, joints_left - 1, angle_weight, length_weight, distance_weight);
|
||||
weight += next_node->weight;
|
||||
|
||||
if (min_node == NULL || weight < min_weight) {
|
||||
min_weight = weight;
|
||||
min_node = next_node;
|
||||
min_next = next;
|
||||
}
|
||||
}
|
||||
|
||||
if (min_node) {
|
||||
node->weight = min_weight;
|
||||
node->next = min_next;
|
||||
return node;
|
||||
}
|
||||
else {
|
||||
node->weight = MAX_COST;
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int testFlipArc(RigArc *iarc, RigNode *inode_start)
|
||||
{
|
||||
ReebArc *earc = iarc->link_mesh;
|
||||
ReebNode *enode_start = BIF_NodeFromIndex(earc, inode_start->link_mesh);
|
||||
|
||||
/* no flip needed if both nodes are the same */
|
||||
if ((enode_start == earc->head && inode_start == iarc->head) ||
|
||||
(enode_start == earc->tail && inode_start == iarc->tail))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void retargetArctoArcAggresive(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start)
|
||||
{
|
||||
ReebArcIterator arc_iter;
|
||||
BArcIterator *iter = (BArcIterator *)&arc_iter;
|
||||
RigEdge *edge;
|
||||
ReebNode *node_start, *node_end;
|
||||
ReebArc *earc = iarc->link_mesh;
|
||||
float angle_weight = 1.0; // GET FROM CONTEXT
|
||||
float length_weight = 1.0;
|
||||
float distance_weight = 1.0;
|
||||
#ifndef USE_THREADS
|
||||
float min_cost = FLT_MAX;
|
||||
#endif
|
||||
float *vec0, *vec1;
|
||||
int *best_positions;
|
||||
int nb_edges = BLI_listbase_count(&iarc->edges);
|
||||
int nb_joints = nb_edges - 1;
|
||||
RetargetMethod method = METHOD_MEMOIZE;
|
||||
int i;
|
||||
|
||||
if (nb_joints > earc->bcount) {
|
||||
printf("NOT ENOUGH BUCKETS!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
best_positions = MEM_callocN(sizeof(int) * nb_joints, "Best positions");
|
||||
|
||||
if (testFlipArc(iarc, inode_start)) {
|
||||
node_start = earc->tail;
|
||||
node_end = earc->head;
|
||||
}
|
||||
else {
|
||||
node_start = earc->head;
|
||||
node_end = earc->tail;
|
||||
}
|
||||
|
||||
/* equal number of joints and potential position, just fill them in */
|
||||
if (nb_joints == earc->bcount) {
|
||||
/* init with first values */
|
||||
for (i = 0; i < nb_joints; i++) {
|
||||
best_positions[i] = i + 1;
|
||||
}
|
||||
}
|
||||
if (method == METHOD_MEMOIZE) {
|
||||
int nb_positions = earc->bcount;
|
||||
int nb_memo_nodes = nb_positions * nb_positions * (nb_joints + 1);
|
||||
MemoNode *table = MEM_callocN(nb_memo_nodes * sizeof(MemoNode), "memoization table");
|
||||
#ifndef USE_THREADS
|
||||
MemoNode *result;
|
||||
#endif
|
||||
float **positions_cache = MEM_callocN(sizeof(float *) * (nb_positions + 2), "positions cache");
|
||||
|
||||
positions_cache[0] = node_start->p;
|
||||
positions_cache[nb_positions + 1] = node_end->p;
|
||||
|
||||
initArcIterator(iter, earc, node_start);
|
||||
|
||||
for (i = 1; i <= nb_positions; i++) {
|
||||
EmbedBucket *bucket = IT_peek(iter, i);
|
||||
positions_cache[i] = bucket->p;
|
||||
}
|
||||
|
||||
#ifndef USE_THREADS
|
||||
result = solveJoints(table, iter, positions_cache, nb_joints, earc->bcount, 0, 0, iarc->edges.first, nb_joints, angle_weight, length_weight, distance_weight);
|
||||
min_cost = result->weight;
|
||||
#else
|
||||
solveJoints(table, iter, positions_cache, nb_joints, earc->bcount, 0, 0, iarc->edges.first, nb_joints, angle_weight, length_weight, distance_weight);
|
||||
#endif
|
||||
|
||||
copyMemoPositions(best_positions, table, earc->bcount, nb_joints);
|
||||
|
||||
MEM_freeN(table);
|
||||
MEM_freeN(positions_cache);
|
||||
}
|
||||
|
||||
vec0 = node_start->p;
|
||||
initArcIterator(iter, earc, node_start);
|
||||
|
||||
#ifndef USE_THREADS
|
||||
printPositions(best_positions, nb_joints);
|
||||
printMovesNeeded(best_positions, nb_joints);
|
||||
printf("min_cost %f\n", min_cost);
|
||||
printf("buckets: %i\n", earc->bcount);
|
||||
#endif
|
||||
|
||||
/* set joints to best position */
|
||||
for (edge = iarc->edges.first, i = 0;
|
||||
edge;
|
||||
edge = edge->next, i++)
|
||||
{
|
||||
float *no = NULL;
|
||||
if (i < nb_joints) {
|
||||
EmbedBucket *bucket = IT_peek(iter, best_positions[i]);
|
||||
vec1 = bucket->p;
|
||||
no = bucket->no;
|
||||
}
|
||||
else {
|
||||
vec1 = node_end->p;
|
||||
no = node_end->no;
|
||||
}
|
||||
|
||||
if (edge->bone) {
|
||||
repositionBone(C, rigg, edge, vec0, vec1, no);
|
||||
}
|
||||
|
||||
vec0 = vec1;
|
||||
}
|
||||
|
||||
MEM_freeN(best_positions);
|
||||
}
|
||||
|
||||
static void retargetArctoArcLength(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start)
|
||||
{
|
||||
ReebArcIterator arc_iter;
|
||||
BArcIterator *iter = (BArcIterator *)&arc_iter;
|
||||
ReebArc *earc = iarc->link_mesh;
|
||||
ReebNode *node_start, *node_end;
|
||||
RigEdge *edge;
|
||||
EmbedBucket *bucket = NULL;
|
||||
float embedding_length = 0;
|
||||
float *vec0 = NULL;
|
||||
float *vec1 = NULL;
|
||||
float *previous_vec = NULL;
|
||||
|
||||
|
||||
if (testFlipArc(iarc, inode_start)) {
|
||||
node_start = (ReebNode *)earc->tail;
|
||||
node_end = (ReebNode *)earc->head;
|
||||
}
|
||||
else {
|
||||
node_start = (ReebNode *)earc->head;
|
||||
node_end = (ReebNode *)earc->tail;
|
||||
}
|
||||
|
||||
initArcIterator(iter, earc, node_start);
|
||||
|
||||
bucket = IT_next(iter);
|
||||
|
||||
vec0 = node_start->p;
|
||||
|
||||
while (bucket != NULL) {
|
||||
vec1 = bucket->p;
|
||||
|
||||
embedding_length += len_v3v3(vec0, vec1);
|
||||
|
||||
vec0 = vec1;
|
||||
bucket = IT_next(iter);
|
||||
}
|
||||
|
||||
embedding_length += len_v3v3(node_end->p, vec1);
|
||||
|
||||
/* fit bones */
|
||||
initArcIterator(iter, earc, node_start);
|
||||
|
||||
bucket = IT_next(iter);
|
||||
|
||||
vec0 = node_start->p;
|
||||
previous_vec = vec0;
|
||||
vec1 = bucket->p;
|
||||
|
||||
for (edge = iarc->edges.first; edge; edge = edge->next) {
|
||||
float new_bone_length = edge->length / iarc->length * embedding_length;
|
||||
float *no = NULL;
|
||||
float length = 0;
|
||||
|
||||
while (bucket && new_bone_length > length) {
|
||||
length += len_v3v3(previous_vec, vec1);
|
||||
bucket = IT_next(iter);
|
||||
previous_vec = vec1;
|
||||
vec1 = bucket->p;
|
||||
no = bucket->no;
|
||||
}
|
||||
|
||||
if (bucket == NULL) {
|
||||
vec1 = node_end->p;
|
||||
no = node_end->no;
|
||||
}
|
||||
|
||||
/* no need to move virtual edges (space between unconnected bones) */
|
||||
if (edge->bone) {
|
||||
repositionBone(C, rigg, edge, vec0, vec1, no);
|
||||
}
|
||||
|
||||
vec0 = vec1;
|
||||
previous_vec = vec1;
|
||||
}
|
||||
}
|
||||
|
||||
static void retargetArctoArc(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start)
|
||||
{
|
||||
RetargetParam *p = MEM_callocN(sizeof(RetargetParam), "RetargetParam");
|
||||
|
||||
p->rigg = rigg;
|
||||
p->iarc = iarc;
|
||||
p->inode_start = inode_start;
|
||||
p->context = C;
|
||||
|
||||
BLI_task_pool_push(rigg->task_pool, exec_retargetArctoArc, p, true, TASK_PRIORITY_HIGH);
|
||||
}
|
||||
|
||||
void exec_retargetArctoArc(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
|
||||
{
|
||||
RetargetParam *p = (RetargetParam *)taskdata;
|
||||
RigGraph *rigg = p->rigg;
|
||||
RigArc *iarc = p->iarc;
|
||||
bContext *C = p->context;
|
||||
RigNode *inode_start = p->inode_start;
|
||||
ReebArc *earc = iarc->link_mesh;
|
||||
|
||||
if (BLI_listbase_is_single(&iarc->edges)) {
|
||||
RigEdge *edge = iarc->edges.first;
|
||||
|
||||
if (testFlipArc(iarc, inode_start)) {
|
||||
repositionBone(C, rigg, edge, earc->tail->p, earc->head->p, earc->head->no);
|
||||
}
|
||||
else {
|
||||
repositionBone(C, rigg, edge, earc->head->p, earc->tail->p, earc->tail->no);
|
||||
}
|
||||
}
|
||||
else {
|
||||
RetargetMode mode = detectArcRetargetMode(iarc);
|
||||
|
||||
if (mode == RETARGET_AGGRESSIVE) {
|
||||
retargetArctoArcAggresive(C, rigg, iarc, inode_start);
|
||||
}
|
||||
else {
|
||||
retargetArctoArcLength(C, rigg, iarc, inode_start);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void matchMultiResolutionNode(RigGraph *rigg, RigNode *inode, ReebNode *top_node)
|
||||
{
|
||||
ReebNode *enode = top_node;
|
||||
ReebGraph *reebg = BIF_graphForMultiNode(rigg->link_mesh, enode);
|
||||
int ishape, eshape;
|
||||
|
||||
ishape = BLI_subtreeShape((BGraph *)rigg, (BNode *)inode, NULL, 0) % SHAPE_LEVELS;
|
||||
eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, NULL, 0) % SHAPE_LEVELS;
|
||||
|
||||
inode->link_mesh = enode;
|
||||
|
||||
while (ishape == eshape && enode->link_down) {
|
||||
inode->link_mesh = enode;
|
||||
|
||||
enode = enode->link_down;
|
||||
reebg = BIF_graphForMultiNode(rigg->link_mesh, enode); /* replace with call to link_down once that exists */
|
||||
eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, NULL, 0) % SHAPE_LEVELS;
|
||||
}
|
||||
}
|
||||
|
||||
static void markMultiResolutionChildArc(ReebNode *end_enode, ReebNode *enode)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < enode->degree; i++) {
|
||||
ReebArc *earc = (ReebArc *)enode->arcs[i];
|
||||
|
||||
if (earc->flag == ARC_FREE) {
|
||||
earc->flag = ARC_TAKEN;
|
||||
|
||||
if (earc->tail->degree > 1 && earc->tail != end_enode) {
|
||||
markMultiResolutionChildArc(end_enode, earc->tail);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void markMultiResolutionArc(ReebArc *start_earc)
|
||||
{
|
||||
if (start_earc->link_up) {
|
||||
ReebArc *earc;
|
||||
for (earc = start_earc->link_up; earc; earc = earc->link_up) {
|
||||
earc->flag = ARC_TAKEN;
|
||||
|
||||
if (earc->tail->index != start_earc->tail->index) {
|
||||
markMultiResolutionChildArc(earc->tail, earc->tail);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void matchMultiResolutionArc(RigGraph *rigg, RigNode *start_node, RigArc *next_iarc, ReebArc *next_earc)
|
||||
{
|
||||
ReebNode *enode = next_earc->head;
|
||||
ReebGraph *reebg = BIF_graphForMultiNode(rigg->link_mesh, enode);
|
||||
int ishape, eshape;
|
||||
|
||||
ishape = BLI_subtreeShape((BGraph *)rigg, (BNode *)start_node, (BArc *)next_iarc, 1) % SHAPE_LEVELS;
|
||||
eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, (BArc *)next_earc, 1) % SHAPE_LEVELS;
|
||||
|
||||
while (ishape != eshape && next_earc->link_up) {
|
||||
next_earc->flag = ARC_TAKEN; // mark previous as taken, to prevent backtrack on lower levels
|
||||
|
||||
next_earc = next_earc->link_up;
|
||||
reebg = reebg->link_up;
|
||||
enode = next_earc->head;
|
||||
eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, (BArc *)next_earc, 1) % SHAPE_LEVELS;
|
||||
}
|
||||
|
||||
next_earc->flag = ARC_USED;
|
||||
next_iarc->link_mesh = next_earc;
|
||||
|
||||
/* mark all higher levels as taken too */
|
||||
markMultiResolutionArc(next_earc);
|
||||
// while (next_earc->link_up)
|
||||
// {
|
||||
// next_earc = next_earc->link_up;
|
||||
// next_earc->flag = ARC_TAKEN;
|
||||
// }
|
||||
}
|
||||
|
||||
static void matchMultiResolutionStartingNode(RigGraph *rigg, ReebGraph *reebg, RigNode *inode)
|
||||
{
|
||||
ReebNode *enode;
|
||||
int ishape, eshape;
|
||||
|
||||
enode = reebg->nodes.first;
|
||||
|
||||
ishape = BLI_subtreeShape((BGraph *)rigg, (BNode *)inode, NULL, 0) % SHAPE_LEVELS;
|
||||
eshape = BLI_subtreeShape((BGraph *)rigg->link_mesh, (BNode *)enode, NULL, 0) % SHAPE_LEVELS;
|
||||
|
||||
while (ishape != eshape && reebg->link_up) {
|
||||
reebg = reebg->link_up;
|
||||
|
||||
enode = reebg->nodes.first;
|
||||
|
||||
eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, NULL, 0) % SHAPE_LEVELS;
|
||||
}
|
||||
|
||||
inode->link_mesh = enode;
|
||||
}
|
||||
|
||||
static void findCorrespondingArc(RigGraph *rigg, RigArc *start_arc, RigNode *start_node, RigArc *next_iarc, int root)
|
||||
{
|
||||
ReebNode *enode = start_node->link_mesh;
|
||||
ReebArc *next_earc;
|
||||
int symmetry_level = next_iarc->symmetry_level;
|
||||
int symmetry_group = next_iarc->symmetry_group;
|
||||
int symmetry_flag = next_iarc->symmetry_flag;
|
||||
int i;
|
||||
|
||||
next_iarc->link_mesh = NULL;
|
||||
|
||||
// if (root)
|
||||
// {
|
||||
// printf("-----------------------\n");
|
||||
// printf("MATCHING LIMB\n");
|
||||
// RIG_printArcBones(next_iarc);
|
||||
// }
|
||||
|
||||
for (i = 0; i < enode->degree; i++) {
|
||||
next_earc = (ReebArc *)enode->arcs[i];
|
||||
|
||||
// if (next_earc->flag == ARC_FREE)
|
||||
// {
|
||||
// printf("candidate (level %i ?= %i) (flag %i ?= %i) (group %i ?= %i)\n",
|
||||
// symmetry_level, next_earc->symmetry_level,
|
||||
// symmetry_flag, next_earc->symmetry_flag,
|
||||
// symmetry_group, next_earc->symmetry_flag);
|
||||
// }
|
||||
|
||||
if (next_earc->flag == ARC_FREE &&
|
||||
next_earc->symmetry_flag == symmetry_flag &&
|
||||
next_earc->symmetry_group == symmetry_group &&
|
||||
next_earc->symmetry_level == symmetry_level)
|
||||
{
|
||||
// printf("CORRESPONDING ARC FOUND\n");
|
||||
// printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group);
|
||||
|
||||
matchMultiResolutionArc(rigg, start_node, next_iarc, next_earc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* not found, try at higher nodes (lower node might have filtered internal arcs, messing shape of tree */
|
||||
if (next_iarc->link_mesh == NULL) {
|
||||
// printf("NO CORRESPONDING ARC FOUND - GOING TO HIGHER LEVELS\n");
|
||||
|
||||
if (enode->link_up) {
|
||||
start_node->link_mesh = enode->link_up;
|
||||
findCorrespondingArc(rigg, start_arc, start_node, next_iarc, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* still not found, print debug info */
|
||||
if (root && next_iarc->link_mesh == NULL) {
|
||||
start_node->link_mesh = enode; /* linking back with root node */
|
||||
|
||||
// printf("NO CORRESPONDING ARC FOUND\n");
|
||||
// RIG_printArcBones(next_iarc);
|
||||
//
|
||||
// printf("ON NODE %i, multilevel %i\n", enode->index, enode->multi_level);
|
||||
//
|
||||
// printf("LOOKING FOR\n");
|
||||
// printf("flag %i -- level %i -- flag %i -- group %i\n", ARC_FREE, symmetry_level, symmetry_flag, symmetry_group);
|
||||
//
|
||||
// printf("CANDIDATES\n");
|
||||
// for (i = 0; i < enode->degree; i++)
|
||||
// {
|
||||
// next_earc = (ReebArc *)enode->arcs[i];
|
||||
// printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group);
|
||||
// }
|
||||
|
||||
/* Emergency matching */
|
||||
for (i = 0; i < enode->degree; i++) {
|
||||
next_earc = (ReebArc *)enode->arcs[i];
|
||||
|
||||
if (next_earc->flag == ARC_FREE && next_earc->symmetry_level == symmetry_level) {
|
||||
// printf("USING:\n");
|
||||
// printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group);
|
||||
matchMultiResolutionArc(rigg, start_node, next_iarc, next_earc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void retargetSubgraph(bContext *C, RigGraph *rigg, RigArc *start_arc, RigNode *start_node)
|
||||
{
|
||||
RigNode *inode = start_node;
|
||||
int i;
|
||||
|
||||
/* no start arc on first node */
|
||||
if (start_arc) {
|
||||
ReebNode *enode = start_node->link_mesh;
|
||||
ReebArc *earc = start_arc->link_mesh;
|
||||
|
||||
retargetArctoArc(C, rigg, start_arc, start_node);
|
||||
|
||||
enode = BIF_otherNodeFromIndex(earc, enode);
|
||||
inode = (RigNode *)BLI_otherNode((BArc *)start_arc, (BNode *)inode);
|
||||
|
||||
/* match with lowest node with correct shape */
|
||||
matchMultiResolutionNode(rigg, inode, enode);
|
||||
}
|
||||
|
||||
for (i = 0; i < inode->degree; i++) {
|
||||
RigArc *next_iarc = (RigArc *)inode->arcs[i];
|
||||
|
||||
/* no back tracking */
|
||||
if (next_iarc != start_arc) {
|
||||
findCorrespondingArc(rigg, start_arc, inode, next_iarc, 1);
|
||||
if (next_iarc->link_mesh) {
|
||||
retargetSubgraph(C, rigg, next_iarc, inode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void finishRetarget(RigGraph *rigg)
|
||||
{
|
||||
BLI_task_pool_work_and_wait(rigg->task_pool);
|
||||
}
|
||||
|
||||
static void adjustGraphs(bContext *C, RigGraph *rigg)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
bArmature *arm = rigg->ob->data;
|
||||
RigArc *arc;
|
||||
|
||||
for (arc = rigg->arcs.first; arc; arc = arc->next) {
|
||||
if (arc->link_mesh) {
|
||||
retargetArctoArc(C, rigg, arc, arc->head);
|
||||
}
|
||||
}
|
||||
|
||||
finishRetarget(rigg);
|
||||
|
||||
/* Turn the list into an armature */
|
||||
arm->edbo = rigg->editbones;
|
||||
ED_armature_from_edit(bmain, arm);
|
||||
|
||||
ED_undo_push(C, "Retarget Skeleton");
|
||||
}
|
||||
|
||||
static void retargetGraphs(bContext *C, RigGraph *rigg)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
bArmature *arm = rigg->ob->data;
|
||||
ReebGraph *reebg = rigg->link_mesh;
|
||||
RigNode *inode;
|
||||
|
||||
/* flag all ReebArcs as free */
|
||||
BIF_flagMultiArcs(reebg, ARC_FREE);
|
||||
|
||||
/* return to first level */
|
||||
inode = rigg->head;
|
||||
|
||||
matchMultiResolutionStartingNode(rigg, reebg, inode);
|
||||
|
||||
retargetSubgraph(C, rigg, NULL, inode);
|
||||
|
||||
//generateMissingArcs(rigg);
|
||||
|
||||
finishRetarget(rigg);
|
||||
|
||||
/* Turn the list into an armature */
|
||||
arm->edbo = rigg->editbones;
|
||||
ED_armature_from_edit(bmain, arm);
|
||||
}
|
||||
|
||||
const char *RIG_nameBone(RigGraph *rg, int arc_index, int bone_index)
|
||||
{
|
||||
RigArc *arc = BLI_findlink(&rg->arcs, arc_index);
|
||||
RigEdge *iedge;
|
||||
|
||||
if (arc == NULL) {
|
||||
return "None";
|
||||
}
|
||||
|
||||
if (bone_index == BLI_listbase_count(&arc->edges)) {
|
||||
return "Last joint";
|
||||
}
|
||||
|
||||
iedge = BLI_findlink(&arc->edges, bone_index);
|
||||
|
||||
if (iedge == NULL) {
|
||||
return "Done";
|
||||
}
|
||||
|
||||
if (iedge->bone == NULL) {
|
||||
return "Bone offset";
|
||||
}
|
||||
|
||||
return iedge->bone->name;
|
||||
}
|
||||
|
||||
int RIG_nbJoints(RigGraph *rg)
|
||||
{
|
||||
RigArc *arc;
|
||||
int total = 0;
|
||||
|
||||
total += BLI_listbase_count(&rg->nodes);
|
||||
|
||||
for (arc = rg->arcs.first; arc; arc = arc->next) {
|
||||
total += BLI_listbase_count(&arc->edges) - 1; /* -1 because end nodes are already counted */
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
static void BIF_freeRetarget(void)
|
||||
{
|
||||
if (GLOBAL_RIGG) {
|
||||
RIG_freeRigGraph((BGraph *)GLOBAL_RIGG);
|
||||
GLOBAL_RIGG = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void BIF_retargetArmature(bContext *C)
|
||||
{
|
||||
ReebGraph *reebg;
|
||||
double start_time, end_time;
|
||||
double gstart_time, gend_time;
|
||||
double reeb_time, rig_time = 0.0, retarget_time = 0.0, total_time;
|
||||
|
||||
gstart_time = start_time = PIL_check_seconds_timer();
|
||||
|
||||
reebg = BIF_ReebGraphMultiFromEditMesh(C);
|
||||
|
||||
end_time = PIL_check_seconds_timer();
|
||||
reeb_time = end_time - start_time;
|
||||
|
||||
printf("Reeb Graph created\n");
|
||||
|
||||
CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
|
||||
{
|
||||
Object *ob = base->object;
|
||||
|
||||
if (ob->type == OB_ARMATURE) {
|
||||
RigGraph *rigg;
|
||||
bArmature *arm;
|
||||
|
||||
arm = ob->data;
|
||||
|
||||
/* Put the armature into editmode */
|
||||
|
||||
|
||||
start_time = PIL_check_seconds_timer();
|
||||
|
||||
rigg = RIG_graphFromArmature(C, ob, arm);
|
||||
|
||||
end_time = PIL_check_seconds_timer();
|
||||
rig_time = end_time - start_time;
|
||||
|
||||
printf("Armature graph created\n");
|
||||
|
||||
//RIG_printGraph(rigg);
|
||||
|
||||
rigg->link_mesh = reebg;
|
||||
|
||||
printf("retargetting %s\n", ob->id.name);
|
||||
|
||||
start_time = PIL_check_seconds_timer();
|
||||
|
||||
retargetGraphs(C, rigg);
|
||||
|
||||
end_time = PIL_check_seconds_timer();
|
||||
retarget_time = end_time - start_time;
|
||||
|
||||
BIF_freeRetarget();
|
||||
|
||||
GLOBAL_RIGG = rigg;
|
||||
|
||||
break; /* only one armature at a time */
|
||||
}
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
|
||||
gend_time = PIL_check_seconds_timer();
|
||||
|
||||
total_time = gend_time - gstart_time;
|
||||
|
||||
printf("-----------\n");
|
||||
printf("runtime: \t%.3f\n", total_time);
|
||||
printf("reeb: \t\t%.3f (%.1f%%)\n", reeb_time, reeb_time / total_time * 100);
|
||||
printf("rig: \t\t%.3f (%.1f%%)\n", rig_time, rig_time / total_time * 100);
|
||||
printf("retarget: \t%.3f (%.1f%%)\n", retarget_time, retarget_time / total_time * 100);
|
||||
printf("-----------\n");
|
||||
|
||||
ED_undo_push(C, "Retarget Skeleton");
|
||||
|
||||
// XXX
|
||||
// allqueue(REDRAWVIEW3D, 0);
|
||||
}
|
||||
|
||||
void BIF_retargetArc(bContext *C, ReebArc *earc, RigGraph *template_rigg)
|
||||
{
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
bArmature *armedit = obedit->data;
|
||||
Object *ob;
|
||||
RigGraph *rigg;
|
||||
RigArc *iarc;
|
||||
char *side_string = scene->toolsettings->skgen_side_string;
|
||||
char *num_string = scene->toolsettings->skgen_num_string;
|
||||
int free_template = 0;
|
||||
|
||||
if (template_rigg) {
|
||||
ob = template_rigg->ob;
|
||||
}
|
||||
else {
|
||||
free_template = 1;
|
||||
ob = obedit;
|
||||
template_rigg = armatureSelectedToGraph(C, ob, ob->data);
|
||||
}
|
||||
|
||||
if (BLI_listbase_is_empty(&template_rigg->arcs)) {
|
||||
// XXX
|
||||
// error("No Template and no deforming bones selected");
|
||||
return;
|
||||
}
|
||||
|
||||
rigg = cloneRigGraph(template_rigg, armedit->edbo, obedit, side_string, num_string);
|
||||
|
||||
iarc = rigg->arcs.first;
|
||||
|
||||
iarc->link_mesh = earc;
|
||||
iarc->head->link_mesh = earc->head;
|
||||
iarc->tail->link_mesh = earc->tail;
|
||||
|
||||
retargetArctoArc(C, rigg, iarc, iarc->head);
|
||||
|
||||
finishRetarget(rigg);
|
||||
|
||||
/* free template if it comes from the edit armature */
|
||||
if (free_template) {
|
||||
RIG_freeRigGraph((BGraph *)template_rigg);
|
||||
}
|
||||
RIG_freeRigGraph((BGraph *)rigg);
|
||||
|
||||
ED_armature_edit_validate_active(armedit);
|
||||
|
||||
// XXX
|
||||
// allqueue(REDRAWVIEW3D, 0);
|
||||
}
|
||||
|
||||
void BIF_adjustRetarget(bContext *C)
|
||||
{
|
||||
if (GLOBAL_RIGG) {
|
||||
adjustGraphs(C, GLOBAL_RIGG);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file ED_keymap_templates.h
|
||||
* \ingroup editors
|
||||
*/
|
||||
|
||||
#ifndef __ED_KEYMAP_TEMPLATES_H__
|
||||
#define __ED_KEYMAP_TEMPLATES_H__
|
||||
|
||||
struct wmKeyMap;
|
||||
|
||||
void ED_keymap_template_select_all(struct wmKeyMap *keymap, const char *idname);
|
||||
|
||||
#endif /* __ED_KEYMAP_TEMPLATES_H__ */
|
||||
@@ -50,7 +50,6 @@
|
||||
#include "ED_paint.h"
|
||||
#include "ED_screen.h"
|
||||
#include "ED_select_utils.h"
|
||||
#include "ED_keymap_templates.h"
|
||||
#include "ED_image.h"
|
||||
#include "ED_gpencil.h"
|
||||
#include "UI_resources.h"
|
||||
|
||||
@@ -1,363 +0,0 @@
|
||||
/*
|
||||
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2009 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* Contributor(s): Blender Foundation
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/editors/space_logic/space_logic.c
|
||||
* \ingroup splogic
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_gpencil_types.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_screen.h"
|
||||
|
||||
#include "ED_space_api.h"
|
||||
#include "ED_screen.h"
|
||||
|
||||
#include "BIF_gl.h"
|
||||
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "UI_resources.h"
|
||||
#include "UI_view2d.h"
|
||||
|
||||
#include "logic_intern.h"
|
||||
|
||||
/* ******************** manage regions ********************* */
|
||||
|
||||
ARegion *logic_has_buttons_region(ScrArea *sa)
|
||||
{
|
||||
ARegion *ar, *arnew;
|
||||
|
||||
ar = BKE_area_find_region_type(sa, RGN_TYPE_UI);
|
||||
if (ar) return ar;
|
||||
|
||||
/* add subdiv level; after header */
|
||||
ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
|
||||
|
||||
/* is error! */
|
||||
if (ar == NULL) return NULL;
|
||||
|
||||
arnew= MEM_callocN(sizeof(ARegion), "buttons for image");
|
||||
|
||||
BLI_insertlinkafter(&sa->regionbase, ar, arnew);
|
||||
arnew->regiontype = RGN_TYPE_UI;
|
||||
arnew->alignment = RGN_ALIGN_RIGHT;
|
||||
|
||||
arnew->flag = RGN_FLAG_HIDDEN;
|
||||
|
||||
return arnew;
|
||||
}
|
||||
|
||||
/* ******************** default callbacks for image space ***************** */
|
||||
|
||||
static SpaceLink *logic_new(const bContext *C)
|
||||
{
|
||||
ScrArea *sa= CTX_wm_area(C);
|
||||
ARegion *ar;
|
||||
SpaceLogic *slogic;
|
||||
|
||||
slogic= MEM_callocN(sizeof(SpaceLogic), "initlogic");
|
||||
slogic->spacetype= SPACE_LOGIC;
|
||||
|
||||
/* default options */
|
||||
slogic->scaflag = ((BUTS_SENS_SEL|BUTS_SENS_ACT|BUTS_SENS_LINK) |
|
||||
(BUTS_CONT_SEL|BUTS_CONT_ACT|BUTS_CONT_LINK) |
|
||||
(BUTS_ACT_SEL|BUTS_ACT_ACT|BUTS_ACT_LINK) |
|
||||
(BUTS_SENS_STATE|BUTS_ACT_STATE));
|
||||
|
||||
|
||||
/* header */
|
||||
ar= MEM_callocN(sizeof(ARegion), "header for logic");
|
||||
|
||||
BLI_addtail(&slogic->regionbase, ar);
|
||||
ar->regiontype= RGN_TYPE_HEADER;
|
||||
ar->alignment= RGN_ALIGN_BOTTOM;
|
||||
|
||||
/* buttons/list view */
|
||||
ar= MEM_callocN(sizeof(ARegion), "buttons for logic");
|
||||
|
||||
BLI_addtail(&slogic->regionbase, ar);
|
||||
ar->regiontype= RGN_TYPE_UI;
|
||||
ar->alignment= RGN_ALIGN_RIGHT;
|
||||
|
||||
/* main region */
|
||||
ar= MEM_callocN(sizeof(ARegion), "main region for logic");
|
||||
|
||||
BLI_addtail(&slogic->regionbase, ar);
|
||||
ar->regiontype= RGN_TYPE_WINDOW;
|
||||
|
||||
ar->v2d.tot.xmin = 0.0f;
|
||||
ar->v2d.tot.ymax = 0.0f;
|
||||
ar->v2d.tot.xmax = 1150.0f;
|
||||
ar->v2d.tot.ymin = ( 1150.0f/(float)sa->winx ) * (float)-sa->winy;
|
||||
|
||||
ar->v2d.cur = ar->v2d.tot;
|
||||
|
||||
ar->v2d.min[0] = 1.0f;
|
||||
ar->v2d.min[1] = 1.0f;
|
||||
|
||||
ar->v2d.max[0] = 32000.0f;
|
||||
ar->v2d.max[1] = 32000.0f;
|
||||
|
||||
ar->v2d.minzoom = 0.5f;
|
||||
ar->v2d.maxzoom = 1.5f;
|
||||
|
||||
ar->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
|
||||
ar->v2d.keepzoom = V2D_KEEPZOOM | V2D_LIMITZOOM | V2D_KEEPASPECT;
|
||||
ar->v2d.keeptot = V2D_KEEPTOT_BOUNDS;
|
||||
ar->v2d.align = V2D_ALIGN_NO_POS_Y | V2D_ALIGN_NO_NEG_X;
|
||||
ar->v2d.keepofs = V2D_KEEPOFS_Y;
|
||||
|
||||
return (SpaceLink *)slogic;
|
||||
}
|
||||
|
||||
/* not spacelink itself */
|
||||
static void logic_free(SpaceLink *UNUSED(sl))
|
||||
{
|
||||
// Spacelogic *slogic= (SpaceLogic *) sl;
|
||||
|
||||
// if (slogic->gpd)
|
||||
// XXX BKE_gpencil_free(slogic->gpd);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* spacetype; init callback */
|
||||
static void logic_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static SpaceLink *logic_duplicate(SpaceLink *sl)
|
||||
{
|
||||
SpaceLogic *slogicn= MEM_dupallocN(sl);
|
||||
|
||||
return (SpaceLink *)slogicn;
|
||||
}
|
||||
|
||||
static void logic_operatortypes(void)
|
||||
{
|
||||
WM_operatortype_append(LOGIC_OT_properties);
|
||||
WM_operatortype_append(LOGIC_OT_links_cut);
|
||||
}
|
||||
|
||||
static void logic_keymap(struct wmKeyConfig *keyconf)
|
||||
{
|
||||
WM_keymap_ensure(keyconf, "Logic Editor", SPACE_LOGIC, 0);
|
||||
}
|
||||
|
||||
static void logic_refresh(const bContext *UNUSED(C), ScrArea *UNUSED(sa))
|
||||
{
|
||||
// SpaceLogic *slogic= CTX_wm_space_logic(C);
|
||||
// Object *obedit= CTX_data_edit_object(C);
|
||||
|
||||
}
|
||||
|
||||
static void logic_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
|
||||
{
|
||||
/* context changes */
|
||||
switch (wmn->category) {
|
||||
case NC_LOGIC:
|
||||
ED_region_tag_redraw(ar);
|
||||
break;
|
||||
case NC_SCENE:
|
||||
switch (wmn->data) {
|
||||
case ND_FRAME:
|
||||
ED_region_tag_redraw(ar);
|
||||
break;
|
||||
|
||||
case ND_OB_ACTIVE:
|
||||
ED_region_tag_redraw(ar);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NC_OBJECT:
|
||||
break;
|
||||
case NC_ID:
|
||||
if (wmn->action == NA_RENAME)
|
||||
ED_region_tag_redraw(ar);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int logic_context(const bContext *UNUSED(C), const char *UNUSED(member), bContextDataResult *UNUSED(result))
|
||||
{
|
||||
// SpaceLogic *slogic= CTX_wm_space_logic(C);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/************************** main region ***************************/
|
||||
|
||||
|
||||
/* add handlers, stuff you only do once or on area/region changes */
|
||||
static void logic_main_region_init(wmWindowManager *wm, ARegion *ar)
|
||||
{
|
||||
wmKeyMap *keymap;
|
||||
|
||||
UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
|
||||
|
||||
/* own keymaps */
|
||||
keymap = WM_keymap_ensure(wm->defaultconf, "Logic Editor", SPACE_LOGIC, 0);
|
||||
WM_event_add_keymap_handler(&ar->handlers, keymap);
|
||||
}
|
||||
|
||||
static void logic_main_region_draw(const bContext *C, ARegion *ar)
|
||||
{
|
||||
/* draw entirely, view changes should be handled here */
|
||||
// SpaceLogic *slogic= CTX_wm_space_logic(C);
|
||||
View2D *v2d= &ar->v2d;
|
||||
View2DScrollers *scrollers;
|
||||
|
||||
/* clear and setup matrix */
|
||||
UI_ThemeClearColor(TH_BACK);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
UI_view2d_view_ortho(v2d);
|
||||
|
||||
logic_buttons((bContext *)C, ar);
|
||||
|
||||
/* reset view matrix */
|
||||
UI_view2d_view_restore(C);
|
||||
|
||||
/* scrollers */
|
||||
scrollers= UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
|
||||
UI_view2d_scrollers_draw(C, v2d, scrollers);
|
||||
UI_view2d_scrollers_free(scrollers);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* *********************** buttons region ************************ */
|
||||
|
||||
/* add handlers, stuff you only do once or on area/region changes */
|
||||
static void logic_buttons_region_init(wmWindowManager *wm, ARegion *ar)
|
||||
{
|
||||
wmKeyMap *keymap;
|
||||
|
||||
ED_region_panels_init(wm, ar);
|
||||
|
||||
keymap = WM_keymap_ensure(wm->defaultconf, "Logic Editor", SPACE_LOGIC, 0);
|
||||
WM_event_add_keymap_handler(&ar->handlers, keymap);
|
||||
}
|
||||
|
||||
static void logic_buttons_region_draw(const bContext *C, ARegion *ar)
|
||||
{
|
||||
ED_region_panels(C, ar, NULL, -1, true);
|
||||
}
|
||||
|
||||
/************************* header region **************************/
|
||||
|
||||
/* add handlers, stuff you only do once or on area/region changes */
|
||||
static void logic_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
|
||||
{
|
||||
ED_region_header_init(ar);
|
||||
}
|
||||
|
||||
static void logic_header_region_draw(const bContext *C, ARegion *ar)
|
||||
{
|
||||
ED_region_header(C, ar);
|
||||
}
|
||||
|
||||
/**************************** spacetype *****************************/
|
||||
|
||||
static void logic_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
|
||||
{
|
||||
SpaceLogic *slog = (SpaceLogic *)slink;
|
||||
|
||||
if (!ELEM(GS(old_id->name), ID_GD)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ID *)slog->gpd == old_id) {
|
||||
slog->gpd = (bGPdata *)new_id;
|
||||
id_us_min(old_id);
|
||||
id_us_plus(new_id);
|
||||
}
|
||||
}
|
||||
|
||||
/* only called once, from space/spacetypes.c */
|
||||
void ED_spacetype_logic(void)
|
||||
{
|
||||
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype logic");
|
||||
ARegionType *art;
|
||||
|
||||
st->spaceid = SPACE_LOGIC;
|
||||
strncpy(st->name, "Logic", BKE_ST_MAXNAME);
|
||||
|
||||
st->new = logic_new;
|
||||
st->free = logic_free;
|
||||
st->init = logic_init;
|
||||
st->duplicate = logic_duplicate;
|
||||
st->operatortypes = logic_operatortypes;
|
||||
st->keymap = logic_keymap;
|
||||
st->refresh = logic_refresh;
|
||||
st->context = logic_context;
|
||||
st->id_remap = logic_id_remap;
|
||||
|
||||
/* regions: main window */
|
||||
art = MEM_callocN(sizeof(ARegionType), "spacetype logic region");
|
||||
art->regionid = RGN_TYPE_WINDOW;
|
||||
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES | ED_KEYMAP_VIEW2D;
|
||||
art->init = logic_main_region_init;
|
||||
art->draw = logic_main_region_draw;
|
||||
art->listener = logic_listener;
|
||||
|
||||
BLI_addhead(&st->regiontypes, art);
|
||||
|
||||
/* regions: listview/buttons */
|
||||
art = MEM_callocN(sizeof(ARegionType), "spacetype logic region");
|
||||
art->regionid = RGN_TYPE_UI;
|
||||
art->prefsizex= 220; // XXX
|
||||
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
|
||||
art->listener = logic_listener;
|
||||
art->init = logic_buttons_region_init;
|
||||
art->draw = logic_buttons_region_draw;
|
||||
BLI_addhead(&st->regiontypes, art);
|
||||
|
||||
/* regions: header */
|
||||
art= MEM_callocN(sizeof(ARegionType), "spacetype logic region");
|
||||
art->regionid = RGN_TYPE_HEADER;
|
||||
art->prefsizey = HEADERY;
|
||||
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
|
||||
art->init = logic_header_region_init;
|
||||
art->draw = logic_header_region_draw;
|
||||
|
||||
BLI_addhead(&st->regiontypes, art);
|
||||
|
||||
BKE_spacetype_register(st);
|
||||
}
|
||||
@@ -1,834 +0,0 @@
|
||||
/*
|
||||
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2008 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* Contributor(s): Blender Foundation
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/editors/space_time/space_time.c
|
||||
* \ingroup sptime
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_gpencil_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_dlrbTree.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_constraint.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_screen.h"
|
||||
#include "BKE_pointcache.h"
|
||||
|
||||
#include "ED_anim_api.h"
|
||||
#include "ED_keyframes_draw.h"
|
||||
#include "ED_screen.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "BIF_gl.h"
|
||||
#include "BIF_glutil.h"
|
||||
|
||||
#include "UI_resources.h"
|
||||
#include "UI_view2d.h"
|
||||
#include "UI_interface.h"
|
||||
|
||||
#include "ED_space_api.h"
|
||||
#include "ED_markers.h"
|
||||
|
||||
#include "time_intern.h"
|
||||
|
||||
/* ************************ main time area region *********************** */
|
||||
|
||||
static void time_draw_sfra_efra(Scene *scene, View2D *v2d)
|
||||
{
|
||||
/* draw darkened area outside of active timeline
|
||||
* frame range used is preview range or scene range
|
||||
*/
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_BLEND);
|
||||
glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
|
||||
|
||||
if (PSFRA < PEFRA) {
|
||||
glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax);
|
||||
glRectf((float)PEFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
|
||||
}
|
||||
else {
|
||||
glRectf(v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
|
||||
}
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
UI_ThemeColorShade(TH_BACK, -60);
|
||||
/* thin lines where the actual frames are */
|
||||
fdrawline((float)PSFRA, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax);
|
||||
fdrawline((float)PEFRA, v2d->cur.ymin, (float)PEFRA, v2d->cur.ymax);
|
||||
}
|
||||
|
||||
static void time_draw_cache(Main *bmain, SpaceTime *stime, Object *ob, Scene *scene)
|
||||
{
|
||||
PTCacheID *pid;
|
||||
ListBase pidlist;
|
||||
SpaceTimeCache *stc = stime->caches.first;
|
||||
const float cache_draw_height = (4.0f * UI_DPI_FAC * U.pixelsize);
|
||||
float yoffs = 0.f;
|
||||
|
||||
if (!(stime->cache_display & TIME_CACHE_DISPLAY) || (!ob))
|
||||
return;
|
||||
|
||||
BKE_ptcache_ids_from_object(bmain, &pidlist, ob, scene, 0);
|
||||
|
||||
/* iterate over pointcaches on the active object,
|
||||
* add spacetimecache and vertex array for each */
|
||||
for (pid = pidlist.first; pid; pid = pid->next) {
|
||||
float col[4], *fp;
|
||||
int i, sta = pid->cache->startframe, end = pid->cache->endframe;
|
||||
int len = (end - sta + 1) * 4;
|
||||
|
||||
switch (pid->type) {
|
||||
case PTCACHE_TYPE_SOFTBODY:
|
||||
if (!(stime->cache_display & TIME_CACHE_SOFTBODY)) continue;
|
||||
break;
|
||||
case PTCACHE_TYPE_PARTICLES:
|
||||
if (!(stime->cache_display & TIME_CACHE_PARTICLES)) continue;
|
||||
break;
|
||||
case PTCACHE_TYPE_CLOTH:
|
||||
if (!(stime->cache_display & TIME_CACHE_CLOTH)) continue;
|
||||
break;
|
||||
case PTCACHE_TYPE_SMOKE_DOMAIN:
|
||||
case PTCACHE_TYPE_SMOKE_HIGHRES:
|
||||
if (!(stime->cache_display & TIME_CACHE_SMOKE)) continue;
|
||||
break;
|
||||
case PTCACHE_TYPE_DYNAMICPAINT:
|
||||
if (!(stime->cache_display & TIME_CACHE_DYNAMICPAINT)) continue;
|
||||
break;
|
||||
case PTCACHE_TYPE_RIGIDBODY:
|
||||
if (!(stime->cache_display & TIME_CACHE_RIGIDBODY)) continue;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pid->cache->cached_frames == NULL)
|
||||
continue;
|
||||
|
||||
/* make sure we have stc with correct array length */
|
||||
if (stc == NULL || MEM_allocN_len(stc->array) != len * 2 * sizeof(float)) {
|
||||
if (stc) {
|
||||
MEM_freeN(stc->array);
|
||||
}
|
||||
else {
|
||||
stc = MEM_callocN(sizeof(SpaceTimeCache), "spacetimecache");
|
||||
BLI_addtail(&stime->caches, stc);
|
||||
}
|
||||
|
||||
stc->array = MEM_callocN(len * 2 * sizeof(float), "SpaceTimeCache array");
|
||||
}
|
||||
|
||||
/* fill the vertex array with a quad for each cached frame */
|
||||
for (i = sta, fp = stc->array; i <= end; i++) {
|
||||
if (pid->cache->cached_frames[i - sta]) {
|
||||
fp[0] = (float)i - 0.5f;
|
||||
fp[1] = 0.0;
|
||||
fp += 2;
|
||||
|
||||
fp[0] = (float)i - 0.5f;
|
||||
fp[1] = 1.0;
|
||||
fp += 2;
|
||||
|
||||
fp[0] = (float)i + 0.5f;
|
||||
fp[1] = 1.0;
|
||||
fp += 2;
|
||||
|
||||
fp[0] = (float)i + 0.5f;
|
||||
fp[1] = 0.0;
|
||||
fp += 2;
|
||||
}
|
||||
}
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(0.0, (float)V2D_SCROLL_HEIGHT + yoffs, 0.0);
|
||||
glScalef(1.0, cache_draw_height, 0.0);
|
||||
|
||||
switch (pid->type) {
|
||||
case PTCACHE_TYPE_SOFTBODY:
|
||||
col[0] = 1.0; col[1] = 0.4; col[2] = 0.02;
|
||||
col[3] = 0.1;
|
||||
break;
|
||||
case PTCACHE_TYPE_PARTICLES:
|
||||
col[0] = 1.0; col[1] = 0.1; col[2] = 0.02;
|
||||
col[3] = 0.1;
|
||||
break;
|
||||
case PTCACHE_TYPE_CLOTH:
|
||||
col[0] = 0.1; col[1] = 0.1; col[2] = 0.75;
|
||||
col[3] = 0.1;
|
||||
break;
|
||||
case PTCACHE_TYPE_SMOKE_DOMAIN:
|
||||
case PTCACHE_TYPE_SMOKE_HIGHRES:
|
||||
col[0] = 0.2; col[1] = 0.2; col[2] = 0.2;
|
||||
col[3] = 0.1;
|
||||
break;
|
||||
case PTCACHE_TYPE_DYNAMICPAINT:
|
||||
col[0] = 1.0; col[1] = 0.1; col[2] = 0.75;
|
||||
col[3] = 0.1;
|
||||
break;
|
||||
case PTCACHE_TYPE_RIGIDBODY:
|
||||
col[0] = 1.0; col[1] = 0.6; col[2] = 0.0;
|
||||
col[3] = 0.1;
|
||||
break;
|
||||
default:
|
||||
col[0] = 1.0; col[1] = 0.0; col[2] = 1.0;
|
||||
col[3] = 0.1;
|
||||
BLI_assert(0);
|
||||
break;
|
||||
}
|
||||
glColor4fv(col);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
glRectf((float)sta, 0.0, (float)end, 1.0);
|
||||
|
||||
col[3] = 0.4f;
|
||||
if (pid->cache->flag & PTCACHE_BAKED) {
|
||||
col[0] -= 0.4f; col[1] -= 0.4f; col[2] -= 0.4f;
|
||||
}
|
||||
else if (pid->cache->flag & PTCACHE_OUTDATED) {
|
||||
col[0] += 0.4f; col[1] += 0.4f; col[2] += 0.4f;
|
||||
}
|
||||
glColor4fv(col);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(2, GL_FLOAT, 0, stc->array);
|
||||
glDrawArrays(GL_QUADS, 0, (fp - stc->array) / 2);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
yoffs += cache_draw_height;
|
||||
|
||||
stc = stc->next;
|
||||
}
|
||||
|
||||
BLI_freelistN(&pidlist);
|
||||
|
||||
/* free excessive caches */
|
||||
while (stc) {
|
||||
SpaceTimeCache *tmp = stc->next;
|
||||
BLI_remlink(&stime->caches, stc);
|
||||
MEM_freeN(stc->array);
|
||||
MEM_freeN(stc);
|
||||
stc = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
static void time_cache_free(SpaceTime *stime)
|
||||
{
|
||||
SpaceTimeCache *stc;
|
||||
|
||||
for (stc = stime->caches.first; stc; stc = stc->next) {
|
||||
if (stc->array) {
|
||||
MEM_freeN(stc->array);
|
||||
stc->array = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_freelistN(&stime->caches);
|
||||
}
|
||||
|
||||
static void time_cache_refresh(SpaceTime *stime)
|
||||
{
|
||||
/* Free previous caches to indicate full refresh */
|
||||
time_cache_free(stime);
|
||||
}
|
||||
|
||||
/* helper function - find actkeycolumn that occurs on cframe, or the nearest one if not found */
|
||||
static ActKeyColumn *time_cfra_find_ak(ActKeyColumn *ak, float cframe)
|
||||
{
|
||||
ActKeyColumn *akn = NULL;
|
||||
|
||||
/* sanity checks */
|
||||
if (ak == NULL)
|
||||
return NULL;
|
||||
|
||||
/* check if this is a match, or whether it is in some subtree */
|
||||
if (cframe < ak->cfra)
|
||||
akn = time_cfra_find_ak(ak->left, cframe);
|
||||
else if (cframe > ak->cfra)
|
||||
akn = time_cfra_find_ak(ak->right, cframe);
|
||||
|
||||
/* if no match found (or found match), just use the current one */
|
||||
if (akn == NULL)
|
||||
return ak;
|
||||
else
|
||||
return akn;
|
||||
}
|
||||
|
||||
/* helper for time_draw_keyframes() */
|
||||
static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel)
|
||||
{
|
||||
bDopeSheet ads = {NULL};
|
||||
DLRBT_Tree keys;
|
||||
ActKeyColumn *ak;
|
||||
|
||||
float fac1 = (GS(id->name) == ID_GD) ? 0.8f : 0.6f; /* draw GPencil keys taller, to help distinguish them */
|
||||
float fac2 = 1.0f - fac1;
|
||||
|
||||
float ymin = v2d->tot.ymin;
|
||||
float ymax = v2d->tot.ymax * fac1 + ymin * fac2;
|
||||
|
||||
/* init binarytree-list for getting keyframes */
|
||||
BLI_dlrbTree_init(&keys);
|
||||
|
||||
/* init dopesheet settings */
|
||||
if (onlysel)
|
||||
ads.filterflag |= ADS_FILTER_ONLYSEL;
|
||||
|
||||
/* populate tree with keyframe nodes */
|
||||
switch (GS(id->name)) {
|
||||
case ID_SCE:
|
||||
scene_to_keylist(&ads, (Scene *)id, &keys, NULL);
|
||||
break;
|
||||
case ID_OB:
|
||||
ob_to_keylist(&ads, (Object *)id, &keys, NULL);
|
||||
break;
|
||||
case ID_GD:
|
||||
gpencil_to_keylist(&ads, (bGPdata *)id, &keys);
|
||||
break;
|
||||
case ID_CF:
|
||||
cachefile_to_keylist(&ads, (CacheFile *)id, &keys, NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* build linked-list for searching */
|
||||
BLI_dlrbTree_linkedlist_sync(&keys);
|
||||
|
||||
/* start drawing keyframes
|
||||
* - we use the binary-search capabilities of the tree to only start from
|
||||
* the first visible keyframe (last one can then be easily checked)
|
||||
* - draw within a single GL block to be faster
|
||||
*/
|
||||
glBegin(GL_LINES);
|
||||
for (ak = time_cfra_find_ak(keys.root, v2d->cur.xmin);
|
||||
(ak) && (ak->cfra <= v2d->cur.xmax);
|
||||
ak = ak->next)
|
||||
{
|
||||
glVertex2f(ak->cfra, ymin);
|
||||
glVertex2f(ak->cfra, ymax);
|
||||
}
|
||||
glEnd(); // GL_LINES
|
||||
|
||||
/* free temp stuff */
|
||||
BLI_dlrbTree_free(&keys);
|
||||
}
|
||||
|
||||
static void time_draw_caches_keyframes(Main *bmain, Scene *scene, View2D *v2d, bool onlysel)
|
||||
{
|
||||
CacheFile *cache_file;
|
||||
|
||||
for (cache_file = bmain->cachefiles.first;
|
||||
cache_file;
|
||||
cache_file = cache_file->id.next)
|
||||
{
|
||||
cache_file->draw_flag &= ~CACHEFILE_KEYFRAME_DRAWN;
|
||||
}
|
||||
|
||||
for (Base *base = scene->base.first; base; base = base->next) {
|
||||
Object *ob = base->object;
|
||||
|
||||
ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
|
||||
|
||||
if (md) {
|
||||
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
|
||||
|
||||
cache_file = mcmd->cache_file;
|
||||
|
||||
if (!cache_file || (cache_file->draw_flag & CACHEFILE_KEYFRAME_DRAWN) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN;
|
||||
|
||||
time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel);
|
||||
}
|
||||
|
||||
for (bConstraint *con = ob->constraints.first; con; con = con->next) {
|
||||
if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bTransformCacheConstraint *data = con->data;
|
||||
|
||||
cache_file = data->cache_file;
|
||||
|
||||
if (!cache_file || (cache_file->draw_flag & CACHEFILE_KEYFRAME_DRAWN) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN;
|
||||
|
||||
time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* draw keyframe lines for timeline */
|
||||
static void time_draw_keyframes(const bContext *C, ARegion *ar)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
View2D *v2d = &ar->v2d;
|
||||
bool onlysel = ((scene->flag & SCE_KEYS_NO_SELONLY) == 0);
|
||||
|
||||
/* set this for all keyframe lines once and for all */
|
||||
glLineWidth(1.0);
|
||||
|
||||
/* draw cache files keyframes (if available) */
|
||||
UI_ThemeColor(TH_TIME_KEYFRAME);
|
||||
time_draw_caches_keyframes(CTX_data_main(C), scene, v2d, onlysel);
|
||||
|
||||
/* draw grease pencil keyframes (if available) */
|
||||
UI_ThemeColor(TH_TIME_GP_KEYFRAME);
|
||||
if (scene->gpd) {
|
||||
time_draw_idblock_keyframes(v2d, (ID *)scene->gpd, onlysel);
|
||||
}
|
||||
if (ob && ob->gpd) {
|
||||
time_draw_idblock_keyframes(v2d, (ID *)ob->gpd, onlysel);
|
||||
}
|
||||
|
||||
/* draw scene keyframes first
|
||||
* - don't try to do this when only drawing active/selected data keyframes,
|
||||
* since this can become quite slow
|
||||
*/
|
||||
if (onlysel == 0) {
|
||||
/* set draw color */
|
||||
UI_ThemeColorShade(TH_TIME_KEYFRAME, -50);
|
||||
time_draw_idblock_keyframes(v2d, (ID *)scene, onlysel);
|
||||
}
|
||||
|
||||
/* draw keyframes from selected objects
|
||||
* - only do the active object if in posemode (i.e. showing only keyframes for the bones)
|
||||
* OR the onlysel flag was set, which means that only active object's keyframes should
|
||||
* be considered
|
||||
*/
|
||||
UI_ThemeColor(TH_TIME_KEYFRAME);
|
||||
|
||||
if (ob && ((ob->mode == OB_MODE_POSE) || onlysel)) {
|
||||
/* draw keyframes for active object only */
|
||||
time_draw_idblock_keyframes(v2d, (ID *)ob, onlysel);
|
||||
}
|
||||
else {
|
||||
bool active_done = false;
|
||||
|
||||
/* draw keyframes from all selected objects */
|
||||
CTX_DATA_BEGIN (C, Object *, obsel, selected_objects)
|
||||
{
|
||||
/* last arg is 0, since onlysel doesn't apply here... */
|
||||
time_draw_idblock_keyframes(v2d, (ID *)obsel, 0);
|
||||
|
||||
/* if this object is the active one, set flag so that we don't draw again */
|
||||
if (obsel == ob)
|
||||
active_done = true;
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
/* if active object hasn't been done yet, draw it... */
|
||||
if (ob && (active_done == 0))
|
||||
time_draw_idblock_keyframes(v2d, (ID *)ob, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------- */
|
||||
|
||||
static void time_refresh(const bContext *UNUSED(C), ScrArea *sa)
|
||||
{
|
||||
/* find the main timeline region and refresh cache display*/
|
||||
ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
|
||||
if (ar) {
|
||||
SpaceTime *stime = (SpaceTime *)sa->spacedata.first;
|
||||
time_cache_refresh(stime);
|
||||
}
|
||||
}
|
||||
|
||||
/* editor level listener */
|
||||
static void time_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
|
||||
{
|
||||
|
||||
/* mainly for updating cache display */
|
||||
switch (wmn->category) {
|
||||
case NC_OBJECT:
|
||||
{
|
||||
switch (wmn->data) {
|
||||
case ND_BONE_SELECT:
|
||||
case ND_BONE_ACTIVE:
|
||||
case ND_POINTCACHE:
|
||||
case ND_MODIFIER:
|
||||
case ND_PARTICLE:
|
||||
case ND_KEYS:
|
||||
ED_area_tag_refresh(sa);
|
||||
ED_area_tag_redraw(sa);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NC_SCENE:
|
||||
{
|
||||
switch (wmn->data) {
|
||||
case ND_RENDER_RESULT:
|
||||
ED_area_tag_redraw(sa);
|
||||
break;
|
||||
case ND_OB_ACTIVE:
|
||||
case ND_FRAME:
|
||||
ED_area_tag_refresh(sa);
|
||||
break;
|
||||
case ND_FRAME_RANGE:
|
||||
{
|
||||
ARegion *ar;
|
||||
Scene *scene = wmn->reference;
|
||||
|
||||
for (ar = sa->regionbase.first; ar; ar = ar->next) {
|
||||
if (ar->regiontype == RGN_TYPE_WINDOW) {
|
||||
ar->v2d.tot.xmin = (float)(SFRA - 4);
|
||||
ar->v2d.tot.xmax = (float)(EFRA + 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NC_SPACE:
|
||||
{
|
||||
switch (wmn->data) {
|
||||
case ND_SPACE_CHANGED:
|
||||
ED_area_tag_refresh(sa);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NC_WM:
|
||||
{
|
||||
switch (wmn->data) {
|
||||
case ND_FILEREAD:
|
||||
ED_area_tag_refresh(sa);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------- */
|
||||
|
||||
/* add handlers, stuff you only do once or on area/region changes */
|
||||
static void time_main_region_init(wmWindowManager *wm, ARegion *ar)
|
||||
{
|
||||
wmKeyMap *keymap;
|
||||
|
||||
UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
|
||||
|
||||
/* own keymap */
|
||||
keymap = WM_keymap_ensure(wm->defaultconf, "Timeline", SPACE_TIME, 0);
|
||||
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
|
||||
}
|
||||
|
||||
static void time_main_region_draw(const bContext *C, ARegion *ar)
|
||||
{
|
||||
/* draw entirely, view changes should be handled here */
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
SpaceTime *stime = CTX_wm_space_time(C);
|
||||
Object *obact = CTX_data_active_object(C);
|
||||
View2D *v2d = &ar->v2d;
|
||||
View2DGrid *grid;
|
||||
View2DScrollers *scrollers;
|
||||
int unit, flag = 0;
|
||||
|
||||
/* clear and setup matrix */
|
||||
UI_ThemeClearColor(TH_BACK);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
UI_view2d_view_ortho(v2d);
|
||||
|
||||
/* grid */
|
||||
unit = (stime->flag & TIME_DRAWFRAMES) ? V2D_UNIT_FRAMES : V2D_UNIT_SECONDS;
|
||||
grid = UI_view2d_grid_calc(scene, v2d, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY, ar->winx, ar->winy);
|
||||
UI_view2d_grid_draw(v2d, grid, (V2D_VERTICAL_LINES | V2D_VERTICAL_AXIS));
|
||||
UI_view2d_grid_free(grid);
|
||||
|
||||
ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
|
||||
|
||||
/* start and end frame */
|
||||
time_draw_sfra_efra(scene, v2d);
|
||||
|
||||
/* current frame */
|
||||
flag = DRAWCFRA_WIDE; /* this is only really needed on frames where there's a keyframe, but this will do... */
|
||||
if ((stime->flag & TIME_DRAWFRAMES) == 0) flag |= DRAWCFRA_UNIT_SECONDS;
|
||||
if (stime->flag & TIME_CFRA_NUM) flag |= DRAWCFRA_SHOW_NUMBOX;
|
||||
ANIM_draw_cfra(C, v2d, flag);
|
||||
|
||||
UI_view2d_view_ortho(v2d);
|
||||
|
||||
/* keyframes */
|
||||
time_draw_keyframes(C, ar);
|
||||
|
||||
/* markers */
|
||||
UI_view2d_view_orthoSpecial(ar, v2d, 1);
|
||||
ED_markers_draw(C, 0);
|
||||
|
||||
/* caches */
|
||||
time_draw_cache(bmain, stime, obact, scene);
|
||||
|
||||
/* callback */
|
||||
UI_view2d_view_ortho(v2d);
|
||||
ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
|
||||
|
||||
/* reset view matrix */
|
||||
UI_view2d_view_restore(C);
|
||||
|
||||
/* scrollers */
|
||||
scrollers = UI_view2d_scrollers_calc(C, v2d, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
|
||||
UI_view2d_scrollers_draw(C, v2d, scrollers);
|
||||
UI_view2d_scrollers_free(scrollers);
|
||||
}
|
||||
|
||||
static void time_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
|
||||
{
|
||||
/* context changes */
|
||||
switch (wmn->category) {
|
||||
case NC_SPACE:
|
||||
if (wmn->data == ND_SPACE_TIME)
|
||||
ED_region_tag_redraw(ar);
|
||||
break;
|
||||
|
||||
case NC_ANIMATION:
|
||||
ED_region_tag_redraw(ar);
|
||||
break;
|
||||
|
||||
case NC_SCENE:
|
||||
switch (wmn->data) {
|
||||
case ND_OB_SELECT:
|
||||
case ND_OB_ACTIVE:
|
||||
case ND_FRAME:
|
||||
case ND_FRAME_RANGE:
|
||||
case ND_KEYINGSET:
|
||||
case ND_RENDER_OPTIONS:
|
||||
ED_region_tag_redraw(ar);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NC_GPENCIL:
|
||||
if (wmn->data == ND_DATA)
|
||||
ED_region_tag_redraw(ar);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************ header time area region *********************** */
|
||||
|
||||
/* add handlers, stuff you only do once or on area/region changes */
|
||||
static void time_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
|
||||
{
|
||||
ED_region_header_init(ar);
|
||||
}
|
||||
|
||||
static void time_header_region_draw(const bContext *C, ARegion *ar)
|
||||
{
|
||||
ED_region_header(C, ar);
|
||||
}
|
||||
|
||||
static void time_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
|
||||
{
|
||||
/* context changes */
|
||||
switch (wmn->category) {
|
||||
case NC_SCREEN:
|
||||
{
|
||||
if (wmn->data == ND_ANIMPLAY)
|
||||
ED_region_tag_redraw(ar);
|
||||
break;
|
||||
}
|
||||
case NC_SCENE:
|
||||
{
|
||||
switch (wmn->data) {
|
||||
case ND_RENDER_RESULT:
|
||||
case ND_OB_SELECT:
|
||||
case ND_FRAME:
|
||||
case ND_FRAME_RANGE:
|
||||
case ND_KEYINGSET:
|
||||
case ND_RENDER_OPTIONS:
|
||||
ED_region_tag_redraw(ar);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NC_SPACE:
|
||||
{
|
||||
if (wmn->data == ND_SPACE_TIME)
|
||||
ED_region_tag_redraw(ar);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ******************** default callbacks for time space ***************** */
|
||||
|
||||
static SpaceLink *time_new(const bContext *C)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ARegion *ar;
|
||||
SpaceTime *stime;
|
||||
|
||||
stime = MEM_callocN(sizeof(SpaceTime), "inittime");
|
||||
|
||||
stime->spacetype = SPACE_TIME;
|
||||
stime->flag |= TIME_DRAWFRAMES;
|
||||
|
||||
/* header */
|
||||
ar = MEM_callocN(sizeof(ARegion), "header for time");
|
||||
|
||||
BLI_addtail(&stime->regionbase, ar);
|
||||
ar->regiontype = RGN_TYPE_HEADER;
|
||||
ar->alignment = RGN_ALIGN_BOTTOM;
|
||||
|
||||
/* main region */
|
||||
ar = MEM_callocN(sizeof(ARegion), "main region for time");
|
||||
|
||||
BLI_addtail(&stime->regionbase, ar);
|
||||
ar->regiontype = RGN_TYPE_WINDOW;
|
||||
|
||||
ar->v2d.tot.xmin = (float)(SFRA - 4);
|
||||
ar->v2d.tot.ymin = 0.0f;
|
||||
ar->v2d.tot.xmax = (float)(EFRA + 4);
|
||||
ar->v2d.tot.ymax = 50.0f;
|
||||
|
||||
ar->v2d.cur = ar->v2d.tot;
|
||||
|
||||
ar->v2d.min[0] = 1.0f;
|
||||
ar->v2d.min[1] = 50.0f;
|
||||
|
||||
ar->v2d.max[0] = MAXFRAMEF;
|
||||
ar->v2d.max[1] = 50.0;
|
||||
|
||||
ar->v2d.minzoom = 0.1f;
|
||||
ar->v2d.maxzoom = 10.0;
|
||||
|
||||
ar->v2d.scroll |= (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL);
|
||||
ar->v2d.align |= V2D_ALIGN_NO_NEG_Y;
|
||||
ar->v2d.keepofs |= V2D_LOCKOFS_Y;
|
||||
ar->v2d.keepzoom |= V2D_LOCKZOOM_Y;
|
||||
|
||||
|
||||
return (SpaceLink *)stime;
|
||||
}
|
||||
|
||||
/* not spacelink itself */
|
||||
static void time_free(SpaceLink *sl)
|
||||
{
|
||||
SpaceTime *stime = (SpaceTime *)sl;
|
||||
|
||||
time_cache_free(stime);
|
||||
}
|
||||
/* spacetype; init callback in ED_area_initialize() */
|
||||
/* init is called to (re)initialize an existing editor (file read, screen changes) */
|
||||
/* validate spacedata, add own area level handlers */
|
||||
static void time_init(wmWindowManager *UNUSED(wm), ScrArea *sa)
|
||||
{
|
||||
SpaceTime *stime = (SpaceTime *)sa->spacedata.first;
|
||||
|
||||
time_cache_free(stime);
|
||||
|
||||
/* enable all cache display */
|
||||
stime->cache_display |= TIME_CACHE_DISPLAY;
|
||||
stime->cache_display |= (TIME_CACHE_SOFTBODY | TIME_CACHE_PARTICLES);
|
||||
stime->cache_display |= (TIME_CACHE_CLOTH | TIME_CACHE_SMOKE | TIME_CACHE_DYNAMICPAINT);
|
||||
stime->cache_display |= TIME_CACHE_RIGIDBODY;
|
||||
}
|
||||
|
||||
static SpaceLink *time_duplicate(SpaceLink *sl)
|
||||
{
|
||||
SpaceTime *stime = (SpaceTime *)sl;
|
||||
SpaceTime *stimen = MEM_dupallocN(stime);
|
||||
|
||||
BLI_listbase_clear(&stimen->caches);
|
||||
|
||||
return (SpaceLink *)stimen;
|
||||
}
|
||||
|
||||
/* only called once, from space_api/spacetypes.c */
|
||||
/* it defines all callbacks to maintain spaces */
|
||||
void ED_spacetype_time(void)
|
||||
{
|
||||
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype time");
|
||||
ARegionType *art;
|
||||
|
||||
st->spaceid = SPACE_TIME;
|
||||
strncpy(st->name, "Timeline", BKE_ST_MAXNAME);
|
||||
|
||||
st->new = time_new;
|
||||
st->free = time_free;
|
||||
st->init = time_init;
|
||||
st->duplicate = time_duplicate;
|
||||
st->operatortypes = time_operatortypes;
|
||||
st->keymap = NULL;
|
||||
st->listener = time_listener;
|
||||
st->refresh = time_refresh;
|
||||
|
||||
/* regions: main window */
|
||||
art = MEM_callocN(sizeof(ARegionType), "spacetype time region");
|
||||
art->regionid = RGN_TYPE_WINDOW;
|
||||
art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES;
|
||||
|
||||
art->init = time_main_region_init;
|
||||
art->draw = time_main_region_draw;
|
||||
art->listener = time_main_region_listener;
|
||||
art->keymap = time_keymap;
|
||||
art->lock = 1; /* Due to pointcache, see T4960. */
|
||||
BLI_addhead(&st->regiontypes, art);
|
||||
|
||||
/* regions: header */
|
||||
art = MEM_callocN(sizeof(ARegionType), "spacetype time region");
|
||||
art->regionid = RGN_TYPE_HEADER;
|
||||
art->prefsizey = HEADERY;
|
||||
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
|
||||
|
||||
art->init = time_header_region_init;
|
||||
art->draw = time_header_region_draw;
|
||||
art->listener = time_header_region_listener;
|
||||
BLI_addhead(&st->regiontypes, art);
|
||||
|
||||
BKE_spacetype_register(st);
|
||||
}
|
||||
@@ -1,218 +0,0 @@
|
||||
/*
|
||||
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2008 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* Contributor(s): Blender Foundation
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/editors/space_time/time_ops.c
|
||||
* \ingroup sptime
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
|
||||
#include "ED_anim_api.h"
|
||||
#include "ED_screen.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "time_intern.h"
|
||||
|
||||
/* ****************** Start/End Frame Operators *******************************/
|
||||
static int time_set_sfra_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
int frame;
|
||||
|
||||
if (scene == NULL)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
frame = CFRA;
|
||||
|
||||
/* if Preview Range is defined, set the 'start' frame for that */
|
||||
if (PRVRANGEON)
|
||||
scene->r.psfra = frame;
|
||||
else
|
||||
scene->r.sfra = frame;
|
||||
|
||||
if (PEFRA < frame) {
|
||||
if (PRVRANGEON)
|
||||
scene->r.pefra = frame;
|
||||
else
|
||||
scene->r.efra = frame;
|
||||
}
|
||||
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void TIME_OT_start_frame_set(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Set Start Frame";
|
||||
ot->idname = "TIME_OT_start_frame_set";
|
||||
ot->description = "Set the start frame";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = time_set_sfra_exec;
|
||||
ot->poll = ED_operator_timeline_active;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
|
||||
static int time_set_efra_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
int frame;
|
||||
|
||||
if (scene == NULL)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
frame = CFRA;
|
||||
|
||||
/* if Preview Range is defined, set the 'end' frame for that */
|
||||
if (PRVRANGEON)
|
||||
scene->r.pefra = frame;
|
||||
else
|
||||
scene->r.efra = frame;
|
||||
|
||||
if (PSFRA > frame) {
|
||||
if (PRVRANGEON)
|
||||
scene->r.psfra = frame;
|
||||
else
|
||||
scene->r.sfra = frame;
|
||||
}
|
||||
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void TIME_OT_end_frame_set(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Set End Frame";
|
||||
ot->idname = "TIME_OT_end_frame_set";
|
||||
ot->description = "Set the end frame";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = time_set_efra_exec;
|
||||
ot->poll = ED_operator_timeline_active;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/* ************************ View All Operator *******************************/
|
||||
|
||||
static int time_view_all_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
|
||||
if (ELEM(NULL, scene, ar))
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
View2D *v2d = &ar->v2d;
|
||||
|
||||
/* set extents of view to start/end frames (Preview Range too) */
|
||||
v2d->cur.xmin = (float)PSFRA;
|
||||
v2d->cur.xmax = (float)PEFRA;
|
||||
|
||||
/* we need an extra "buffer" factor on either side so that the endpoints are visible */
|
||||
const float extra = 0.01f * BLI_rctf_size_x(&v2d->cur);
|
||||
v2d->cur.xmin -= extra;
|
||||
v2d->cur.xmax += extra;
|
||||
|
||||
/* this only affects this TimeLine instance, so just force redraw of this region */
|
||||
ED_region_tag_redraw(ar);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void TIME_OT_view_all(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "View All";
|
||||
ot->idname = "TIME_OT_view_all";
|
||||
ot->description = "Show the entire playable frame range";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = time_view_all_exec;
|
||||
ot->poll = ED_operator_timeline_active;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/* ************************ View Frame Operator *******************************/
|
||||
|
||||
static int time_view_frame_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
|
||||
ANIM_center_frame(C, smooth_viewtx);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void TIME_OT_view_frame(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "View Frame";
|
||||
ot->idname = "TIME_OT_view_frame";
|
||||
ot->description = "Reset viewable area to show range around current frame";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = time_view_frame_exec;
|
||||
ot->poll = ED_operator_timeline_active;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/* ************************** registration **********************************/
|
||||
|
||||
void time_operatortypes(void)
|
||||
{
|
||||
WM_operatortype_append(TIME_OT_start_frame_set);
|
||||
WM_operatortype_append(TIME_OT_end_frame_set);
|
||||
WM_operatortype_append(TIME_OT_view_all);
|
||||
WM_operatortype_append(TIME_OT_view_frame);
|
||||
}
|
||||
|
||||
void time_keymap(wmKeyConfig *keyconf)
|
||||
{
|
||||
WM_keymap_ensure(keyconf, "Timeline", SPACE_TIME, 0);
|
||||
}
|
||||
@@ -1,939 +0,0 @@
|
||||
/*
|
||||
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contributor(s): Blender Foundation (2008).
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/makesrna/intern/rna_sensor.c
|
||||
* \ingroup RNA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_sensor_types.h"
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_string_utils.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "RNA_define.h"
|
||||
#include "RNA_enum_types.h"
|
||||
#include "RNA_access.h"
|
||||
|
||||
#include "rna_internal.h"
|
||||
|
||||
#include "WM_types.h"
|
||||
|
||||
/* Always keep in alphabetical order */
|
||||
static const EnumPropertyItem sensor_type_items[] = {
|
||||
{SENS_ACTUATOR, "ACTUATOR", 0, "Actuator", ""},
|
||||
{SENS_ALWAYS, "ALWAYS", 0, "Always", ""},
|
||||
{SENS_ARMATURE, "ARMATURE", 0, "Armature", ""},
|
||||
{SENS_COLLISION, "COLLISION", 0, "Collision", ""},
|
||||
{SENS_DELAY, "DELAY", 0, "Delay", ""},
|
||||
{SENS_JOYSTICK, "JOYSTICK", 0, "Joystick", ""},
|
||||
{SENS_KEYBOARD, "KEYBOARD", 0, "Keyboard", ""},
|
||||
{SENS_MESSAGE, "MESSAGE", 0, "Message", ""},
|
||||
{SENS_MOUSE, "MOUSE", 0, "Mouse", ""},
|
||||
{SENS_NEAR, "NEAR", 0, "Near", ""},
|
||||
{SENS_PROPERTY, "PROPERTY", 0, "Property", ""},
|
||||
{SENS_RADAR, "RADAR", 0, "Radar", ""},
|
||||
{SENS_RANDOM, "RANDOM", 0, "Random", ""},
|
||||
{SENS_RAY, "RAY", 0, "Ray", ""},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
#ifdef RNA_RUNTIME
|
||||
|
||||
#include "BKE_sca.h"
|
||||
#include "DNA_controller_types.h"
|
||||
|
||||
static StructRNA *rna_Sensor_refine(struct PointerRNA *ptr)
|
||||
{
|
||||
bSensor *sensor = (bSensor *)ptr->data;
|
||||
|
||||
switch (sensor->type) {
|
||||
case SENS_ALWAYS:
|
||||
return &RNA_AlwaysSensor;
|
||||
case SENS_NEAR:
|
||||
return &RNA_NearSensor;
|
||||
case SENS_KEYBOARD:
|
||||
return &RNA_KeyboardSensor;
|
||||
case SENS_PROPERTY:
|
||||
return &RNA_PropertySensor;
|
||||
case SENS_ARMATURE:
|
||||
return &RNA_ArmatureSensor;
|
||||
case SENS_MOUSE:
|
||||
return &RNA_MouseSensor;
|
||||
case SENS_COLLISION:
|
||||
return &RNA_CollisionSensor;
|
||||
case SENS_RADAR:
|
||||
return &RNA_RadarSensor;
|
||||
case SENS_RANDOM:
|
||||
return &RNA_RandomSensor;
|
||||
case SENS_RAY:
|
||||
return &RNA_RaySensor;
|
||||
case SENS_MESSAGE:
|
||||
return &RNA_MessageSensor;
|
||||
case SENS_JOYSTICK:
|
||||
return &RNA_JoystickSensor;
|
||||
case SENS_ACTUATOR:
|
||||
return &RNA_ActuatorSensor;
|
||||
case SENS_DELAY:
|
||||
return &RNA_DelaySensor;
|
||||
default:
|
||||
return &RNA_Sensor;
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_Sensor_name_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
Object *ob = ptr->id.data;
|
||||
bSensor *sens = ptr->data;
|
||||
BLI_strncpy_utf8(sens->name, value, sizeof(sens->name));
|
||||
BLI_uniquename(&ob->sensors, sens, DATA_("Sensor"), '.', offsetof(bSensor, name), sizeof(sens->name));
|
||||
}
|
||||
|
||||
static void rna_Sensor_type_set(struct PointerRNA *ptr, int value)
|
||||
{
|
||||
bSensor *sens = (bSensor *)ptr->data;
|
||||
if (value != sens->type) {
|
||||
sens->type = value;
|
||||
init_sensor(sens);
|
||||
}
|
||||
}
|
||||
|
||||
/* Always keep in alphabetical order */
|
||||
|
||||
static void rna_Sensor_controllers_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
|
||||
{
|
||||
bSensor *sens = (bSensor *)ptr->data;
|
||||
rna_iterator_array_begin(iter, sens->links, sizeof(bController *), (int)sens->totlinks, 0, NULL);
|
||||
}
|
||||
|
||||
static int rna_Sensor_controllers_length(PointerRNA *ptr)
|
||||
{
|
||||
bSensor *sens = (bSensor *)ptr->data;
|
||||
return (int) sens->totlinks;
|
||||
}
|
||||
|
||||
const EnumPropertyItem *rna_Sensor_type_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
|
||||
{
|
||||
EnumPropertyItem *item = NULL;
|
||||
Object *ob = NULL;
|
||||
int totitem = 0;
|
||||
|
||||
if (ptr->type == &RNA_Sensor || RNA_struct_is_a(ptr->type, &RNA_Sensor)) {
|
||||
ob = (Object *)ptr->id.data;
|
||||
}
|
||||
else {
|
||||
/* can't use ob from ptr->id.data because that enum is also used by operators */
|
||||
ob = CTX_data_active_object(C);
|
||||
}
|
||||
|
||||
RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_ACTUATOR);
|
||||
RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_ALWAYS);
|
||||
|
||||
if (ob != NULL) {
|
||||
if (ob->type == OB_ARMATURE) {
|
||||
RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_ARMATURE);
|
||||
}
|
||||
}
|
||||
RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_COLLISION);
|
||||
RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_DELAY);
|
||||
RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_JOYSTICK);
|
||||
RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_KEYBOARD);
|
||||
RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_MESSAGE);
|
||||
RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_MOUSE);
|
||||
RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_NEAR);
|
||||
RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_PROPERTY);
|
||||
RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_RADAR);
|
||||
RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_RANDOM);
|
||||
RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_RAY);
|
||||
RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_TOUCH);
|
||||
|
||||
RNA_enum_item_end(&item, &totitem);
|
||||
*r_free = true;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
static void rna_Sensor_keyboard_key_set(struct PointerRNA *ptr, int value)
|
||||
{
|
||||
bSensor *sens = (bSensor *)ptr->data;
|
||||
bKeyboardSensor *ks = (bKeyboardSensor *)sens->data;
|
||||
|
||||
if (ISKEYBOARD(value))
|
||||
ks->key = value;
|
||||
else
|
||||
ks->key = 0;
|
||||
}
|
||||
|
||||
static void rna_Sensor_keyboard_modifier_set(struct PointerRNA *ptr, int value)
|
||||
{
|
||||
bSensor *sens = (bSensor *)ptr->data;
|
||||
bKeyboardSensor *ks = (bKeyboardSensor *)sens->data;
|
||||
|
||||
if (ISKEYBOARD(value))
|
||||
ks->qual = value;
|
||||
else
|
||||
ks->qual = 0;
|
||||
}
|
||||
|
||||
static void rna_Sensor_keyboard_modifier2_set(struct PointerRNA *ptr, int value)
|
||||
{
|
||||
bSensor *sens = (bSensor *)ptr->data;
|
||||
bKeyboardSensor *ks = (bKeyboardSensor *)sens->data;
|
||||
|
||||
if (ISKEYBOARD(value))
|
||||
ks->qual2 = value;
|
||||
else
|
||||
ks->qual2 = 0;
|
||||
}
|
||||
|
||||
static void rna_Sensor_tap_set(struct PointerRNA *ptr, bool value)
|
||||
{
|
||||
bSensor *sens = (bSensor *)ptr->data;
|
||||
|
||||
sens->tap = value;
|
||||
if (sens->tap == 1)
|
||||
sens->level = 0;
|
||||
}
|
||||
|
||||
static void rna_Sensor_level_set(struct PointerRNA *ptr, bool value)
|
||||
{
|
||||
bSensor *sens = (bSensor *)ptr->data;
|
||||
|
||||
sens->level = value;
|
||||
if (sens->level == 1)
|
||||
sens->tap = 0;
|
||||
}
|
||||
|
||||
static void rna_Sensor_Armature_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
|
||||
{
|
||||
bSensor *sens = (bSensor *)ptr->data;
|
||||
bArmatureSensor *as = sens->data;
|
||||
Object *ob = (Object *)ptr->id.data;
|
||||
|
||||
char *posechannel = as->posechannel;
|
||||
char *constraint = as->constraint;
|
||||
|
||||
/* check that bone exist in the active object */
|
||||
if (ob->type == OB_ARMATURE && ob->pose) {
|
||||
bPoseChannel *pchan;
|
||||
bPose *pose = ob->pose;
|
||||
for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
|
||||
if (STREQ(pchan->name, posechannel)) {
|
||||
/* found it, now look for constraint channel */
|
||||
bConstraint *con;
|
||||
for (con = pchan->constraints.first; con; con = con->next) {
|
||||
if (STREQ(con->name, constraint)) {
|
||||
/* found it, all ok */
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* didn't find constraint, make empty */
|
||||
constraint[0] = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* didn't find any */
|
||||
posechannel[0] = 0;
|
||||
constraint[0] = 0;
|
||||
}
|
||||
#else
|
||||
|
||||
static void rna_def_sensor(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "Sensor", NULL);
|
||||
RNA_def_struct_ui_text(srna, "Sensor", "Game engine logic brick to detect events");
|
||||
RNA_def_struct_sdna(srna, "bSensor");
|
||||
RNA_def_struct_refine_func(srna, "rna_Sensor_refine");
|
||||
|
||||
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Name", "Sensor name");
|
||||
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Sensor_name_set");
|
||||
RNA_def_struct_name_property(srna, prop);
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_enum_items(prop, sensor_type_items);
|
||||
RNA_def_property_enum_funcs(prop, NULL, "rna_Sensor_type_set", "rna_Sensor_type_itemf");
|
||||
RNA_def_property_ui_text(prop, "Type", "");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "pin", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", SENS_PIN);
|
||||
RNA_def_property_ui_text(prop, "Pinned", "Display when not linked to a visible states controller");
|
||||
RNA_def_property_ui_icon(prop, ICON_UNPINNED, 1);
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SENS_DEACTIVATE);
|
||||
RNA_def_property_ui_text(prop, "Active", "Set active state of the sensor");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", SENS_SHOW);
|
||||
RNA_def_property_ui_text(prop, "Expanded", "Set sensor expanded in the user interface");
|
||||
RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "invert", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Invert Output", "Invert the level(output) of this sensor");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_level", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "level", 1);
|
||||
RNA_def_property_ui_text(prop, "Level",
|
||||
"Level detector, trigger controllers of new states "
|
||||
"(only applicable upon logic state transition)");
|
||||
RNA_def_property_boolean_funcs(prop, NULL, "rna_Sensor_level_set");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_pulse_true_level", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "pulse", SENS_PULSE_REPEAT);
|
||||
RNA_def_property_ui_text(prop, "Pulse True Level", "Activate TRUE level triggering (pulse mode)");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_pulse_false_level", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "pulse", SENS_NEG_PULSE_MODE);
|
||||
RNA_def_property_ui_text(prop, "Pulse False Level", "Activate FALSE level triggering (pulse mode)");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "tick_skip", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "freq");
|
||||
RNA_def_property_ui_text(prop, "Skip",
|
||||
"Number of logic ticks skipped between 2 active pulses "
|
||||
"(0 = pulse every logic tick, 1 = skip 1 logic tick between pulses, etc.)");
|
||||
RNA_def_property_range(prop, 0, 10000);
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_tap", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "tap", 1);
|
||||
RNA_def_property_boolean_funcs(prop, NULL, "rna_Sensor_tap_set");
|
||||
RNA_def_property_ui_text(prop, "Tap",
|
||||
"Trigger controllers only for an instant, even while the sensor remains true");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "controllers", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_collection_sdna(prop, NULL, "links", NULL);
|
||||
RNA_def_property_struct_type(prop, "Controller");
|
||||
RNA_def_property_ui_text(prop, "Controllers", "The list containing the controllers connected to the sensor");
|
||||
RNA_def_property_collection_funcs(prop, "rna_Sensor_controllers_begin", "rna_iterator_array_next",
|
||||
"rna_iterator_array_end", "rna_iterator_array_dereference_get",
|
||||
"rna_Sensor_controllers_length", NULL, NULL, NULL);
|
||||
|
||||
|
||||
RNA_api_sensor(srna);
|
||||
}
|
||||
|
||||
static void rna_def_always_sensor(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
srna = RNA_def_struct(brna, "AlwaysSensor", "Sensor");
|
||||
RNA_def_struct_ui_text(srna, "Always Sensor", "Sensor to generate continuous pulses");
|
||||
}
|
||||
|
||||
static void rna_def_near_sensor(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "NearSensor", "Sensor");
|
||||
RNA_def_struct_ui_text(srna, "Near Sensor", "Sensor to detect nearby objects");
|
||||
RNA_def_struct_sdna_from(srna, "bNearSensor", "data");
|
||||
|
||||
prop = RNA_def_property(srna, "property", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "name");
|
||||
RNA_def_property_ui_text(prop, "Property", "Only look for objects with this property (blank = all objects)");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "dist");
|
||||
RNA_def_property_ui_text(prop, "Distance", "Trigger distance");
|
||||
RNA_def_property_range(prop, 0.0f, 10000.0f);
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "reset_distance", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "resetdist");
|
||||
RNA_def_property_ui_text(prop, "Reset Distance", "The distance where the sensor forgets the actor");
|
||||
RNA_def_property_range(prop, 0.0f, 10000.0f);
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_mouse_sensor(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
static const EnumPropertyItem mouse_event_items[] = {
|
||||
{BL_SENS_MOUSE_LEFT_BUTTON, "LEFTCLICK", 0, "Left Button", ""},
|
||||
{BL_SENS_MOUSE_MIDDLE_BUTTON, "MIDDLECLICK", 0, "Middle Button", ""},
|
||||
{BL_SENS_MOUSE_RIGHT_BUTTON, "RIGHTCLICK", 0, "Right Button", ""},
|
||||
{BL_SENS_MOUSE_WHEEL_UP, "WHEELUP", 0, "Wheel Up", ""},
|
||||
{BL_SENS_MOUSE_WHEEL_DOWN, "WHEELDOWN", 0, "Wheel Down", ""},
|
||||
{BL_SENS_MOUSE_MOVEMENT, "MOVEMENT", 0, "Movement", ""},
|
||||
{BL_SENS_MOUSE_MOUSEOVER, "MOUSEOVER", 0, "Mouse Over", ""},
|
||||
{BL_SENS_MOUSE_MOUSEOVER_ANY, "MOUSEOVERANY", 0, "Mouse Over Any", ""},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
static const EnumPropertyItem prop_mouse_type_items[] = {
|
||||
{SENS_COLLISION_PROPERTY, "PROPERTY", ICON_LOGIC, "Property", "Use a property for ray intersections"},
|
||||
{SENS_COLLISION_MATERIAL, "MATERIAL", ICON_MATERIAL_DATA, "Material", "Use a material for ray intersections"},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
srna = RNA_def_struct(brna, "MouseSensor", "Sensor");
|
||||
RNA_def_struct_ui_text(srna, "Mouse Sensor", "Sensor to detect mouse events");
|
||||
RNA_def_struct_sdna_from(srna, "bMouseSensor", "data");
|
||||
|
||||
prop = RNA_def_property(srna, "mouse_event", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "type");
|
||||
RNA_def_property_enum_items(prop, mouse_event_items);
|
||||
RNA_def_property_ui_text(prop, "Mouse Event", "Type of event this mouse sensor should trigger on");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_pulse", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", SENS_MOUSE_FOCUS_PULSE);
|
||||
RNA_def_property_ui_text(prop, "Pulse", "Moving the mouse over a different object generates a pulse");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_material", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_bitflag_sdna(prop, NULL, "mode");
|
||||
RNA_def_property_enum_items(prop, prop_mouse_type_items);
|
||||
RNA_def_property_ui_text(prop, "M/P", "Toggle collision on material or property");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "property", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "propname");
|
||||
RNA_def_property_ui_text(prop, "Property", "Only look for objects with this property (blank = all objects)");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "matname");
|
||||
RNA_def_property_ui_text(prop, "Material", "Only look for objects with this material (blank = all objects)");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_x_ray", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", SENS_RAY_XRAY);
|
||||
RNA_def_property_ui_text(prop, "X-Ray", "Toggle X-Ray option (see through objects that don't have the property)");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_keyboard_sensor(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "KeyboardSensor", "Sensor");
|
||||
RNA_def_struct_ui_text(srna, "Keyboard Sensor", "Sensor to detect keyboard events");
|
||||
RNA_def_struct_sdna_from(srna, "bKeyboardSensor", "data");
|
||||
|
||||
prop = RNA_def_property(srna, "key", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "key");
|
||||
RNA_def_property_enum_items(prop, rna_enum_event_type_items);
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS);
|
||||
RNA_def_property_enum_funcs(prop, NULL, "rna_Sensor_keyboard_key_set", NULL);
|
||||
RNA_def_property_ui_text(prop, "Key", "");
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_WINDOWMANAGER);
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "modifier_key_1", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "qual");
|
||||
RNA_def_property_enum_items(prop, rna_enum_event_type_items);
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS);
|
||||
RNA_def_property_enum_funcs(prop, NULL, "rna_Sensor_keyboard_modifier_set", NULL);
|
||||
RNA_def_property_ui_text(prop, "Modifier Key", "Modifier key code");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "modifier_key_2", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "qual2");
|
||||
RNA_def_property_enum_items(prop, rna_enum_event_type_items);
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS);
|
||||
RNA_def_property_enum_funcs(prop, NULL, "rna_Sensor_keyboard_modifier2_set", NULL);
|
||||
RNA_def_property_ui_text(prop, "Second Modifier Key", "Modifier key code");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "target", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "targetName");
|
||||
RNA_def_property_ui_text(prop, "Target", "Property that receives the keystrokes in case a string is logged");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "log", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "toggleName");
|
||||
RNA_def_property_ui_text(prop, "Log Toggle", "Property that indicates whether to log keystrokes as a string");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_all_keys", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "type", 1);
|
||||
RNA_def_property_ui_text(prop, "All Keys", "Trigger this sensor on any keystroke");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_property_sensor(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
static const EnumPropertyItem prop_type_items[] = {
|
||||
{SENS_PROP_EQUAL, "PROPEQUAL", 0, "Equal", ""},
|
||||
{SENS_PROP_NEQUAL, "PROPNEQUAL", 0, "Not Equal", ""},
|
||||
{SENS_PROP_INTERVAL, "PROPINTERVAL", 0, "Interval", ""},
|
||||
{SENS_PROP_CHANGED, "PROPCHANGED", 0, "Changed", ""},
|
||||
/* {SENS_PROP_EXPRESSION, "PROPEXPRESSION", 0, "Expression", ""}, NOT_USED_IN_UI */
|
||||
{SENS_PROP_LESSTHAN, "PROPLESSTHAN", 0, "Less Than", ""},
|
||||
{SENS_PROP_GREATERTHAN, "PROPGREATERTHAN", 0, "Greater Than", ""},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
srna = RNA_def_struct(brna, "PropertySensor", "Sensor");
|
||||
RNA_def_struct_ui_text(srna, "Property Sensor", "Sensor to detect values and changes in values of properties");
|
||||
RNA_def_struct_sdna_from(srna, "bPropertySensor", "data");
|
||||
|
||||
prop = RNA_def_property(srna, "evaluation_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "type");
|
||||
RNA_def_property_enum_items(prop, prop_type_items);
|
||||
RNA_def_property_ui_text(prop, "Evaluation Type", "Type of property evaluation");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "property", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "name");
|
||||
RNA_def_property_ui_text(prop, "Property", "");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "value", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "value");
|
||||
RNA_def_property_ui_text(prop, "Value", "Check for this value in types in Equal, Not Equal, Less Than and Greater Than types");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "value_min", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "value");
|
||||
RNA_def_property_ui_text(prop, "Minimum Value", "Minimum value in Interval type");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "value_max", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "maxvalue");
|
||||
RNA_def_property_ui_text(prop, "Maximum Value", "Maximum value in Interval type");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_armature_sensor(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
static const EnumPropertyItem prop_type_items[] = {
|
||||
{SENS_ARM_STATE_CHANGED, "STATECHG", 0, "State Changed", ""},
|
||||
{SENS_ARM_LIN_ERROR_BELOW, "LINERRORBELOW", 0, "Lin error below", ""},
|
||||
{SENS_ARM_LIN_ERROR_ABOVE, "LINERRORABOVE", 0, "Lin error above", ""},
|
||||
{SENS_ARM_ROT_ERROR_BELOW, "ROTERRORBELOW", 0, "Rot error below", ""},
|
||||
{SENS_ARM_ROT_ERROR_ABOVE, "ROTERRORABOVE", 0, "Rot error above", ""},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
srna = RNA_def_struct(brna, "ArmatureSensor", "Sensor");
|
||||
RNA_def_struct_ui_text(srna, "Armature Sensor", "Sensor to detect values and changes in values of IK solver");
|
||||
RNA_def_struct_sdna_from(srna, "bArmatureSensor", "data");
|
||||
|
||||
prop = RNA_def_property(srna, "test_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "type");
|
||||
RNA_def_property_enum_items(prop, prop_type_items);
|
||||
RNA_def_property_ui_text(prop, "Test", "Type of value and test");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "bone", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "posechannel");
|
||||
RNA_def_property_ui_text(prop, "Bone Name", "Identify the bone to check value from");
|
||||
RNA_def_property_update(prop, NC_LOGIC, "rna_Sensor_Armature_update");
|
||||
|
||||
prop = RNA_def_property(srna, "constraint", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "constraint");
|
||||
RNA_def_property_ui_text(prop, "Constraint Name", "Identify the bone constraint to check value from");
|
||||
RNA_def_property_update(prop, NC_LOGIC, "rna_Sensor_Armature_update");
|
||||
|
||||
prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "value");
|
||||
RNA_def_property_ui_text(prop, "Compare Value", "Value to be used in comparison");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_actuator_sensor(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "ActuatorSensor", "Sensor");
|
||||
RNA_def_struct_ui_text(srna, "Actuator Sensor", "Sensor to detect state modifications of actuators");
|
||||
RNA_def_struct_sdna_from(srna, "bActuatorSensor", "data");
|
||||
|
||||
/* XXX if eventually have Logics using RNA 100%, we could use the actuator data-block isntead of its name */
|
||||
prop = RNA_def_property(srna, "actuator", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "name");
|
||||
RNA_def_property_ui_text(prop, "Actuator", "Actuator name, actuator active state modifications will be detected");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_delay_sensor(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "DelaySensor", "Sensor");
|
||||
RNA_def_struct_ui_text(srna, "Delay Sensor", "Sensor to send delayed events");
|
||||
RNA_def_struct_sdna_from(srna, "bDelaySensor", "data");
|
||||
|
||||
prop = RNA_def_property(srna, "delay", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Delay",
|
||||
"Delay in number of logic tics before the positive trigger (default 60 per second)");
|
||||
RNA_def_property_range(prop, 0, 5000);
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "duration", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Duration",
|
||||
"If >0, delay in number of logic tics before the negative trigger following "
|
||||
"the positive trigger");
|
||||
RNA_def_property_range(prop, 0, 5000);
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_repeat", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", SENS_DELAY_REPEAT);
|
||||
RNA_def_property_ui_text(prop, "Repeat",
|
||||
"Toggle repeat option (if selected, the sensor restarts after Delay+Duration "
|
||||
"logic tics)");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_collision_sensor(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "CollisionSensor", "Sensor");
|
||||
RNA_def_struct_ui_text(srna, "Collision Sensor",
|
||||
"Sensor to detect objects colliding with the current object, with more settings than "
|
||||
"the Touch sensor");
|
||||
RNA_def_struct_sdna_from(srna, "bCollisionSensor", "data");
|
||||
|
||||
prop = RNA_def_property(srna, "use_pulse", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "mode", SENS_COLLISION_PULSE);
|
||||
RNA_def_property_ui_text(prop, "Pulse", "Change to the set of colliding objects generates pulse");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_material", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "mode", SENS_COLLISION_MATERIAL);
|
||||
RNA_def_property_ui_text(prop, "M/P", "Toggle collision on material or property");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "property", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "name");
|
||||
RNA_def_property_ui_text(prop, "Property", "Only look for objects with this property (blank = all objects)");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
/*XXX to make a setFunction to create a lookup with all materials in Blend File (not only this object mat.) */
|
||||
prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "materialName");
|
||||
RNA_def_property_ui_text(prop, "Material", "Only look for objects with this material (blank = all objects)");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
#if 0
|
||||
/* XXX either use a data-block look up to store the string name (material)
|
||||
* or to do a doversion and use a material pointer. */
|
||||
prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "Material");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "ma");
|
||||
RNA_def_property_ui_text(prop, "Material", "Only look for objects with this material (blank = all objects)");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void rna_def_radar_sensor(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
static const EnumPropertyItem axis_items[] = {
|
||||
{SENS_RADAR_X_AXIS, "XAXIS", 0, "+X axis", ""},
|
||||
{SENS_RADAR_Y_AXIS, "YAXIS", 0, "+Y axis", ""},
|
||||
{SENS_RADAR_Z_AXIS, "ZAXIS", 0, "+Z axis", ""},
|
||||
{SENS_RADAR_NEG_X_AXIS, "NEGXAXIS", 0, "-X axis", ""},
|
||||
{SENS_RADAR_NEG_Y_AXIS, "NEGYAXIS", 0, "-Y axis", ""},
|
||||
{SENS_RADAR_NEG_Z_AXIS, "NEGZAXIS", 0, "-Z axis", ""},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
srna = RNA_def_struct(brna, "RadarSensor", "Sensor");
|
||||
RNA_def_struct_ui_text(srna, "Radar Sensor",
|
||||
"Sensor to detect objects in a cone shaped radar emanating from the current object");
|
||||
RNA_def_struct_sdna_from(srna, "bRadarSensor", "data");
|
||||
|
||||
prop = RNA_def_property(srna, "property", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "name");
|
||||
RNA_def_property_ui_text(prop, "Property", "Only look for objects with this property (blank = all objects)");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, axis_items);
|
||||
RNA_def_property_ui_text(prop, "Axis", "Along which axis the radar cone is cast");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
|
||||
RNA_def_property_range(prop, 0.0, DEG2RADF(179.9f));
|
||||
RNA_def_property_ui_text(prop, "Angle", "Opening angle of the radar cone");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "range");
|
||||
RNA_def_property_range(prop, 0.0, 10000.0);
|
||||
RNA_def_property_ui_text(prop, "Distance", "Depth of the radar cone");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_random_sensor(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "RandomSensor", "Sensor");
|
||||
RNA_def_struct_ui_text(srna, "Random Sensor", "Sensor to send random events");
|
||||
RNA_def_struct_sdna_from(srna, "bRandomSensor", "data");
|
||||
|
||||
prop = RNA_def_property(srna, "seed", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0, 1000);
|
||||
RNA_def_property_ui_text(prop, "Seed", "Initial seed of the generator (choose 0 for not random)");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_ray_sensor(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
static const EnumPropertyItem axis_items[] = {
|
||||
{SENS_RAY_X_AXIS, "XAXIS", 0, "+X axis", ""},
|
||||
{SENS_RAY_Y_AXIS, "YAXIS", 0, "+Y axis", ""},
|
||||
{SENS_RAY_Z_AXIS, "ZAXIS", 0, "+Z axis", ""},
|
||||
{SENS_RAY_NEG_X_AXIS, "NEGXAXIS", 0, "-X axis", ""},
|
||||
{SENS_RAY_NEG_Y_AXIS, "NEGYAXIS", 0, "-Y axis", ""},
|
||||
{SENS_RAY_NEG_Z_AXIS, "NEGZAXIS", 0, "-Z axis", ""},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
static const EnumPropertyItem prop_ray_type_items[] = {
|
||||
{SENS_COLLISION_PROPERTY, "PROPERTY", ICON_LOGIC, "Property", "Use a property for ray intersections"},
|
||||
{SENS_COLLISION_MATERIAL, "MATERIAL", ICON_MATERIAL_DATA, "Material", "Use a material for ray intersections"},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
srna = RNA_def_struct(brna, "RaySensor", "Sensor");
|
||||
RNA_def_struct_ui_text(srna, "Ray Sensor",
|
||||
"Sensor to detect intersections with a ray emanating from the current object");
|
||||
RNA_def_struct_sdna_from(srna, "bRaySensor", "data");
|
||||
|
||||
prop = RNA_def_property(srna, "ray_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_bitflag_sdna(prop, NULL, "mode");
|
||||
RNA_def_property_enum_items(prop, prop_ray_type_items);
|
||||
RNA_def_property_ui_text(prop, "Ray Type", "Toggle collision on material or property");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "property", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "propname");
|
||||
RNA_def_property_ui_text(prop, "Property", "Only look for objects with this property (blank = all objects)");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "matname");
|
||||
RNA_def_property_ui_text(prop, "Material", "Only look for objects with this material (blank = all objects)");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
#if 0
|
||||
/* XXX either use a data-block look up to store the string name (material)
|
||||
* or to do a doversion and use a material pointer. */
|
||||
prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "Material");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "ma");
|
||||
RNA_def_property_ui_text(prop, "Material", "Only look for objects with this material (blank = all objects)");
|
||||
#endif
|
||||
|
||||
prop = RNA_def_property(srna, "use_x_ray", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "mode", SENS_RAY_XRAY);
|
||||
RNA_def_property_ui_text(prop, "X-Ray Mode",
|
||||
"Toggle X-Ray option (see through objects that don't have the property)");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "range", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.01, 10000.0);
|
||||
RNA_def_property_ui_text(prop, "Range", "Sense objects no farther than this distance");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "axisflag");
|
||||
RNA_def_property_enum_items(prop, axis_items);
|
||||
RNA_def_property_ui_text(prop, "Axis", "Along which axis the ray is cast");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_message_sensor(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "MessageSensor", "Sensor");
|
||||
RNA_def_struct_ui_text(srna, "Message Sensor", "Sensor to detect incoming messages");
|
||||
RNA_def_struct_sdna_from(srna, "bMessageSensor", "data");
|
||||
|
||||
prop = RNA_def_property(srna, "subject", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Subject",
|
||||
"Optional subject filter: only accept messages with this subject, "
|
||||
"or empty to accept all");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_joystick_sensor(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
static const EnumPropertyItem event_type_joystick_items[] = {
|
||||
{SENS_JOY_BUTTON, "BUTTON", 0, "Button", ""},
|
||||
{SENS_JOY_AXIS, "AXIS", 0, "Axis", ""},
|
||||
{SENS_JOY_HAT, "HAT", 0, "Hat", ""},
|
||||
{SENS_JOY_AXIS_SINGLE, "AXIS_SINGLE", 0, "Single Axis", ""},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
static const EnumPropertyItem axis_direction_items[] = {
|
||||
{SENS_JOY_X_AXIS, "RIGHTAXIS", 0, "Right Axis", ""},
|
||||
{SENS_JOY_Y_AXIS, "UPAXIS", 0, "Up Axis", ""},
|
||||
{SENS_JOY_NEG_X_AXIS, "LEFTAXIS", 0, "Left Axis", ""},
|
||||
{SENS_JOY_NEG_Y_AXIS, "DOWNAXIS", 0, "Down Axis", ""},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
static const EnumPropertyItem hat_direction_items[] = {
|
||||
{SENS_JOY_HAT_UP, "UP", 0, "Up", ""},
|
||||
{SENS_JOY_HAT_DOWN, "DOWN", 0, "Down", ""},
|
||||
{SENS_JOY_HAT_LEFT, "LEFT", 0, "Left", ""},
|
||||
{SENS_JOY_HAT_RIGHT, "RIGHT", 0, "Right", ""},
|
||||
|
||||
{SENS_JOY_HAT_UP_RIGHT, "UPRIGHT", 0, "Up/Right", ""},
|
||||
{SENS_JOY_HAT_DOWN_LEFT, "DOWNLEFT", 0, "Down/Left", ""},
|
||||
{SENS_JOY_HAT_UP_LEFT, "UPLEFT", 0, "Up/Left", ""},
|
||||
{SENS_JOY_HAT_DOWN_RIGHT, "DOWNRIGHT", 0, "Down/Right", ""},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
srna = RNA_def_struct(brna, "JoystickSensor", "Sensor");
|
||||
RNA_def_struct_ui_text(srna, "Joystick Sensor", "Sensor to detect joystick events");
|
||||
RNA_def_struct_sdna_from(srna, "bJoystickSensor", "data");
|
||||
|
||||
prop = RNA_def_property(srna, "joystick_index", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "joyindex");
|
||||
RNA_def_property_ui_text(prop, "Index", "Which joystick to use");
|
||||
RNA_def_property_range(prop, 0, SENS_JOY_MAXINDEX - 1);
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "event_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "type");
|
||||
RNA_def_property_enum_items(prop, event_type_joystick_items);
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS);
|
||||
RNA_def_property_ui_text(prop, "Event Type", "The type of event this joystick sensor is triggered on");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_all_events", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", SENS_JOY_ANY_EVENT);
|
||||
RNA_def_property_ui_text(prop, "All Events",
|
||||
"Triggered by all events on this joystick's current type (axis/button/hat)");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
/* Button */
|
||||
prop = RNA_def_property(srna, "button_number", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "button");
|
||||
RNA_def_property_ui_text(prop, "Button Number", "Which button to use");
|
||||
RNA_def_property_range(prop, 0, 18);
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
/* Axis */
|
||||
prop = RNA_def_property(srna, "axis_number", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "axis");
|
||||
RNA_def_property_ui_text(prop, "Axis Number", "Which axis pair to use, 1 is usually the main direction input");
|
||||
RNA_def_property_range(prop, 1, 8);
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "axis_threshold", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "precision");
|
||||
RNA_def_property_ui_text(prop, "Axis Threshold", "Precision of the axis");
|
||||
RNA_def_property_range(prop, 0, 32768);
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "axis_direction", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "axisf");
|
||||
RNA_def_property_enum_items(prop, axis_direction_items);
|
||||
RNA_def_property_ui_text(prop, "Axis Direction", "The direction of the axis");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
/* Single Axis */
|
||||
prop = RNA_def_property(srna, "single_axis_number", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "axis_single");
|
||||
RNA_def_property_ui_text(prop, "Axis Number", "Single axis (vertical/horizontal/other) to detect");
|
||||
RNA_def_property_range(prop, 1, 16);
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
/* Hat */
|
||||
prop = RNA_def_property(srna, "hat_number", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "hat");
|
||||
RNA_def_property_ui_text(prop, "Hat Number", "Which hat to use");
|
||||
RNA_def_property_range(prop, 1, 2);
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "hat_direction", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "hatf");
|
||||
RNA_def_property_enum_items(prop, hat_direction_items);
|
||||
RNA_def_property_ui_text(prop, "Hat Direction", "Hat direction");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
}
|
||||
|
||||
void RNA_def_sensor(BlenderRNA *brna)
|
||||
{
|
||||
rna_def_sensor(brna);
|
||||
|
||||
rna_def_always_sensor(brna);
|
||||
rna_def_near_sensor(brna);
|
||||
rna_def_mouse_sensor(brna);
|
||||
rna_def_keyboard_sensor(brna);
|
||||
rna_def_property_sensor(brna);
|
||||
rna_def_armature_sensor(brna);
|
||||
rna_def_actuator_sensor(brna);
|
||||
rna_def_delay_sensor(brna);
|
||||
rna_def_collision_sensor(brna);
|
||||
rna_def_radar_sensor(brna);
|
||||
rna_def_random_sensor(brna);
|
||||
rna_def_ray_sensor(brna);
|
||||
rna_def_message_sensor(brna);
|
||||
rna_def_joystick_sensor(brna);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,571 +0,0 @@
|
||||
/*
|
||||
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): Raul Fernandez Hernandez (Farsthary), Matt Ebb.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/render/intern/source/voxeldata.c
|
||||
* \ingroup render
|
||||
*/
|
||||
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include "BLI_winstuff.h"
|
||||
#endif
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_threads.h"
|
||||
#include "BLI_voxel.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "IMB_imbuf.h"
|
||||
#include "IMB_imbuf_types.h"
|
||||
|
||||
#include "BKE_cloth.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_image.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_modifier.h"
|
||||
|
||||
#include "smoke_API.h"
|
||||
#include "BPH_mass_spring.h"
|
||||
|
||||
#include "DNA_texture_types.h"
|
||||
#include "DNA_object_force_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_particle_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_smoke_types.h"
|
||||
|
||||
|
||||
#include "render_types.h"
|
||||
#include "texture.h"
|
||||
#include "voxeldata.h"
|
||||
|
||||
static bool is_vd_res_ok(VoxelData *vd)
|
||||
{
|
||||
/* arbitrary large value so corrupt headers don't break */
|
||||
const int min = 1, max = 100000;
|
||||
return (vd->resol[0] >= min && vd->resol[0] <= max) &&
|
||||
(vd->resol[1] >= min && vd->resol[1] <= max) &&
|
||||
(vd->resol[2] >= min && vd->resol[2] <= max);
|
||||
}
|
||||
|
||||
/* use size_t because the result may exceed INT_MAX */
|
||||
static size_t vd_resol_size(VoxelData *vd)
|
||||
{
|
||||
return (size_t)vd->resol[0] * (size_t)vd->resol[1] * (size_t)vd->resol[2];
|
||||
}
|
||||
|
||||
static int load_frame_blendervoxel(VoxelData *vd, FILE *fp, int frame)
|
||||
{
|
||||
const size_t size = vd_resol_size(vd);
|
||||
size_t offset = sizeof(VoxelDataHeader);
|
||||
|
||||
if (is_vd_res_ok(vd) == false)
|
||||
return 0;
|
||||
|
||||
vd->dataset = MEM_mapallocN(sizeof(float) * size, "voxel dataset");
|
||||
if (vd->dataset == NULL) return 0;
|
||||
|
||||
if (fseek(fp, frame * size * sizeof(float) + offset, 0) == -1)
|
||||
return 0;
|
||||
if (fread(vd->dataset, sizeof(float), size, fp) != size)
|
||||
return 0;
|
||||
|
||||
vd->cachedframe = frame;
|
||||
vd->ok = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int load_frame_raw8(VoxelData *vd, FILE *fp, int frame)
|
||||
{
|
||||
const size_t size = vd_resol_size(vd);
|
||||
size_t i;
|
||||
char *data_c;
|
||||
|
||||
if (is_vd_res_ok(vd) == false)
|
||||
return 0;
|
||||
|
||||
vd->dataset = MEM_mapallocN(sizeof(float) * size, "voxel dataset");
|
||||
if (vd->dataset == NULL) return 0;
|
||||
data_c = (char *)MEM_mallocN(sizeof(char) * size, "temporary voxel file reading storage");
|
||||
if (data_c == NULL) {
|
||||
MEM_freeN(vd->dataset);
|
||||
vd->dataset = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fseek(fp, (frame - 1) * size * sizeof(char), 0) == -1) {
|
||||
MEM_freeN(data_c);
|
||||
MEM_freeN(vd->dataset);
|
||||
vd->dataset = NULL;
|
||||
return 0;
|
||||
}
|
||||
if (fread(data_c, sizeof(char), size, fp) != size) {
|
||||
MEM_freeN(data_c);
|
||||
MEM_freeN(vd->dataset);
|
||||
vd->dataset = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
vd->dataset[i] = (float)data_c[i] / 255.f;
|
||||
}
|
||||
MEM_freeN(data_c);
|
||||
|
||||
vd->cachedframe = frame;
|
||||
vd->ok = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void load_frame_image_sequence(VoxelData *vd, Tex *tex)
|
||||
{
|
||||
ImBuf *ibuf;
|
||||
Image *ima = tex->ima;
|
||||
ImageUser *tiuser = &tex->iuser;
|
||||
ImageUser iuser = *(tiuser);
|
||||
int x = 0, y = 0, z = 0;
|
||||
const float *rf;
|
||||
|
||||
if (!ima) return;
|
||||
if (iuser.frames == 0) return;
|
||||
|
||||
ima->source = IMA_SRC_SEQUENCE;
|
||||
iuser.framenr = 1 + iuser.offset;
|
||||
|
||||
/* find the first valid ibuf and use it to initialize the resolution of the data set */
|
||||
/* need to do this in advance so we know how much memory to allocate */
|
||||
ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
|
||||
while (!ibuf && (iuser.framenr < iuser.frames)) {
|
||||
iuser.framenr++;
|
||||
ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
|
||||
}
|
||||
if (!ibuf) return;
|
||||
if (!ibuf->rect_float) IMB_float_from_rect(ibuf);
|
||||
|
||||
vd->flag |= TEX_VD_STILL;
|
||||
vd->resol[0] = ibuf->x;
|
||||
vd->resol[1] = ibuf->y;
|
||||
vd->resol[2] = iuser.frames;
|
||||
vd->dataset = MEM_mapallocN(sizeof(float) * vd_resol_size(vd), "voxel dataset");
|
||||
|
||||
for (z = 0; z < iuser.frames; z++) {
|
||||
/* get a new ibuf for each frame */
|
||||
if (z > 0) {
|
||||
iuser.framenr++;
|
||||
BKE_image_release_ibuf(ima, ibuf, NULL);
|
||||
ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
|
||||
if (!ibuf) break;
|
||||
if (!ibuf->rect_float) IMB_float_from_rect(ibuf);
|
||||
}
|
||||
rf = ibuf->rect_float;
|
||||
|
||||
for (y = 0; y < ibuf->y; y++) {
|
||||
for (x = 0; x < ibuf->x; x++) {
|
||||
/* currently averaged to monchrome */
|
||||
vd->dataset[BLI_VOXEL_INDEX(x, y, z, vd->resol)] = (rf[0] + rf[1] + rf[2]) / 3.0f;
|
||||
rf += 4;
|
||||
}
|
||||
}
|
||||
|
||||
BKE_image_free_anim_ibufs(ima, iuser.framenr);
|
||||
}
|
||||
|
||||
BKE_image_release_ibuf(ima, ibuf, NULL);
|
||||
|
||||
vd->ok = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
static int read_voxeldata_header(FILE *fp, struct VoxelData *vd)
|
||||
{
|
||||
VoxelDataHeader *h = (VoxelDataHeader *)MEM_mallocN(sizeof(VoxelDataHeader), "voxel data header");
|
||||
|
||||
rewind(fp);
|
||||
if (fread(h, sizeof(VoxelDataHeader), 1, fp) != 1) {
|
||||
MEM_freeN(h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
vd->resol[0] = h->resolX;
|
||||
vd->resol[1] = h->resolY;
|
||||
vd->resol[2] = h->resolZ;
|
||||
|
||||
MEM_freeN(h);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void init_frame_smoke(VoxelData *vd, int cfra)
|
||||
{
|
||||
#ifdef WITH_SMOKE
|
||||
Object *ob;
|
||||
ModifierData *md;
|
||||
|
||||
vd->dataset = NULL;
|
||||
if (vd->object == NULL) return;
|
||||
ob = vd->object;
|
||||
|
||||
/* draw code for smoke */
|
||||
if ((md = (ModifierData *)modifiers_findByType(ob, eModifierType_Smoke))) {
|
||||
SmokeModifierData *smd = (SmokeModifierData *)md;
|
||||
SmokeDomainSettings *sds = smd->domain;
|
||||
|
||||
if (sds && sds->fluid) {
|
||||
BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);
|
||||
|
||||
if (!sds->fluid) {
|
||||
BLI_rw_mutex_unlock(sds->fluid_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cfra < sds->point_cache[0]->startframe)
|
||||
; /* don't show smoke before simulation starts, this could be made an option in the future */
|
||||
else if (vd->smoked_type == TEX_VD_SMOKEHEAT) {
|
||||
size_t totRes;
|
||||
size_t i;
|
||||
float *heat;
|
||||
|
||||
if (!smoke_has_heat(sds->fluid)) {
|
||||
BLI_rw_mutex_unlock(sds->fluid_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
copy_v3_v3_int(vd->resol, sds->res);
|
||||
totRes = vd_resol_size(vd);
|
||||
vd->dataset = MEM_mapallocN(sizeof(float) * (totRes), "smoke data");
|
||||
/* get heat data */
|
||||
heat = smoke_get_heat(sds->fluid);
|
||||
|
||||
/* scale heat values from -2.0-2.0 to 0.0-1.0 */
|
||||
for (i = 0; i < totRes; i++) {
|
||||
vd->dataset[i] = (heat[i] + 2.0f) / 4.0f;
|
||||
}
|
||||
}
|
||||
else if (vd->smoked_type == TEX_VD_SMOKEVEL) {
|
||||
size_t totRes;
|
||||
size_t i;
|
||||
float *xvel, *yvel, *zvel;
|
||||
|
||||
copy_v3_v3_int(vd->resol, sds->res);
|
||||
totRes = vd_resol_size(vd);
|
||||
vd->dataset = MEM_mapallocN(sizeof(float) * (totRes), "smoke data");
|
||||
/* get velocity data */
|
||||
xvel = smoke_get_velocity_x(sds->fluid);
|
||||
yvel = smoke_get_velocity_y(sds->fluid);
|
||||
zvel = smoke_get_velocity_z(sds->fluid);
|
||||
|
||||
/* map velocities between 0 and 0.3f */
|
||||
for (i = 0; i < totRes; i++) {
|
||||
vd->dataset[i] = sqrtf(xvel[i] * xvel[i] + yvel[i] * yvel[i] + zvel[i] * zvel[i]) * 3.0f;
|
||||
}
|
||||
|
||||
}
|
||||
else if (vd->smoked_type == TEX_VD_SMOKEFLAME) {
|
||||
size_t totRes;
|
||||
float *flame;
|
||||
|
||||
if (sds->flags & MOD_SMOKE_HIGHRES) {
|
||||
if (!smoke_turbulence_has_fuel(sds->wt)) {
|
||||
BLI_rw_mutex_unlock(sds->fluid_mutex);
|
||||
return;
|
||||
}
|
||||
smoke_turbulence_get_res(sds->wt, vd->resol);
|
||||
flame = smoke_turbulence_get_flame(sds->wt);
|
||||
}
|
||||
else {
|
||||
if (!smoke_has_fuel(sds->fluid)) {
|
||||
BLI_rw_mutex_unlock(sds->fluid_mutex);
|
||||
return;
|
||||
}
|
||||
copy_v3_v3_int(vd->resol, sds->res);
|
||||
flame = smoke_get_flame(sds->fluid);
|
||||
}
|
||||
|
||||
/* always store copy, as smoke internal data can change */
|
||||
totRes = vd_resol_size(vd);
|
||||
vd->dataset = MEM_mapallocN(sizeof(float)*(totRes), "smoke data");
|
||||
memcpy(vd->dataset, flame, sizeof(float)*totRes);
|
||||
}
|
||||
else {
|
||||
size_t totCells;
|
||||
int depth = 4;
|
||||
vd->data_type = TEX_VD_RGBA_PREMUL;
|
||||
|
||||
/* data resolution */
|
||||
if (sds->flags & MOD_SMOKE_HIGHRES) {
|
||||
smoke_turbulence_get_res(sds->wt, vd->resol);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3_int(vd->resol, sds->res);
|
||||
}
|
||||
|
||||
/* TODO: is_vd_res_ok(rvd) doesnt check this resolution */
|
||||
totCells = vd_resol_size(vd) * depth;
|
||||
/* always store copy, as smoke internal data can change */
|
||||
vd->dataset = MEM_mapallocN(sizeof(float) * totCells, "smoke data");
|
||||
|
||||
if (sds->flags & MOD_SMOKE_HIGHRES) {
|
||||
if (smoke_turbulence_has_colors(sds->wt)) {
|
||||
smoke_turbulence_get_rgba(sds->wt, vd->dataset, 1);
|
||||
}
|
||||
else {
|
||||
smoke_turbulence_get_rgba_from_density(sds->wt, sds->active_color, vd->dataset, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (smoke_has_colors(sds->fluid)) {
|
||||
smoke_get_rgba(sds->fluid, vd->dataset, 1);
|
||||
}
|
||||
else {
|
||||
smoke_get_rgba_from_density(sds->fluid, sds->active_color, vd->dataset, 1);
|
||||
}
|
||||
}
|
||||
} /* end of fluid condition */
|
||||
|
||||
BLI_rw_mutex_unlock(sds->fluid_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
vd->ok = 1;
|
||||
|
||||
#else // WITH_SMOKE
|
||||
(void)vd;
|
||||
(void)cfra;
|
||||
|
||||
vd->dataset = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void init_frame_hair(VoxelData *vd, int UNUSED(cfra))
|
||||
{
|
||||
Object *ob;
|
||||
ModifierData *md;
|
||||
|
||||
vd->dataset = NULL;
|
||||
if (vd->object == NULL) return;
|
||||
ob = vd->object;
|
||||
|
||||
if ((md = (ModifierData *)modifiers_findByType(ob, eModifierType_ParticleSystem))) {
|
||||
ParticleSystemModifierData *pmd = (ParticleSystemModifierData *)md;
|
||||
|
||||
if (pmd->psys && pmd->psys->clmd) {
|
||||
vd->ok |= BPH_cloth_solver_get_texture_data(ob, pmd->psys->clmd, vd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cache_voxeldata(Tex *tex, int scene_frame)
|
||||
{
|
||||
VoxelData *vd = tex->vd;
|
||||
FILE *fp;
|
||||
int curframe;
|
||||
char path[sizeof(vd->source_path)];
|
||||
|
||||
/* only re-cache if dataset needs updating */
|
||||
if ((vd->flag & TEX_VD_STILL) || (vd->cachedframe == scene_frame))
|
||||
if (vd->ok) return;
|
||||
|
||||
/* clear out old cache, ready for new */
|
||||
if (vd->dataset) {
|
||||
MEM_freeN(vd->dataset);
|
||||
vd->dataset = NULL;
|
||||
}
|
||||
/* reset data_type */
|
||||
vd->data_type = TEX_VD_INTENSITY;
|
||||
|
||||
if (vd->flag & TEX_VD_STILL)
|
||||
curframe = vd->still_frame;
|
||||
else
|
||||
curframe = scene_frame;
|
||||
|
||||
BLI_strncpy(path, vd->source_path, sizeof(path));
|
||||
|
||||
/* each type is responsible for setting to true */
|
||||
vd->ok = false;
|
||||
|
||||
switch (vd->file_format) {
|
||||
case TEX_VD_IMAGE_SEQUENCE:
|
||||
load_frame_image_sequence(vd, tex);
|
||||
return;
|
||||
case TEX_VD_SMOKE:
|
||||
init_frame_smoke(vd, scene_frame);
|
||||
return;
|
||||
case TEX_VD_HAIR:
|
||||
init_frame_hair(vd, scene_frame);
|
||||
return;
|
||||
case TEX_VD_BLENDERVOXEL:
|
||||
BLI_path_abs(path, BKE_main_blendfile_path_from_global());
|
||||
fp = BLI_fopen(path, "rb");
|
||||
if (!fp) return;
|
||||
|
||||
if (read_voxeldata_header(fp, vd))
|
||||
load_frame_blendervoxel(vd, fp, curframe - 1);
|
||||
|
||||
fclose(fp);
|
||||
return;
|
||||
case TEX_VD_RAW_8BIT:
|
||||
BLI_path_abs(path, BKE_main_blendfile_path_from_global());
|
||||
fp = BLI_fopen(path, "rb");
|
||||
if (!fp) return;
|
||||
|
||||
load_frame_raw8(vd, fp, curframe);
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void make_voxeldata(struct Render *re)
|
||||
{
|
||||
Tex *tex;
|
||||
|
||||
re->i.infostr = IFACE_("Loading voxel datasets");
|
||||
re->stats_draw(re->sdh, &re->i);
|
||||
|
||||
/* XXX: should be doing only textures used in this render */
|
||||
for (tex = re->main->tex.first; tex; tex = tex->id.next) {
|
||||
if (tex->id.us && tex->type == TEX_VOXELDATA) {
|
||||
cache_voxeldata(tex, re->r.cfra);
|
||||
}
|
||||
}
|
||||
|
||||
re->i.infostr = NULL;
|
||||
re->stats_draw(re->sdh, &re->i);
|
||||
|
||||
}
|
||||
|
||||
int voxeldatatex(struct Tex *tex, const float texvec[3], struct TexResult *texres)
|
||||
{
|
||||
VoxelData *vd = tex->vd;
|
||||
float co[3], offset[3] = {0.5, 0.5, 0.5}, a;
|
||||
int retval = (vd->data_type == TEX_VD_RGBA_PREMUL) ? TEX_RGB : TEX_INT;
|
||||
int depth = (vd->data_type == TEX_VD_RGBA_PREMUL) ? 4 : 1;
|
||||
int ch;
|
||||
|
||||
if (vd->dataset == NULL) {
|
||||
texres->tin = 0.0f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* scale lookup from 0.0-1.0 (original location) to -1.0, 1.0, consistent with image texture tex coords */
|
||||
/* in implementation this works backwards, bringing sample locations from -1.0, 1.0
|
||||
* to the range 0.0, 1.0, before looking up in the voxel structure. */
|
||||
copy_v3_v3(co, texvec);
|
||||
mul_v3_fl(co, 0.5f);
|
||||
add_v3_v3(co, offset);
|
||||
|
||||
/* co is now in the range 0.0, 1.0 */
|
||||
switch (vd->extend) {
|
||||
case TEX_CLIP:
|
||||
{
|
||||
if ((co[0] < 0.f || co[0] > 1.f) || (co[1] < 0.f || co[1] > 1.f) || (co[2] < 0.f || co[2] > 1.f)) {
|
||||
texres->tin = 0.f;
|
||||
return retval;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TEX_REPEAT:
|
||||
{
|
||||
co[0] = co[0] - floorf(co[0]);
|
||||
co[1] = co[1] - floorf(co[1]);
|
||||
co[2] = co[2] - floorf(co[2]);
|
||||
break;
|
||||
}
|
||||
case TEX_EXTEND:
|
||||
{
|
||||
CLAMP(co[0], 0.f, 1.f);
|
||||
CLAMP(co[1], 0.f, 1.f);
|
||||
CLAMP(co[2], 0.f, 1.f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (ch = 0; ch < depth; ch++) {
|
||||
float *dataset = vd->dataset + ch*vd->resol[0]*vd->resol[1]*vd->resol[2];
|
||||
float *result = &texres->tin;
|
||||
|
||||
if (vd->data_type == TEX_VD_RGBA_PREMUL) {
|
||||
switch (ch) {
|
||||
case 0:
|
||||
result = &texres->tr;
|
||||
break;
|
||||
case 1:
|
||||
result = &texres->tg;
|
||||
break;
|
||||
case 2:
|
||||
result = &texres->tb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (vd->interp_type) {
|
||||
case TEX_VD_NEARESTNEIGHBOR:
|
||||
*result = BLI_voxel_sample_nearest(dataset, vd->resol, co);
|
||||
break;
|
||||
case TEX_VD_LINEAR:
|
||||
*result = BLI_voxel_sample_trilinear(dataset, vd->resol, co);
|
||||
break;
|
||||
case TEX_VD_QUADRATIC:
|
||||
*result = BLI_voxel_sample_triquadratic(dataset, vd->resol, co);
|
||||
break;
|
||||
case TEX_VD_TRICUBIC_CATROM:
|
||||
case TEX_VD_TRICUBIC_BSPLINE:
|
||||
*result = BLI_voxel_sample_tricubic(dataset, vd->resol, co, (vd->interp_type == TEX_VD_TRICUBIC_BSPLINE));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
a = texres->tin;
|
||||
texres->tin *= vd->int_multiplier;
|
||||
BRICONT;
|
||||
|
||||
if (vd->data_type == TEX_VD_RGBA_PREMUL) {
|
||||
/* unmultiply */
|
||||
if (a>0.001f) {
|
||||
texres->tr /= a;
|
||||
texres->tg /= a;
|
||||
texres->tb /= a;
|
||||
}
|
||||
texres->talpha = 1;
|
||||
}
|
||||
else {
|
||||
texres->tr = texres->tin;
|
||||
texres->tg = texres->tin;
|
||||
texres->tb = texres->tin;
|
||||
}
|
||||
|
||||
texres->ta = texres->tin;
|
||||
BRICONTRGB;
|
||||
|
||||
return retval;
|
||||
}
|
||||
Reference in New Issue
Block a user