add missing files after merging
This commit is contained in:
43
source/blender/blenkernel/BKE_speaker.h
Executable file
43
source/blender/blenkernel/BKE_speaker.h
Executable 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
|
||||
139
source/blender/blenkernel/intern/speaker.c
Executable file
139
source/blender/blenkernel/intern/speaker.c
Executable 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);
|
||||
}
|
||||
1300
source/blender/collada/AnimationExporter.cpp
Executable file
1300
source/blender/collada/AnimationExporter.cpp
Executable 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 ¶m = 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 ¶m = 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 ¶m = 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 ¶m = 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 ¶m = 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 ¶m = 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 ¶m = 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);
|
||||
}
|
||||
|
||||
|
||||
163
source/blender/collada/AnimationExporter.h
Executable file
163
source/blender/collada/AnimationExporter.h
Executable 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);
|
||||
};
|
||||
133
source/blender/imbuf/intern/IMB_indexer.h
Executable file
133
source/blender/imbuf/intern/IMB_indexer.h
Executable 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
|
||||
1142
source/blender/imbuf/intern/indexer.c
Executable file
1142
source/blender/imbuf/intern/indexer.c
Executable 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);
|
||||
}
|
||||
|
||||
392
source/blender/imbuf/intern/indexer_dv.c
Executable file
392
source/blender/imbuf/intern/indexer_dv.c
Executable 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;
|
||||
}
|
||||
69
source/blender/makesdna/DNA_speaker_types.h
Executable file
69
source/blender/makesdna/DNA_speaker_types.h
Executable 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 */
|
||||
|
||||
172
source/blender/makesrna/intern/rna_speaker.c
Executable file
172
source/blender/makesrna/intern/rna_speaker.c
Executable 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
|
||||
|
||||
96
source/blender/makesrna/intern/rna_texture_api.c
Executable file
96
source/blender/makesrna/intern/rna_texture_api.c
Executable 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
|
||||
453
source/gameengine/Ketsji/BL_Action.cpp
Executable file
453
source/gameengine/Ketsji/BL_Action.cpp
Executable 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);
|
||||
}
|
||||
}
|
||||
144
source/gameengine/Ketsji/BL_Action.h
Executable file
144
source/gameengine/Ketsji/BL_Action.h
Executable 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
|
||||
|
||||
110
source/gameengine/Ketsji/BL_ActionManager.cpp
Executable file
110
source/gameengine/Ketsji/BL_ActionManager.cpp
Executable 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
106
source/gameengine/Ketsji/BL_ActionManager.h
Executable file
106
source/gameengine/Ketsji/BL_ActionManager.h
Executable 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
|
||||
|
||||
Reference in New Issue
Block a user