add missing files after merging

This commit is contained in:
Xiao Xiangquan
2011-09-05 14:44:11 +00:00
parent d31d7fd487
commit 034cda72d3
41 changed files with 40542 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
/*
* $Id: BKE_speaker.h 39792 2011-08-30 09:15:55Z nexyon $
*
* ***** 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): Jörg Müller.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef BKE_SPEAKER_H
#define BKE_SPEAKER_H
/** \file BKE_speaker.h
* \ingroup bke
* \brief General operations for speakers.
*/
void *add_speaker(const char *name);
struct Speaker *copy_speaker(struct Speaker *spk);
void make_local_speaker(struct Speaker *spk);
void free_speaker(struct Speaker *spk);
#endif

View File

@@ -0,0 +1,139 @@
/* speaker.c
*
*
* $Id: speaker.c 39792 2011-08-30 09:15:55Z nexyon $
*
* ***** 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): Jörg Müller.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/blenkernel/intern/speaker.c
* \ingroup bke
*/
#include "DNA_object_types.h"
#include "DNA_sound_types.h"
#include "DNA_speaker_types.h"
#include "BLI_math.h"
#include "BKE_animsys.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_speaker.h"
void *add_speaker(const char *name)
{
Speaker *spk;
spk= alloc_libblock(&G.main->speaker, ID_SPK, name);
spk->attenuation = 1.0f;
spk->cone_angle_inner = 360.0f;
spk->cone_angle_outer = 360.0f;
spk->cone_volume_outer = 1.0f;
spk->distance_max = FLT_MAX;
spk->distance_reference = 1.0f;
spk->flag = 0;
spk->pitch = 1.0f;
spk->sound = NULL;
spk->volume = 1.0f;
spk->volume_max = 1.0f;
spk->volume_min = 0.0f;
return spk;
}
Speaker *copy_speaker(Speaker *spk)
{
Speaker *spkn;
spkn= copy_libblock(spk);
if(spkn->sound)
spkn->sound->id.us++;
return spkn;
}
void make_local_speaker(Speaker *spk)
{
Main *bmain= G.main;
Object *ob;
int local=0, lib=0;
/* - only lib users: do nothing
* - only local users: set flag
* - mixed: make copy
*/
if(spk->id.lib==NULL) return;
if(spk->id.us==1) {
spk->id.lib= NULL;
spk->id.flag= LIB_LOCAL;
new_id(&bmain->speaker, (ID *)spk, NULL);
return;
}
ob= bmain->object.first;
while(ob) {
if(ob->data==spk) {
if(ob->id.lib) lib= 1;
else local= 1;
}
ob= ob->id.next;
}
if(local && lib==0) {
spk->id.lib= NULL;
spk->id.flag= LIB_LOCAL;
new_id(&bmain->speaker, (ID *)spk, NULL);
}
else if(local && lib) {
Speaker *spkn= copy_speaker(spk);
spkn->id.us= 0;
ob= bmain->object.first;
while(ob) {
if(ob->data==spk) {
if(ob->id.lib==NULL) {
ob->data= spkn;
spkn->id.us++;
spk->id.us--;
}
}
ob= ob->id.next;
}
}
}
void free_speaker(Speaker *spk)
{
if(spk->sound)
spk->sound->id.us--;
BKE_free_animdata((ID *)spk);
}

View File

@@ -0,0 +1,1300 @@
/*
* $Id: AnimationExporter.cpp 39792 2011-08-30 09:15:55Z nexyon $
*
* ***** 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 "GeometryExporter.h"
#include "AnimationExporter.h"
#include "MaterialExporter.h"
template<class Functor>
void forEachObjectInScene(Scene *sce, Functor &f)
{
Base *base= (Base*) sce->base.first;
while(base) {
Object *ob = base->object;
f(ob);
base= base->next;
}
}
void AnimationExporter::exportAnimations(Scene *sce)
{
if(hasAnimations(sce)) {
this->scene = sce;
openLibrary();
forEachObjectInScene(sce, *this);
closeLibrary();
}
}
// called for each exported object
void AnimationExporter::operator() (Object *ob)
{
FCurve *fcu;
char * transformName ;
bool isMatAnim = false;
//Export transform animations
if(ob->adt && ob->adt->action)
{
fcu = (FCurve*)ob->adt->action->curves.first;
//transform matrix export for bones are temporarily disabled here.
if ( ob->type == OB_ARMATURE )
{
bArmature *arm = (bArmature*)ob->data;
for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next)
write_bone_animation_matrix(ob, bone);
}
while (fcu) {
//for armature animations as objects
if ( ob->type == OB_ARMATURE )
transformName = fcu->rna_path;
else
transformName = extract_transform_name( fcu->rna_path );
if ((!strcmp(transformName, "location") || !strcmp(transformName, "scale")) ||
(!strcmp(transformName, "rotation_euler") && ob->rotmode == ROT_MODE_EUL)||
(!strcmp(transformName, "rotation_quaternion")))
dae_animation(ob ,fcu, transformName, false);
fcu = fcu->next;
}
}
//Export Lamp parameter animations
if( (ob->type == OB_LAMP ) && ((Lamp*)ob ->data)->adt && ((Lamp*)ob ->data)->adt->action )
{
fcu = (FCurve*)(((Lamp*)ob ->data)->adt->action->curves.first);
while (fcu) {
transformName = extract_transform_name( fcu->rna_path );
if ((!strcmp(transformName, "color")) || (!strcmp(transformName, "spot_size"))|| (!strcmp(transformName, "spot_blend"))||
(!strcmp(transformName, "distance")) )
dae_animation(ob , fcu, transformName, true );
fcu = fcu->next;
}
}
//Export Camera parameter animations
if( (ob->type == OB_CAMERA ) && ((Camera*)ob ->data)->adt && ((Camera*)ob ->data)->adt->action )
{
fcu = (FCurve*)(((Camera*)ob ->data)->adt->action->curves.first);
while (fcu) {
transformName = extract_transform_name( fcu->rna_path );
if ((!strcmp(transformName, "lens"))||
(!strcmp(transformName, "ortho_scale"))||
(!strcmp(transformName, "clip_end"))||(!strcmp(transformName, "clip_start")))
dae_animation(ob , fcu, transformName, true );
fcu = fcu->next;
}
}
//Export Material parameter animations.
for(int a = 0; a < ob->totcol; a++)
{
Material *ma = give_current_material(ob, a+1);
if (!ma) continue;
if(ma->adt && ma->adt->action)
{
isMatAnim = true;
fcu = (FCurve*)ma->adt->action->curves.first;
while (fcu) {
transformName = extract_transform_name( fcu->rna_path );
if ((!strcmp(transformName, "specular_hardness"))||(!strcmp(transformName, "specular_color"))
||(!strcmp(transformName, "diffuse_color"))||(!strcmp(transformName, "alpha"))||
(!strcmp(transformName, "ior")))
dae_animation(ob ,fcu, transformName, true, ma );
fcu = fcu->next;
}
}
}
}
//euler sources from quternion sources
float * AnimationExporter::get_eul_source_for_quat(Object *ob )
{
FCurve *fcu = (FCurve*)ob->adt->action->curves.first;
const int keys = fcu->totvert;
float *quat = (float*)MEM_callocN(sizeof(float) * fcu->totvert * 4, "quat output source values");
float *eul = (float*)MEM_callocN(sizeof(float) * fcu->totvert * 3, "quat output source values");
float temp_quat[4];
float temp_eul[3];
while(fcu)
{
char * transformName = extract_transform_name( fcu->rna_path );
if( !strcmp(transformName, "rotation_quaternion") ) {
for ( int i = 0 ; i < fcu->totvert ; i++){
*(quat + ( i * 4 ) + fcu->array_index) = fcu->bezt[i].vec[1][1];
}
}
fcu = fcu->next;
}
for ( int i = 0 ; i < keys ; i++){
for ( int j = 0;j<4;j++)
temp_quat[j] = quat[(i*4)+j];
quat_to_eul(temp_eul,temp_quat);
for (int k = 0;k<3;k++)
eul[i*3 + k] = temp_eul[k];
}
MEM_freeN(quat);
return eul;
}
//Get proper name for bones
std::string AnimationExporter::getObjectBoneName( Object* ob,const FCurve* fcu )
{
//hard-way to derive the bone name from rna_path. Must find more compact method
std::string rna_path = std::string(fcu->rna_path);
char* boneName = strtok((char *)rna_path.c_str(), "\"");
boneName = strtok(NULL,"\"");
if( boneName != NULL )
return /*id_name(ob) + "_" +*/ std::string(boneName);
else
return id_name(ob);
}
//convert f-curves to animation curves and write
void AnimationExporter::dae_animation(Object* ob, FCurve *fcu, char* transformName , bool is_param, Material * ma )
{
const char *axis_name = NULL;
char anim_id[200];
bool has_tangents = false;
bool quatRotation = false;
if ( !strcmp(transformName, "rotation_quaternion") )
{
fprintf(stderr, "quaternion rotation curves are not supported. rotation curve will not be exported\n");
quatRotation = true;
return;
}
//axis names for colors
else if ( !strcmp(transformName, "color")||!strcmp(transformName, "specular_color")||!strcmp(transformName, "diffuse_color")||
(!strcmp(transformName, "alpha")))
{
const char *axis_names[] = {"R", "G", "B"};
if (fcu->array_index < 3)
axis_name = axis_names[fcu->array_index];
}
//axis names for transforms
else if ((!strcmp(transformName, "location") || !strcmp(transformName, "scale")) ||
(!strcmp(transformName, "rotation_euler"))||(!strcmp(transformName, "rotation_quaternion")))
{
const char *axis_names[] = {"X", "Y", "Z"};
if (fcu->array_index < 3)
axis_name = axis_names[fcu->array_index];
}
//no axis name. single parameter.
else{
axis_name = "";
}
std::string ob_name = std::string("null");
//Create anim Id
if (ob->type == OB_ARMATURE)
{
ob_name = getObjectBoneName( ob , fcu);
BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s.%s", (char*)translate_id(ob_name).c_str(),
transformName, axis_name);
}
else
{
if (ma)
ob_name = id_name(ob) + "_material";
else
ob_name = id_name(ob);
BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
fcu->rna_path, axis_name);
}
openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
// create input source
std::string input_id = create_source_from_fcurve(COLLADASW::InputSemantic::INPUT, fcu, anim_id, axis_name);
// create output source
std::string output_id ;
//quat rotations are skipped for now, because of complications with determining axis.
if(quatRotation)
{
float * eul = get_eul_source_for_quat(ob);
float * eul_axis = (float*)MEM_callocN(sizeof(float) * fcu->totvert, "quat output source values");
for ( int i = 0 ; i< fcu->totvert ; i++)
eul_axis[i] = eul[i*3 + fcu->array_index];
output_id= create_source_from_array(COLLADASW::InputSemantic::OUTPUT, eul_axis , fcu->totvert, quatRotation, anim_id, axis_name);
MEM_freeN(eul);
MEM_freeN(eul_axis);
}
else
{
output_id= create_source_from_fcurve(COLLADASW::InputSemantic::OUTPUT, fcu, anim_id, axis_name);
}
// create interpolations source
std::string interpolation_id = create_interpolation_source(fcu, anim_id, axis_name, &has_tangents);
// handle tangents (if required)
std::string intangent_id;
std::string outtangent_id;
if (has_tangents) {
// create in_tangent source
intangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::IN_TANGENT, fcu, anim_id, axis_name);
// create out_tangent source
outtangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUT_TANGENT, fcu, anim_id, axis_name);
}
std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
std::string empty;
sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
// this input is required
sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
if (has_tangents) {
sampler.addInput(COLLADASW::InputSemantic::IN_TANGENT, COLLADABU::URI(empty, intangent_id));
sampler.addInput(COLLADASW::InputSemantic::OUT_TANGENT, COLLADABU::URI(empty, outtangent_id));
}
addSampler(sampler);
std::string target ;
if ( !is_param )
target = translate_id(ob_name)
+ "/" + get_transform_sid(fcu->rna_path, -1, axis_name, true);
else
{
if ( ob->type == OB_LAMP )
target = get_light_id(ob)
+ "/" + get_light_param_sid(fcu->rna_path, -1, axis_name, true);
if ( ob->type == OB_CAMERA )
target = get_camera_id(ob)
+ "/" + get_camera_param_sid(fcu->rna_path, -1, axis_name, true);
if( ma )
target = translate_id(id_name(ma)) + "-effect"
+"/common/" /*profile common is only supported */ + get_transform_sid(fcu->rna_path, -1, axis_name, true);
}
addChannel(COLLADABU::URI(empty, sampler_id), target);
closeAnimation();
}
//write bone animations in transform matrix sources
void AnimationExporter::write_bone_animation_matrix(Object *ob_arm, Bone *bone)
{
if (!ob_arm->adt)
return;
//This will only export animations of bones in deform group.
/*if(!is_bone_deform_group(bone))
return;*/
sample_and_write_bone_animation_matrix(ob_arm, bone);
for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next)
write_bone_animation_matrix(ob_arm, child);
}
bool AnimationExporter::is_bone_deform_group(Bone * bone)
{
bool is_def;
//Check if current bone is deform
if((bone->flag & BONE_NO_DEFORM) == 0 ) return true;
//Check child bones
else
{
for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next){
//loop through all the children until deform bone is found, and then return
is_def = is_bone_deform_group(child);
if (is_def) return true;
}
}
//no deform bone found in children also
return false;
}
void AnimationExporter::sample_and_write_bone_animation_matrix(Object *ob_arm, Bone *bone)
{
bArmature *arm = (bArmature*)ob_arm->data;
int flag = arm->flag;
std::vector<float> fra;
//char prefix[256];
FCurve* fcu = (FCurve*)ob_arm->adt->action->curves.first;
while(fcu)
{
std::string bone_name = getObjectBoneName(ob_arm,fcu);
int val = BLI_strcasecmp((char*)bone_name.c_str(),bone->name);
if(val==0) break;
fcu = fcu->next;
}
if(!(fcu)) return;
bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name);
if (!pchan)
return;
find_frames(ob_arm, fra);
if (flag & ARM_RESTPOS) {
arm->flag &= ~ARM_RESTPOS;
where_is_pose(scene, ob_arm);
}
if (fra.size()) {
dae_baked_animation(fra ,ob_arm, bone );
}
if (flag & ARM_RESTPOS)
arm->flag = flag;
where_is_pose(scene, ob_arm);
}
void AnimationExporter::dae_baked_animation(std::vector<float> &fra, Object *ob_arm , Bone *bone)
{
std::string ob_name = id_name(ob_arm);
std::string bone_name = bone->name;
char anim_id[200];
if (!fra.size())
return;
BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
(char*)translate_id(bone_name).c_str(), "pose_matrix");
openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
// create input source
std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, false, anim_id, "");
// create output source
std::string output_id;
output_id = create_4x4_source( fra, ob_arm , bone , anim_id);
// create interpolations source
std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, "");
std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
std::string empty;
sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
// TODO create in/out tangents source
// this input is required
sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
addSampler(sampler);
std::string target = translate_id(bone_name) + "/transform";
addChannel(COLLADABU::URI(empty, sampler_id), target);
closeAnimation();
}
// dae_bone_animation -> add_bone_animation
// (blend this into dae_bone_animation)
void AnimationExporter::dae_bone_animation(std::vector<float> &fra, float *values, int tm_type, int axis, std::string ob_name, std::string bone_name)
{
const char *axis_names[] = {"X", "Y", "Z"};
const char *axis_name = NULL;
char anim_id[200];
bool is_rot = tm_type == 0;
if (!fra.size())
return;
char rna_path[200];
BLI_snprintf(rna_path, sizeof(rna_path), "pose.bones[\"%s\"].%s", bone_name.c_str(),
tm_type == 0 ? "rotation_quaternion" : (tm_type == 1 ? "scale" : "location"));
if (axis > -1)
axis_name = axis_names[axis];
std::string transform_sid = get_transform_sid(NULL, tm_type, axis_name, false);
BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
(char*)translate_id(bone_name).c_str(), (char*)transform_sid.c_str());
openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
// create input source
std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, is_rot, anim_id, axis_name);
// create output source
std::string output_id;
if (axis == -1)
output_id = create_xyz_source(values, fra.size(), anim_id);
else
output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, values, fra.size(), is_rot, anim_id, axis_name);
// create interpolations source
std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, axis_name);
std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
std::string empty;
sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
// TODO create in/out tangents source
// this input is required
sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
addSampler(sampler);
std::string target = translate_id(ob_name + "_" + bone_name) + "/" + transform_sid;
addChannel(COLLADABU::URI(empty, sampler_id), target);
closeAnimation();
}
float AnimationExporter::convert_time(float frame)
{
return FRA2TIME(frame);
}
float AnimationExporter::convert_angle(float angle)
{
return COLLADABU::Math::Utils::radToDegF(angle);
}
std::string AnimationExporter::get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic)
{
switch(semantic) {
case COLLADASW::InputSemantic::INPUT:
return INPUT_SOURCE_ID_SUFFIX;
case COLLADASW::InputSemantic::OUTPUT:
return OUTPUT_SOURCE_ID_SUFFIX;
case COLLADASW::InputSemantic::INTERPOLATION:
return INTERPOLATION_SOURCE_ID_SUFFIX;
case COLLADASW::InputSemantic::IN_TANGENT:
return INTANGENT_SOURCE_ID_SUFFIX;
case COLLADASW::InputSemantic::OUT_TANGENT:
return OUTTANGENT_SOURCE_ID_SUFFIX;
default:
break;
}
return "";
}
void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param,
COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis, bool transform)
{
switch(semantic) {
case COLLADASW::InputSemantic::INPUT:
param.push_back("TIME");
break;
case COLLADASW::InputSemantic::OUTPUT:
if (is_rot) {
param.push_back("ANGLE");
}
else {
if (axis) {
param.push_back(axis);
}
else
if ( transform )
{
param.push_back("TRANSFORM");
}else{ //assumes if axis isn't specified all axises are added
param.push_back("X");
param.push_back("Y");
param.push_back("Z");
}
}
break;
case COLLADASW::InputSemantic::IN_TANGENT:
case COLLADASW::InputSemantic::OUT_TANGENT:
param.push_back("X");
param.push_back("Y");
break;
default:
break;
}
}
void AnimationExporter::get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool rotation, float *values, int *length)
{
switch (semantic) {
case COLLADASW::InputSemantic::INPUT:
*length = 1;
values[0] = convert_time(bezt->vec[1][0]);
break;
case COLLADASW::InputSemantic::OUTPUT:
*length = 1;
if (rotation) {
values[0] = (bezt->vec[1][1]) * 180.0f/M_PI;
}
else {
values[0] = bezt->vec[1][1];
}
break;
case COLLADASW::InputSemantic::IN_TANGENT:
*length = 2;
values[0] = convert_time(bezt->vec[0][0]);
if (bezt->ipo != BEZT_IPO_BEZ) {
// We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data
values[0] = 0;
values[1] = 0;
}
else if (rotation) {
values[1] = (bezt->vec[0][1]) * 180.0f/M_PI;
} else {
values[1] = bezt->vec[0][1];
}
break;
case COLLADASW::InputSemantic::OUT_TANGENT:
*length = 2;
values[0] = convert_time(bezt->vec[2][0]);
if (bezt->ipo != BEZT_IPO_BEZ) {
// We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data
values[0] = 0;
values[1] = 0;
}
else if (rotation) {
values[1] = (bezt->vec[2][1]) * 180.0f/M_PI;
} else {
values[1] = bezt->vec[2][1];
}
break;
break;
default:
*length = 0;
break;
}
}
std::string AnimationExporter::create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name)
{
std::string source_id = anim_id + get_semantic_suffix(semantic);
//bool is_rotation = !strcmp(fcu->rna_path, "rotation");
bool is_angle = false;
if (strstr(fcu->rna_path, "rotation")) is_angle = true;
COLLADASW::FloatSourceF source(mSW);
source.setId(source_id);
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
source.setAccessorCount(fcu->totvert);
switch (semantic) {
case COLLADASW::InputSemantic::INPUT:
case COLLADASW::InputSemantic::OUTPUT:
source.setAccessorStride(1);
break;
case COLLADASW::InputSemantic::IN_TANGENT:
case COLLADASW::InputSemantic::OUT_TANGENT:
source.setAccessorStride(2);
break;
}
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
add_source_parameters(param, semantic, is_angle, axis_name, false);
source.prepareToAppendValues();
for (unsigned int i = 0; i < fcu->totvert; i++) {
float values[3]; // be careful!
int length = 0;
get_source_values(&fcu->bezt[i], semantic, is_angle, values, &length);
for (int j = 0; j < length; j++)
source.appendValues(values[j]);
}
source.finish();
return source_id;
}
//Currently called only to get OUTPUT source values ( if rotation and hence the axis is also specified )
std::string AnimationExporter::create_source_from_array(COLLADASW::InputSemantic::Semantics semantic, float *v, int tot, bool is_rot, const std::string& anim_id, const char *axis_name)
{
std::string source_id = anim_id + get_semantic_suffix(semantic);
COLLADASW::FloatSourceF source(mSW);
source.setId(source_id);
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
source.setAccessorCount(tot);
source.setAccessorStride(1);
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
add_source_parameters(param, semantic, is_rot, axis_name, false);
source.prepareToAppendValues();
for (int i = 0; i < tot; i++) {
float val = v[i];
////if (semantic == COLLADASW::InputSemantic::INPUT)
// val = convert_time(val);
//else
if (is_rot)
val *= 180.0f / M_PI;
source.appendValues(val);
}
source.finish();
return source_id;
}
// only used for sources with INPUT semantic
std::string AnimationExporter::create_source_from_vector(COLLADASW::InputSemantic::Semantics semantic, std::vector<float> &fra, bool is_rot, const std::string& anim_id, const char *axis_name)
{
std::string source_id = anim_id + get_semantic_suffix(semantic);
COLLADASW::FloatSourceF source(mSW);
source.setId(source_id);
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
source.setAccessorCount(fra.size());
source.setAccessorStride(1);
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
add_source_parameters(param, semantic, is_rot, axis_name, false);
source.prepareToAppendValues();
std::vector<float>::iterator it;
for (it = fra.begin(); it != fra.end(); it++) {
float val = *it;
//if (semantic == COLLADASW::InputSemantic::INPUT)
val = convert_time(val);
/*else if (is_rot)
val = convert_angle(val);*/
source.appendValues(val);
}
source.finish();
return source_id;
}
std::string AnimationExporter::create_4x4_source(std::vector<float> &frames , Object * ob_arm, Bone *bone , const std::string& anim_id)
{
COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
std::string source_id = anim_id + get_semantic_suffix(semantic);
COLLADASW::Float4x4Source source(mSW);
source.setId(source_id);
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
source.setAccessorCount(frames.size());
source.setAccessorStride(16);
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
add_source_parameters(param, semantic, false, NULL, true);
source.prepareToAppendValues();
bPoseChannel *parchan = NULL;
bPoseChannel *pchan = NULL;
bPose *pose = ob_arm->pose;
pchan = get_pose_channel(pose, bone->name);
if (!pchan)
return "";
parchan = pchan->parent;
enable_fcurves(ob_arm->adt->action, bone->name);
std::vector<float>::iterator it;
int j = 0;
for (it = frames.begin(); it != frames.end(); it++) {
float mat[4][4], ipar[4][4];
float ctime = bsystem_time(scene, ob_arm, *it, 0.0f);
BKE_animsys_evaluate_animdata(scene , &ob_arm->id, ob_arm->adt, ctime, ADT_RECALC_ANIM);
where_is_pose_bone(scene, ob_arm, pchan, ctime, 1);
// compute bone local mat
if (bone->parent) {
invert_m4_m4(ipar, parchan->pose_mat);
mul_m4_m4m4(mat, pchan->pose_mat, ipar);
}
else
copy_m4_m4(mat, pchan->pose_mat);
UnitConverter converter;
float outmat[4][4];
converter.mat4_to_dae(outmat,mat);
source.appendValues(outmat);
j++;
}
enable_fcurves(ob_arm->adt->action, NULL);
source.finish();
return source_id;
}
// only used for sources with OUTPUT semantic ( locations and scale)
std::string AnimationExporter::create_xyz_source(float *v, int tot, const std::string& anim_id)
{
COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
std::string source_id = anim_id + get_semantic_suffix(semantic);
COLLADASW::FloatSourceF source(mSW);
source.setId(source_id);
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
source.setAccessorCount(tot);
source.setAccessorStride(3);
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
add_source_parameters(param, semantic, false, NULL, false);
source.prepareToAppendValues();
for (int i = 0; i < tot; i++) {
source.appendValues(*v, *(v + 1), *(v + 2));
v += 3;
}
source.finish();
return source_id;
}
std::string AnimationExporter::create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents)
{
std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
COLLADASW::NameSource source(mSW);
source.setId(source_id);
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
source.setAccessorCount(fcu->totvert);
source.setAccessorStride(1);
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
param.push_back("INTERPOLATION");
source.prepareToAppendValues();
*has_tangents = false;
for (unsigned int i = 0; i < fcu->totvert; i++) {
if (fcu->bezt[i].ipo==BEZT_IPO_BEZ) {
source.appendValues(BEZIER_NAME);
*has_tangents = true;
} else if (fcu->bezt[i].ipo==BEZT_IPO_CONST) {
source.appendValues(STEP_NAME);
} else { // BEZT_IPO_LIN
source.appendValues(LINEAR_NAME);
}
}
// unsupported? -- HERMITE, CARDINAL, BSPLINE, NURBS
source.finish();
return source_id;
}
std::string AnimationExporter::fake_interpolation_source(int tot, const std::string& anim_id, const char *axis_name)
{
std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
COLLADASW::NameSource source(mSW);
source.setId(source_id);
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
source.setAccessorCount(tot);
source.setAccessorStride(1);
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
param.push_back("INTERPOLATION");
source.prepareToAppendValues();
for (int i = 0; i < tot; i++) {
source.appendValues(LINEAR_NAME);
}
source.finish();
return source_id;
}
std::string AnimationExporter::get_light_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
{
std::string tm_name;
// when given rna_path, determine tm_type from it
if (rna_path) {
char *name = extract_transform_name(rna_path);
if (!strcmp(name, "color"))
tm_type = 1;
else if (!strcmp(name, "spot_size"))
tm_type = 2;
else if (!strcmp(name, "spot_blend"))
tm_type = 3;
else if (!strcmp(name, "distance"))
tm_type = 4;
else
tm_type = -1;
}
switch (tm_type) {
case 1:
tm_name = "color";
break;
case 2:
tm_name = "fall_off_angle";
break;
case 3:
tm_name = "fall_off_exponent";
break;
case 4:
tm_name = "blender/blender_dist";
break;
default:
tm_name = "";
break;
}
if (tm_name.size()) {
if (axis_name != "")
return tm_name + "." + std::string(axis_name);
else
return tm_name;
}
return std::string("");
}
std::string AnimationExporter::get_camera_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
{
std::string tm_name;
// when given rna_path, determine tm_type from it
if (rna_path) {
char *name = extract_transform_name(rna_path);
if (!strcmp(name, "lens"))
tm_type = 0;
else if (!strcmp(name, "ortho_scale"))
tm_type = 1;
else if (!strcmp(name, "clip_end"))
tm_type = 2;
else if (!strcmp(name, "clip_start"))
tm_type = 3;
else
tm_type = -1;
}
switch (tm_type) {
case 0:
tm_name = "xfov";
break;
case 1:
tm_name = "xmag";
break;
case 2:
tm_name = "zfar";
break;
case 3:
tm_name = "znear";
break;
default:
tm_name = "";
break;
}
if (tm_name.size()) {
if (axis_name != "")
return tm_name + "." + std::string(axis_name);
else
return tm_name;
}
return std::string("");
}
// Assign sid of the animated parameter or transform
// for rotation, axis name is always appended and the value of append_axis is ignored
std::string AnimationExporter::get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
{
std::string tm_name;
bool is_rotation =false;
// when given rna_path, determine tm_type from it
if (rna_path) {
char *name = extract_transform_name(rna_path);
if (!strcmp(name, "rotation_euler"))
tm_type = 0;
else if (!strcmp(name, "rotation_quaternion"))
tm_type = 1;
else if (!strcmp(name, "scale"))
tm_type = 2;
else if (!strcmp(name, "location"))
tm_type = 3;
else if (!strcmp(name, "specular_hardness"))
tm_type = 4;
else if (!strcmp(name, "specular_color"))
tm_type = 5;
else if (!strcmp(name, "diffuse_color"))
tm_type = 6;
else if (!strcmp(name, "alpha"))
tm_type = 7;
else if (!strcmp(name, "ior"))
tm_type = 8;
else
tm_type = -1;
}
switch (tm_type) {
case 0:
case 1:
tm_name = "rotation";
is_rotation = true;
break;
case 2:
tm_name = "scale";
break;
case 3:
tm_name = "location";
break;
case 4:
tm_name = "shininess";
break;
case 5:
tm_name = "specular";
break;
case 6:
tm_name = "diffuse";
break;
case 7:
tm_name = "transparency";
break;
case 8:
tm_name = "index_of_refraction";
break;
default:
tm_name = "";
break;
}
if (tm_name.size()) {
if (is_rotation)
return tm_name + std::string(axis_name) + ".ANGLE";
else
if (axis_name != "")
return tm_name + "." + std::string(axis_name);
else
return tm_name;
}
return std::string("");
}
char* AnimationExporter::extract_transform_name(char *rna_path)
{
char *dot = strrchr(rna_path, '.');
return dot ? (dot + 1) : rna_path;
}
//find keyframes of all the objects animations
void AnimationExporter::find_frames(Object *ob, std::vector<float> &fra)
{
FCurve *fcu= (FCurve*)ob->adt->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]; //
if (std::find(fra.begin(), fra.end(), f) == fra.end())
fra.push_back(f);
}
}
// keep the keys in ascending order
std::sort(fra.begin(), fra.end());
}
// enable fcurves driving a specific bone, disable all the rest
// if bone_name = NULL enable all fcurves
void AnimationExporter::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 (!strncmp(fcu->rna_path, prefix, strlen(prefix)))
fcu->flag &= ~FCURVE_DISABLED;
else
fcu->flag |= FCURVE_DISABLED;
}
else {
fcu->flag &= ~FCURVE_DISABLED;
}
}
}
bool AnimationExporter::hasAnimations(Scene *sce)
{
Base *base= (Base*) sce->base.first;
while(base) {
Object *ob = base->object;
FCurve *fcu = 0;
//Check for object transform animations
if(ob->adt && ob->adt->action)
fcu = (FCurve*)ob->adt->action->curves.first;
//Check for Lamp parameter animations
else if( (ob->type == OB_LAMP ) && ((Lamp*)ob ->data)->adt && ((Lamp*)ob ->data)->adt->action )
fcu = (FCurve*)(((Lamp*)ob ->data)->adt->action->curves.first);
//Check for Camera parameter animations
else if( (ob->type == OB_CAMERA ) && ((Camera*)ob ->data)->adt && ((Camera*)ob ->data)->adt->action )
fcu = (FCurve*)(((Camera*)ob ->data)->adt->action->curves.first);
//Check Material Effect parameter animations.
for(int a = 0; a < ob->totcol; a++)
{
Material *ma = give_current_material(ob, a+1);
if (!ma) continue;
if(ma->adt && ma->adt->action)
{
fcu = (FCurve*)ma->adt->action->curves.first;
}
}
if ( fcu)
return true;
base= base->next;
}
return false;
}
//------------------------------- Not used in the new system.--------------------------------------------------------
void AnimationExporter::find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode)
{
if (rotmode > 0)
find_frames(ob, fra, prefix, "rotation_euler");
else if (rotmode == ROT_MODE_QUAT)
find_frames(ob, fra, prefix, "rotation_quaternion");
/*else if (rotmode == ROT_MODE_AXISANGLE)
;*/
}
void AnimationExporter::find_frames(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name)
{
FCurve *fcu= (FCurve*)ob->adt->action->curves.first;
for (; fcu; fcu = fcu->next) {
if (prefix && strncmp(prefix, fcu->rna_path, strlen(prefix)))
continue;
char *name = extract_transform_name(fcu->rna_path);
if (!strcmp(name, tm_name)) {
for (unsigned int i = 0; i < fcu->totvert; i++) {
float f = fcu->bezt[i].vec[1][0]; //
if (std::find(fra.begin(), fra.end(), f) == fra.end())
fra.push_back(f);
}
}
}
// keep the keys in ascending order
std::sort(fra.begin(), fra.end());
}
void AnimationExporter::write_bone_animation(Object *ob_arm, Bone *bone)
{
if (!ob_arm->adt)
return;
//write bone animations for 3 transform types
//i=0 --> rotations
//i=1 --> scale
//i=2 --> location
for (int i = 0; i < 3; i++)
sample_and_write_bone_animation(ob_arm, bone, i);
for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next)
write_bone_animation(ob_arm, child);
}
void AnimationExporter::sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type)
{
bArmature *arm = (bArmature*)ob_arm->data;
int flag = arm->flag;
std::vector<float> fra;
char prefix[256];
BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone->name);
bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name);
if (!pchan)
return;
//Fill frame array with key frame values framed at @param:transform_type
switch (transform_type) {
case 0:
find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode);
break;
case 1:
find_frames(ob_arm, fra, prefix, "scale");
break;
case 2:
find_frames(ob_arm, fra, prefix, "location");
break;
default:
return;
}
// exit rest position
if (flag & ARM_RESTPOS) {
arm->flag &= ~ARM_RESTPOS;
where_is_pose(scene, ob_arm);
}
//v array will hold all values which will be exported.
if (fra.size()) {
float *values = (float*)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames");
sample_animation(values, fra, transform_type, bone, ob_arm, pchan);
if (transform_type == 0) {
// write x, y, z curves separately if it is rotation
float *axisValues = (float*)MEM_callocN(sizeof(float) * fra.size(), "temp. anim frames");
for (int i = 0; i < 3; i++) {
for (unsigned int j = 0; j < fra.size(); j++)
axisValues[j] = values[j * 3 + i];
dae_bone_animation(fra, axisValues, transform_type, i, id_name(ob_arm), bone->name);
}
MEM_freeN(axisValues);
}
else {
// write xyz at once if it is location or scale
dae_bone_animation(fra, values, transform_type, -1, id_name(ob_arm), bone->name);
}
MEM_freeN(values);
}
// restore restpos
if (flag & ARM_RESTPOS)
arm->flag = flag;
where_is_pose(scene, ob_arm);
}
void AnimationExporter::sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm, bPoseChannel *pchan)
{
bPoseChannel *parchan = NULL;
bPose *pose = ob_arm->pose;
pchan = get_pose_channel(pose, bone->name);
if (!pchan)
return;
parchan = pchan->parent;
enable_fcurves(ob_arm->adt->action, bone->name);
std::vector<float>::iterator it;
for (it = frames.begin(); it != frames.end(); it++) {
float mat[4][4], ipar[4][4];
float ctime = bsystem_time(scene, ob_arm, *it, 0.0f);
BKE_animsys_evaluate_animdata(scene , &ob_arm->id, ob_arm->adt, ctime, ADT_RECALC_ANIM);
where_is_pose_bone(scene, ob_arm, pchan, ctime, 1);
// compute bone local mat
if (bone->parent) {
invert_m4_m4(ipar, parchan->pose_mat);
mul_m4_m4m4(mat, pchan->pose_mat, ipar);
}
else
copy_m4_m4(mat, pchan->pose_mat);
switch (type) {
case 0:
mat4_to_eul(v, mat);
break;
case 1:
mat4_to_size(v, mat);
break;
case 2:
copy_v3_v3(v, mat[3]);
break;
}
v += 3;
}
enable_fcurves(ob_arm->adt->action, NULL);
}

View File

@@ -0,0 +1,163 @@
/*
* $Id: AnimationExporter.h 39809 2011-08-30 19:38:32Z gsrb3d $
*
* ***** 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 <stdlib.h>
#include <stdio.h>
#include <math.h>
extern "C"
{
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_anim_types.h"
#include "DNA_action_types.h"
#include "DNA_curve_types.h"
#include "DNA_lamp_types.h"
#include "DNA_camera_types.h"
#include "DNA_armature_types.h"
#include "DNA_material_types.h"
#include "BKE_DerivedMesh.h"
#include "BKE_fcurve.h"
#include "BKE_animsys.h"
#ifdef NAN_BUILDINFO
extern char build_rev[];
#endif
}
#include "MEM_guardedalloc.h"
#include "BKE_action.h" // pose functions
#include "BKE_armature.h"
#include "BKE_object.h"
#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_listbase.h"
#include "RNA_access.h"
#include "COLLADASWSource.h"
#include "COLLADASWInstanceGeometry.h"
#include "COLLADASWInputList.h"
#include "COLLADASWPrimitves.h"
#include "COLLADASWVertices.h"
#include "COLLADASWLibraryAnimations.h"
#include "COLLADASWParamTemplate.h"
#include "COLLADASWParamBase.h"
#include "COLLADASWSampler.h"
#include "COLLADASWConstants.h"
#include "COLLADASWBaseInputElement.h"
#include "EffectExporter.h"
#include "collada_internal.h"
#include <vector>
#include <algorithm> // std::find
class AnimationExporter: COLLADASW::LibraryAnimations
{
private:
Scene *scene;
COLLADASW::StreamWriter *sw;
public:
AnimationExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryAnimations(sw) { this->sw = sw; }
void exportAnimations(Scene *sce);
// called for each exported object
void operator() (Object *ob);
protected:
void dae_animation(Object* ob, FCurve *fcu, char* transformName , bool is_param, Material *ma = NULL);
void write_bone_animation_matrix(Object *ob_arm, Bone *bone);
void write_bone_animation(Object *ob_arm, Bone *bone);
void sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type);
bool is_bone_deform_group(Bone * bone);
void sample_and_write_bone_animation_matrix(Object *ob_arm, Bone *bone);
void sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm, bPoseChannel *pChan);
void sample_animation(std::vector<float[4][4]> &mats, std::vector<float> &frames, Bone *bone, Object *ob_arm, bPoseChannel *pChan);
// dae_bone_animation -> add_bone_animation
// (blend this into dae_bone_animation)
void dae_bone_animation(std::vector<float> &fra, float *v, int tm_type, int axis, std::string ob_name, std::string bone_name);
void dae_baked_animation(std::vector<float> &fra, Object *ob_arm , Bone *bone);
float convert_time(float frame);
float convert_angle(float angle);
std::string get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic);
void add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param,
COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis , bool transform);
void get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool rotation, float *values, int *length);
float * get_eul_source_for_quat(Object *ob );
std::string create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name);
std::string create_source_from_array(COLLADASW::InputSemantic::Semantics semantic, float *v, int tot, bool is_rot, const std::string& anim_id, const char *axis_name);
std::string create_source_from_vector(COLLADASW::InputSemantic::Semantics semantic, std::vector<float> &fra, bool is_rot, const std::string& anim_id, const char *axis_name);
std::string create_xyz_source(float *v, int tot, const std::string& anim_id);
std::string create_4x4_source(std::vector<float> &frames , Object * ob_arm, Bone *bone , const std::string& anim_id);
std::string create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents);
std::string fake_interpolation_source(int tot, const std::string& anim_id, const char *axis_name);
// for rotation, axis name is always appended and the value of append_axis is ignored
std::string get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis);
std::string get_light_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis);
std::string get_camera_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis);
void find_frames(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name);
void find_frames(Object *ob, std::vector<float> &fra);
void find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode);
// enable fcurves driving a specific bone, disable all the rest
// if bone_name = NULL enable all fcurves
void enable_fcurves(bAction *act, char *bone_name);
bool hasAnimations(Scene *sce);
char* extract_transform_name(char *rna_path);
std::string getObjectBoneName ( Object *ob,const FCurve * fcu);
};

View File

@@ -0,0 +1,133 @@
/**
* $Id: IMB_indexer.h 39759 2011-08-28 21:48:52Z gsrb3d $
*
* ***** 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): Peter Schlaile
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef IMB_INDEXER_H
#define IMB_INDEXER_H
#ifdef WIN32
#include <io.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include "BKE_utildefines.h"
#include "IMB_anim.h"
/*
seperate animation index files to solve the following problems:
a) different timecodes within one file (like DTS/PTS, Timecode-Track,
"implicit" timecodes within DV-files and HDV-files etc.)
b) seeking difficulties within ffmpeg for files with timestamp holes
c) broken files that miss several frames / have varying framerates
d) use proxies accordingly
... we need index files, that provide us with
the binary(!) position, where we have to seek into the file *and*
the continuous frame number (ignoring the holes) starting from the
beginning of the file, so that we know, which proxy frame to serve.
This index has to be only built once for a file and is written into
the BL_proxy directory structure for later reuse in different blender files.
*/
typedef struct anim_index_entry {
int frameno;
unsigned long long seek_pos;
unsigned long long seek_pos_dts;
unsigned long long pts;
} anim_index_entry;
struct anim_index {
char name[256];
int num_entries;
struct anim_index_entry * entries;
};
struct anim_index_builder;
typedef struct anim_index_builder {
FILE * fp;
char name[FILE_MAXDIR + FILE_MAXFILE];
char temp_name[FILE_MAXDIR + FILE_MAXFILE];
void * private_data;
void (*delete_priv_data)(struct anim_index_builder * idx);
void (*proc_frame)(struct anim_index_builder * idx,
unsigned char * buffer,
int data_size,
struct anim_index_entry * entry);
} anim_index_builder;
anim_index_builder * IMB_index_builder_create(const char * name);
void IMB_index_builder_add_entry(anim_index_builder * fp,
int frameno, unsigned long long seek_pos,
unsigned long long seek_pos_dts,
unsigned long long pts);
void IMB_index_builder_proc_frame(anim_index_builder * fp,
unsigned char * buffer,
int data_size,
int frameno, unsigned long long seek_pos,
unsigned long long seek_pos_dts,
unsigned long long pts);
void IMB_index_builder_finish(anim_index_builder * fp, int rollback);
struct anim_index * IMB_indexer_open(const char * name);
unsigned long long IMB_indexer_get_seek_pos(
struct anim_index * idx, int frameno_index);
unsigned long long IMB_indexer_get_seek_pos_dts(
struct anim_index * idx, int frameno_index);
int IMB_indexer_get_frame_index(struct anim_index * idx, int frameno);
unsigned long long IMB_indexer_get_pts(struct anim_index * idx,
int frame_index);
int IMB_indexer_get_duration(struct anim_index * idx);
int IMB_indexer_can_scan(struct anim_index * idx,
int old_frame_index, int new_frame_index);
void IMB_indexer_close(struct anim_index * idx);
void IMB_free_indices(struct anim * anim);
int IMB_anim_index_get_frame_index(
struct anim * anim, IMB_Timecode_Type tc, int position);
struct anim * IMB_anim_open_proxy(
struct anim * anim, IMB_Proxy_Size preview_size);
struct anim_index * IMB_anim_open_index(
struct anim * anim, IMB_Timecode_Type tc);
int IMB_proxy_size_to_array_index(IMB_Proxy_Size pr_size);
int IMB_timecode_to_array_index(IMB_Timecode_Type tc);
#endif

View File

@@ -0,0 +1,1142 @@
/*
* $Id: indexer.c 39764 2011-08-29 01:00:14Z campbellbarton $
*
* ***** 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.
*
* Peter Schlaile <peter [at] schlaile [dot] de> 2011
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "IMB_indexer.h"
#include "IMB_anim.h"
#include "AVI_avi.h"
#include "imbuf.h"
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
#include "BLI_math_base.h"
#include "BLI_string.h"
#include "MEM_guardedalloc.h"
#include "DNA_userdef_types.h"
#include "BKE_global.h"
#include <stdlib.h>
#ifdef WITH_FFMPEG
#include "ffmpeg_compat.h"
#endif //WITH_FFMPEG
static char magic[] = "BlenMIdx";
static char temp_ext [] = "_part";
static int proxy_sizes[] = { IMB_PROXY_25, IMB_PROXY_50, IMB_PROXY_75,
IMB_PROXY_100 };
static float proxy_fac[] = { 0.25, 0.50, 0.75, 1.00 };
#ifdef WITH_FFMPEG
static int tc_types[] = { IMB_TC_RECORD_RUN, IMB_TC_FREE_RUN,
IMB_TC_INTERPOLATED_REC_DATE_FREE_RUN };
#endif
#define INDEX_FILE_VERSION 1
/* ----------------------------------------------------------------------
- special indexers
----------------------------------------------------------------------
*/
extern void IMB_indexer_dv_new(anim_index_builder * idx);
/* ----------------------------------------------------------------------
- time code index functions
---------------------------------------------------------------------- */
anim_index_builder * IMB_index_builder_create(const char * name)
{
anim_index_builder * rv
= MEM_callocN( sizeof(struct anim_index_builder),
"index builder");
fprintf(stderr, "Starting work on index: %s\n", name);
BLI_strncpy(rv->name, name, sizeof(rv->name));
BLI_strncpy(rv->temp_name, name, sizeof(rv->temp_name));
strcat(rv->temp_name, temp_ext);
BLI_make_existing_file(rv->temp_name);
rv->fp = fopen(rv->temp_name, "w");
if (!rv->fp) {
fprintf(stderr, "Couldn't open index target: %s! "
"Index build broken!\n", rv->temp_name);
MEM_freeN(rv);
return NULL;
}
fprintf(rv->fp, "%s%c%.3d", magic, (ENDIAN_ORDER==B_ENDIAN)?'V':'v',
INDEX_FILE_VERSION);
return rv;
}
void IMB_index_builder_add_entry(anim_index_builder * fp,
int frameno,unsigned long long seek_pos,
unsigned long long seek_pos_dts,
unsigned long long pts)
{
fwrite(&frameno, sizeof(int), 1, fp->fp);
fwrite(&seek_pos, sizeof(unsigned long long), 1, fp->fp);
fwrite(&seek_pos_dts, sizeof(unsigned long long), 1, fp->fp);
fwrite(&pts, sizeof(unsigned long long), 1, fp->fp);
}
void IMB_index_builder_proc_frame(anim_index_builder * fp,
unsigned char * buffer,
int data_size,
int frameno, unsigned long long seek_pos,
unsigned long long seek_pos_dts,
unsigned long long pts)
{
if (fp->proc_frame) {
anim_index_entry e;
e.frameno = frameno;
e.seek_pos = seek_pos;
e.seek_pos_dts = seek_pos_dts;
e.pts = pts;
fp->proc_frame(fp, buffer, data_size, &e);
} else {
IMB_index_builder_add_entry(fp, frameno, seek_pos,
seek_pos_dts, pts);
}
}
void IMB_index_builder_finish(anim_index_builder * fp, int rollback)
{
if (fp->delete_priv_data) {
fp->delete_priv_data(fp);
}
fclose(fp->fp);
if (rollback) {
unlink(fp->temp_name);
} else {
rename(fp->temp_name, fp->name);
}
MEM_freeN(fp);
}
struct anim_index * IMB_indexer_open(const char * name)
{
char header[13];
struct anim_index * idx;
FILE * fp = fopen(name, "rb");
int i;
if (!fp) {
return 0;
}
if (fread(header, 12, 1, fp) != 1) {
fclose(fp);
return 0;
}
header[12] = 0;
if (memcmp(header, magic, 8) != 0) {
fclose(fp);
return 0;
}
if (atoi(header+9) != INDEX_FILE_VERSION) {
fclose(fp);
return 0;
}
idx = MEM_callocN( sizeof(struct anim_index), "anim_index");
BLI_strncpy(idx->name, name, sizeof(idx->name));
fseek(fp, 0, SEEK_END);
idx->num_entries = (ftell(fp) - 12)
/ (sizeof(int) // framepos
+ sizeof(unsigned long long) // seek_pos
+ sizeof(unsigned long long) // seek_pos_dts
+ sizeof(unsigned long long) // pts
);
fseek(fp, 12, SEEK_SET);
idx->entries = MEM_callocN( sizeof(struct anim_index_entry)
* idx->num_entries, "anim_index_entries");
for (i = 0; i < idx->num_entries; i++) {
fread(&idx->entries[i].frameno,
sizeof(int), 1, fp);
fread(&idx->entries[i].seek_pos,
sizeof(unsigned long long), 1, fp);
fread(&idx->entries[i].seek_pos_dts,
sizeof(unsigned long long), 1, fp);
fread(&idx->entries[i].pts,
sizeof(unsigned long long), 1, fp);
}
if (((ENDIAN_ORDER == B_ENDIAN) != (header[8] == 'V'))) {
for (i = 0; i < idx->num_entries; i++) {
SWITCH_INT(idx->entries[i].frameno);
SWITCH_INT64(idx->entries[i].seek_pos);
SWITCH_INT64(idx->entries[i].seek_pos_dts);
SWITCH_INT64(idx->entries[i].pts);
}
}
fclose(fp);
return idx;
}
unsigned long long IMB_indexer_get_seek_pos(
struct anim_index * idx, int frame_index)
{
if (frame_index < 0) {
frame_index = 0;
}
if (frame_index >= idx->num_entries) {
frame_index = idx->num_entries - 1;
}
return idx->entries[frame_index].seek_pos;
}
unsigned long long IMB_indexer_get_seek_pos_dts(
struct anim_index * idx, int frame_index)
{
if (frame_index < 0) {
frame_index = 0;
}
if (frame_index >= idx->num_entries) {
frame_index = idx->num_entries - 1;
}
return idx->entries[frame_index].seek_pos_dts;
}
int IMB_indexer_get_frame_index(struct anim_index * idx, int frameno)
{
int len = idx->num_entries;
int half;
int middle;
int first = 0;
/* bsearch (lower bound) the right index */
while (len > 0) {
half = len >> 1;
middle = first;
middle += half;
if (idx->entries[middle].frameno < frameno) {
first = middle;
++first;
len = len - half - 1;
} else {
len = half;
}
}
if (first == idx->num_entries) {
return idx->num_entries - 1;
} else {
return first;
}
}
unsigned long long IMB_indexer_get_pts(struct anim_index * idx,
int frame_index)
{
if (frame_index < 0) {
frame_index = 0;
}
if (frame_index >= idx->num_entries) {
frame_index = idx->num_entries - 1;
}
return idx->entries[frame_index].pts;
}
int IMB_indexer_get_duration(struct anim_index * idx)
{
if (idx->num_entries == 0) {
return 0;
}
return idx->entries[idx->num_entries-1].frameno + 1;
}
int IMB_indexer_can_scan(struct anim_index * idx,
int old_frame_index, int new_frame_index)
{
/* makes only sense, if it is the same I-Frame and we are not
trying to run backwards in time... */
return (IMB_indexer_get_seek_pos(idx, old_frame_index)
== IMB_indexer_get_seek_pos(idx, new_frame_index) &&
old_frame_index < new_frame_index);
}
void IMB_indexer_close(struct anim_index * idx)
{
MEM_freeN(idx->entries);
MEM_freeN(idx);
}
int IMB_proxy_size_to_array_index(IMB_Proxy_Size pr_size)
{
switch (pr_size) {
case IMB_PROXY_NONE: /* if we got here, something is broken anyways,
so sane defaults... */
return 0;
case IMB_PROXY_25:
return 0;
case IMB_PROXY_50:
return 1;
case IMB_PROXY_75:
return 2;
case IMB_PROXY_100:
return 3;
default:
return 0;
};
return 0;
}
int IMB_timecode_to_array_index(IMB_Timecode_Type tc)
{
switch (tc) {
case IMB_TC_NONE: /* if we got here, something is broken anyways,
so sane defaults... */
return 0;
case IMB_TC_RECORD_RUN:
return 0;
case IMB_TC_FREE_RUN:
return 1;
case IMB_TC_INTERPOLATED_REC_DATE_FREE_RUN:
return 2;
default:
return 0;
};
return 0;
}
/* ----------------------------------------------------------------------
- rebuild helper functions
---------------------------------------------------------------------- */
static void get_index_dir(struct anim * anim, char * index_dir)
{
if (!anim->index_dir[0]) {
char fname[FILE_MAXFILE];
BLI_strncpy(index_dir, anim->name, FILE_MAXDIR);
BLI_splitdirstring(index_dir, fname);
BLI_join_dirfile(index_dir, FILE_MAXDIR, index_dir, "BL_proxy");
BLI_join_dirfile(index_dir, FILE_MAXDIR, index_dir, fname);
} else {
BLI_strncpy(index_dir, anim->index_dir, FILE_MAXDIR);
}
}
static void get_proxy_filename(struct anim * anim, IMB_Proxy_Size preview_size,
char * fname, int temp)
{
char index_dir[FILE_MAXDIR];
int i = IMB_proxy_size_to_array_index(preview_size);
char proxy_name[256];
char proxy_temp_name[256];
char stream_suffix[20];
stream_suffix[0] = 0;
if (anim->streamindex > 0) {
BLI_snprintf(stream_suffix, 20, "_st%d", anim->streamindex);
}
BLI_snprintf(proxy_name, 256, "proxy_%d%s.avi",
(int) (proxy_fac[i] * 100), stream_suffix);
BLI_snprintf(proxy_temp_name, 256, "proxy_%d%s_part.avi",
(int) (proxy_fac[i] * 100), stream_suffix);
get_index_dir(anim, index_dir);
BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR, index_dir,
temp ? proxy_temp_name : proxy_name);
}
static void get_tc_filename(struct anim * anim, IMB_Timecode_Type tc,
char * fname)
{
char index_dir[FILE_MAXDIR];
int i = IMB_timecode_to_array_index(tc);
const char * index_names[] = {
"record_run%s.blen_tc", "free_run%s.blen_tc",
"interp_free_run%s.blen_tc" };
char stream_suffix[20];
char index_name[256];
stream_suffix[0] = 0;
if (anim->streamindex > 0) {
BLI_snprintf(stream_suffix, 20, "_st%d", anim->streamindex);
}
BLI_snprintf(index_name, 256, index_names[i], stream_suffix);
get_index_dir(anim, index_dir);
BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR,
index_dir, index_name);
}
/* ----------------------------------------------------------------------
- ffmpeg rebuilder
---------------------------------------------------------------------- */
#ifdef WITH_FFMPEG
struct proxy_output_ctx {
AVFormatContext* of;
AVStream* st;
AVCodecContext* c;
AVCodec* codec;
struct SwsContext * sws_ctx;
AVFrame* frame;
uint8_t* video_buffer;
int video_buffersize;
int cfra;
int proxy_size;
int orig_height;
struct anim * anim;
};
// work around stupid swscaler 16 bytes alignment bug...
static int round_up(int x, int mod)
{
return x + ((mod - (x % mod)) % mod);
}
static struct proxy_output_ctx * alloc_proxy_output_ffmpeg(
struct anim * anim,
AVStream * st, int proxy_size, int width, int height,
int quality)
{
struct proxy_output_ctx * rv = MEM_callocN(
sizeof(struct proxy_output_ctx), "alloc_proxy_output");
char fname[FILE_MAXDIR+FILE_MAXFILE];
// JPEG requires this
width = round_up(width, 8);
height = round_up(height, 8);
rv->proxy_size = proxy_size;
rv->anim = anim;
get_proxy_filename(rv->anim, rv->proxy_size, fname, TRUE);
BLI_make_existing_file(fname);
rv->of = avformat_alloc_context();
rv->of->oformat = av_guess_format("avi", NULL, NULL);
BLI_snprintf(rv->of->filename, sizeof(rv->of->filename), "%s", fname);
fprintf(stderr, "Starting work on proxy: %s\n", rv->of->filename);
rv->st = av_new_stream(rv->of, 0);
rv->c = rv->st->codec;
rv->c->codec_type = AVMEDIA_TYPE_VIDEO;
rv->c->codec_id = CODEC_ID_MJPEG;
rv->c->width = width;
rv->c->height = height;
rv->of->oformat->video_codec = rv->c->codec_id;
rv->codec = avcodec_find_encoder(rv->c->codec_id);
if (!rv->codec) {
fprintf(stderr, "No ffmpeg MJPEG encoder available? "
"Proxy not built!\n");
av_free(rv->of);
return NULL;
}
if (rv->codec->pix_fmts) {
rv->c->pix_fmt = rv->codec->pix_fmts[0];
} else {
rv->c->pix_fmt = PIX_FMT_YUVJ420P;
}
rv->c->sample_aspect_ratio
= rv->st->sample_aspect_ratio
= st->codec->sample_aspect_ratio;
rv->c->time_base.den = 25;
rv->c->time_base.num = 1;
rv->st->time_base = rv->c->time_base;
if (rv->of->flags & AVFMT_GLOBALHEADER) {
rv->c->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
if (av_set_parameters(rv->of, NULL) < 0) {
fprintf(stderr, "Couldn't set output parameters? "
"Proxy not built!\n");
av_free(rv->of);
return 0;
}
if (avio_open(&rv->of->pb, fname, AVIO_FLAG_WRITE) < 0) {
fprintf(stderr, "Couldn't open outputfile! "
"Proxy not built!\n");
av_free(rv->of);
return 0;
}
avcodec_open(rv->c, rv->codec);
rv->video_buffersize = 2000000;
rv->video_buffer = (uint8_t*)MEM_mallocN(
rv->video_buffersize, "FFMPEG video buffer");
rv->orig_height = st->codec->height;
if (st->codec->width != width || st->codec->height != height
|| st->codec->pix_fmt != rv->c->pix_fmt) {
rv->frame = avcodec_alloc_frame();
avpicture_fill((AVPicture*) rv->frame,
MEM_mallocN(avpicture_get_size(
rv->c->pix_fmt,
round_up(width, 16), height),
"alloc proxy output frame"),
rv->c->pix_fmt, round_up(width, 16), height);
rv->sws_ctx = sws_getContext(
st->codec->width,
st->codec->height,
st->codec->pix_fmt,
width, height,
rv->c->pix_fmt,
SWS_FAST_BILINEAR | SWS_PRINT_INFO,
NULL, NULL, NULL);
}
av_write_header(rv->of);
return rv;
}
static int add_to_proxy_output_ffmpeg(
struct proxy_output_ctx * ctx, AVFrame * frame)
{
int outsize = 0;
if (!ctx) {
return 0;
}
if (ctx->sws_ctx && frame &&
(frame->data[0] || frame->data[1] ||
frame->data[2] || frame->data[3])) {
sws_scale(ctx->sws_ctx, (const uint8_t * const*) frame->data,
frame->linesize, 0, ctx->orig_height,
ctx->frame->data, ctx->frame->linesize);
}
frame = ctx->sws_ctx ? (frame ? ctx->frame : 0) : frame;
if (frame) {
frame->pts = ctx->cfra++;
}
outsize = avcodec_encode_video(
ctx->c, ctx->video_buffer, ctx->video_buffersize,
frame);
if (outsize < 0) {
fprintf(stderr, "Error encoding proxy frame %d for '%s'\n",
ctx->cfra - 1, ctx->of->filename);
return 0;
}
if (outsize != 0) {
AVPacket packet;
av_init_packet(&packet);
if (ctx->c->coded_frame->pts != AV_NOPTS_VALUE) {
packet.pts = av_rescale_q(ctx->c->coded_frame->pts,
ctx->c->time_base,
ctx->st->time_base);
}
if (ctx->c->coded_frame->key_frame)
packet.flags |= AV_PKT_FLAG_KEY;
packet.stream_index = ctx->st->index;
packet.data = ctx->video_buffer;
packet.size = outsize;
if (av_interleaved_write_frame(ctx->of, &packet) != 0) {
fprintf(stderr, "Error writing proxy frame %d "
"into '%s'\n", ctx->cfra - 1,
ctx->of->filename);
return 0;
}
return 1;
} else {
return 0;
}
}
static void free_proxy_output_ffmpeg(struct proxy_output_ctx * ctx,
int rollback)
{
int i;
char fname[FILE_MAXDIR+FILE_MAXFILE];
char fname_tmp[FILE_MAXDIR+FILE_MAXFILE];
if (!ctx) {
return;
}
if (!rollback) {
while (add_to_proxy_output_ffmpeg(ctx, NULL)) ;
}
avcodec_flush_buffers(ctx->c);
av_write_trailer(ctx->of);
avcodec_close(ctx->c);
for (i = 0; i < ctx->of->nb_streams; i++) {
if (&ctx->of->streams[i]) {
av_freep(&ctx->of->streams[i]);
}
}
if (ctx->of->oformat) {
if (!(ctx->of->oformat->flags & AVFMT_NOFILE)) {
avio_close(ctx->of->pb);
}
}
av_free(ctx->of);
MEM_freeN(ctx->video_buffer);
if (ctx->sws_ctx) {
sws_freeContext(ctx->sws_ctx);
MEM_freeN(ctx->frame->data[0]);
av_free(ctx->frame);
}
get_proxy_filename(ctx->anim, ctx->proxy_size,
fname_tmp, TRUE);
if (rollback) {
unlink(fname_tmp);
} else {
get_proxy_filename(ctx->anim, ctx->proxy_size,
fname, FALSE);
rename(fname_tmp, fname);
}
MEM_freeN(ctx);
}
static int index_rebuild_ffmpeg(struct anim * anim,
IMB_Timecode_Type tcs_in_use,
IMB_Proxy_Size proxy_sizes_in_use,
int quality,
short *stop, short *do_update,
float *progress)
{
int i, videoStream;
unsigned long long seek_pos = 0;
unsigned long long last_seek_pos = 0;
unsigned long long seek_pos_dts = 0;
unsigned long long seek_pos_pts = 0;
unsigned long long last_seek_pos_dts = 0;
unsigned long long start_pts = 0;
double frame_rate;
double pts_time_base;
int frameno = 0;
int start_pts_set = FALSE;
AVFormatContext *iFormatCtx;
AVCodecContext *iCodecCtx;
AVCodec *iCodec;
AVStream *iStream;
AVFrame* in_frame = 0;
AVPacket next_packet;
int streamcount;
struct proxy_output_ctx * proxy_ctx[IMB_PROXY_MAX_SLOT];
anim_index_builder * indexer [IMB_TC_MAX_SLOT];
int num_proxy_sizes = IMB_PROXY_MAX_SLOT;
int num_indexers = IMB_TC_MAX_SLOT;
uint64_t stream_size;
memset(proxy_ctx, 0, sizeof(proxy_ctx));
memset(indexer, 0, sizeof(indexer));
if(av_open_input_file(&iFormatCtx, anim->name, NULL, 0, NULL) != 0) {
return 0;
}
if (av_find_stream_info(iFormatCtx) < 0) {
av_close_input_file(iFormatCtx);
return 0;
}
streamcount = anim->streamindex;
/* Find the video stream */
videoStream = -1;
for (i = 0; i < iFormatCtx->nb_streams; i++)
if(iFormatCtx->streams[i]->codec->codec_type
== AVMEDIA_TYPE_VIDEO) {
if (streamcount > 0) {
streamcount--;
continue;
}
videoStream = i;
break;
}
if (videoStream == -1) {
av_close_input_file(iFormatCtx);
return 0;
}
iStream = iFormatCtx->streams[videoStream];
iCodecCtx = iStream->codec;
iCodec = avcodec_find_decoder(iCodecCtx->codec_id);
if (iCodec == NULL) {
av_close_input_file(iFormatCtx);
return 0;
}
iCodecCtx->workaround_bugs = 1;
if (avcodec_open(iCodecCtx, iCodec) < 0) {
av_close_input_file(iFormatCtx);
return 0;
}
in_frame = avcodec_alloc_frame();
stream_size = avio_size(iFormatCtx->pb);
for (i = 0; i < num_proxy_sizes; i++) {
if (proxy_sizes_in_use & proxy_sizes[i]) {
proxy_ctx[i] = alloc_proxy_output_ffmpeg(
anim, iStream, proxy_sizes[i],
iCodecCtx->width * proxy_fac[i],
iCodecCtx->height * proxy_fac[i],
quality);
if (!proxy_ctx[i]) {
proxy_sizes_in_use &= ~proxy_sizes[i];
}
}
}
for (i = 0; i < num_indexers; i++) {
if (tcs_in_use & tc_types[i]) {
char fname[FILE_MAXDIR+FILE_MAXFILE];
get_tc_filename(anim, tc_types[i], fname);
indexer[i] = IMB_index_builder_create(fname);
if (!indexer[i]) {
tcs_in_use &= ~tc_types[i];
}
}
}
frame_rate = av_q2d(iStream->r_frame_rate);
pts_time_base = av_q2d(iStream->time_base);
while(av_read_frame(iFormatCtx, &next_packet) >= 0) {
int frame_finished = 0;
float next_progress = ((int)floor(((double) next_packet.pos) * 100 /
((double) stream_size)+0.5)) / 100;
if (*progress != next_progress) {
*progress = next_progress;
*do_update = 1;
}
if (*stop) {
av_free_packet(&next_packet);
break;
}
if (next_packet.stream_index == videoStream) {
if (next_packet.flags & AV_PKT_FLAG_KEY) {
last_seek_pos = seek_pos;
last_seek_pos_dts = seek_pos_dts;
seek_pos = next_packet.pos;
seek_pos_dts = next_packet.dts;
seek_pos_pts = next_packet.pts;
}
avcodec_decode_video2(
iCodecCtx, in_frame, &frame_finished,
&next_packet);
}
if (frame_finished) {
unsigned long long s_pos = seek_pos;
unsigned long long s_dts = seek_pos_dts;
unsigned long long pts
= av_get_pts_from_frame(iFormatCtx, in_frame);
for (i = 0; i < num_proxy_sizes; i++) {
add_to_proxy_output_ffmpeg(
proxy_ctx[i], in_frame);
}
if (!start_pts_set) {
start_pts = pts;
start_pts_set = TRUE;
}
frameno = (pts - start_pts)
* pts_time_base * frame_rate;
/* decoding starts *always* on I-Frames,
so: P-Frames won't work, even if all the
information is in place, when we seek
to the I-Frame presented *after* the P-Frame,
but located before the P-Frame within
the stream */
if (pts < seek_pos_pts) {
s_pos = last_seek_pos;
s_dts = last_seek_pos_dts;
}
for (i = 0; i < num_indexers; i++) {
if (tcs_in_use & tc_types[i]) {
IMB_index_builder_proc_frame(
indexer[i],
next_packet.data,
next_packet.size,
frameno, s_pos, s_dts, pts);
}
}
}
av_free_packet(&next_packet);
}
for (i = 0; i < num_indexers; i++) {
if (tcs_in_use & tc_types[i]) {
IMB_index_builder_finish(indexer[i], *stop);
}
}
for (i = 0; i < num_proxy_sizes; i++) {
if (proxy_sizes_in_use & proxy_sizes[i]) {
free_proxy_output_ffmpeg(proxy_ctx[i], *stop);
}
}
av_free(in_frame);
return 1;
}
#endif
/* ----------------------------------------------------------------------
- internal AVI (fallback) rebuilder
---------------------------------------------------------------------- */
static AviMovie * alloc_proxy_output_avi(
struct anim * anim, char * filename, int width, int height,
int quality)
{
int x, y;
AviFormat format;
double framerate;
AviMovie * avi;
short frs_sec = 25; /* it doesn't really matter for proxies,
but sane defaults help anyways...*/
float frs_sec_base = 1.0;
IMB_anim_get_fps(anim, &frs_sec, &frs_sec_base);
x = width;
y = height;
framerate= (double) frs_sec / (double) frs_sec_base;
avi = MEM_mallocN (sizeof(AviMovie), "avimovie");
format = AVI_FORMAT_MJPEG;
if (AVI_open_compress (filename, avi, 1, format) != AVI_ERROR_NONE) {
MEM_freeN(avi);
return 0;
}
AVI_set_compress_option (avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_WIDTH, &x);
AVI_set_compress_option (avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_HEIGHT, &y);
AVI_set_compress_option (avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_QUALITY, &quality);
AVI_set_compress_option (avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_FRAMERATE, &framerate);
avi->interlace= 0;
avi->odd_fields= 0;
return avi;
}
static void index_rebuild_fallback(struct anim * anim,
IMB_Timecode_Type UNUSED(tcs_in_use),
IMB_Proxy_Size proxy_sizes_in_use,
int quality,
short *stop, short *do_update,
float *progress)
{
int cnt = IMB_anim_get_duration(anim, IMB_TC_NONE);
int i, pos;
AviMovie * proxy_ctx[IMB_PROXY_MAX_SLOT];
char fname[FILE_MAXDIR+FILE_MAXFILE];
char fname_tmp[FILE_MAXDIR+FILE_MAXFILE];
memset(proxy_ctx, 0, sizeof(proxy_ctx));
/* since timecode indices only work with ffmpeg right now,
don't know a sensible fallback here...
so no proxies, no game to play...
*/
if (proxy_sizes_in_use == IMB_PROXY_NONE) {
return;
}
for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
if (proxy_sizes_in_use & proxy_sizes[i]) {
char fname[FILE_MAXDIR+FILE_MAXFILE];
get_proxy_filename(anim, proxy_sizes[i], fname, TRUE);
BLI_make_existing_file(fname);
proxy_ctx[i] = alloc_proxy_output_avi(
anim, fname,
anim->x * proxy_fac[i],
anim->y * proxy_fac[i],
quality);
}
}
for (pos = 0; pos < cnt; pos++) {
struct ImBuf * ibuf = IMB_anim_absolute(
anim, pos, IMB_TC_NONE, IMB_PROXY_NONE);
int next_progress = (int) ((double) pos / (double) cnt);
if (*progress != next_progress) {
*progress = next_progress;
*do_update = 1;
}
if (*stop) {
break;
}
IMB_flipy(ibuf);
for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
if (proxy_sizes_in_use & proxy_sizes[i]) {
int x = anim->x * proxy_fac[i];
int y = anim->y * proxy_fac[i];
struct ImBuf * s_ibuf = IMB_scalefastImBuf(
ibuf, x, y);
IMB_convert_rgba_to_abgr(s_ibuf);
AVI_write_frame (proxy_ctx[i], pos,
AVI_FORMAT_RGB32,
s_ibuf->rect, x * y * 4);
/* note that libavi free's the buffer... */
s_ibuf->rect = 0;
IMB_freeImBuf(s_ibuf);
}
}
}
for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
if (proxy_sizes_in_use & proxy_sizes[i]) {
AVI_close_compress (proxy_ctx[i]);
MEM_freeN (proxy_ctx[i]);
get_proxy_filename(anim, proxy_sizes[i],
fname_tmp, TRUE);
get_proxy_filename(anim, proxy_sizes[i],
fname, FALSE);
if (*stop) {
unlink(fname_tmp);
} else {
rename(fname_tmp, fname);
}
}
}
}
/* ----------------------------------------------------------------------
- public API
---------------------------------------------------------------------- */
void IMB_anim_index_rebuild(struct anim * anim, IMB_Timecode_Type tcs_in_use,
IMB_Proxy_Size proxy_sizes_in_use,
int quality,
short *stop, short *do_update, float *progress)
{
switch (anim->curtype) {
#ifdef WITH_FFMPEG
case ANIM_FFMPEG:
index_rebuild_ffmpeg(anim, tcs_in_use, proxy_sizes_in_use,
quality, stop, do_update, progress);
break;
#endif
default:
index_rebuild_fallback(anim, tcs_in_use, proxy_sizes_in_use,
quality, stop, do_update, progress);
break;
}
}
void IMB_free_indices(struct anim * anim)
{
int i;
for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
if (anim->proxy_anim[i]) {
IMB_close_anim(anim->proxy_anim[i]);
anim->proxy_anim[i] = 0;
}
}
for (i = 0; i < IMB_TC_MAX_SLOT; i++) {
if (anim->curr_idx[i]) {
IMB_indexer_close(anim->curr_idx[i]);
anim->curr_idx[i] = 0;
}
}
anim->proxies_tried = 0;
anim->indices_tried = 0;
}
void IMB_anim_set_index_dir(struct anim * anim, const char * dir)
{
if (strcmp(anim->index_dir, dir) == 0) {
return;
}
BLI_strncpy(anim->index_dir, dir, sizeof(anim->index_dir));
IMB_free_indices(anim);
}
struct anim * IMB_anim_open_proxy(
struct anim * anim, IMB_Proxy_Size preview_size)
{
char fname[FILE_MAXDIR+FILE_MAXFILE];
int i = IMB_proxy_size_to_array_index(preview_size);
if (anim->proxy_anim[i]) {
return anim->proxy_anim[i];
}
if (anim->proxies_tried & preview_size) {
return NULL;
}
get_proxy_filename(anim, preview_size, fname, FALSE);
anim->proxy_anim[i] = IMB_open_anim(fname, 0, 0);
anim->proxies_tried |= preview_size;
return anim->proxy_anim[i];
}
struct anim_index * IMB_anim_open_index(
struct anim * anim, IMB_Timecode_Type tc)
{
char fname[FILE_MAXDIR+FILE_MAXFILE];
int i = IMB_timecode_to_array_index(tc);
if (anim->curr_idx[i]) {
return anim->curr_idx[i];
}
if (anim->indices_tried & tc) {
return 0;
}
get_tc_filename(anim, tc, fname);
anim->curr_idx[i] = IMB_indexer_open(fname);
anim->indices_tried |= tc;
return anim->curr_idx[i];
}
int IMB_anim_index_get_frame_index(struct anim * anim, IMB_Timecode_Type tc,
int position)
{
struct anim_index * idx = IMB_anim_open_index(anim, tc);
if (!idx) {
return position;
}
return IMB_indexer_get_frame_index(idx, position);
}

View File

@@ -0,0 +1,392 @@
/*
* $Id: indexer_dv.c 39833 2011-09-01 01:48:50Z campbellbarton $
*
* ***** 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.
*
* Peter Schlaile <peter [at] schlaile [dot] de> 2011
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "IMB_indexer.h"
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
#include <time.h>
typedef struct indexer_dv_bitstream {
unsigned char* buffer;
int bit_pos;
} indexer_dv_bitstream;
static indexer_dv_bitstream bitstream_new(unsigned char* buffer_)
{
indexer_dv_bitstream rv;
rv.buffer = buffer_;
rv.bit_pos = 0;
return rv;
}
static unsigned long bitstream_get_bits(indexer_dv_bitstream * This, int num)
{
int byte_pos = This->bit_pos >> 3;
unsigned long i =
This->buffer[byte_pos] | (This->buffer[byte_pos + 1] << 8) |
(This->buffer[byte_pos + 2] << 16) |
(This->buffer[byte_pos + 3] << 24);
int rval = (i >> (This->bit_pos & 0x7)) & ((1 << num) - 1);
This->bit_pos += num;
return rval;
}
static int parse_num(indexer_dv_bitstream * b, int numbits) {
return bitstream_get_bits(b, numbits);
}
static int parse_bcd(indexer_dv_bitstream * b, int n)
{
char s[256];
char * p = s + (n+3)/4;
*p-- = 0;
while (n > 4) {
char a;
int v = bitstream_get_bits(b, 4);
n -= 4;
a = '0' + v;
if (a > '9') {
bitstream_get_bits(b, n);
return -1;
}
*p-- = a;
}
if (n) {
char a;
int v = bitstream_get_bits(b, n);
a = '0' + v;
if (a > '9') {
return -1;
}
*p-- = a;
}
return atol(s);
}
typedef struct indexer_dv_context
{
int rec_curr_frame;
int rec_curr_second;
int rec_curr_minute;
int rec_curr_hour;
int rec_curr_day;
int rec_curr_month;
int rec_curr_year;
char got_record_date;
char got_record_time;
time_t ref_time_read;
time_t ref_time_read_new;
int curr_frame;
time_t gap_start;
int gap_frame;
int frameno_offset;
anim_index_entry backbuffer[31];
int fsize;
anim_index_builder * idx;
} indexer_dv_context;
static void parse_packet(indexer_dv_context * This, unsigned char * p)
{
indexer_dv_bitstream b;
int type = p[0];
b = bitstream_new(p + 1);
switch (type) {
case 0x62: // Record date
parse_num(&b, 8);
This->rec_curr_day = parse_bcd(&b, 6);
parse_num(&b, 2);
This->rec_curr_month = parse_bcd(&b, 5);
parse_num(&b, 3);
This->rec_curr_year = parse_bcd(&b, 8);
if (This->rec_curr_year < 25) {
This->rec_curr_year += 2000;
} else {
This->rec_curr_year += 1900;
}
This->got_record_date = 1;
break;
case 0x63: // Record time
This->rec_curr_frame = parse_bcd(&b, 6);
parse_num(&b, 2);
This->rec_curr_second = parse_bcd(&b, 7);
parse_num(&b, 1);
This->rec_curr_minute = parse_bcd(&b, 7);
parse_num(&b, 1);
This->rec_curr_hour = parse_bcd(&b, 6);
This->got_record_time = 1;
break;
}
}
static void parse_header_block(indexer_dv_context * This, unsigned char* target)
{
int i;
for (i = 3; i < 80; i += 5) {
if (target[i] != 0xff) {
parse_packet(This, target + i);
}
}
}
static void parse_subcode_blocks(
indexer_dv_context * This, unsigned char* target)
{
int i,j;
for (j = 0; j < 2; j++) {
for (i = 3; i < 80; i += 5) {
if (target[i] != 0xff) {
parse_packet(This, target + i);
}
}
}
}
static void parse_vaux_blocks(
indexer_dv_context * This, unsigned char* target)
{
int i,j;
for (j = 0; j < 3; j++) {
for (i = 3; i < 80; i += 5) {
if (target[i] != 0xff) {
parse_packet(This, target + i);
}
}
target += 80;
}
}
static void parse_audio_headers(
indexer_dv_context * This, unsigned char* target)
{
int i;
for(i = 0; i < 9; i++) {
if (target[3] != 0xff) {
parse_packet(This, target + 3);
}
target += 16 * 80;
}
}
static void parse_frame(indexer_dv_context * This,
unsigned char * framebuffer, int isPAL)
{
int numDIFseq = isPAL ? 12 : 10;
unsigned char* target = framebuffer;
int ds;
for (ds = 0; ds < numDIFseq; ds++) {
parse_header_block(This, target);
target += 1 * 80;
parse_subcode_blocks(This, target);
target += 2 * 80;
parse_vaux_blocks(This, target);
target += 3 * 80;
parse_audio_headers(This, target);
target += 144 * 80;
}
}
static void inc_frame(int * frame, time_t * t, int isPAL)
{
if ((isPAL && *frame >= 25) || (!isPAL && *frame >= 30)) {
fprintf(stderr, "Ouchie: inc_frame: invalid_frameno: %d\n",
*frame);
}
(*frame)++;
if (isPAL && *frame >= 25) {
(*t)++;
*frame = 0;
} else if (!isPAL && *frame >= 30) {
(*t)++;
*frame = 0;
}
}
static void write_index(indexer_dv_context * This, anim_index_entry * entry)
{
IMB_index_builder_add_entry(
This->idx, entry->frameno + This->frameno_offset,
entry->seek_pos, entry->seek_pos_dts, entry->pts);
}
static void fill_gap(indexer_dv_context * This, int isPAL)
{
int i;
for (i = 0; i < This->fsize; i++) {
if (This->gap_start == This->ref_time_read &&
This->gap_frame == This->curr_frame) {
fprintf(stderr,
"indexer_dv::fill_gap: "
"can't seek backwards !\n");
break;
}
inc_frame(&This->gap_frame, &This->gap_start, isPAL);
}
while (This->gap_start != This->ref_time_read ||
This->gap_frame != This->curr_frame) {
inc_frame(&This->gap_frame, &This->gap_start, isPAL);
This->frameno_offset++;
}
for (i = 0; i < This->fsize; i++) {
write_index(This, This->backbuffer + i);
}
This->fsize = 0;
}
static void proc_frame(indexer_dv_context * This,
unsigned char* UNUSED(framebuffer), int isPAL)
{
struct tm recDate;
time_t t;
if (!This->got_record_date || !This->got_record_time) {
return;
}
recDate.tm_sec = This->rec_curr_second;
recDate.tm_min = This->rec_curr_minute;
recDate.tm_hour = This->rec_curr_hour;
recDate.tm_mday = This->rec_curr_day;
recDate.tm_mon = This->rec_curr_month - 1;
recDate.tm_year = This->rec_curr_year - 1900;
recDate.tm_wday = -1;
recDate.tm_yday = -1;
recDate.tm_isdst = -1;
t = mktime(&recDate);
if (t == -1) {
return;
}
This->ref_time_read_new = t;
if (This->ref_time_read < 0) {
This->ref_time_read = This->ref_time_read_new;
This->curr_frame = 0;
} else {
if (This->ref_time_read_new - This->ref_time_read == 1) {
This->curr_frame = 0;
This->ref_time_read = This->ref_time_read_new;
if (This->gap_frame >= 0) {
fill_gap(This, isPAL);
This->gap_frame = -1;
}
} else if (This->ref_time_read_new == This->ref_time_read) {
// do nothing
} else {
This->gap_start = This->ref_time_read;
This->gap_frame = This->curr_frame;
This->ref_time_read = This->ref_time_read_new;
This->curr_frame = -1;
}
}
}
static void indexer_dv_proc_frame(anim_index_builder * idx,
unsigned char * buffer,
int UNUSED(data_size),
struct anim_index_entry * entry)
{
int isPAL;
indexer_dv_context * This = (indexer_dv_context *) idx->private_data;
isPAL = (buffer[3] & 0x80);
This->got_record_date = FALSE;
This->got_record_time = FALSE;
parse_frame(This, buffer, isPAL);
proc_frame(This, buffer, isPAL);
if (This->curr_frame >= 0) {
write_index(This, entry);
inc_frame(&This->curr_frame, &This->ref_time_read, isPAL);
} else {
This->backbuffer[This->fsize++] = *entry;
if (This->fsize >= 31) {
int i;
fprintf(stderr, "indexer_dv::indexer_dv_proc_frame: "
"backbuffer overrun, emergency flush");
for (i = 0; i < This->fsize; i++) {
write_index(This, This->backbuffer+i);
}
This->fsize = 0;
}
}
}
static void indexer_dv_delete(anim_index_builder * idx)
{
int i = 0;
indexer_dv_context * This = (indexer_dv_context *) idx->private_data;
for (i = 0; i < This->fsize; i++) {
write_index(This, This->backbuffer+i);
}
MEM_freeN(This);
}
void IMB_indexer_dv_new(anim_index_builder * idx)
{
indexer_dv_context * rv = MEM_callocN(
sizeof(indexer_dv_context), "index_dv builder context");
rv->ref_time_read = -1;
rv->curr_frame = -1;
rv->gap_frame = -1;
rv->idx = idx;
idx->private_data = rv;
idx->proc_frame = indexer_dv_proc_frame;
idx->delete_priv_data = indexer_dv_delete;
}

View File

@@ -0,0 +1,69 @@
/*
* $Id: DNA_speaker_types.h 39792 2011-08-30 09:15:55Z nexyon $
*
* ***** 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): Jörg Müller.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef DNA_SPEAKER_TYPES_H
#define DNA_SPEAKER_TYPES_H
/** \file DNA_speaker_types.h
* \ingroup DNA
*/
#include "DNA_ID.h"
struct AnimData;
struct bSound;
typedef struct Speaker {
ID id;
struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */
struct bSound *sound;
// not animatable properties
float volume_max;
float volume_min;
float distance_max;
float distance_reference;
float attenuation;
float cone_angle_outer;
float cone_angle_inner;
float cone_volume_outer;
// animatable properties
float volume;
float pitch;
// flag
short flag;
short pad1[3];
} Speaker;
/* **************** SPEAKER ********************* */
/* flag */
#define SPK_DS_EXPAND (1<<0)
#define SPK_MUTED (1<<1)
#define SPK_RELATIVE (1<<2)
#endif /* DNA_SPEAKER_TYPES_H */

View File

@@ -0,0 +1,172 @@
/*
* $Id: rna_speaker.c 39792 2011-08-30 09:15:55Z nexyon $
*
* ***** 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): Jörg Müller.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/makesrna/intern/rna_speaker.c
* \ingroup RNA
*/
#include <stdlib.h>
#include "RNA_define.h"
#include "RNA_enum_types.h"
#include "rna_internal.h"
#include "DNA_speaker_types.h"
#include "DNA_sound_types.h"
#ifdef RNA_RUNTIME
#include "MEM_guardedalloc.h"
#include "BKE_depsgraph.h"
#include "BKE_main.h"
#include "WM_api.h"
#include "WM_types.h"
#else
static void rna_def_speaker(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna= RNA_def_struct(brna, "Speaker", "ID");
RNA_def_struct_ui_text(srna, "Speaker", "Speaker datablock for 3D audio speaker objects");
RNA_def_struct_ui_icon(srna, ICON_SPEAKER);
prop= RNA_def_property(srna, "muted", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SPK_MUTED);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Mute", "Mutes the speaker.");
// RNA_def_property_update(prop, 0, "rna_Speaker_update");
/* This shouldn't be changed actually, hiding it!
prop= RNA_def_property(srna, "relative", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SPK_RELATIVE);
RNA_def_property_ui_text(prop, "Relative", "Whether the source is relative to the camera or not.");
// RNA_def_property_update(prop, 0, "rna_Speaker_update");*/
prop= RNA_def_property(srna, "sound", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "sound");
RNA_def_property_struct_type(prop, "Sound");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Sound", "Sound datablock used by this speaker.");
// RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_sound_set", NULL);
// RNA_def_property_update(prop, 0, "rna_Speaker_update");
prop= RNA_def_property(srna, "volume_max", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "volume_max");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Maximum Volume", "Maximum volume, no matter how near the object is.");
// RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_volume_max_set", NULL);
// RNA_def_property_update(prop, 0, "rna_Speaker_update");
prop= RNA_def_property(srna, "volume_min", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "volume_min");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Minimum Volume", "Minimum volume, no matter how far away the object is.");
// RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_volume_min_set", NULL);
// RNA_def_property_update(prop, 0, "rna_Speaker_update");
prop= RNA_def_property(srna, "distance_max", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "distance_max");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_text(prop, "Maximum Distance", "Maximum distance for volume calculation, no matter how far away the object is.");
// RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_distance_max_set", NULL);
// RNA_def_property_update(prop, 0, "rna_Speaker_update");
prop= RNA_def_property(srna, "distance_reference", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "distance_reference");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_text(prop, "Reference Distance", "Reference distance at which volume is 100 %.");
// RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_distance_reference_set", NULL);
// RNA_def_property_update(prop, 0, "rna_Speaker_update");
prop= RNA_def_property(srna, "attenuation", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "attenuation");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_text(prop, "Attenuation", "How strong the distance affects volume, depending on distance model.");
// RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_attenuation_set", NULL);
// RNA_def_property_update(prop, 0, "rna_Speaker_update");
prop= RNA_def_property(srna, "cone_angle_outer", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "cone_angle_outer");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_range(prop, 0.0f, 360.0f);
RNA_def_property_ui_text(prop, "Outer Cone Angle", "Outer angle of the cone in degrees, outside this cone the volume is the outer cone volume, between inner and outer cone the volume is interpolated.");
// RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_cone_angle_outer_set", NULL);
// RNA_def_property_update(prop, 0, "rna_Speaker_update");
prop= RNA_def_property(srna, "cone_angle_inner", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "cone_angle_inner");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_range(prop, 0.0f, 360.0f);
RNA_def_property_ui_text(prop, "Inner Cone Angle", "Inner angle of the cone in degrees, inside the cone the volume is 100 %.");
// RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_cone_angle_inner_set", NULL);
// RNA_def_property_update(prop, 0, "rna_Speaker_update");
prop= RNA_def_property(srna, "cone_volume_outer", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "cone_volume_outer");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Outer Cone Volume", "Volume outside the outer cone.");
// RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_cone_volume_outer_set", NULL);
// RNA_def_property_update(prop, 0, "rna_Speaker_update");
prop= RNA_def_property(srna, "volume", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "volume");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Volume", "How loud the sound is.");
// RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_volume_set", NULL);
// RNA_def_property_update(prop, 0, "rna_Speaker_update");
prop= RNA_def_property(srna, "pitch", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "pitch");
RNA_def_property_range(prop, 0.1f, 10.0f);
RNA_def_property_ui_text(prop, "Pitch", "Playback pitch of the sound.");
// RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_pitch_set", NULL);
// RNA_def_property_update(prop, 0, "rna_Speaker_update");
/* common */
rna_def_animdata_common(srna);
}
void RNA_def_speaker(BlenderRNA *brna)
{
rna_def_speaker(brna);
}
#endif

View File

@@ -0,0 +1,96 @@
/*
* $Id: rna_texture_api.c 39762 2011-08-28 23:44:43Z gsrb3d $
*
* ***** 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): Tom Edwards
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/makesrna/intern/rna_texture_api.c
* \ingroup RNA
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "RNA_define.h"
#include "BKE_utildefines.h"
#ifdef RNA_RUNTIME
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "DNA_scene_types.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "RE_pipeline.h"
void save_envmap(struct EnvMap *env, bContext *C, ReportList *reports, const char* filepath, struct Scene *scene, float layout[12])
{
if (scene == NULL) {
scene = CTX_data_scene(C);
}
RE_WriteEnvmapResult(reports, scene, env, filepath, scene->r.imtype, layout);
}
void clear_envmap(struct EnvMap *env, bContext *C)
{
Main *bmain = CTX_data_main(C);
Tex *tex;
BKE_free_envmapdata(env);
for (tex=bmain->tex.first; tex; tex=tex->id.next)
if (tex->env == env) {
WM_event_add_notifier(C, NC_TEXTURE|NA_EDITED, tex);
break;
}
}
#else
void RNA_api_environment_map(StructRNA *srna)
{
FunctionRNA *func;
PropertyRNA *parm;
static const float default_layout[] = { 0,0, 1,0, 2,0, 0,1, 1,1, 2,1 };
func= RNA_def_function(srna, "clear", "clear_envmap");
RNA_def_function_ui_description(func, "Discard the environment map and free it from memory.");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
func= RNA_def_function(srna,"save", "save_envmap");
RNA_def_function_ui_description(func, "Save the environment map to disc using the scene render settings.");
RNA_def_function_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS);
parm= RNA_def_string_file_name(func,"filepath","",FILE_MAX,"File path","Location of the output file");
RNA_def_property_flag(parm, PROP_REQUIRED);
RNA_def_pointer(func, "scene", "Scene", "", "Overrides the scene from which image parameters are taken.");
parm = RNA_def_float_array(func, "layout", 12, default_layout, 0.0f, 0.0f, "File layout", "Flat array describing the X,Y position of each cube face in the output image, where 1 is the size of a face. Order is [+Z -Z +Y -X -Y +X]. Use -1 to skip a face.", 0.0f, 0.0f);
}
#endif

View File

@@ -0,0 +1,453 @@
/**
* $Id: BL_Action.cpp 39792 2011-08-30 09:15:55Z nexyon $
*
* ***** 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): Mitchell Stokes.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file BL_Action.cpp
* \ingroup ketsji
*/
#include <cstdlib>
#include "BL_Action.h"
#include "BL_ArmatureObject.h"
#include "BL_DeformableGameObject.h"
#include "BL_ShapeDeformer.h"
#include "KX_IpoConvert.h"
#include "KX_GameObject.h"
// These three are for getting the action from the logic manager
#include "KX_Scene.h"
#include "KX_PythonInit.h"
#include "SCA_LogicManager.h"
extern "C" {
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "RNA_access.h"
#include "RNA_define.h"
}
BL_Action::BL_Action(class KX_GameObject* gameobj)
:
m_action(NULL),
m_pose(NULL),
m_blendpose(NULL),
m_blendinpose(NULL),
m_ptrrna(NULL),
m_obj(gameobj),
m_startframe(0.f),
m_endframe(0.f),
m_endtime(0.f),
m_localtime(0.f),
m_blendin(0.f),
m_blendframe(0.f),
m_blendstart(0.f),
m_speed(0.f),
m_priority(0),
m_playmode(0),
m_ipo_flags(0),
m_done(true),
m_calc_localtime(true)
{
if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
{
BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj;
m_ptrrna = new PointerRNA();
RNA_id_pointer_create(&obj->GetArmatureObject()->id, m_ptrrna);
}
else
{
BL_DeformableGameObject *obj = (BL_DeformableGameObject*)m_obj;
BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer());
if (shape_deformer)
{
m_ptrrna = new PointerRNA();
RNA_id_pointer_create(&shape_deformer->GetKey()->id, m_ptrrna);
}
}
}
BL_Action::~BL_Action()
{
if (m_pose)
game_free_pose(m_pose);
if (m_blendpose)
game_free_pose(m_blendpose);
if (m_blendinpose)
game_free_pose(m_blendinpose);
if (m_ptrrna)
delete m_ptrrna;
ClearControllerList();
}
void BL_Action::ClearControllerList()
{
// Clear out the controller list
std::vector<SG_Controller*>::iterator it;
for (it = m_sg_contr_list.begin(); it != m_sg_contr_list.end(); it++)
{
m_obj->GetSGNode()->RemoveSGController((*it));
delete *it;
}
m_sg_contr_list.clear();
}
bool BL_Action::Play(const char* name,
float start,
float end,
short priority,
float blendin,
short play_mode,
float layer_weight,
short ipo_flags,
float playback_speed)
{
// Only start playing a new action if we're done, or if
// the new action has a higher priority
if (priority != 0 && !IsDone() && priority >= m_priority)
return false;
m_priority = priority;
bAction* prev_action = m_action;
// First try to load the action
m_action = (bAction*)KX_GetActiveScene()->GetLogicManager()->GetActionByName(name);
if (!m_action)
{
printf("Failed to load action: %s\n", name);
m_done = true;
return false;
}
if (prev_action != m_action)
{
// First get rid of any old controllers
ClearControllerList();
// Create an SG_Controller
SG_Controller *sg_contr = BL_CreateIPO(m_action, m_obj, KX_GetActiveScene()->GetSceneConverter());
m_sg_contr_list.push_back(sg_contr);
m_obj->GetSGNode()->AddSGController(sg_contr);
sg_contr->SetObject(m_obj->GetSGNode());
// Extra controllers
if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_LIGHT)
{
sg_contr = BL_CreateLampIPO(m_action, m_obj, KX_GetActiveScene()->GetSceneConverter());
m_sg_contr_list.push_back(sg_contr);
m_obj->GetSGNode()->AddSGController(sg_contr);
sg_contr->SetObject(m_obj->GetSGNode());
}
else if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_CAMERA)
{
sg_contr = BL_CreateCameraIPO(m_action, m_obj, KX_GetActiveScene()->GetSceneConverter());
m_sg_contr_list.push_back(sg_contr);
m_obj->GetSGNode()->AddSGController(sg_contr);
sg_contr->SetObject(m_obj->GetSGNode());
}
}
m_ipo_flags = ipo_flags;
InitIPO();
// Setup blendin shapes/poses
if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
{
BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj;
obj->GetMRDPose(&m_blendinpose);
}
else
{
BL_DeformableGameObject *obj = (BL_DeformableGameObject*)m_obj;
BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer());
if (shape_deformer && shape_deformer->GetKey())
{
obj->GetShape(m_blendinshape);
// Now that we have the previous blend shape saved, we can clear out the key to avoid any
// further interference.
KeyBlock *kb;
for (kb=(KeyBlock*)shape_deformer->GetKey()->block.first; kb; kb=(KeyBlock*)kb->next)
kb->curval = 0.f;
}
}
// Now that we have an action, we have something we can play
m_starttime = KX_GetActiveEngine()->GetFrameTime();
m_startframe = m_localtime = start;
m_endframe = end;
m_blendin = blendin;
m_playmode = play_mode;
m_endtime = 0.f;
m_blendframe = 0.f;
m_blendstart = 0.f;
m_speed = playback_speed;
m_layer_weight = layer_weight;
m_done = false;
return true;
}
void BL_Action::Stop()
{
m_done = true;
}
bool BL_Action::IsDone()
{
return m_done;
}
void BL_Action::InitIPO()
{
// Initialize the IPOs
std::vector<SG_Controller*>::iterator it;
for (it = m_sg_contr_list.begin(); it != m_sg_contr_list.end(); it++)
{
(*it)->SetOption(SG_Controller::SG_CONTR_IPO_RESET, true);
(*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_AS_FORCE, m_ipo_flags & ACT_IPOFLAG_FORCE);
(*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_ADD, m_ipo_flags & ACT_IPOFLAG_ADD);
(*it)->SetOption(SG_Controller::SG_CONTR_IPO_LOCAL, m_ipo_flags & ACT_IPOFLAG_LOCAL);
}
}
bAction *BL_Action::GetAction()
{
return (IsDone()) ? NULL : m_action;
}
float BL_Action::GetFrame()
{
return m_localtime;
}
void BL_Action::SetFrame(float frame)
{
// Clamp the frame to the start and end frame
if (frame < min(m_startframe, m_endframe))
frame = min(m_startframe, m_endframe);
else if (frame > max(m_startframe, m_endframe))
frame = max(m_startframe, m_endframe);
m_localtime = frame;
m_calc_localtime = false;
}
void BL_Action::SetPlayMode(short play_mode)
{
m_playmode = play_mode;
}
void BL_Action::SetTimes(float start, float end)
{
m_startframe = start;
m_endframe = end;
}
void BL_Action::SetLocalTime(float curtime)
{
float dt = (curtime-m_starttime)*KX_KetsjiEngine::GetAnimFrameRate()*m_speed;
if (m_endframe < m_startframe)
dt = -dt;
m_localtime = m_startframe + dt;
}
void BL_Action::ResetStartTime(float curtime)
{
float dt = m_localtime - m_startframe;
m_starttime = curtime - dt / (KX_KetsjiEngine::GetAnimFrameRate()*m_speed);
SetLocalTime(curtime);
}
void BL_Action::IncrementBlending(float curtime)
{
// Setup m_blendstart if we need to
if (m_blendstart == 0.f)
m_blendstart = curtime;
// Bump the blend frame
m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate();
// Clamp
if (m_blendframe>m_blendin)
m_blendframe = m_blendin;
}
void BL_Action::BlendShape(Key* key, float srcweight, std::vector<float>& blendshape)
{
vector<float>::const_iterator it;
float dstweight;
KeyBlock *kb;
dstweight = 1.0F - srcweight;
//printf("Dst: %f\tSrc: %f\n", srcweight, dstweight);
for (it=blendshape.begin(), kb = (KeyBlock*)key->block.first;
kb && it != blendshape.end();
kb = (KeyBlock*)kb->next, it++) {
//printf("OirgKeys: %f\t%f\n", kb->curval, (*it));
kb->curval = kb->curval * dstweight + (*it) * srcweight;
//printf("NewKey: %f\n", kb->curval);
}
//printf("\n");
}
void BL_Action::Update(float curtime)
{
// Don't bother if we're done with the animation
if (m_done)
return;
curtime -= KX_KetsjiEngine::GetSuspendedDelta();
if (m_calc_localtime)
SetLocalTime(curtime);
else
{
ResetStartTime(curtime);
m_calc_localtime = true;
}
// Handle wrap around
if (m_localtime < min(m_startframe, m_endframe) || m_localtime > max(m_startframe, m_endframe))
{
switch(m_playmode)
{
case ACT_MODE_PLAY:
// Clamp
m_localtime = m_endframe;
m_done = true;
break;
case ACT_MODE_LOOP:
// Put the time back to the beginning
m_localtime = m_startframe;
m_starttime = curtime;
break;
case ACT_MODE_PING_PONG:
// Swap the start and end frames
float temp = m_startframe;
m_startframe = m_endframe;
m_endframe = temp;
m_starttime = curtime;
break;
}
if (!m_done)
InitIPO();
}
if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
{
BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj;
obj->GetPose(&m_pose);
// Extract the pose from the action
{
Object *arm = obj->GetArmatureObject();
bPose *temp = arm->pose;
arm->pose = m_pose;
animsys_evaluate_action(m_ptrrna, m_action, NULL, m_localtime);
arm->pose = temp;
}
// Handle blending between armature actions
if (m_blendin && m_blendframe<m_blendin)
{
IncrementBlending(curtime);
// Calculate weight
float weight = 1.f - (m_blendframe/m_blendin);
// Blend the poses
game_blend_poses(m_pose, m_blendinpose, weight);
}
// Handle layer blending
if (m_layer_weight >= 0)
{
obj->GetMRDPose(&m_blendpose);
game_blend_poses(m_pose, m_blendpose, m_layer_weight);
}
obj->SetPose(m_pose);
obj->SetActiveAction(NULL, 0, curtime);
}
else
{
BL_DeformableGameObject *obj = (BL_DeformableGameObject*)m_obj;
BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer());
// Handle shape actions if we have any
if (shape_deformer && shape_deformer->GetKey())
{
Key *key = shape_deformer->GetKey();
animsys_evaluate_action(m_ptrrna, m_action, NULL, m_localtime);
// Handle blending between shape actions
if (m_blendin && m_blendframe < m_blendin)
{
IncrementBlending(curtime);
float weight = 1.f - (m_blendframe/m_blendin);
// We go through and clear out the keyblocks so there isn't any interference
// from other shape actions
KeyBlock *kb;
for (kb=(KeyBlock*)key->block.first; kb; kb=(KeyBlock*)kb->next)
kb->curval = 0.f;
// Now blend the shape
BlendShape(key, weight, m_blendinshape);
}
// Handle layer blending
if (m_layer_weight >= 0)
{
obj->GetShape(m_blendshape);
BlendShape(key, m_layer_weight, m_blendshape);
}
obj->SetActiveAction(NULL, 0, curtime);
}
InitIPO();
m_obj->UpdateIPO(m_localtime, m_ipo_flags & ACT_IPOFLAG_CHILD);
}
}

View File

@@ -0,0 +1,144 @@
/**
* $Id: BL_Action.h 39792 2011-08-30 09:15:55Z nexyon $
*
* ***** 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): Mitchell Stokes.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file BL_Action.h
* \ingroup ketsji
*/
#ifndef __BL_ACTION
#define __BL_ACTION
#include <vector>
#ifdef WITH_CXX_GUARDEDALLOC
#include "MEM_guardedalloc.h"
#endif
class BL_Action
{
private:
struct bAction* m_action;
struct bPose* m_pose;
struct bPose* m_blendpose;
struct bPose* m_blendinpose;
struct PointerRNA *m_ptrrna;
std::vector<class SG_Controller*> m_sg_contr_list;
class KX_GameObject* m_obj;
std::vector<float> m_blendshape;
std::vector<float> m_blendinshape;
float m_startframe;
float m_endframe;
float m_starttime;
float m_endtime;
float m_localtime;
float m_blendin;
float m_blendframe;
float m_blendstart;
float m_layer_weight;
float m_speed;
short m_priority;
short m_playmode;
short m_ipo_flags;
bool m_done;
bool m_calc_localtime;
void ClearControllerList();
void InitIPO();
void SetLocalTime(float curtime);
void ResetStartTime(float curtime);
void IncrementBlending(float curtime);
void BlendShape(struct Key* key, float srcweight, std::vector<float>& blendshape);
public:
BL_Action(class KX_GameObject* gameobj);
~BL_Action();
/**
* Play an action
*/
bool Play(const char* name,
float start,
float end,
short priority,
float blendin,
short play_mode,
float layer_weight,
short ipo_flags,
float playback_speed);
/**
* Stop playing the action
*/
void Stop();
/**
* Whether or not the action is still playing
*/
bool IsDone();
/**
* Update the action's frame, etc.
*/
void Update(float curtime);
// Accessors
float GetFrame();
struct bAction *GetAction();
// Mutators
void SetFrame(float frame);
void SetPlayMode(short play_mode);
void SetTimes(float start, float end);
enum
{
ACT_MODE_PLAY = 0,
ACT_MODE_LOOP,
ACT_MODE_PING_PONG,
ACT_MODE_MAX,
};
enum
{
ACT_IPOFLAG_FORCE = 1,
ACT_IPOFLAG_LOCAL = 2,
ACT_IPOFLAG_ADD = 4,
ACT_IPOFLAG_CHILD = 8,
};
#ifdef WITH_CXX_GUARDEDALLOC
public:
void *operator new(size_t num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_Action"); }
void operator delete( void *mem ) { MEM_freeN(mem); }
#endif
};
#endif //BL_ACTION

View File

@@ -0,0 +1,110 @@
/**
* $Id: BL_ActionManager.cpp 39792 2011-08-30 09:15:55Z nexyon $
*
* ***** 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): Mitchell Stokes.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file BL_ActionManager.cpp
* \ingroup ketsji
*/
#include "BL_ActionManager.h"
BL_ActionManager::BL_ActionManager(class KX_GameObject *obj)
{
for (int i=0; i<MAX_ACTION_LAYERS; ++i)
m_layers[i] = new BL_Action(obj);
}
BL_ActionManager::~BL_ActionManager()
{
for (int i=0; i<MAX_ACTION_LAYERS; ++i)
delete m_layers[i];
}
float BL_ActionManager::GetActionFrame(short layer)
{
return m_layers[layer]->GetFrame();
return 0.f;
}
void BL_ActionManager::SetActionFrame(short layer, float frame)
{
m_layers[layer]->SetFrame(frame);
}
struct bAction *BL_ActionManager::GetCurrentAction(short layer)
{
return m_layers[layer]->GetAction();
return 0;
}
void BL_ActionManager::SetPlayMode(short layer, short mode)
{
m_layers[layer]->SetPlayMode(mode);
}
void BL_ActionManager::SetTimes(short layer, float start, float end)
{
m_layers[layer]->SetTimes(start, end);
}
bool BL_ActionManager::PlayAction(const char* name,
float start,
float end,
short layer,
short priority,
float blendin,
short play_mode,
float layer_weight,
short ipo_flags,
float playback_speed)
{
// Disable layer blending on the first layer
if (layer == 0) layer_weight = -1.f;
return m_layers[layer]->Play(name, start, end, priority, blendin, play_mode, layer_weight, ipo_flags, playback_speed);
}
void BL_ActionManager::StopAction(short layer)
{
m_layers[layer]->Stop();
}
bool BL_ActionManager::IsActionDone(short layer)
{
return m_layers[layer]->IsDone();
return true;
}
void BL_ActionManager::Update(float curtime)
{
for (int i=0; i<MAX_ACTION_LAYERS; ++i)
{
if (!m_layers[i]->IsDone())
{
m_layers[i]->Update(curtime);
}
}
}

View File

@@ -0,0 +1,106 @@
/**
* $Id: BL_ActionManager.h 39792 2011-08-30 09:15:55Z nexyon $
*
* ***** 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): Mitchell Stokes.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file BL_ActionManager.cpp
* \ingroup ketsji
*/
#ifndef __BL_ACTIONMANAGER
#define __BL_ACTIONMANAGER
#include "BL_Action.h"
#define MAX_ACTION_LAYERS 8
/**
* BL_ActionManager is responsible for handling a KX_GameObject's actions.
*/
class BL_ActionManager
{
private:
BL_Action* m_layers[MAX_ACTION_LAYERS];
public:
BL_ActionManager(class KX_GameObject* obj);
~BL_ActionManager();
bool PlayAction(const char* name,
float start,
float end,
short layer=0,
short priority=0,
float blendin=0.f,
short play_mode=0,
float layer_weight=0.f,
short ipo_flags=0,
float playback_speed=1.f);
/**
* Gets the current frame of an action
*/
float GetActionFrame(short layer);
/**
* Sets the current frame of an action
*/
void SetActionFrame(short layer, float frame);
/**
* Gets the currently running action on the given layer
*/
struct bAction *GetCurrentAction(short layer);
/**
* Sets play mode of the action on the given layer
*/
void SetPlayMode(short layer, short mode);
/**
* Sets the start and end times of the action on the given layer
*/
void SetTimes(short layer, float start, float end);
/**
* Stop playing the action on the given layer
*/
void StopAction(short layer);
/**
* Check if an action has finished playing
*/
bool IsActionDone(short layer);
/**
* Update any running actions
*/
void Update(float);
#ifdef WITH_CXX_GUARDEDALLOC
public:
void *operator new(size_t num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_ActionManager"); }
void operator delete( void *mem ) { MEM_freeN(mem); }
#endif
};
#endif //BL_ACTIONMANAGER