Merge with trunk revision 37149.
authorJoerg Mueller <nexyon@gmail.com>
Fri, 3 Jun 2011 23:24:01 +0000 (23:24 +0000)
committerJoerg Mueller <nexyon@gmail.com>
Fri, 3 Jun 2011 23:24:01 +0000 (23:24 +0000)
58 files changed:
intern/audaspace/intern/AUD_ConverterFunctions.cpp
release/scripts/modules/mocap_tools.py [new file with mode: 0644]
release/scripts/modules/retarget.py [new file with mode: 0644]
release/scripts/startup/bl_operators/nla.py
release/scripts/startup/bl_operators/object.py
release/scripts/startup/bl_ui/properties_object_constraint.py
release/scripts/startup/bl_ui/space_view3d.py
source/blender/blenkernel/BKE_constraint.h
source/blender/blenkernel/intern/constraint.c
source/blender/blenkernel/intern/fmodifier.c
source/blender/collada/AnimationExporter.cpp [new file with mode: 0644]
source/blender/collada/AnimationExporter.h [new file with mode: 0644]
source/blender/collada/CMakeLists.txt
source/blender/collada/DocumentExporter.cpp
source/blender/editors/animation/anim_channels_edit.c
source/blender/editors/animation/anim_markers.c
source/blender/editors/animation/fmodifier_ui.c
source/blender/editors/animation/keyframes_general.c
source/blender/editors/animation/keyingsets.c
source/blender/editors/armature/poseobject.c
source/blender/editors/include/ED_markers.h
source/blender/editors/interface/resources.c
source/blender/editors/object/object_constraint.c
source/blender/editors/space_action/action_ops.c
source/blender/editors/space_graph/graph_edit.c
source/blender/editors/space_graph/graph_ops.c
source/blender/editors/space_logic/logic_window.c
source/blender/editors/space_nla/nla_ops.c
source/blender/editors/space_view3d/drawarmature.c
source/blender/editors/transform/transform.c
source/blender/editors/transform/transform_conversions.c
source/blender/editors/transform/transform_ops.c
source/blender/makesdna/DNA_anim_types.h
source/blender/makesdna/DNA_armature_types.h
source/blender/makesdna/DNA_constraint_types.h
source/blender/makesrna/intern/rna_actuator.c
source/blender/makesrna/intern/rna_armature.c
source/blender/makesrna/intern/rna_constraint.c
source/blender/makesrna/intern/rna_fcurve.c
source/gameengine/Converter/BL_ActionActuator.cpp
source/gameengine/Converter/BL_ActionActuator.h
source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp
source/gameengine/Converter/KX_BlenderScalarInterpolator.h
source/gameengine/Converter/KX_ConvertActuators.cpp
source/gameengine/Converter/KX_IpoConvert.cpp
source/gameengine/Converter/KX_IpoConvert.h
source/gameengine/Expressions/PyObjectPlus.h
source/gameengine/Ketsji/BL_Action.cpp [new file with mode: 0644]
source/gameengine/Ketsji/BL_Action.h [new file with mode: 0644]
source/gameengine/Ketsji/BL_ActionManager.cpp [new file with mode: 0644]
source/gameengine/Ketsji/BL_ActionManager.h [new file with mode: 0644]
source/gameengine/Ketsji/CMakeLists.txt
source/gameengine/Ketsji/KX_GameObject.cpp
source/gameengine/Ketsji/KX_GameObject.h
source/gameengine/Ketsji/KX_Scene.cpp
source/gameengine/Ketsji/SConscript
source/gameengine/SceneGraph/SG_IObject.cpp
source/gameengine/SceneGraph/SG_IObject.h

index d3cc9fa820289c62a4793eb073834ba36d015c55..8f2ac21acd6a0da7906b325c0eb9ad7fc7343c9c 100644 (file)
 void AUD_convert_u8_s16(data_t* target, data_t* source, int length)
 {
        int16_t* t = (int16_t*) target;
-       for(int i = 0; i < length; i++)
+       for(int i = length - 1; i >= 0; i++)
                t[i] = (((int16_t)source[i]) - AUD_U8_0) << 8;
 }
 
 void AUD_convert_u8_s24_be(data_t* target, data_t* source, int length)
 {
-       for(int i = 0; i < length; i++)
+       for(int i = length - 1; i >= 0; i++)
        {
                target[i*3] = source[i] - AUD_U8_0;
                target[i*3+1] = 0;
@@ -61,7 +61,7 @@ void AUD_convert_u8_s24_be(data_t* target, data_t* source, int length)
 
 void AUD_convert_u8_s24_le(data_t* target, data_t* source, int length)
 {
-       for(int i = 0; i < length; i++)
+       for(int i = length - 1; i >= 0; i++)
        {
                target[i*3+2] = source[i] - AUD_U8_0;
                target[i*3+1] = 0;
@@ -72,21 +72,21 @@ void AUD_convert_u8_s24_le(data_t* target, data_t* source, int length)
 void AUD_convert_u8_s32(data_t* target, data_t* source, int length)
 {
        int32_t* t = (int32_t*) target;
-       for(int i = 0; i < length; i++)
+       for(int i = length - 1; i >= 0; i++)
                t[i] = (((int32_t)source[i]) - AUD_U8_0) << 24;
 }
 
 void AUD_convert_u8_float(data_t* target, data_t* source, int length)
 {
        float* t = (float*) target;
-       for(int i = 0; i < length; i++)
+       for(int i = length - 1; i >= 0; i++)
                t[i] = (((int32_t)source[i]) - AUD_U8_0) / ((float)AUD_U8_0);
 }
 
 void AUD_convert_u8_double(data_t* target, data_t* source, int length)
 {
        double* t = (double*) target;
-       for(int i = 0; i < length; i++)
+       for(int i = length - 1; i >= 0; i++)
                t[i] = (((int32_t)source[i]) - AUD_U8_0) / ((double)AUD_U8_0);
 }
 
@@ -100,10 +100,12 @@ void AUD_convert_s16_u8(data_t* target, data_t* source, int length)
 void AUD_convert_s16_s24_be(data_t* target, data_t* source, int length)
 {
        int16_t* s = (int16_t*) source;
-       for(int i = 0; i < length; i++)
+       int16_t t;
+       for(int i = length - 1; i >= 0; i++)
        {
-               target[i*3] = s[i] >> 8 & 0xFF;
-               target[i*3+1] = s[i] & 0xFF;
+               t = s[i];
+               target[i*3] = t >> 8 & 0xFF;
+               target[i*3+1] = t & 0xFF;
                target[i*3+2] = 0;
        }
 }
@@ -111,10 +113,12 @@ void AUD_convert_s16_s24_be(data_t* target, data_t* source, int length)
 void AUD_convert_s16_s24_le(data_t* target, data_t* source, int length)
 {
        int16_t* s = (int16_t*) source;
-       for(int i = 0; i < length; i++)
+       int16_t t;
+       for(int i = length - 1; i >= 0; i++)
        {
-               target[i*3+2] = s[i] >> 8 & 0xFF;
-               target[i*3+1] = s[i] & 0xFF;
+               t = s[i];
+               target[i*3+2] = t >> 8 & 0xFF;
+               target[i*3+1] = t & 0xFF;
                target[i*3] = 0;
        }
 }
@@ -123,7 +127,7 @@ void AUD_convert_s16_s32(data_t* target, data_t* source, int length)
 {
        int16_t* s = (int16_t*) source;
        int32_t* t = (int32_t*) target;
-       for(int i = 0; i < length; i++)
+       for(int i = length - 1; i >= 0; i++)
                t[i] = ((int32_t)s[i]) << 16;
 }
 
@@ -131,7 +135,7 @@ void AUD_convert_s16_float(data_t* target, data_t* source, int length)
 {
        int16_t* s = (int16_t*) source;
        float* t = (float*) target;
-       for(int i = 0; i < length; i++)
+       for(int i = length - 1; i >= 0; i++)
                t[i] = s[i] / AUD_S16_FLT;
 }
 
@@ -139,7 +143,7 @@ void AUD_convert_s16_double(data_t* target, data_t* source, int length)
 {
        int16_t* s = (int16_t*) source;
        double* t = (double*) target;
-       for(int i = 0; i < length; i++)
+       for(int i = length - 1; i >= 0; i++)
                t[i] = s[i] / AUD_S16_FLT;
 }
 
@@ -177,14 +181,14 @@ void AUD_convert_s24_s24(data_t* target, data_t* source, int length)
 void AUD_convert_s24_s32_be(data_t* target, data_t* source, int length)
 {
        int32_t* t = (int32_t*) target;
-       for(int i = 0; i < length; i++)
+       for(int i = length - 1; i >= 0; i++)
                t[i] = source[i*3] << 24 | source[i*3+1] << 16 | source[i*3+2] << 8;
 }
 
 void AUD_convert_s24_s32_le(data_t* target, data_t* source, int length)
 {
        int32_t* t = (int32_t*) target;
-       for(int i = 0; i < length; i++)
+       for(int i = length - 1; i >= 0; i++)
                t[i] = source[i*3+2] << 24 | source[i*3+1] << 16 | source[i*3] << 8;
 }
 
@@ -192,7 +196,7 @@ void AUD_convert_s24_float_be(data_t* target, data_t* source, int length)
 {
        float* t = (float*) target;
        int32_t s;
-       for(int i = 0; i < length; i++)
+       for(int i = length - 1; i >= 0; i++)
        {
                s = source[i*3] << 24 | source[i*3+1] << 16 | source[i*3+2] << 8;
                t[i] = s / AUD_S32_FLT;
@@ -203,7 +207,7 @@ void AUD_convert_s24_float_le(data_t* target, data_t* source, int length)
 {
        float* t = (float*) target;
        int32_t s;
-       for(int i = 0; i < length; i++)
+       for(int i = length - 1; i >= 0; i++)
        {
                s = source[i*3+2] << 24 | source[i*3+1] << 16 | source[i*3] << 8;
                t[i] = s / AUD_S32_FLT;
@@ -214,7 +218,7 @@ void AUD_convert_s24_double_be(data_t* target, data_t* source, int length)
 {
        double* t = (double*) target;
        int32_t s;
-       for(int i = 0; i < length; i++)
+       for(int i = length - 1; i >= 0; i++)
        {
                s = source[i*3] << 24 | source[i*3+1] << 16 | source[i*3+2] << 8;
                t[i] = s / AUD_S32_FLT;
@@ -225,7 +229,7 @@ void AUD_convert_s24_double_le(data_t* target, data_t* source, int length)
 {
        double* t = (double*) target;
        int32_t s;
-       for(int i = 0; i < length; i++)
+       for(int i = length - 1; i >= 0; i++)
        {
                s = source[i*3+2] << 24 | source[i*3+1] << 16 | source[i*3] << 8;
                t[i] = s / AUD_S32_FLT;
@@ -250,22 +254,26 @@ void AUD_convert_s32_s16(data_t* target, data_t* source, int length)
 void AUD_convert_s32_s24_be(data_t* target, data_t* source, int length)
 {
        int32_t* s = (int32_t*) source;
+       int32_t t;
        for(int i = 0; i < length; i++)
        {
-               target[i*3] = s[i] >> 24 & 0xFF;
-               target[i*3+1] = s[i] >> 16 & 0xFF;
-               target[i*3+2] = s[i] >> 8 & 0xFF;
+               t = s[i];
+               target[i*3] = t >> 24 & 0xFF;
+               target[i*3+1] = t >> 16 & 0xFF;
+               target[i*3+2] = t >> 8 & 0xFF;
        }
 }
 
 void AUD_convert_s32_s24_le(data_t* target, data_t* source, int length)
 {
-       int16_t* s = (int16_t*) source;
+       int32_t* s = (int32_t*) source;
+       int32_t t;
        for(int i = 0; i < length; i++)
        {
-               target[i*3+2] = s[i] >> 24 & 0xFF;
-               target[i*3+1] = s[i] >> 16 & 0xFF;
-               target[i*3] = s[i] >> 8 & 0xFF;
+               t = s[i];
+               target[i*3+2] = t >> 24 & 0xFF;
+               target[i*3+1] = t >> 16 & 0xFF;
+               target[i*3] = t >> 8 & 0xFF;
        }
 }
 
@@ -281,7 +289,7 @@ void AUD_convert_s32_double(data_t* target, data_t* source, int length)
 {
        int32_t* s = (int32_t*) source;
        double* t = (double*) target;
-       for(int i = 0; i < length; i++)
+       for(int i = length - 1; i >= 0; i++)
                t[i] = s[i] / AUD_S32_FLT;
 }
 
@@ -371,7 +379,7 @@ void AUD_convert_float_double(data_t* target, data_t* source, int length)
 {
        float* s = (float*) source;
        double* t = (double*) target;
-       for(int i = 0; i < length; i++)
+       for(int i = length - 1; i >= 0; i++)
                t[i] = s[i];
 }
 
diff --git a/release/scripts/modules/mocap_tools.py b/release/scripts/modules/mocap_tools.py
new file mode 100644 (file)
index 0000000..739dc40
--- /dev/null
@@ -0,0 +1,451 @@
+from math import hypot, sqrt, isfinite
+import bpy
+import time
+from mathutils import Vector
+
+#Vector utility functions
+class NdVector:
+    vec = []
+    
+    def __init__(self,vec):
+        self.vec = vec[:]
+        
+    def __len__(self):
+        return len(self.vec)
+    
+    def __mul__(self,otherMember):
+        if type(otherMember)==type(1) or type(otherMember)==type(1.0):
+            return NdVector([otherMember*x for x in self.vec])
+        else:
+            a = self.vec
+            b = otherMember.vec
+            n = len(self)
+            return sum([a[i]*b[i] for i in range(n)])
+    
+    def __sub__(self,otherVec):
+        a = self.vec
+        b = otherVec.vec
+        n = len(self)
+        return NdVector([a[i]-b[i] for i in range(n)])
+        
+    def __add__(self,otherVec):
+        a = self.vec
+        b = otherVec.vec
+        n = len(self)
+        return NdVector([a[i]+b[i] for i in range(n)])
+    
+    def vecLength(self):
+        return sqrt(self * self)
+        
+    def vecLengthSq(self):
+        return (self * self)
+        
+    def __getitem__(self,i):
+        return self.vec[i]
+    
+    length = property(vecLength)
+    lengthSq = property(vecLengthSq)
+
+class dataPoint:
+    index = 0
+    co = Vector((0,0,0,0)) # x,y1,y2,y3 coordinate of original point
+    u = 0 #position according to parametric view of original data, [0,1] range
+    temp = 0 #use this for anything
+
+    def __init__(self,index,co,u=0):
+        self.index = index
+        self.co = co
+        self.u = u
+
+def autoloop_anim():
+    context = bpy.context
+    obj = context.active_object
+    fcurves = [x for x in obj.animation_data.action.fcurves if x.select]
+
+    data = []
+    end = len(fcurves[0].keyframe_points)
+        
+    for i in range(1,end):
+        vec = []
+        for fcurve in fcurves:
+            vec.append(fcurve.evaluate(i))
+        data.append(NdVector(vec))
+    
+    def comp(a,b):
+        return a*b
+    
+    N = len(data)
+    Rxy = [0.0] * N
+    for i in range(N):
+        for j in range(i,min(i+N,N)):
+            Rxy[i]+=comp(data[j],data[j-i]) 
+        for j in range(i):
+            Rxy[i]+=comp(data[j],data[j-i+N])
+        Rxy[i]/=float(N)
+    
+    def bestLocalMaximum(Rxy):
+        Rxyd = [Rxy[i]-Rxy[i-1] for i in range(1,len(Rxy))]
+        maxs = []
+        for i in range(1,len(Rxyd)-1):
+            a = Rxyd[i-1]
+            b = Rxyd[i]
+            print(a,b)
+            if (a>=0 and b<0) or (a<0 and b>=0): #sign change (zerocrossing) at point i, denoting max point (only)
+                maxs.append((i,max(Rxy[i],Rxy[i-1])))
+        return max(maxs,key=lambda x: x[1])[0]         
+    flm = bestLocalMaximum(Rxy[0:int(len(Rxy))])
+    
+    diff = []
+    
+    for i in range(len(data)-flm):
+        diff.append((data[i]-data[i+flm]).lengthSq)
+    
+    def lowerErrorSlice(diff,e):
+        bestSlice = (0,100000) #index, error at index
+        for i in range(e,len(diff)-e):
+            errorSlice = sum(diff[i-e:i+e+1])
+            if errorSlice<bestSlice[1]:
+                bestSlice = (i,errorSlice)
+        return bestSlice[0]
+    
+    margin = 2
+    
+    s = lowerErrorSlice(diff,margin)
+    
+    print(flm,s)
+    loop = data[s:s+flm+margin]
+    
+    #find *all* loops, s:s+flm, s+flm:s+2flm, etc... and interpolate between all
+    # to find "the perfect loop". Maybe before finding s? interp(i,i+flm,i+2flm)....
+    for i in range(1,margin+1):
+        w1 = sqrt(float(i)/margin)
+        loop[-i] = (loop[-i]*w1)+(loop[0]*(1-w1))
+
+    
+    for curve in fcurves:
+        pts = curve.keyframe_points
+        for i in range(len(pts)-1,-1,-1):
+            pts.remove(pts[i])
+    
+    for c,curve in enumerate(fcurves):
+        pts = curve.keyframe_points
+        for i in range(len(loop)):
+            pts.insert(i+1,loop[i][c])
+            
+    context.scene.frame_end = flm+1
+    
+    
+    
+    
+
+
+def simplifyCurves(curveGroup, error, reparaError, maxIterations, group_mode):
+
+    def unitTangent(v,data_pts):
+        tang = Vector((0,0,0,0)) #
+        if v!=0:
+            #If it's not the first point, we can calculate a leftside tangent
+            tang+= data_pts[v].co-data_pts[v-1].co
+        if v!=len(data_pts)-1:
+            #If it's not the last point, we can calculate a rightside tangent
+            tang+= data_pts[v+1].co-data_pts[v].co
+        tang.normalize()
+        return tang
+
+    #assign parametric u value for each point in original data
+    def chordLength(data_pts,s,e):
+        totalLength = 0
+        for pt in data_pts[s:e+1]:
+            i = pt.index
+            if i==s:
+                chordLength = 0
+            else:
+                chordLength = (data_pts[i].co-data_pts[i-1].co).length
+            totalLength+= chordLength
+            pt.temp = totalLength
+        for pt in data_pts[s:e+1]:
+            if totalLength==0:
+                print(s,e)
+            pt.u = (pt.temp/totalLength)
+
+    # get binomial coefficient, this function/table is only called with args (3,0),(3,1),(3,2),(3,3),(2,0),(2,1),(2,2)!
+    binomDict = {(3,0): 1, (3,1): 3, (3,2): 3, (3,3): 1, (2,0): 1, (2,1): 2, (2,2): 1}
+    #value at pt t of a single bernstein Polynomial
+
+    def bernsteinPoly(n,i,t):
+        binomCoeff = binomDict[(n,i)]
+        return binomCoeff * pow(t,i) * pow(1-t,n-i)
+            
+    # fit a single cubic to data points in range [s(tart),e(nd)].  
+    def fitSingleCubic(data_pts,s,e):
+
+        # A - matrix used for calculating C matrices for fitting
+        def A(i,j,s,e,t1,t2):
+            if j==1:
+                t = t1
+            if j==2:
+                t = t2
+            u = data_pts[i].u
+            return t * bernsteinPoly(3,j,u)
+        
+        # X component, used for calculating X matrices for fitting
+        def xComponent(i,s,e):
+            di = data_pts[i].co
+            u = data_pts[i].u
+            v0 = data_pts[s].co
+            v3 = data_pts[e].co
+            a = v0*bernsteinPoly(3,0,u)
+            b = v0*bernsteinPoly(3,1,u) #
+            c = v3*bernsteinPoly(3,2,u)
+            d = v3*bernsteinPoly(3,3,u)
+            return (di -(a+b+c+d))
+        
+        t1 = unitTangent(s,data_pts)
+        t2 = unitTangent(e,data_pts)    
+        c11 = sum([A(i,1,s,e,t1,t2)*A(i,1,s,e,t1,t2) for i in range(s,e+1)])
+        c12 = sum([A(i,1,s,e,t1,t2)*A(i,2,s,e,t1,t2) for i in range(s,e+1)])
+        c21 = c12
+        c22 = sum([A(i,2,s,e,t1,t2)*A(i,2,s,e,t1,t2) for i in range(s,e+1)])
+        
+        x1 = sum([xComponent(i,s,e)*A(i,1,s,e,t1,t2) for i in range(s,e+1)])
+        x2 = sum([xComponent(i,s,e)*A(i,2,s,e,t1,t2) for i in range(s,e+1)])
+        
+        # calculate Determinate of the 3 matrices
+        det_cc = c11 * c22 - c21 * c12
+        det_cx = c11 * x2 - c12 * x1
+        det_xc = x1 * c22 - x2 * c12
+
+        # if matrix is not homogenous, fudge the data a bit 
+        if det_cc == 0:
+            det_cc=0.01
+
+        # alpha's are the correct offset for bezier handles
+        alpha0 = det_xc / det_cc #offset from right (first) point
+        alpha1 = det_cx / det_cc #offset from left (last) point
+       
+        sRightHandle = data_pts[s].co.copy()
+        sTangent = t1*abs(alpha0)
+        sRightHandle+= sTangent #position of first pt's handle
+        eLeftHandle = data_pts[e].co.copy()
+        eTangent = t2*abs(alpha1)
+        eLeftHandle+= eTangent #position of last pt's handle.
+        
+        #return a 4 member tuple representing the bezier
+        return (data_pts[s].co,
+              sRightHandle,
+              eLeftHandle,
+              data_pts[e].co)
+
+    # convert 2 given data points into a cubic bezier.
+    # handles are offset along the tangent at a 3rd of the length between the points.          
+    def fitSingleCubic2Pts(data_pts,s,e):
+        alpha0 = alpha1 = (data_pts[s].co-data_pts[e].co).length / 3
+
+        sRightHandle = data_pts[s].co.copy()
+        sTangent = unitTangent(s,data_pts)*abs(alpha0)
+        sRightHandle+= sTangent #position of first pt's handle
+        eLeftHandle = data_pts[e].co.copy()
+        eTangent = unitTangent(e,data_pts)*abs(alpha1)
+        eLeftHandle+= eTangent #position of last pt's handle.
+        
+        #return a 4 member tuple representing the bezier
+        return (data_pts[s].co,
+          sRightHandle,
+          eLeftHandle,
+          data_pts[e].co)
+              
+    #evaluate bezier, represented by a 4 member tuple (pts) at point t.
+    def bezierEval(pts,t):
+        sumVec = Vector((0,0,0,0))
+        for i in range(4):
+            sumVec+=pts[i]*bernsteinPoly(3,i,t)
+        return sumVec
+
+    #calculate the highest error between bezier and original data
+    #returns the distance and the index of the point where max error occurs.
+    def maxErrorAmount(data_pts,bez,s,e):
+        maxError = 0
+        maxErrorPt = s
+        if e-s<3: return 0, None
+        for pt in data_pts[s:e+1]:
+            bezVal = bezierEval(bez,pt.u) 
+            tmpError = (pt.co-bezVal).length/pt.co.length
+            if tmpError >= maxError:
+                maxError = tmpError
+                maxErrorPt = pt.index
+        return maxError,maxErrorPt
+
+
+    #calculated bezier derivative at point t.
+    #That is, tangent of point t.
+    def getBezDerivative(bez,t):
+        n = len(bez)-1
+        sumVec = Vector((0,0,0,0))
+        for i in range(n-1):
+            sumVec+=bernsteinPoly(n-1,i,t)*(bez[i+1]-bez[i])
+        return sumVec
+        
+        
+    #use Newton-Raphson to find a better paramterization of datapoints,
+    #one that minimizes the distance (or error) between bezier and original data.
+    def newtonRaphson(data_pts,s,e,bez):
+        for pt in data_pts[s:e+1]:
+            if pt.index==s:
+                pt.u=0
+            elif pt.index==e:
+                pt.u=1
+            else:
+                u = pt.u
+                qu = bezierEval(bez,pt.u)
+                qud = getBezDerivative(bez,u)
+                #we wish to minimize f(u), the squared distance between curve and data
+                fu = (qu-pt.co).length**2 
+                fud = (2*(qu.x-pt.co.x)*(qud.x))-(2*(qu.y-pt.co.y)*(qud.y))
+                if fud==0:
+                    fu = 0
+                    fud = 1
+                pt.u=pt.u-(fu/fud)
+
+    def createDataPts(curveGroup, group_mode):
+        data_pts = []
+        if group_mode:
+            for i in range(len(curveGroup[0].keyframe_points)):
+                x = curveGroup[0].keyframe_points[i].co.x
+                y1 = curveGroup[0].keyframe_points[i].co.y
+                y2 = curveGroup[1].keyframe_points[i].co.y
+                y3 = curveGroup[2].keyframe_points[i].co.y
+                data_pts.append(dataPoint(i,Vector((x,y1,y2,y3))))
+        else:
+            for i in range(len(curveGroup.keyframe_points)):
+                x = curveGroup.keyframe_points[i].co.x
+                y1 = curveGroup.keyframe_points[i].co.y
+                y2 = 0
+                y3 = 0
+                data_pts.append(dataPoint(i,Vector((x,y1,y2,y3))))
+        return data_pts
+
+    def fitCubic(data_pts,s,e):
+
+        if e-s<3: # if there are less than 3 points, fit a single basic bezier
+            bez = fitSingleCubic2Pts(data_pts,s,e)
+        else:
+            #if there are more, parameterize the points and fit a single cubic bezier
+            chordLength(data_pts,s,e)
+            bez = fitSingleCubic(data_pts,s,e)
+        
+        #calculate max error and point where it occurs
+        maxError,maxErrorPt = maxErrorAmount(data_pts,bez,s,e)
+        #if error is small enough, reparameterization might be enough
+        if maxError<reparaError and maxError>error:
+            for i in range(maxIterations):
+                newtonRaphson(data_pts,s,e,bez)
+                if e-s<3:
+                    bez = fitSingleCubic2Pts(data_pts,s,e)
+                else:
+                    bez = fitSingleCubic(data_pts,s,e)
+       
+
+        #recalculate max error and point where it occurs
+        maxError,maxErrorPt = maxErrorAmount(data_pts,bez,s,e)
+        
+        #repara wasn't enough, we need 2 beziers for this range.
+        #Split the bezier at point of maximum error
+        if maxError>error:
+            fitCubic(data_pts,s,maxErrorPt)
+            fitCubic(data_pts,maxErrorPt,e)
+        else:
+            #error is small enough, return the beziers.
+            beziers.append(bez)
+            return
+
+    def createNewCurves(curveGroup,beziers,group_mode):
+        #remove all existing data points
+        if group_mode:
+            for fcurve in curveGroup:
+                for i in range(len(fcurve.keyframe_points)-1,0,-1):
+                    fcurve.keyframe_points.remove(fcurve.keyframe_points[i])
+        else:
+            fcurve = curveGroup
+            for i in range(len(fcurve.keyframe_points)-1,0,-1):
+                fcurve.keyframe_points.remove(fcurve.keyframe_points[i])
+        
+        #insert the calculated beziers to blender data.\
+        if group_mode: 
+            for fullbez in beziers:
+                for i,fcurve in enumerate(curveGroup):
+                    bez = [Vector((vec[0],vec[i+1])) for vec in fullbez]
+                    newKey = fcurve.keyframe_points.insert(frame=bez[0].x,value=bez[0].y)
+                    newKey.handle_right = (bez[1].x,bez[1].y)
+                           
+                    newKey = fcurve.keyframe_points.insert(frame=bez[3].x,value=bez[3].y)
+                    newKey.handle_left= (bez[2].x,bez[2].y)
+        else:
+            for bez in beziers:
+                for vec in bez:
+                    vec.resize_2d()
+                newKey = fcurve.keyframe_points.insert(frame=bez[0].x,value=bez[0].y)
+                newKey.handle_right = (bez[1].x,bez[1].y)
+                        
+                newKey = fcurve.keyframe_points.insert(frame=bez[3].x,value=bez[3].y)
+                newKey.handle_left= (bez[2].x,bez[2].y)
+
+    #indices are detached from data point's frame (x) value and stored in the dataPoint object, represent a range
+
+    data_pts = createDataPts(curveGroup,group_mode)
+        
+    s = 0 #start
+    e = len(data_pts)-1 #end
+    
+    beziers = []
+
+    #begin the recursive fitting algorithm.            
+    fitCubic(data_pts,s,e)
+    #remove old Fcurves and insert the new ones
+    createNewCurves(curveGroup,beziers,group_mode)
+    
+#Main function of simplification
+#sel_opt: either "sel" or "all" for which curves to effect
+#error: maximum error allowed, in fraction (20% = 0.0020), i.e. divide by 10000 from percentage wanted.
+#group_mode: boolean, to analyze each curve seperately or in groups, where group is all curves that effect the same property (e.g. a bone's x,y,z rotation)
+
+def fcurves_simplify(sel_opt="all", error=0.002, group_mode=True):
+    # main vars
+    context = bpy.context
+    obj = context.active_object
+    fcurves = obj.animation_data.action.fcurves
+    
+    if sel_opt=="sel":
+        sel_fcurves = [fcurve for fcurve in fcurves if fcurve.select]
+    else:
+        sel_fcurves = fcurves[:]
+
+    #Error threshold for Newton Raphson reparamatizing
+    reparaError = error*32
+    maxIterations = 16
+    
+    if group_mode:
+        fcurveDict = {}
+        #this loop sorts all the fcurves into groups of 3, based on their RNA Data path, which corresponds to which property they effect
+        for curve in sel_fcurves:
+            if curve.data_path in fcurveDict: #if this bone has been added, append the curve to its list
+                fcurveDict[curve.data_path].append(curve)
+            else:
+                fcurveDict[curve.data_path] = [curve] #new bone, add a new dict value with this first curve
+        fcurveGroups = fcurveDict.values()
+    else:
+        fcurveGroups = sel_fcurves
+     
+    if error>0.00000:
+        #simplify every selected curve.
+        totalt = 0
+        for i,fcurveGroup in enumerate(fcurveGroups):
+            print("Processing curve "+str(i+1)+"/"+str(len(fcurveGroups)))
+            t = time.clock()
+            simplifyCurves(fcurveGroup,error,reparaError,maxIterations,group_mode)
+            t = time.clock() - t
+            print(str(t)[:5]+" seconds to process last curve")
+            totalt+=t
+            print(str(totalt)[:5]+" seconds, total time elapsed")
+
+    return        
+
diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py
new file mode 100644 (file)
index 0000000..c7a4826
--- /dev/null
@@ -0,0 +1,136 @@
+import bpy
+from mathutils import *
+from math import radians, acos
+performer_obj = bpy.data.objects["performer"]
+enduser_obj = bpy.data.objects["enduser"]
+scene = bpy.context.scene
+
+# dictionary of mapping
+bonemap = { "LeftFoot": ("DEF_Foot.L","DEF_Toes.L"),
+            "LeftUpLeg": "DEF_Thigh.L",
+            "Hips": "DEF_Hip",
+            "LowerBack": "DEF_Spine",
+            "Spine": "DEF_Torso",
+            "Neck": "DEF_Neck",
+            "Neck1": "DEF_Neck",
+            "Head": "DEF_Head",
+            "LeftShoulder": "DEF_Shoulder.L",
+            "LeftArm": "DEF_Forearm.L",
+            "LeftForeArm": "DEF_Arm.L",
+            "LeftHand": "DEF_Hand.L",
+            "RightShoulder": "DEF_Shoulder.R",
+            "RightArm": "DEF_Forearm.R",
+            "RightForeArm": "DEF_Arm.R",
+            "RightHand": "DEF_Hand.R",
+            "RightFoot": ("DEF_Foot.R","DEF_Toes.R"),
+            "RightUpLeg": "DEF_Thigh.R",
+            "RightLeg": "DEF_Shin.R",
+            "LeftLeg": "DEF_Shin.L"}
+# creation of a reverse map
+# multiple keys get mapped to list values
+bonemapr = {}
+for key in bonemap.keys():
+    if not bonemap[key] in bonemapr:
+        if type(bonemap[key])==type((0,0)):
+            for key_x in bonemap[key]:
+                bonemapr[key_x] = [key]
+        else:
+            bonemapr[bonemap[key]] = [key]
+    else:
+        bonemapr[bonemap[key]].append(key)
+        
+# list of empties created to keep track of "original"
+# position data
+# in final product, these locations can be stored as custom props
+
+constraints = []
+
+#creation of intermediate armature
+# the intermediate armature has the hiearchy of the end user,
+# does not have rotation inheritence
+# and bone roll is identical to the performer
+# its purpose is to copy over the rotations
+# easily while concentrating on the hierarchy changes
+def createIntermediate():
+    
+    #creates and keyframes an empty with its location
+    #the original position of the tail bone
+    #useful for storing the important data in the original motion
+    #i.e. using this empty to IK the chain to that pos.
+    def locOfOriginal(inter_bone,perf_bone):
+        if not perf_bone.name+"Org" in bpy.data.objects:
+            bpy.ops.object.add()
+            empty = bpy.context.active_object
+            empty.name = perf_bone.name+"Org"
+        empty = bpy.data.objects[perf_bone.name+"Org"]
+        offset = perf_bone.vector
+        scaling = perf_bone.length / inter_bone.length
+        offset/=scaling
+        empty.location = inter_bone.head + offset
+        empty.keyframe_insert("location")
+    
+    #Simple 1to1 retarget of a bone
+    def singleBoneRetarget(inter_bone,perf_bone):
+            perf_world_rotation = perf_bone.matrix * performer_obj.matrix_world         
+            inter_world_base_rotation = inter_bone.bone.matrix_local * inter_obj.matrix_world
+            inter_world_base_inv = Matrix(inter_world_base_rotation)
+            inter_world_base_inv.invert()
+            return (inter_world_base_inv.to_3x3() * perf_world_rotation.to_3x3()).to_4x4()
+        
+    #uses 1to1 and interpolation/averaging to match many to 1 retarget    
+    def manyPerfToSingleInterRetarget(inter_bone,performer_bones_s):
+        retarget_matrices = [singleBoneRetarget(inter_bone,perf_bone) for perf_bone in performer_bones_s]
+        lerp_matrix = Matrix()
+        for i in range(len(retarget_matrices)-1):
+            first_mat = retarget_matrices[i]
+            next_mat = retarget_matrices[i+1]
+            lerp_matrix = first_mat.lerp(next_mat,0.5)
+        return lerp_matrix
+    
+    #determines the type of hierachy change needed and calls the 
+    #right function        
+    def retargetPerfToInter(inter_bone):
+        if inter_bone.name in bonemapr.keys():
+            perf_bone_name = bonemapr[inter_bone.name]
+            #is it a 1 to many?
+            if type(bonemap[perf_bone_name[0]])==type((0,0)):
+                perf_bone = performer_bones[perf_bone_name[0]]
+                if inter_bone.name == bonemap[perf_bone_name[0]][0]:
+                    locOfOriginal(inter_bone,perf_bone)
+            else:
+                # then its either a many to 1 or 1 to 1
+                
+                if len(perf_bone_name) > 1:
+                    performer_bones_s = [performer_bones[name] for name in perf_bone_name]
+                    #we need to map several performance bone to a single
+                    inter_bone.matrix_basis = manyPerfToSingleInterRetarget(inter_bone,performer_bones_s)
+                else:
+                    perf_bone = performer_bones[perf_bone_name[0]]
+                    inter_bone.matrix_basis = singleBoneRetarget(inter_bone,perf_bone)
+                    
+        inter_bone.keyframe_insert("rotation_quaternion")
+        for child in inter_bone.children:
+            retargetPerfToInter(child)
+            
+    #creates the intermediate armature object        
+    bpy.ops.object.select_name(name="enduser",extend=False)
+    bpy.ops.object.duplicate(linked=False)
+    bpy.context.active_object.name = "intermediate"
+    inter_obj = bpy.context.active_object
+    bpy.ops.object.mode_set(mode='EDIT')
+    #resets roll 
+    bpy.ops.armature.calculate_roll(type='Z')
+    bpy.ops.object.mode_set(mode="OBJECT")
+    performer_bones = performer_obj.pose.bones
+    inter_bones =  inter_obj.pose.bones
+    
+    #clears inheritance
+    for inter_bone in inter_bones:
+        inter_bone.bone.use_inherit_rotation = False
+        
+    for t in range(1,150):
+        scene.frame_set(t)
+        inter_bone = inter_bones["DEF_Hip"]
+        retargetPerfToInter(inter_bone)
+         
+createIntermediate()   
\ No newline at end of file
index 923ca92a16297d804f505838d2389c36b5acb18f..82849cca2ccf5366756fdabbf436e372ff4c8ad6 100644 (file)
@@ -168,3 +168,37 @@ class BakeAction(bpy.types.Operator):
     def invoke(self, context, event):
         wm = context.window_manager
         return wm.invoke_props_dialog(self)
+        
+#################################
+
+class ClearUselessActions(bpy.types.Operator):
+    '''Mark actions with no F-Curves for deletion after save+reload of file preserving "action libraries"'''
+    bl_idname = "anim.clear_useless_actions"
+    bl_label = "Clear Useless Actions"
+    bl_options = {'REGISTER', 'UNDO'}
+    
+    only_unused = BoolProperty(name="Only Unused", 
+            description="Only unused (Fake User only) actions get considered",
+            default=True)
+    
+    @classmethod
+    def poll(cls, context):
+        return len(bpy.data.actions) != 0
+        
+    def execute(self, context):
+        removed = 0
+        
+        for action in bpy.data.actions:
+            # if only user is "fake" user...
+            if ((self.only_unused is False) or 
+                (action.use_fake_user and action.users == 1)):
+                
+                # if it has F-Curves, then it's a "action library" (i.e. walk, wave, jump, etc.) 
+                # and should be left alone as that's what fake users are for!
+                if not action.fcurves:
+                    # mark action for deletion
+                    action.user_clear()
+                    removed += 1
+        
+        self.report({'INFO'}, "Removed %d empty and/or fake-user only Actions" % (removed))
+        return {'FINISHED'}
index 0342a14a1b23c7e1fe4491222b0b010347b24004..7a9a9d419396fe9d33abee8f6d24161c3f51f476 100644 (file)
@@ -564,3 +564,44 @@ class ClearAllRestrictRender(bpy.types.Operator):
         for obj in context.scene.objects:
             obj.hide_render = False
         return {'FINISHED'}
+
+class TransformsToDeltasAnim(bpy.types.Operator):
+    '''Convert object animation for normal transforms to delta transforms'''
+    bl_idname = "object.anim_transforms_to_deltas"
+    bl_label = "Animated Transforms to Deltas"
+    bl_options = {'REGISTER', 'UNDO'}
+    
+    @classmethod
+    def poll(cls, context):
+        obs = context.selected_editable_objects
+        return (obs is not None)
+    
+    def execute(self, context):
+        for obj in context.selected_editable_objects:
+            # get animation data
+            adt = obj.animation_data
+            if (adt is None) or (adt.action is None):
+                self.report({'WARNING'}, "No animation data to convert on object: " + obj.name)
+                continue
+            
+            # if F-Curve uses standard transform path, just append "delta_" to this path
+            for fcu in adt.action.fcurves:
+                if fcu.data_path == "location":
+                    fcu.data_path = "delta_location"
+                    obj.location.zero()
+                elif fcu.data_path == "rotation_euler":
+                    fcu.data_path = "delta_rotation_euler"
+                    obj.rotation_euler.zero()
+                elif fcu.data_path == "rotation_quaternion":
+                    fcu.data_path = "delta_rotation_quaternion"
+                    obj.rotation_quaternion.identity()
+                #elif fcu.data_path == "rotation_axis_angle":  # XXX: currently not implemented 
+                #   fcu.data_path = "delta_rotation_axis_angle"
+                elif fcu.data_path == "scale":
+                    fcu.data_path = "delta_scale"
+                    obj.scale = (1, 1, 1)
+        
+        # hack: force animsys flush by changing frame, so that deltas get run
+        context.scene.frame_set(context.scene.frame_current)
+        
+        return {'FINISHED'}
index 7c2fe76fe1481a9d86b155afcf3e85cb0096308c..70121a12caaca6e5225878a42c0a6320eeb23551 100644 (file)
@@ -476,6 +476,11 @@ class ConstraintButtonsPanel():
         row.label(text="Clamp Region:")
         row.prop(con, "limit_mode", text="")
 
+        row = layout.row()
+        row.prop(con, "use_transform_limit")
+        row.label()
+
+
     def STRETCH_TO(self, context, layout, con):
         self.target_template(layout, con)
 
index 0583dc7e4be22986f34a3463ae86903e25ec249f..3ea5480a99e904a0d11b33c39ca4e4a62962c1bc 100644 (file)
@@ -181,6 +181,10 @@ class VIEW3D_MT_transform(bpy.types.Menu):
 
         layout.operator("object.randomize_transform")
         layout.operator("object.align")
+        
+        layout.separator()
+        
+        layout.operator("object.anim_transforms_to_deltas")
 
 
 class VIEW3D_MT_mirror(bpy.types.Menu):
index 7c0e7050a9f8a9d089674b3e7a579f73e1158adc..ddff45c54224e311d3896e786abc4b03cbb6b6cb 100644 (file)
@@ -154,6 +154,7 @@ void constraints_clear_evalob(struct bConstraintOb *cob);
 void constraint_mat_convertspace(struct Object *ob, struct bPoseChannel *pchan, float mat[][4], short from, short to);
 
 void get_constraint_target_matrix(struct Scene *scene, struct bConstraint *con, int n, short ownertype, void *ownerdata, float mat[][4], float ctime);
+void get_constraint_targets_for_solving(struct bConstraint *con, struct bConstraintOb *ob, struct ListBase *targets, float ctime);
 void solve_constraints(struct ListBase *conlist, struct bConstraintOb *cob, float ctime);
 
 #ifdef __cplusplus
index d3c14a9dd12c57f3f836b4f9e94578ae98a5709d..fe3286dcc2be1dbd7c841ae831871f0e36cddc75 100644 (file)
@@ -2648,7 +2648,7 @@ static void distlimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *
                        /* if inside, then move to surface */
                        if (dist <= data->dist) {
                                clamp_surf= 1;
-                               sfac= data->dist / dist;
+                               if (dist != 0.0f) sfac= data->dist / dist;
                        }
                        /* if soft-distance is enabled, start fading once owner is dist+softdist from the target */
                        else if (data->flag & LIMITDIST_USESOFT) {
@@ -2661,14 +2661,14 @@ static void distlimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *
                        /* if outside, then move to surface */
                        if (dist >= data->dist) {
                                clamp_surf= 1;
-                               sfac= data->dist / dist;
+                               if (dist != 0.0f) sfac= data->dist / dist;
                        }
                        /* if soft-distance is enabled, start fading once owner is dist-soft from the target */
                        else if (data->flag & LIMITDIST_USESOFT) {
                                // FIXME: there's a problem with "jumping" when this kicks in
                                if (dist >= (data->dist - data->soft)) {
                                        sfac = (float)( data->soft*(1.0f - expf(-(dist - data->dist)/data->soft)) + data->dist );
-                                       sfac /= dist;
+                                       if (dist != 0.0f) sfac /= dist;
                                        
                                        clamp_surf= 1;
                                }
@@ -2677,7 +2677,7 @@ static void distlimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *
                else {
                        if (IS_EQF(dist, data->dist)==0) {
                                clamp_surf= 1;
-                               sfac= data->dist / dist;
+                               if (dist != 0.0f) sfac= data->dist / dist;
                        }
                }
                
@@ -4427,6 +4427,34 @@ void get_constraint_target_matrix (struct Scene *scene, bConstraint *con, int n,
                unit_m4(mat);
        }
 }
+
+/* Get the list of targets required for solving a constraint */
+void get_constraint_targets_for_solving (bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime)
+{
+       bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+       
+       if (cti && cti->get_constraint_targets) {
+               bConstraintTarget *ct;
+               
+               /* get targets 
+                *      - constraints should use ct->matrix, not directly accessing values
+                *      - ct->matrix members have not yet been calculated here! 
+                */
+               cti->get_constraint_targets(con, targets);
+               
+               /* set matrices 
+                *      - calculate if possible, otherwise just initialise as identity matrix 
+                */
+               if (cti->get_target_matrix) {
+                       for (ct= targets->first; ct; ct= ct->next) 
+                               cti->get_target_matrix(con, cob, ct, ctime);
+               }
+               else {
+                       for (ct= targets->first; ct; ct= ct->next)
+                               unit_m4(ct->matrix);
+               }
+       }
+}
  
 /* ---------- Evaluation ----------- */
 
@@ -4471,27 +4499,7 @@ void solve_constraints (ListBase *conlist, bConstraintOb *cob, float ctime)
                constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace);
                
                /* prepare targets for constraint solving */
-               if (cti->get_constraint_targets) {
-                       bConstraintTarget *ct;
-                       
-                       /* get targets 
-                        *      - constraints should use ct->matrix, not directly accessing values
-                        *      - ct->matrix members have not yet been calculated here! 
-                        */
-                       cti->get_constraint_targets(con, &targets);
-                       
-                       /* set matrices 
-                        *      - calculate if possible, otherwise just initialise as identity matrix 
-                        */
-                       if (cti->get_target_matrix) {
-                               for (ct= targets.first; ct; ct= ct->next) 
-                                       cti->get_target_matrix(con, cob, ct, ctime);
-                       }
-                       else {
-                               for (ct= targets.first; ct; ct= ct->next)
-                                       unit_m4(ct->matrix);
-                       }
-               }
+               get_constraint_targets_for_solving(con, cob, &targets, ctime);
                
                /* Solve the constraint and put result in cob->matrix */
                cti->evaluate_constraint(con, cob, &targets);
index 844f25e6d21505075b414eceecb0cf70af9dd941..4a1a0f9ac6b949f000c031dcc26e8e4fe440e95d 100644 (file)
@@ -1230,11 +1230,21 @@ float evaluate_time_fmodifiers (ListBase *modifiers, FCurve *fcu, float cvalue,
        for (fcm= modifiers->last; fcm; fcm= fcm->prev) {
                FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
                
-               /* only evaluate if there's a callback for this */
-               // TODO: implement the 'influence' control feature...
-               if (fmi && fmi->evaluate_modifier_time) {
-                       if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
-                               evaltime= fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime);
+               if (fmi == NULL) 
+                       continue;
+               
+               /* if modifier cannot be applied on this frame (whatever scale it is on, it won't affect the results)
+                * hence we shouldn't bother seeing what it would do given the chance
+                */
+               if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT)==0 || 
+                       ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime)) )
+               {
+                       /* only evaluate if there's a callback for this */
+                       // TODO: implement the 'influence' control feature...
+                       if (fmi->evaluate_modifier_time) {
+                               if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
+                                       evaltime= fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime);
+                       }
                }
        }
        
@@ -1257,11 +1267,18 @@ void evaluate_value_fmodifiers (ListBase *modifiers, FCurve *fcu, float *cvalue,
        for (fcm= modifiers->first; fcm; fcm= fcm->next) {
                FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
                
-               /* only evaluate if there's a callback for this */
+               if (fmi == NULL) 
+                       continue;
+               
+               /* only evaluate if there's a callback for this, and if F-Modifier can be evaluated on this frame */
                // TODO: implement the 'influence' control feature...
-               if (fmi && fmi->evaluate_modifier) {
-                       if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
-                               fmi->evaluate_modifier(fcu, fcm, cvalue, evaltime);
+               if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT)==0 || 
+                       ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime)) )
+               {
+                       if (fmi->evaluate_modifier) {
+                               if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
+                                       fmi->evaluate_modifier(fcu, fcm, cvalue, evaltime);
+                       }
                }
        }
 } 
diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp
new file mode 100644 (file)
index 0000000..f28883c
--- /dev/null
@@ -0,0 +1,751 @@
+/*
+ * $Id: DocumentExporter.cpp 36898 2011-05-25 17:14:31Z phabtar $
+ *
+ * ***** 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"
+
+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) 
+       {
+               if (!ob->adt || !ob->adt->action) return;  //this is already checked in hasAnimations()
+               
+               FCurve *fcu = (FCurve*)ob->adt->action->curves.first;
+               
+               if (ob->type == OB_ARMATURE) {
+                       if (!ob->data) return;
+
+                       bArmature *arm = (bArmature*)ob->data;
+                       for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next)
+                               write_bone_animation(ob, bone);
+               }
+               else {
+                       while (fcu) {
+                               // TODO "rotation_quaternion" is also possible for objects (although euler is default)
+                               if ((!strcmp(fcu->rna_path, "location") || !strcmp(fcu->rna_path, "scale")) ||
+                                       (!strcmp(fcu->rna_path, "rotation_euler") && ob->rotmode == ROT_MODE_EUL))
+                                       dae_animation(fcu, id_name(ob));
+
+                               fcu = fcu->next;
+                       }
+               }
+       }
+
+       void AnimationExporter::dae_animation(FCurve *fcu, std::string ob_name)
+       {
+               const char *axis_names[] = {"X", "Y", "Z"};
+               const char *axis_name = NULL;
+               char anim_id[200];
+               bool has_tangents = false;
+               
+               if (fcu->array_index < 3)
+                       axis_name = axis_names[fcu->array_index];
+
+               BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
+                                        fcu->rna_path, axis_names[fcu->array_index]);
+
+               // check rna_path is one of: rotation, scale, location
+
+               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 = 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 = translate_id(ob_name)
+                       + "/" + get_transform_sid(fcu->rna_path, -1, axis_name, true);
+               addChannel(COLLADABU::URI(empty, sampler_id), target);
+
+               closeAnimation();
+       }
+
+       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(&ob_arm->id, ob_arm->adt, *it, 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);
+       }
+
+       // 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)
+       {
+               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 {                           //assumes if axis isn't specified all axi 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] = convert_angle(bezt->vec[1][1]);
+                       }
+                       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] = convert_angle(bezt->vec[0][1]);
+                       } 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] = convert_angle(bezt->vec[2][1]);
+                       } 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_rotation = false;
+               
+               if (strstr(fcu->rna_path, "rotation")) is_rotation = true;
+               
+               COLLADASW::FloatSourceF source(mSW);
+               source.setId(source_id);
+               source.setArrayId(source_id + ARRAY_ID_SUFFIX);
+               source.setAccessorCount(fcu->totvert);
+               
+               switch (semantic) {
+               case COLLADASW::InputSemantic::INPUT:
+               case COLLADASW::InputSemantic::OUTPUT:
+               source.setAccessorStride(1);                    
+                       break;
+               case COLLADASW::InputSemantic::IN_TANGENT:
+               case COLLADASW::InputSemantic::OUT_TANGENT:
+               source.setAccessorStride(2);                    
+                       break;
+               }
+               
+               
+               COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
+               add_source_parameters(param, semantic, is_rotation, axis_name);
+
+               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_rotation, values, &length);
+                       for (int j = 0; j < length; j++)
+                               source.appendValues(values[j]);
+               }
+
+               source.finish();
+
+               return source_id;
+       }
+    //Currently called only to get OUTPUT source values ( if rotation and hence the axis is also specified )
+       std::string AnimationExporter::create_source_from_array(COLLADASW::InputSemantic::Semantics semantic, float *v, int tot, bool is_rot, const std::string& anim_id, const char *axis_name)
+       {
+               std::string source_id = anim_id + get_semantic_suffix(semantic);
+
+               COLLADASW::FloatSourceF source(mSW);
+               source.setId(source_id);
+               source.setArrayId(source_id + ARRAY_ID_SUFFIX);
+               source.setAccessorCount(tot);
+               source.setAccessorStride(1);
+               
+               COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
+               add_source_parameters(param, semantic, is_rot, axis_name);
+
+               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 = convert_angle(val);
+                       source.appendValues(val);
+               }
+
+               source.finish();
+
+               return source_id;
+       }
+// only used for sources with INPUT semantic
+       std::string AnimationExporter::create_source_from_vector(COLLADASW::InputSemantic::Semantics semantic, std::vector<float> &fra, bool is_rot, const std::string& anim_id, const char *axis_name)
+       {
+               std::string source_id = anim_id + get_semantic_suffix(semantic);
+
+               COLLADASW::FloatSourceF source(mSW);
+               source.setId(source_id);
+               source.setArrayId(source_id + ARRAY_ID_SUFFIX);
+               source.setAccessorCount(fra.size());
+               source.setAccessorStride(1);
+               
+               COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
+               add_source_parameters(param, semantic, is_rot, axis_name);
+
+               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;
+       }
+
+       // only used for sources with OUTPUT semantic ( locations and scale)
+       std::string AnimationExporter::create_xyz_source(float *v, int tot, const std::string& anim_id)
+       {
+               COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
+               std::string source_id = anim_id + get_semantic_suffix(semantic);
+
+               COLLADASW::FloatSourceF source(mSW);
+               source.setId(source_id);
+               source.setArrayId(source_id + ARRAY_ID_SUFFIX);
+               source.setAccessorCount(tot);
+               source.setAccessorStride(3);
+               
+               COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
+               add_source_parameters(param, semantic, false, NULL);
+
+               source.prepareToAppendValues();
+
+               for (int i = 0; i < tot; i++) {
+                       source.appendValues(*v, *(v + 1), *(v + 2));
+                       v += 3;
+               }
+
+               source.finish();
+
+               return source_id;
+       }
+
+       std::string AnimationExporter::create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents)
+       {
+               std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
+
+               COLLADASW::NameSource source(mSW);
+               source.setId(source_id);
+               source.setArrayId(source_id + ARRAY_ID_SUFFIX);
+               source.setAccessorCount(fcu->totvert);
+               source.setAccessorStride(1);
+               
+               COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
+               param.push_back("INTERPOLATION");
+
+               source.prepareToAppendValues();
+
+               *has_tangents = false;
+
+               for (unsigned int i = 0; i < fcu->totvert; i++) {
+                       if (fcu->bezt[i].ipo==BEZT_IPO_BEZ) {
+                               source.appendValues(BEZIER_NAME);
+                               *has_tangents = true;
+                       } else if (fcu->bezt[i].ipo==BEZT_IPO_CONST) {
+                               source.appendValues(STEP_NAME);
+                       } else { // BEZT_IPO_LIN
+                               source.appendValues(LINEAR_NAME);
+                       }
+               }
+               // unsupported? -- HERMITE, CARDINAL, BSPLINE, NURBS
+
+               source.finish();
+
+               return source_id;
+       }
+
+       std::string AnimationExporter::fake_interpolation_source(int tot, const std::string& anim_id, const char *axis_name)
+       {
+               std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
+
+               COLLADASW::NameSource source(mSW);
+               source.setId(source_id);
+               source.setArrayId(source_id + ARRAY_ID_SUFFIX);
+               source.setAccessorCount(tot);
+               source.setAccessorStride(1);
+               
+               COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
+               param.push_back("INTERPOLATION");
+
+               source.prepareToAppendValues();
+
+               for (int i = 0; i < tot; i++) {
+                       source.appendValues(LINEAR_NAME);
+               }
+
+               source.finish();
+
+               return source_id;
+       }
+
+       // 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;
+
+               // when given rna_path, determine tm_type from it
+               if (rna_path) {
+                       char *name = extract_transform_name(rna_path);
+
+                       if (strstr(name, "rotation"))
+                               tm_type = 0;
+                       else if (!strcmp(name, "scale"))
+                               tm_type = 1;
+                       else if (!strcmp(name, "location"))
+                               tm_type = 2;
+                       else
+                               tm_type = -1;
+               }
+
+               switch (tm_type) {
+               case 0:
+                       return std::string("rotation") + std::string(axis_name) + ".ANGLE";
+               case 1:
+                       tm_name = "scale";
+                       break;
+               case 2:
+                       tm_name = "location";
+                       break;
+               default:
+                       tm_name = "";
+                       break;
+               }
+
+               if (tm_name.size()) {
+                       if (append_axis)
+                               return tm_name + std::string(".") + 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;
+       }
+
+       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::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)
+                       ;*/
+       }
+
+       // 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;
+                       if(ob->adt && ob->adt->action)      
+                               fcu = (FCurve*)ob->adt->action->curves.first;
+                               
+                       //The Scene has animations if object type is armature or object has f-curve
+                       if ((ob->type == OB_ARMATURE && ob->data) || fcu) {
+                               return true;
+                       }
+                       base= base->next;
+               }
+               return false;
+       }
diff --git a/source/blender/collada/AnimationExporter.h b/source/blender/collada/AnimationExporter.h
new file mode 100644 (file)
index 0000000..3968401
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * $Id: DocumentExporter.cpp 36898 2011-05-25 17:14:31Z phabtar $
+ *
+ * ***** 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_armature_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 "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(FCurve *fcu, std::string ob_name);
+
+       void write_bone_animation(Object *ob_arm, Bone *bone);
+
+       void sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type);
+
+       void sample_animation(float *v, std::vector<float> &frames, int type, 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);
+
+       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);
+       
+    void get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool rotation, float *values, int *length);
+
+       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_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);
+       
+       void find_frames(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name);
+       
+       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);
+};
\ No newline at end of file
index a7e7c973f361e364c7d1d324a3adce19432ea10a..7c43c09bc12495b88fd0864b3a33ea06768b09d4 100644 (file)
@@ -62,6 +62,7 @@ endif()
 
 set(SRC
        AnimationImporter.cpp
+       AnimationExporter.cpp
        ArmatureExporter.cpp
        ArmatureImporter.cpp
        CameraExporter.cpp
@@ -84,6 +85,7 @@ set(SRC
        collada_utils.cpp
 
        AnimationImporter.h
+       AnimationExporter.h     
        ArmatureExporter.h
        ArmatureImporter.h
        CameraExporter.h
index 00daac6028182d5ec270791dd8e295b940a0db57..0bdf41f15eb7b7a75804c32bb64d1ec811bd118c 100644 (file)
@@ -114,6 +114,7 @@ extern char build_rev[];
 #include "TransformWriter.h"
 
 #include "ArmatureExporter.h"
+#include "AnimationExporter.h"
 #include "CameraExporter.h"
 #include "EffectExporter.h"
 #include "GeometryExporter.h"
@@ -298,636 +299,6 @@ public:
 // TODO: it would be better to instantiate animations rather than create a new one per object
 // COLLADA allows this through multiple <channel>s in <animation>.
 // For this to work, we need to know objects that use a certain action.
-class AnimationExporter: COLLADASW::LibraryAnimations
-{
-       Scene *scene;
-       COLLADASW::StreamWriter *sw;
-
-public:
-
-       AnimationExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryAnimations(sw) { this->sw = sw; }
-
-
-
-       void exportAnimations(Scene *sce)
-       {
-               if(hasAnimations(sce)) {
-                       this->scene = sce;
-
-                       openLibrary();
-
-                       forEachObjectInScene(sce, *this);
-
-                       closeLibrary();
-               }
-       }
-
-       // called for each exported object
-       void operator() (Object *ob) 
-       {
-               if (!ob->adt || !ob->adt->action) return;
-               
-               FCurve *fcu = (FCurve*)ob->adt->action->curves.first;
-               
-               if (ob->type == OB_ARMATURE) {
-                       if (!ob->data) return;
-
-                       bArmature *arm = (bArmature*)ob->data;
-                       for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next)
-                               write_bone_animation(ob, bone);
-               }
-               else {
-                       while (fcu) {
-                               // TODO "rotation_quaternion" is also possible for objects (although euler is default)
-                               if ((!strcmp(fcu->rna_path, "location") || !strcmp(fcu->rna_path, "scale")) ||
-                                       (!strcmp(fcu->rna_path, "rotation_euler") && ob->rotmode == ROT_MODE_EUL))
-                                       dae_animation(fcu, id_name(ob));
-
-                               fcu = fcu->next;
-                       }
-               }
-       }
-
-protected:
-
-       void dae_animation(FCurve *fcu, std::string ob_name)
-       {
-               const char *axis_names[] = {"X", "Y", "Z"};
-               const char *axis_name = NULL;
-               char anim_id[200];
-               
-               if (fcu->array_index < 3)
-                       axis_name = axis_names[fcu->array_index];
-
-               BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
-                                        fcu->rna_path, axis_names[fcu->array_index]);
-
-               // check rna_path is one of: rotation, scale, location
-
-               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 = create_source_from_fcurve(COLLADASW::InputSemantic::OUTPUT, fcu, anim_id, axis_name);
-
-               // create interpolations source
-               std::string interpolation_id = create_interpolation_source(fcu->totvert, 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));
-
-               addSampler(sampler);
-
-               std::string target = translate_id(ob_name)
-                       + "/" + get_transform_sid(fcu->rna_path, -1, axis_name, true);
-               addChannel(COLLADABU::URI(empty, sampler_id), target);
-
-               closeAnimation();
-       }
-
-       void write_bone_animation(Object *ob_arm, Bone *bone)
-       {
-               if (!ob_arm->adt)
-                       return;
-
-               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 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;
-
-               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);
-               }
-
-               if (fra.size()) {
-                       float *v = (float*)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames");
-                       sample_animation(v, fra, transform_type, bone, ob_arm);
-
-                       if (transform_type == 0) {
-                               // write x, y, z curves separately if it is rotation
-                               float *c = (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++)
-                                               c[j] = v[j * 3 + i];
-
-                                       dae_bone_animation(fra, c, transform_type, i, id_name(ob_arm), bone->name);
-                               }
-                               MEM_freeN(c);
-                       }
-                       else {
-                               // write xyz at once if it is location or scale
-                               dae_bone_animation(fra, v, transform_type, -1, id_name(ob_arm), bone->name);
-                       }
-
-                       MEM_freeN(v);
-               }
-
-               // restore restpos
-               if (flag & ARM_RESTPOS) 
-                       arm->flag = flag;
-               where_is_pose(scene, ob_arm);
-       }
-
-       void sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm)
-       {
-               bPoseChannel *pchan, *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(&ob_arm->id, ob_arm->adt, *it, 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);
-       }
-
-       // 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)
-       {
-               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(v, fra.size(), anim_id);
-               else
-                       output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, v, fra.size(), is_rot, anim_id, axis_name);
-
-               // create interpolations source
-               std::string interpolation_id = create_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 convert_time(float frame)
-       {
-               return FRA2TIME(frame);
-       }
-
-       float convert_angle(float angle)
-       {
-               return COLLADABU::Math::Utils::radToDegF(angle);
-       }
-
-       std::string 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 add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param,
-                                                          COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis)
-       {
-               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 {
-                                       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 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] = convert_angle(bezt->vec[1][1]);
-                       }
-                       else {
-                               values[0] = bezt->vec[1][1];
-                       }
-                       break;
-               case COLLADASW::InputSemantic::IN_TANGENT:
-               case COLLADASW::InputSemantic::OUT_TANGENT:
-                       // XXX
-                       *length = 2;
-                       break;
-               default:
-                       *length = 0;
-                       break;
-               }
-       }
-
-       std::string 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_rotation = false;
-               
-               if (strstr(fcu->rna_path, "rotation")) is_rotation = true;
-               
-               COLLADASW::FloatSourceF source(mSW);
-               source.setId(source_id);
-               source.setArrayId(source_id + ARRAY_ID_SUFFIX);
-               source.setAccessorCount(fcu->totvert);
-               source.setAccessorStride(1);
-               
-               COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
-               add_source_parameters(param, semantic, is_rotation, axis_name);
-
-               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_rotation, values, &length);
-                       for (int j = 0; j < length; j++)
-                               source.appendValues(values[j]);
-               }
-
-               source.finish();
-
-               return source_id;
-       }
-
-       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 source_id = anim_id + get_semantic_suffix(semantic);
-
-               COLLADASW::FloatSourceF source(mSW);
-               source.setId(source_id);
-               source.setArrayId(source_id + ARRAY_ID_SUFFIX);
-               source.setAccessorCount(tot);
-               source.setAccessorStride(1);
-               
-               COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
-               add_source_parameters(param, semantic, is_rot, axis_name);
-
-               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 = convert_angle(val);
-                       source.appendValues(val);
-               }
-
-               source.finish();
-
-               return source_id;
-       }
-
-       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 source_id = anim_id + get_semantic_suffix(semantic);
-
-               COLLADASW::FloatSourceF source(mSW);
-               source.setId(source_id);
-               source.setArrayId(source_id + ARRAY_ID_SUFFIX);
-               source.setAccessorCount(fra.size());
-               source.setAccessorStride(1);
-               
-               COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
-               add_source_parameters(param, semantic, is_rot, axis_name);
-
-               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;
-       }
-
-       // only used for sources with OUTPUT semantic
-       std::string create_xyz_source(float *v, int tot, const std::string& anim_id)
-       {
-               COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
-               std::string source_id = anim_id + get_semantic_suffix(semantic);
-
-               COLLADASW::FloatSourceF source(mSW);
-               source.setId(source_id);
-               source.setArrayId(source_id + ARRAY_ID_SUFFIX);
-               source.setAccessorCount(tot);
-               source.setAccessorStride(3);
-               
-               COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
-               add_source_parameters(param, semantic, false, NULL);
-
-               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 create_interpolation_source(int tot, const std::string& anim_id, const char *axis_name)
-       {
-               std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
-
-               COLLADASW::NameSource source(mSW);
-               source.setId(source_id);
-               source.setArrayId(source_id + ARRAY_ID_SUFFIX);
-               source.setAccessorCount(tot);
-               source.setAccessorStride(1);
-               
-               COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
-               param.push_back("INTERPOLATION");
-
-               source.prepareToAppendValues();
-
-               for (int i = 0; i < tot; i++) {
-                       source.appendValues(LINEAR_NAME);
-               }
-
-               source.finish();
-
-               return source_id;
-       }
-
-       // 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 tm_name;
-
-               // when given rna_path, determine tm_type from it
-               if (rna_path) {
-                       char *name = extract_transform_name(rna_path);
-
-                       if (strstr(name, "rotation"))
-                               tm_type = 0;
-                       else if (!strcmp(name, "scale"))
-                               tm_type = 1;
-                       else if (!strcmp(name, "location"))
-                               tm_type = 2;
-                       else
-                               tm_type = -1;
-               }
-
-               switch (tm_type) {
-               case 0:
-                       return std::string("rotation") + std::string(axis_name) + ".ANGLE";
-               case 1:
-                       tm_name = "scale";
-                       break;
-               case 2:
-                       tm_name = "location";
-                       break;
-               default:
-                       tm_name = "";
-                       break;
-               }
-
-               if (tm_name.size()) {
-                       if (append_axis)
-                               return tm_name + std::string(".") + std::string(axis_name);
-                       else
-                               return tm_name;
-               }
-
-               return std::string("");
-       }
-
-       char *extract_transform_name(char *rna_path)
-       {
-               char *dot = strrchr(rna_path, '.');
-               return dot ? (dot + 1) : rna_path;
-       }
-
-       void 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 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)
-                       ;*/
-       }
-
-       // 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)
-       {
-               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 hasAnimations(Scene *sce)
-       {
-               Base *base= (Base*) sce->base.first;
-               while(base) {
-                       Object *ob = base->object;
-                       
-                       FCurve *fcu = 0;
-                       if(ob->adt && ob->adt->action)
-                               fcu = (FCurve*)ob->adt->action->curves.first;
-                               
-                       if ((ob->type == OB_ARMATURE && ob->data) || fcu) {
-                               return true;
-                       }
-                       base= base->next;
-               }
-               return false;
-       }
-};
 
 void DocumentExporter::exportCurrentScene(Scene *sce, const char* filename)
 {
index f755df799867fc30b1ea37303c72f33dd4111fb8..438c6e7e95ecffa7205825ca7f34dca99bcf9597 100644 (file)
@@ -38,7 +38,7 @@
 
 #include "BLI_blenlib.h"
 #include "BLI_utildefines.h"
-
+#include "BKE_library.h"
 
 #include "DNA_anim_types.h"
 #include "DNA_object_types.h"
@@ -515,12 +515,34 @@ void ANIM_fcurve_delete_from_animdata (bAnimContext *ac, AnimData *adt, FCurve *
         *      - Drivers
         *      - TODO... some others?
         */
-       if (fcu->grp)
-               action_groups_remove_channel(adt->action, fcu);
-       else if ((ac) && (ac->datatype == ANIMCONT_DRIVERS))
+       if ((ac) && (ac->datatype == ANIMCONT_DRIVERS)) {
+               /* driver F-Curve */
                BLI_remlink(&adt->drivers, fcu);
-       else if (adt->action)
-               BLI_remlink(&adt->action->curves, fcu);
+       }
+       else if (adt->action) {
+               /* remove from group or action, whichever one "owns" the F-Curve */
+               if (fcu->grp)
+                       action_groups_remove_channel(adt->action, fcu);
+               else
+                       BLI_remlink(&adt->action->curves, fcu);
+                       
+               /* if action has no more F-Curves as a result of this, unlink it from
+                * AnimData if it did not come from a NLA Strip being tweaked.
+                *
+                * This is done so that we don't have dangling Object+Action entries in
+                * channel list that are empty, and linger around long after the data they
+                * are for has disappeared (and probably won't come back).
+                */
+                       // XXX: does everybody always want this?
+                       /* XXX: there's a problem where many actions could build up in the file if multiple
+                        * full add/delete cycles are performed on the same objects, but assume that this is rare
+                        */
+               if ((adt->action->curves.first == NULL) && (adt->flag & ADT_NLA_EDIT_ON)==0)
+               {
+                       id_us_min(&adt->action->id);
+                       adt->action = NULL;
+               }
+       }
                
        /* free the F-Curve itself */
        free_fcurve(fcu);
index c802ba621f1a8e1888db5a9059cc6b0a55f8af02..f61c1ff796208e727ce752cbc06be93ff3e175a7 100644 (file)
@@ -1495,3 +1495,14 @@ void ED_marker_keymap(wmKeyConfig *keyconf)
        WM_keymap_add_item(keymap, "MARKER_OT_camera_bind", BKEY, KM_PRESS, KM_CTRL, 0);
 #endif
 }
+
+/* to be called from animation editor keymaps, see note below */
+void ED_marker_keymap_animedit_conflictfree(wmKeyMap *keymap)
+{
+       /* duplicate of some marker-hotkeys but without the bounds checking
+        * since these are handy to be able to do unrestricted and won't conflict
+        * with primary function hotkeys (Usability tweak [#27469])
+        */
+       WM_keymap_add_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "MARKER_OT_rename", MKEY, KM_PRESS, KM_CTRL, 0);
+}
index 954928fc48609b4c327427ab482125ee7d9b0282..3018fa697b841769ed9bca89a7bc9f8363b9fc9c 100644 (file)
@@ -694,6 +694,24 @@ void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifie
                        default: /* unknown type */
                                break;
                }
+               
+               /* one last panel below this: FModifier range */
+               // TODO: experiment with placement of this
+               {
+                       box = uiLayoutBox(layout);
+                       
+                       /* top row: use restricted range */
+                       row= uiLayoutRow(box, 0);
+                       uiItemR(row, &ptr, "use_restricted_range", 0, NULL, ICON_NONE);
+                       
+                       if (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) {
+                               /* second row: settings */
+                               row = uiLayoutRow(box, 1);
+                               
+                               uiItemR(row, &ptr, "frame_start", 0, "Start", ICON_NONE);
+                               uiItemR(row, &ptr, "frame_end", 0, "End", ICON_NONE);
+                       }
+               }
        }
 }
 
index f111339b96380b5ecfeca63361c7c267e55e6d14..e2afda04d305e1cbcb8991281e569af94e0045c2 100644 (file)
@@ -111,7 +111,7 @@ void delete_fcurve_keys(FCurve *fcu)
 {
        int i;
        
-       if(fcu->bezt==NULL) /* ignore baked curves */
+       if (fcu->bezt==NULL) /* ignore baked curves */
                return;
 
        /* Delete selected BezTriples */
@@ -124,7 +124,7 @@ void delete_fcurve_keys(FCurve *fcu)
        }
        
        /* Free the array of BezTriples if there are not keyframes */
-       if(fcu->totvert == 0)
+       if (fcu->totvert == 0)
                clear_fcurve_keys(fcu);
 }
 
index c525c9af626bfb220178fff1d9acb311f2a44ac4..610022660bd40c0be462b50dfdc6926758612469 100644 (file)
@@ -782,19 +782,19 @@ void ANIM_keying_sets_menu_setup (bContext *C, const char title[], const char op
         *      - these are listed in the order in which they were defined for the active scene
         */
        if (scene->keyingsets.first) {
-               for (ks= scene->keyingsets.first; ks; ks= ks->next) {
+               for (ks= scene->keyingsets.first; ks; ks=ks->next, i++) {
                        if (ANIM_keyingset_context_ok_poll(C, ks))
-                               uiItemIntO(layout, ks->name, ICON_NONE, op_name, "type", i++);
+                               uiItemIntO(layout, ks->name, ICON_NONE, op_name, "type", i);
                }
                uiItemS(layout);
        }
        
        /* builtin Keying Sets */
        i= -1;
-       for (ks= builtin_keyingsets.first; ks; ks= ks->next) {
+       for (ks= builtin_keyingsets.first; ks; ks=ks->next, i--) {
                /* only show KeyingSet if context is suitable */
                if (ANIM_keyingset_context_ok_poll(C, ks))
-                       uiItemEnumO_value(layout, ks->name, ICON_NONE, op_name, "type", i--);
+                       uiItemEnumO_value(layout, ks->name, ICON_NONE, op_name, "type", i);
        }
        
        uiPupMenuEnd(C, pup);
index 8176aa5893b5376d47f2588e36097cf4c3912d4e..fa5fecbd9d0e5032754f292384a956ec6e620e7a 100644 (file)
@@ -1002,6 +1002,14 @@ static int pose_paste_exec (bContext *C, wmOperator *op)
                return OPERATOR_CANCELLED;
        }
        
+       /* if selOnly option is enabled, if user hasn't selected any bones, 
+        * just go back to default behaviour to be more in line with other pose tools
+        */
+       if (selOnly) {
+               if (CTX_DATA_COUNT(C, selected_pose_bones) == 0)
+                       selOnly = 0;
+       }
+       
        /* Safely merge all of the channels in the buffer pose into any existing pose */
        for (chan= g_posebuf->chanbase.first; chan; chan=chan->next) {
                if (chan->flag & POSE_KEY) {
@@ -1169,7 +1177,7 @@ void POSE_OT_paste (wmOperatorType *ot)
        
        /* properties */
        RNA_def_boolean(ot->srna, "flipped", 0, "Flipped on X-Axis", "Paste the stored pose flipped on to current pose");
-       RNA_def_boolean(ot->srna, "selected_mask", 0, "On Selected Only", "Only paste the stored pose on to selected bones in the current pose");
+       RNA_def_boolean(ot->srna, "selected_mask", 1, "On Selected Only", "Only paste the stored pose on to selected bones in the current pose");
 }
 
 /* ********************************************** */
index f804e0523017f4a86ac2b1a6b241c38ef5753916..a8e91add34808098c8a0bee108cb762d44ba12ac 100644 (file)
@@ -34,6 +34,7 @@
 #define ED_MARKERS_H
 
 struct wmKeyConfig;
+struct wmKeyMap;
 struct bContext;
 struct bAnimContext;
 struct Scene;
@@ -72,6 +73,9 @@ void ED_operatortypes_marker(void);
 /* called in screen_ops.c:ED_keymap_screen() */
 void ED_marker_keymap(struct wmKeyConfig *keyconf);
 
+/* called in animation editors - keymap defines */
+void ED_marker_keymap_animedit_conflictfree(struct wmKeyMap *keymap);
+
 /* debugging only */
 void debug_markers_print_list(struct ListBase *markers);
 
index 1a2a2906f1af3a0af44e64f05b4f29cead726ba5..3564dad474a3984c316e7fd242c52dc822ac816c 100644 (file)
@@ -663,7 +663,7 @@ void ui_theme_init_default(void)
 
        SETCOL(btheme->tipo.handle_vertex,              0, 0, 0, 255);
        SETCOL(btheme->tipo.handle_vertex_select, 255, 133, 0, 255);
-       btheme->tipo.handle_vertex_size= 3;
+       btheme->tipo.handle_vertex_size= 4;
        
        SETCOL(btheme->tipo.ds_channel,         82, 96, 110, 255);
        SETCOL(btheme->tipo.ds_subchannel,      124, 137, 150, 255);
index 450bd70a568f18e3644d1ea9c8720e4138421505..a3df25824a443fceab98209cef3ffe02d4a6cafa 100644 (file)
@@ -567,7 +567,8 @@ static bConstraint *edit_constraint_property_get(wmOperator *op, Object *ob, int
        }
        
        con = constraints_findByName(list, constraint_name);
-       printf("constraint found = %p, %s\n", (void *)con, (con)?con->name:"<Not found>");
+       //if (G.f & G_DEBUG)
+       //printf("constraint found = %p, %s\n", (void *)con, (con)?con->name:"<Not found>");
 
        if (con && (type != 0) && (con->type != type))
                con = NULL;
index 6c3f80cda4152cc33c39bc6def810755bfecae15..2ccad308676ded7b74e425fa084f848f6df8e463 100644 (file)
@@ -40,6 +40,7 @@
 #include "BLI_blenlib.h"
 
 #include "ED_anim_api.h"
+#include "ED_markers.h"
 #include "ED_transform.h"
 
 #include "action_intern.h"
@@ -162,7 +163,7 @@ static void action_keymap_keyframes (wmKeyConfig *keyconf, wmKeyMap *keymap)
        
                /* menu + set setting */
        WM_keymap_add_item(keymap, "ACTION_OT_handle_type", VKEY, KM_PRESS, 0, 0);
-       WM_keymap_add_item(keymap, "ACTION_OT_interpolation_type", TKEY, KM_PRESS, KM_SHIFT, 0);
+       WM_keymap_add_item(keymap, "ACTION_OT_interpolation_type", TKEY, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "ACTION_OT_extrapolation_type", EKEY, KM_PRESS, KM_SHIFT, 0); 
        WM_keymap_add_item(keymap, "ACTION_OT_keyframe_type", RKEY, KM_PRESS, 0, 0); 
        
@@ -193,6 +194,9 @@ static void action_keymap_keyframes (wmKeyConfig *keyconf, wmKeyMap *keymap)
        
        /* transform system */
        transform_keymap_for_space(keyconf, keymap, SPACE_ACTION);
+       
+       /* special markers hotkeys for anim editors: see note in definition of this function */
+       ED_marker_keymap_animedit_conflictfree(keymap);
 }
 
 /* --------------- */
index 962cadba1f3e03174f8ed9279b58c3a5c2c8aa67..0da03832d15a6a969e8dd583597dd7ef04bfd949 100644 (file)
@@ -2248,7 +2248,7 @@ void GRAPH_OT_fmodifier_paste (wmOperatorType *ot)
        
        /* api callbacks */
        ot->exec= graph_fmodifier_paste_exec;
-       ot->poll= graphop_editable_keyframes_poll;
+       ot->poll= graphop_active_fcurve_poll;
        
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
index 03cc8bb9e80227d1c661a10861fd2137d81afb1c..0d7cdf94bc7a81ea6543c9c6fb0b02065b9e4c6c 100644 (file)
@@ -46,6 +46,7 @@
 #include "UI_view2d.h"
 
 #include "ED_anim_api.h"
+#include "ED_markers.h"
 #include "ED_screen.h"
 #include "ED_transform.h"
 
@@ -361,7 +362,7 @@ static void graphedit_keymap_keyframes (wmKeyConfig *keyconf, wmKeyMap *keymap)
        
        WM_keymap_add_item(keymap, "GRAPH_OT_handle_type", VKEY, KM_PRESS, 0, 0);
 
-       WM_keymap_add_item(keymap, "GRAPH_OT_interpolation_type", TKEY, KM_PRESS, KM_SHIFT, 0);
+       WM_keymap_add_item(keymap, "GRAPH_OT_interpolation_type", TKEY, KM_PRESS, 0, 0);
        
                /* destructive */
        WM_keymap_add_item(keymap, "GRAPH_OT_clean", OKEY, KM_PRESS, 0, 0);
@@ -399,6 +400,9 @@ static void graphedit_keymap_keyframes (wmKeyConfig *keyconf, wmKeyMap *keymap)
        
        /* transform system */
        transform_keymap_for_space(keyconf, keymap, SPACE_IPO);
+       
+       /* special markers hotkeys for anim editors: see note in definition of this function */
+       ED_marker_keymap_animedit_conflictfree(keymap);
 }
 
 /* --------------- */
index bce492f5a040ae4e1ade57cc7330407599d40960..0a9a91a53afb86448b7d6404b135ec8e960867e8 100644 (file)
@@ -3679,10 +3679,6 @@ static void draw_actuator_action(uiLayout *layout, PointerRNA *ptr)
        PointerRNA settings_ptr;
        uiLayout *row;
 
-       if(ob->type != OB_ARMATURE){
-               uiItemL(layout, "Actuator only available for armatures", ICON_NONE);
-               return;
-       }
        RNA_pointer_create((ID *)ob, &RNA_GameObjectSettings, ob, &settings_ptr);
 
        row= uiLayoutRow(layout, 0);
index 85dcf14adac10e8442e667bf8a865e27e13fb810..ea8e8961f02fb47ac04c512d5eb678d2b8f0663d 100644 (file)
@@ -45,6 +45,7 @@
 #include "BKE_screen.h"
 
 #include "ED_anim_api.h"
+#include "ED_markers.h"
 #include "ED_screen.h"
 #include "ED_transform.h"
 
@@ -262,6 +263,9 @@ static void nla_keymap_main (wmKeyConfig *keyconf, wmKeyMap *keymap)
        
        /* transform system */
        transform_keymap_for_space(keyconf, keymap, SPACE_NLA);
+       
+       /* special markers hotkeys for anim editors: see note in definition of this function */
+       ED_marker_keymap_animedit_conflictfree(keymap);
 }
 
 /* --------------- */
index 7c66cec5730e9e6c4f11ba32b106f9eee948406e..f42fd46151052af30cbff91c5243c27cc5e5d4ee 100644 (file)
@@ -1217,6 +1217,87 @@ static void draw_b_bone(int dt, int armflag, int boneflag, int constflag, unsign
        }
 }
 
+static void draw_wire_bone_segments(bPoseChannel *pchan, Mat4 *bbones, float length, int segments)
+{
+       if ((segments > 1) && (pchan)) {
+               float dlen= length/(float)segments;
+               Mat4 *bbone = bbones;
+               int a;
+               
+               for (a=0; a<segments; a++, bbone++) {
+                       glPushMatrix();
+                       glMultMatrixf(bbone->mat);
+                       
+                       glBegin(GL_LINES);
+                       glVertex3f(0.0f, 0.0f, 0.0f);
+                       glVertex3f(0.0f, dlen, 0.0f);
+                       glEnd(); // GL_LINES
+                       
+                       glPopMatrix();
+               }
+       }
+       else {
+               glPushMatrix();
+               
+               glBegin(GL_LINES);
+               glVertex3f(0.0f, 0.0f, 0.0f);
+               glVertex3f(0.0f, length, 0.0f);
+               glEnd();
+               
+               glPopMatrix();
+       }
+}
+
+static void draw_wire_bone(int dt, int armflag, int boneflag, int constflag, unsigned int id, bPoseChannel *pchan, EditBone *ebone)
+{
+       Mat4 *bbones = NULL;
+       int segments = 0;
+       float length;
+       
+       if (pchan) {
+               segments= pchan->bone->segments;
+               length= pchan->bone->length;
+               
+               if (segments > 1)
+                       bbones = b_bone_spline_setup(pchan, 0);
+       }
+       else 
+               length= ebone->length;
+       
+       /* draw points only if... */
+       if (armflag & ARM_EDITMODE) {
+               /* move to unitspace */
+               glPushMatrix();
+               glScalef(length, length, length);
+               draw_bone_points(dt, armflag, boneflag, id);
+               glPopMatrix();
+               length *= 0.95f;        // make vertices visible
+       }
+       
+       /* this chunk not in object mode */
+       if (armflag & (ARM_EDITMODE|ARM_POSEMODE)) {
+               if (id != -1)
+                       glLoadName((GLuint) id|BONESEL_BONE);
+               
+               draw_wire_bone_segments(pchan, bbones, length, segments);
+               
+               /* further we send no names */
+               if (id != -1)
+                       glLoadName(id & 0xFFFF);        /* object tag, for bordersel optim */
+       }
+       
+       /* colors for modes */
+       if (armflag & ARM_POSEMODE) {
+               set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag);
+       }
+       else if (armflag & ARM_EDITMODE) {
+               set_ebone_glColor(boneflag);
+       }
+       
+       /* draw normal */
+       draw_wire_bone_segments(pchan, bbones, length, segments);
+}
+
 static void draw_bone(int dt, int armflag, int boneflag, int constflag, unsigned int id, float length)
 {
        
@@ -1656,7 +1737,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
                                        int use_custom = (pchan->custom) && !(arm->flag & ARM_NO_CUSTOM);
                                        glPushMatrix();
                                        
-                                       if(use_custom && pchan->custom_tx) {
+                                       if (use_custom && pchan->custom_tx) {
                                                glMultMatrixf(pchan->custom_tx->pose_mat);
                                        } 
                                        else {
@@ -1684,6 +1765,8 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
                                        }
                                        else if (arm->drawtype==ARM_LINE)
                                                ;       /* nothing in solid */
+                                       else if (arm->drawtype==ARM_WIRE)
+                                               ;       /* nothing in solid */
                                        else if (arm->drawtype==ARM_ENVELOPE)
                                                draw_sphere_bone(OB_SOLID, arm->flag, flag, 0, index, pchan, NULL);
                                        else if (arm->drawtype==ARM_B_BONE)
@@ -1702,7 +1785,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
                /* very very confusing... but in object mode, solid draw, we cannot do glLoadName yet,
                 * stick bones and/or wire custom-shapes are drawn in next loop 
                 */
-               if ((arm->drawtype != ARM_LINE) && (draw_wire == 0)) {
+               if (ELEM(arm->drawtype,ARM_LINE,ARM_WIRE)==0 && (draw_wire == 0)) {
                        /* object tag, for bordersel optim */
                        glLoadName(index & 0xFFFF);     
                        index= -1;
@@ -1773,8 +1856,8 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
                        if (index != -1) 
                                index+= 0x10000;        // pose bones count in higher 2 bytes only
                }
-               /* stick bones have not been drawn yet so dont clear object selection in this case */
-               if ((arm->drawtype != ARM_LINE) && draw_wire) {
+               /* stick or wire bones have not been drawn yet so dont clear object selection in this case */
+               if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)==0 && draw_wire) {
                        /* object tag, for bordersel optim */
                        glLoadName(index & 0xFFFF);     
                        index= -1;
@@ -1784,7 +1867,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
        /* wire draw over solid only in posemode */
        if ((dt <= OB_WIRE) || (arm->flag & ARM_POSEMODE) || (arm->drawtype==ARM_LINE)) {
                /* draw line check first. we do selection indices */
-               if (arm->drawtype==ARM_LINE) {
+               if ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) {
                        if (arm->flag & ARM_POSEMODE) 
                                index= base->selcol;
                }
@@ -1879,6 +1962,8 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
                                        }
                                        else if (arm->drawtype==ARM_LINE)
                                                draw_line_bone(arm->flag, flag, constflag, index, pchan, NULL);
+                                       else if (arm->drawtype==ARM_WIRE)
+                                               draw_wire_bone(dt, arm->flag, flag, constflag, index, pchan, NULL);
                                        else if (arm->drawtype==ARM_B_BONE)
                                                draw_b_bone(OB_WIRE, arm->flag, flag, constflag, index, pchan, NULL);
                                        else
@@ -2013,7 +2098,7 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, int dt)
        }
        
        /* if solid we draw it first */
-       if ((dt > OB_WIRE) && (arm->drawtype!=ARM_LINE)) {
+       if ((dt > OB_WIRE) && (arm->drawtype != ARM_LINE)) {
                for (eBone=arm->edbo->first, index=0; eBone; eBone=eBone->next, index++) {
                        if (eBone->layer & arm->layer) {
                                if ((eBone->flag & BONE_HIDDEN_A)==0) {
@@ -2034,6 +2119,8 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, int dt)
                                                draw_sphere_bone(OB_SOLID, arm->flag, flag, 0, index, NULL, eBone);
                                        else if(arm->drawtype==ARM_B_BONE)
                                                draw_b_bone(OB_SOLID, arm->flag, flag, 0, index, NULL, eBone);
+                                       else if (arm->drawtype==ARM_WIRE)
+                                               draw_wire_bone(OB_SOLID, arm->flag, flag, 0, index, NULL, eBone);
                                        else {
                                                draw_bone(OB_SOLID, arm->flag, flag, 0, index, eBone->length);
                                        }
@@ -2047,7 +2134,7 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, int dt)
        /* if wire over solid, set offset */
        index= -1;
        glLoadName(-1);
-       if (arm->drawtype==ARM_LINE) {
+       if ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) {
                if(G.f & G_PICKSEL)
                        index= 0;
        }
@@ -2081,6 +2168,8 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, int dt)
                                        
                                        if (arm->drawtype == ARM_LINE) 
                                                draw_line_bone(arm->flag, flag, 0, index, NULL, eBone);
+                                       else if (arm->drawtype==ARM_WIRE)
+                                               draw_wire_bone(OB_WIRE, arm->flag, flag, 0, index, NULL, eBone);
                                        else if (arm->drawtype == ARM_B_BONE)
                                                draw_b_bone(OB_WIRE, arm->flag, flag, 0, index, NULL, eBone);
                                        else
@@ -2109,7 +2198,7 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, int dt)
        
        /* restore */
        if(index!=-1) glLoadName(-1);
-       if (arm->drawtype==ARM_LINE);
+       if ELEM(arm->drawtype,ARM_LINE,ARM_WIRE);
        else if (dt>OB_WIRE) bglPolygonOffset(rv3d->dist, 0.0f);
        
        /* finally names and axes */
index 27ca345e132b1aa9efdc894d671519aab174ab47..0ce21c2efee9a6dcff88dd6b547ebdb808f4a3cb 100644 (file)
@@ -1982,12 +1982,15 @@ static void protectedQuaternionBits(short protectflag, float *quat, float *oldqu
 
 /* ******************* TRANSFORM LIMITS ********************** */
 
-static void constraintTransLim(TransInfo *UNUSED(t), TransData *td)
+static void constraintTransLim(TransInfo *t, TransData *td)
 {
        if (td->con) {
-               bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT);
+               bConstraintTypeInfo *ctiLoc= get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT);
+               bConstraintTypeInfo *ctiDist= get_constraint_typeinfo(CONSTRAINT_TYPE_DISTLIMIT);
+               
                bConstraintOb cob= {NULL};
                bConstraint *con;
+               float ctime = (float)(t->scene->r.cfra);
                
                /* Make a temporary bConstraintOb for using these limit constraints
                 *      - they only care that cob->matrix is correctly set ;-)
@@ -1998,6 +2001,8 @@ static void constraintTransLim(TransInfo *UNUSED(t), TransData *td)
                
                /* Evaluate valid constraints */
                for (con= td->con; con; con= con->next) {
+                       bConstraintTypeInfo *cti = NULL;
+                       ListBase targets = {NULL, NULL};
                        float tmat[4][4];
                        
                        /* only consider constraint if enabled */
@@ -2010,7 +2015,17 @@ static void constraintTransLim(TransInfo *UNUSED(t), TransData *td)
                                
                                if ((data->flag2 & LIMIT_TRANSFORM)==0)
                                        continue;
+                               cti = ctiLoc;
+                       }
+                       else if (con->type == CONSTRAINT_TYPE_DISTLIMIT) {
+                               bDistLimitConstraint *data= con->data;
                                
+                               if ((data->flag & LIMITDIST_TRANSFORM)==0)
+                                       continue;
+                               cti = ctiDist;
+                       }
+                       
+                       if (cti) {
                                /* do space conversions */
                                if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
                                        /* just multiply by td->mtx (this should be ok) */
@@ -2022,8 +2037,11 @@ static void constraintTransLim(TransInfo *UNUSED(t), TransData *td)
                                        continue;
                                }
                                
+                               /* get constraint targets if needed */
+                               get_constraint_targets_for_solving(con, &cob, &targets, ctime);
+                               
                                /* do constraint */
-                               cti->evaluate_constraint(con, &cob, NULL);
+                               cti->evaluate_constraint(con, &cob, &targets);
                                
                                /* convert spaces again */
                                if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
@@ -2031,6 +2049,9 @@ static void constraintTransLim(TransInfo *UNUSED(t), TransData *td)
                                        copy_m4_m4(tmat, cob.matrix);
                                        mul_m4_m3m4(cob.matrix, td->smtx, tmat);
                                }
+                               
+                               /* free targets list */
+                               BLI_freelistN(&targets);
                        }
                }
                
@@ -5780,8 +5801,8 @@ int TimeSlide(TransInfo *t, const int mval[2])
        char str[200];
 
        /* calculate mouse co-ordinates */
-       UI_view2d_region_to_view(v2d, mval[0], mval[0], &cval[0], &cval[1]);
-       UI_view2d_region_to_view(v2d, t->imval[0], t->imval[0], &sval[0], &sval[1]);
+       UI_view2d_region_to_view(v2d, mval[0], mval[1], &cval[0], &cval[1]);
+       UI_view2d_region_to_view(v2d, t->imval[0], t->imval[1], &sval[0], &sval[1]);
 
        /* t->values[0] stores cval[0], which is the current mouse-pointer location (in frames) */
        // XXX Need to be able to repeat this
index c7699f7249cf287803d51948e040b0d1fce31874..29fc514f01fde8b53e0394c0b8340e07a121228a 100644 (file)
@@ -3131,12 +3131,18 @@ static void createTransActionData(bContext *C, TransInfo *t)
                float min=999999999.0f, max=-999999999.0f;
                int i;
                
-               td= (t->data + 1);
-               for (i=1; i < count; i+=3, td+=3) {
+               td= t->data;
+               for (i=0; i < count; i++, td++) {
                        if (min > *(td->val)) min= *(td->val);
                        if (max < *(td->val)) max= *(td->val);
                }
                
+               if (min == max) {
+                       /* just use the current frame ranges */
+                       min = (float)PSFRA;
+                       max = (float)PEFRA;
+               }
+               
                /* minx/maxx values used by TimeSlide are stored as a
                 * calloced 2-float array in t->customData. This gets freed
                 * in postTrans (T_FREE_CUSTOMDATA).
index 7bdf6c909d9775f5e281d25cd11d8e0b520199f3..4b0a734a98e05ab6eabd373ac9f7741cb826d10f 100644 (file)
@@ -897,7 +897,7 @@ void transform_keymap_for_space(wmKeyConfig *keyconf, wmKeyMap *keymap, int spac
                        km= WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", SKEY, KM_PRESS, 0, 0);
                        RNA_enum_set(km->ptr, "mode", TFM_TIME_SCALE);
                        
-                       km= WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", TKEY, KM_PRESS, 0, 0);
+                       km= WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", TKEY, KM_PRESS, KM_SHIFT, 0);
                        RNA_enum_set(km->ptr, "mode", TFM_TIME_SLIDE);
                        break;
                case SPACE_IPO:
index 4b649031f97eea39471ed69bc6b8b71801c4f80d..88a3fe81825fb7baa94fc26aa1279e97d002474c 100644 (file)
@@ -62,6 +62,9 @@ typedef struct FModifier {
        short flag;                     /* settings for the modifier */
        
        float influence;        /* the amount that the modifier should influence the value */
+       
+       float sfra;                     /* start frame of restricted frame-range */
+       float efra;                     /* end frame of restricted frame-range */
 } FModifier;
 
 /* Types of F-Curve modifier 
@@ -86,13 +89,15 @@ typedef enum eFModifier_Types {
 /* F-Curve Modifier Settings */
 typedef enum eFModifier_Flags {
                /* modifier is not able to be evaluated for some reason, and should be skipped (internal) */
-       FMODIFIER_FLAG_DISABLED         = (1<<0),
+       FMODIFIER_FLAG_DISABLED          = (1<<0),
                /* modifier's data is expanded (in UI) */
-       FMODIFIER_FLAG_EXPANDED         = (1<<1),
+       FMODIFIER_FLAG_EXPANDED          = (1<<1),
                /* modifier is active one (in UI) for editing purposes */
-       FMODIFIER_FLAG_ACTIVE           = (1<<2),
+       FMODIFIER_FLAG_ACTIVE            = (1<<2),
                /* user wants modifier to be skipped */
-       FMODIFIER_FLAG_MUTED            = (1<<3)
+       FMODIFIER_FLAG_MUTED             = (1<<3),
+               /* restrict range that F-Modifier can be considered over */
+       FMODIFIER_FLAG_RANGERESTRICT = (1<<4)
 } eFModifier_Flags; 
 
 /* --- */
index 3547101612fa0d4fd2a94c36bc24906e9aa27cbc..808db1f4843161c3e2ccc6d2f3edb262bd6d53c4 100644 (file)
@@ -136,7 +136,8 @@ typedef enum eArmature_Drawtype {
        ARM_OCTA = 0,
        ARM_LINE,
        ARM_B_BONE,
-       ARM_ENVELOPE
+       ARM_ENVELOPE,
+       ARM_WIRE
 } eArmature_Drawtype;
 
 /* armature->deformflag */
index 1d752fce4ef66aa4f7c2d2eab5723ffe5e504a6a..c2c0c6f1611e276dd451645da9f4bf0722954339 100644 (file)
@@ -677,7 +677,10 @@ typedef enum eRotLimit_Flags {
 /* distance limit constraint */
        /* bDistLimitConstraint->flag */
 typedef enum eDistLimit_Flag {
-       LIMITDIST_USESOFT       = (1<<0)
+       /* "soft" cushion effect when reaching the limit sphere */ // NOT IMPLEMENTED!
+       LIMITDIST_USESOFT       = (1<<0),
+       /* as for all Limit constraints - allow to be used during transform? */
+       LIMITDIST_TRANSFORM = (1<<1)
 } eDistLimit_Flag;
 
        /* bDistLimitConstraint->mode */
index c7cf511d5c7991f21c2f2c15e05485d5ccd72dac..e16d13fafaa57632453be25d4422e8c602102098 100644 (file)
@@ -426,11 +426,11 @@ EnumPropertyItem *rna_Actuator_type_itemf(bContext *C, PointerRNA *ptr, Property
        
        if (ob != NULL) {
                if (ob->type==OB_ARMATURE) {
-                       RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_ACTION);
                        RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_ARMATURE);
                }
        }
-
+       
+       RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_ACTION);
        RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_CAMERA);
        RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_CONSTRAINT);
        RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_EDIT_OBJECT);
index 2060f75f9deb2e757ffae4c7b1227f4a851c7987..41d169a887075cc19adb1c8d5f53324f6bb13d56 100644 (file)
@@ -814,6 +814,7 @@ static void rna_def_armature(BlenderRNA *brna)
                {ARM_LINE, "STICK", 0, "Stick", "Display bones as simple 2D lines with dots"},
                {ARM_B_BONE, "BBONE", 0, "B-Bone", "Display bones as boxes, showing subdivision and B-Splines"},
                {ARM_ENVELOPE, "ENVELOPE", 0, "Envelope", "Display bones as extruded spheres, showing deformation influence volume"},
+               {ARM_WIRE, "WIRE", 0, "Wire", "Display bones as thin wires, showing subdivision and B-Splines"},
                {0, NULL, 0, NULL, NULL}};
        static EnumPropertyItem prop_ghost_type_items[] = {
                {ARM_GHOST_CUR, "CURRENT_FRAME", 0, "Around Frame", "Display Ghosts of poses within a fixed number of frames around the current frame"},
index a75ff601d0859a24f126e7a30c238726d7e7c2d9..4e178e77fd92aa6c7ef474606f71d5ec10f715aa 100644 (file)
@@ -85,7 +85,7 @@ static EnumPropertyItem target_space_pchan_items[] = {
 static EnumPropertyItem owner_space_pchan_items[] = {
        {0, "WORLD", 0, "World Space", "The constraint is applied relative to the world coordinate system"},
        {2, "POSE", 0, "Pose Space", "The constraint is applied in Pose Space, the object transformation is ignored"},
-       {3, "LOCAL_WITH_PARENT", 0, "The constraint is applied relative to the local coordinate system of the object, with the parent transformation added"},
+       {3, "LOCAL_WITH_PARENT", 0, "Local With Parent", "The constraint is applied relative to the local coordinate system of the object, with the parent transformation added"},
        {1, "LOCAL", 0, "Local Space", "The constraint is applied relative to the local coordinate sytem of the object"},
        {0, NULL, 0, NULL, NULL}};
 
@@ -1787,6 +1787,11 @@ static void rna_def_constraint_distance_limit(BlenderRNA *brna)
        RNA_def_property_enum_items(prop, constraint_distance_items);
        RNA_def_property_ui_text(prop, "Limit Mode", "Distances in relation to sphere of influence to allow");
        RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update");
+       
+       prop= RNA_def_property(srna, "use_transform_limit", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", LIMITDIST_TRANSFORM);
+       RNA_def_property_ui_text(prop, "For Transform", "Transforms are affected by this constraint as well");
+       RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update");
 }
 
 static void rna_def_constraint_shrinkwrap(BlenderRNA *brna)
index a46f84a22d243dd383f8b5206c3a172499d27331..ba0563f554abcc6fe852542efb43acbe58db1d6b 100644 (file)
@@ -454,6 +454,22 @@ static void rna_FModifier_active_set(PointerRNA *ptr, int UNUSED(value))
        fm->flag |= FMODIFIER_FLAG_ACTIVE;
 }
 
+static void rna_FModifier_start_frame_range(PointerRNA *ptr, float *min, float *max)
+{
+       FModifier *fcm= (FModifier*)ptr->data;
+       
+       *min= MINAFRAMEF;
+       *max= (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT)? fcm->efra : MAXFRAMEF;
+}
+
+static void rna_FModifier_end_frame_range(PointerRNA *ptr, float *min, float *max)
+{
+       FModifier *fcm= (FModifier*)ptr->data;
+
+       *min= (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT)? fcm->sfra : MINAFRAMEF;
+       *max= MAXFRAMEF;
+}
+
 static void rna_FModifier_active_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
 {
        FModifier *fm, *fmo= (FModifier*)ptr->data;
@@ -1015,6 +1031,25 @@ static void rna_def_fmodifier(BlenderRNA *brna)
        RNA_def_property_boolean_funcs(prop, NULL, "rna_FModifier_active_set");
        RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_PROP, "rna_FModifier_active_update");
        RNA_def_property_ui_icon(prop, ICON_RADIOBUT_OFF, 1);
+       
+       /* restricted range */
+       prop= RNA_def_property(srna, "use_restricted_range", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", FMODIFIER_FLAG_RANGERESTRICT);
+       RNA_def_property_ui_text(prop, "Restrict Frame Range", "F-Curve Modifier is only applied for the specified frame range to help mask off effects in order to chain them");
+       RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
+       RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1); // XXX: depends on UI implementation
+       
+       prop= RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_float_sdna(prop, NULL, "sfra");
+       RNA_def_property_float_funcs(prop, NULL, NULL, "rna_FModifier_start_frame_range");
+       RNA_def_property_ui_text(prop, "Start Frame", "Frame that modifier's influence starts (if Restrict Frame Range is in use)");
+       RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
+       
+       prop= RNA_def_property(srna, "frame_end", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_float_sdna(prop, NULL, "efra");
+       RNA_def_property_float_funcs(prop, NULL, NULL, "rna_FModifier_end_frame_range");
+       RNA_def_property_ui_text(prop, "End Frame", "Frame that modifier's influence ends (if Restrict Frame Range is in use)");
+       RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
 }      
 
 /* *********************** */
index c00e7ec7e2916d6977ac74ff9945f8ca90ebff00..7e5e4e1d1d92628a25ec4201151bfd358490b08b 100644 (file)
@@ -36,6 +36,7 @@
 #include "BL_ActionActuator.h"
 #include "BL_ArmatureObject.h"
 #include "BL_SkinDeformer.h"
+#include "BL_Action.h"
 #include "KX_GameObject.h"
 #include "STR_HashedString.h"
 #include "MEM_guardedalloc.h"
@@ -143,7 +144,62 @@ void BL_ActionActuator::SetLocalTime(float curtime)
                m_localtime = m_endframe - delta_time;
 }
 
+bool BL_ActionActuator::Update(double curtime, bool frame)
+{
+       bool bNegativeEvent = false;
+       bool bPositiveEvent = false;
+       KX_GameObject *obj = (KX_GameObject*)GetParent();
+       short play_mode = BL_Action::ACT_MODE_PLAY;
+
+       // Don't do anything if we're not "active"
+       if (!frame)
+               return true;
+       
+       // Convert playmode
+       if (m_playtype == ACT_ACTION_LOOP_END)
+               play_mode = BL_Action::ACT_MODE_LOOP;
+       else if (m_playtype == ACT_ACTION_LOOP_STOP)
+               play_mode = BL_Action::ACT_MODE_LOOP;
+       else if (m_playtype == ACT_ACTION_PINGPONG)
+               play_mode = BL_Action::ACT_MODE_PING_PONG;
+
+
+       // Handle events
+       bNegativeEvent = m_negevent;
+       bPositiveEvent = m_posevent;
+       RemoveAllEvents();
+
+       if (!m_is_going && bPositiveEvent)
+       {               
+               m_is_going = true;
+               obj->PlayAction(m_action->id.name+2, m_startframe, m_endframe, 0, m_blendin, play_mode);
+               if (m_end_reset)
+                       obj->SetActionFrame(0, m_localtime);
+       }
+       else if (m_is_going && bNegativeEvent)
+       {
+               m_is_going = false;
+               
+               if (!m_end_reset)
+               {
+                       obj->StopAction(0);
+                       return false;
+               }
 
+               m_localtime = obj->GetActionFrame(0);
+               obj->StopAction(0); // Stop the action after getting the frame
+       }
+
+       // Handle a finished animation
+       if (m_is_going && obj->IsActionDone(0))
+       {
+               return false;
+       }
+
+       return true;
+}
+
+#if 0 // Kept around as reference for now
 bool BL_ActionActuator::Update(double curtime, bool frame)
 {
        bool bNegativeEvent = false;
@@ -449,6 +505,7 @@ bool BL_ActionActuator::Update(double curtime, bool frame)
        }
        return keepgoing;
 };
+#endif
 
 #ifdef WITH_PYTHON
 
index ff4ca785a96143bc3f73938fcfb00fecb8f4deaf..1530ccda00b45e59be43c96b7df06c9f6f90e0ab 100644 (file)
@@ -70,6 +70,7 @@ public:
                m_playtype(playtype),
                m_priority(priority),
                m_end_reset(end_reset),
+               m_is_going(false),
                m_pose(NULL),
                m_blendpose(NULL),
                m_userpose(NULL),
@@ -163,6 +164,7 @@ protected:
        short   m_playtype;
        short   m_priority;
        bool    m_end_reset;
+       bool    m_is_going;
        struct bPose* m_pose;
        struct bPose* m_blendpose;
        struct bPose* m_userpose;
index a9a3e66f99673e548cf581f044cb8207b6ec9258..75c0e012226b2da765df059a91a1de257aa4e493 100644 (file)
@@ -47,11 +47,11 @@ float BL_ScalarInterpolator::GetValue(float currentTime) const {
        return evaluate_fcurve(m_fcu, currentTime);
 }
 
-BL_InterpolatorList::BL_InterpolatorList(struct AnimData *adt) {
-       if(adt->action==NULL)
+BL_InterpolatorList::BL_InterpolatorList(bAction *action) {
+       if(action==NULL)
                return;
        
-       for(FCurve *fcu= (FCurve *)adt->action->curves.first; fcu; fcu= (FCurve *)fcu->next) {
+       for(FCurve *fcu= (FCurve *)action->curves.first; fcu; fcu= (FCurve *)fcu->next) {
                if(fcu->rna_path) {
                        BL_ScalarInterpolator *new_ipo = new BL_ScalarInterpolator(fcu); 
                        //assert(new_ipo);
index bd786bae969080b7dd5616a792b9cf78077a9834..cca66b3771c4ed9d88308938c306bfcc3ad64df6 100644 (file)
@@ -66,7 +66,7 @@ public:
 
 class BL_InterpolatorList : public std::vector<KX_IScalarInterpolator *> {
 public:
-       BL_InterpolatorList(struct AnimData *adt);
+       BL_InterpolatorList(struct bAction *action);
        ~BL_InterpolatorList();
 
        KX_IScalarInterpolator *GetScalarInterpolator(const char *rna_path, int array_index);   
index 01516a24182003570860d8c16777c4068c4666cc..b8e19c9187adfb64d7a14c46249d249a74761aa6 100644 (file)
@@ -191,30 +191,26 @@ void BL_ConvertActuators(char* maggiename,
                        }
                case ACT_ACTION:
                        {
-                               if (blenderobject->type==OB_ARMATURE){
-                                       bActionActuator* actact = (bActionActuator*) bact->data;
-                                       STR_String propname = (actact->name ? actact->name : "");
-                                       STR_String propframe = (actact->frameProp ? actact->frameProp : "");
+                               bActionActuator* actact = (bActionActuator*) bact->data;
+                               STR_String propname = (actact->name ? actact->name : "");
+                               STR_String propframe = (actact->frameProp ? actact->frameProp : "");
                                        
-                                       BL_ActionActuator* tmpbaseact = new BL_ActionActuator(
-                                               gameobj,
-                                               propname,
-                                               propframe,
-                                               actact->sta,
-                                               actact->end,
-                                               actact->act,
-                                               actact->type, // + 1, because Blender starts to count at zero,
-                                               actact->blendin,
-                                               actact->priority,
-                                               actact->end_reset,
-                                               actact->stridelength
-                                               // Ketsji at 1, because zero is reserved for "NoDef"
-                                               );
-                                       baseact= tmpbaseact;
-                                       break;
-                               }
-                               else
-                                       printf ("Discarded action actuator from non-armature object [%s]\n", blenderobject->id.name+2);
+                               BL_ActionActuator* tmpbaseact = new BL_ActionActuator(
+                                       gameobj,
+                                       propname,
+                                       propframe,
+                                       actact->sta,
+                                       actact->end,
+                                       actact->act,
+                                       actact->type, // + 1, because Blender starts to count at zero,
+                                       actact->blendin,
+                                       actact->priority,
+                                       actact->end_reset,
+                                       actact->stridelength
+                                       // Ketsji at 1, because zero is reserved for "NoDef"
+                                       );
+                               baseact= tmpbaseact;
+                               break;
                        }
                case ACT_SHAPEACTION:
                        {
index 2ad56717e26805cf7dd5f7f36f517809ed97fd3a..27ae857f45cecf599a50cf4a8e44212c0e63dffd 100644 (file)
@@ -54,6 +54,7 @@
 
 #include "DNA_object_types.h"
 #include "DNA_action_types.h"
+#include "DNA_anim_types.h"
 #include "DNA_ipo_types.h"
 #include "DNA_lamp_types.h"
 #include "DNA_world_types.h"
@@ -76,133 +77,134 @@ static BL_InterpolatorList *GetAdtList(struct AnimData *for_adt, KX_BlenderScene
        BL_InterpolatorList *adtList= converter->FindInterpolatorList(for_adt);
 
        if (!adtList) {         
-               adtList = new BL_InterpolatorList(for_adt);
+               adtList = new BL_InterpolatorList(for_adt->action);
                converter->RegisterInterpolatorList(adtList, for_adt);
        }
                        
        return adtList; 
 }
 
-void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_BlenderSceneConverter *converter)
+SG_Controller *BL_CreateIPO(struct bAction *action, KX_GameObject* gameobj, KX_BlenderSceneConverter *converter)
 {
-       if (blenderobject->adt) {
-
-               KX_IpoSGController* ipocontr = new KX_IpoSGController();
-               gameobj->GetSGNode()->AddSGController(ipocontr);
-               ipocontr->SetObject(gameobj->GetSGNode());
-               
-               // For ipo_as_force, we need to know which SM object and Scene the
-               // object associated with this ipo is in. Is this already known here?
-               // I think not.... then it must be done later :(
-//             ipocontr->SetSumoReference(gameobj->GetSumoScene(), 
-//                                                                gameobj->GetSumoObject());
-
-               ipocontr->SetGameObject(gameobj);
-
-               ipocontr->GetIPOTransform().SetPosition(
-                       MT_Point3(
-                       blenderobject->loc[0]/*+blenderobject->dloc[0]*/,
-                       blenderobject->loc[1]/*+blenderobject->dloc[1]*/,
-                       blenderobject->loc[2]/*+blenderobject->dloc[2]*/
-                       )
-               );
-               ipocontr->GetIPOTransform().SetEulerAngles(
-                       MT_Vector3(
-                       blenderobject->rot[0],
-                       blenderobject->rot[1],
-                       blenderobject->rot[2]
-                       )
-               );
-               ipocontr->GetIPOTransform().SetScaling(
-                       MT_Vector3(
-                       blenderobject->size[0],
-                       blenderobject->size[1],
-                       blenderobject->size[2]
-                       )
-               );
-
-               const char *rotmode, *drotmode;
-
-               switch(blenderobject->rotmode)
-               {
-               case ROT_MODE_AXISANGLE:
-                       rotmode = "rotation_axis_angle";
-                       drotmode = "delta_rotation_axis_angle";
-               case ROT_MODE_QUAT:
-                       rotmode = "rotation_quaternion";
-                       drotmode = "delta_rotation_quaternion";
-               default:
-                       rotmode = "rotation_euler";
-                       drotmode = "delta_rotation_euler";
-               }
+       KX_IpoSGController* ipocontr = new KX_IpoSGController();
+       ipocontr->SetGameObject(gameobj);
+
+       Object* blenderobject = gameobj->GetBlenderObject();
+
+       ipocontr->GetIPOTransform().SetPosition(
+               MT_Point3(
+               blenderobject->loc[0]/*+blenderobject->dloc[0]*/,
+               blenderobject->loc[1]/*+blenderobject->dloc[1]*/,
+               blenderobject->loc[2]/*+blenderobject->dloc[2]*/
+               )
+       );
+       ipocontr->GetIPOTransform().SetEulerAngles(
+               MT_Vector3(
+               blenderobject->rot[0],
+               blenderobject->rot[1],
+               blenderobject->rot[2]
+               )
+       );
+       ipocontr->GetIPOTransform().SetScaling(
+               MT_Vector3(
+               blenderobject->size[0],
+               blenderobject->size[1],
+               blenderobject->size[2]
+               )
+       );
+
+       const char *rotmode, *drotmode;
+
+       switch(blenderobject->rotmode)
+       {
+       case ROT_MODE_AXISANGLE:
+               rotmode = "rotation_axis_angle";
+               drotmode = "delta_rotation_axis_angle";
+       case ROT_MODE_QUAT:
+               rotmode = "rotation_quaternion";
+               drotmode = "delta_rotation_quaternion";
+       default:
+               rotmode = "rotation_euler";
+               drotmode = "delta_rotation_euler";
+       }
 
-               BL_InterpolatorList *adtList= GetAdtList(blenderobject->adt, converter);
+       BL_InterpolatorList *adtList= GetAdtList(blenderobject->adt, converter);
                
-               // For each active channel in the adtList add an
-               // interpolator to the game object.
+       // For each active channel in the adtList add an
+       // interpolator to the game object.
                
-               KX_IInterpolator *interpolator;
-               KX_IScalarInterpolator *interp;
+       KX_IInterpolator *interpolator;
+       KX_IScalarInterpolator *interp;
                
-               for(int i=0; i<3; i++) {
-                       if ((interp = adtList->GetScalarInterpolator("location", i))) {
-                               interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetPosition()[i]), interp);
-                               ipocontr->AddInterpolator(interpolator);
-                               ipocontr->SetIPOChannelActive(OB_LOC_X+i, true);
-                       }
+       for(int i=0; i<3; i++) {
+               if ((interp = adtList->GetScalarInterpolator("location", i))) {
+                       interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetPosition()[i]), interp);
+                       ipocontr->AddInterpolator(interpolator);
+                       ipocontr->SetIPOChannelActive(OB_LOC_X+i, true);
                }
-               for(int i=0; i<3; i++) {
-                       if ((interp = adtList->GetScalarInterpolator("delta_location", i))) {
-                               interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetDeltaPosition()[i]), interp);
-                               ipocontr->AddInterpolator(interpolator);
-                               ipocontr->SetIPOChannelActive(OB_DLOC_X+i, true);
-                       }
+       }
+       for(int i=0; i<3; i++) {
+               if ((interp = adtList->GetScalarInterpolator("delta_location", i))) {
+                       interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetDeltaPosition()[i]), interp);
+                       ipocontr->AddInterpolator(interpolator);
+                       ipocontr->SetIPOChannelActive(OB_DLOC_X+i, true);
                }
-               for(int i=0; i<3; i++) {
-                       if ((interp = adtList->GetScalarInterpolator(rotmode, i))) {
-                               interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetEulerAngles()[i]), interp);
-                               ipocontr->AddInterpolator(interpolator);
-                               ipocontr->SetIPOChannelActive(OB_ROT_X+i, true);
-                       }
+       }
+       for(int i=0; i<3; i++) {
+               if ((interp = adtList->GetScalarInterpolator(rotmode, i))) {
+                       interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetEulerAngles()[i]), interp);
+                       ipocontr->AddInterpolator(interpolator);
+                       ipocontr->SetIPOChannelActive(OB_ROT_X+i, true);
                }
-               for(int i=0; i<3; i++) {
-                       if ((interp = adtList->GetScalarInterpolator(drotmode, i))) {
-                               interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetDeltaEulerAngles()[i]), interp);
-                               ipocontr->AddInterpolator(interpolator);
-                               ipocontr->SetIPOChannelActive(OB_DROT_X+i, true);
-                       }
+       }
+       for(int i=0; i<3; i++) {
+               if ((interp = adtList->GetScalarInterpolator(drotmode, i))) {
+                       interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetDeltaEulerAngles()[i]), interp);
+                       ipocontr->AddInterpolator(interpolator);
+                       ipocontr->SetIPOChannelActive(OB_DROT_X+i, true);
                }
-               for(int i=0; i<3; i++) {
-                       if ((interp = adtList->GetScalarInterpolator("scale", i))) {
-                               interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetScaling()[i]), interp);
-                               ipocontr->AddInterpolator(interpolator);
-                               ipocontr->SetIPOChannelActive(OB_SIZE_X+i, true);
-                       }
+       }
+       for(int i=0; i<3; i++) {
+               if ((interp = adtList->GetScalarInterpolator("scale", i))) {
+                       interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetScaling()[i]), interp);
+                       ipocontr->AddInterpolator(interpolator);
+                       ipocontr->SetIPOChannelActive(OB_SIZE_X+i, true);
                }
-               for(int i=0; i<3; i++) {
-                       if ((interp = adtList->GetScalarInterpolator("delta_scale", i))) {
-                               interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetDeltaScaling()[i]), interp);
-                               ipocontr->AddInterpolator(interpolator);
-                               ipocontr->SetIPOChannelActive(OB_DSIZE_X+i, true);
-                       }
+       }
+       for(int i=0; i<3; i++) {
+               if ((interp = adtList->GetScalarInterpolator("delta_scale", i))) {
+                       interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetDeltaScaling()[i]), interp);
+                       ipocontr->AddInterpolator(interpolator);
+                       ipocontr->SetIPOChannelActive(OB_DSIZE_X+i, true);
                }
+       }
                
-               {
-                       KX_ObColorIpoSGController* ipocontr_obcol=NULL;
+       {
+               KX_ObColorIpoSGController* ipocontr_obcol=NULL;
                        
-                       for(int i=0; i<4; i++) {
-                               if ((interp = adtList->GetScalarInterpolator("color", i))) {
-                                       if (!ipocontr_obcol) {
-                                               ipocontr_obcol = new KX_ObColorIpoSGController();
-                                               gameobj->GetSGNode()->AddSGController(ipocontr_obcol);
-                                               ipocontr_obcol->SetObject(gameobj->GetSGNode());
-                                       }
-                                       interpolator= new KX_ScalarInterpolator(&ipocontr_obcol->m_rgba[i], interp);
-                                       ipocontr_obcol->AddInterpolator(interpolator);
+               for(int i=0; i<4; i++) {
+                       if ((interp = adtList->GetScalarInterpolator("color", i))) {
+                               if (!ipocontr_obcol) {
+                                       ipocontr_obcol = new KX_ObColorIpoSGController();
+                                       gameobj->GetSGNode()->AddSGController(ipocontr_obcol);
+                                       ipocontr_obcol->SetObject(gameobj->GetSGNode());
                                }
+                               interpolator= new KX_ScalarInterpolator(&ipocontr_obcol->m_rgba[i], interp);
+                               ipocontr_obcol->AddInterpolator(interpolator);
                        }
                }
        }
+
+       return ipocontr;
+}
+
+void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_BlenderSceneConverter *converter)
+{
+       if (blenderobject->adt) {
+               SG_Controller *ipocontr = BL_CreateIPO(blenderobject->adt->action, gameobj, converter);
+               gameobj->GetSGNode()->AddSGController(ipocontr);
+               ipocontr->SetObject(gameobj->GetSGNode());
+       }
 }
 
 void BL_ConvertLampIpos(struct Lamp* blenderlamp, KX_GameObject *lightobj,KX_BlenderSceneConverter *converter)
index d77a72a82e28703b8b32f26371b942cc695e1666..914422ba83fbf16bb4bc07cbcdc36855ab1a40df 100644 (file)
 
 struct Object;
 
+class SG_Controller *BL_CreateIPO(struct bAction *action,
+       class KX_GameObject* gameobj,
+       class KX_BlenderSceneConverter *converter);
+
 void BL_ConvertIpos(struct Object* blenderobject,
        class KX_GameObject* gameobj, 
        class KX_BlenderSceneConverter *converter);
index 157124ebc810692fa80a9bfab2fcfb2e5072b865..88a9f3afd7d8fff500a9edb37524ecd3934aa28c 100644 (file)
@@ -254,12 +254,15 @@ typedef struct PyObjectPlus_Proxy {
 #define KX_PYMETHODTABLE_NOARGS(class_name, method_name) \
        {#method_name , (PyCFunction) class_name::sPy##method_name, METH_NOARGS, (const char *)class_name::method_name##_doc}
 
+#define KX_PYMETHODTABLE_KEYWORDS(class_name, method_name) \
+       {#method_name , (PyCFunction) class_name::sPy##method_name, METH_VARARGS|METH_KEYWORDS, (const char *)class_name::method_name##_doc}
+
 /**
  * Function implementation macro
  */
 #define KX_PYMETHODDEF_DOC(class_name, method_name, doc_string) \
 const char class_name::method_name##_doc[] = doc_string; \
-PyObject* class_name::Py##method_name(PyObject* args, PyObject*)
+PyObject* class_name::Py##method_name(PyObject* args, PyObject* kwds)
 
 #define KX_PYMETHODDEF_DOC_VARARGS(class_name, method_name, doc_string) \
 const char class_name::method_name##_doc[] = doc_string; \
diff --git a/source/gameengine/Ketsji/BL_Action.cpp b/source/gameengine/Ketsji/BL_Action.cpp
new file mode 100644 (file)
index 0000000..77cb5de
--- /dev/null
@@ -0,0 +1,265 @@
+/**
+ * $Id$
+ *
+ * ***** 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): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <cstdlib>
+
+#include "BL_Action.h"
+#include "BL_ArmatureObject.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,
+                                       const char* name,
+                                       float start,
+                                       float end,
+                                       float blendin,
+                                       short play_mode,
+                                       short blend_mode,
+                                       float playback_speed)
+:
+       m_obj(gameobj),
+       m_startframe(start),
+       m_endframe(end),
+       m_blendin(blendin),
+       m_playmode(play_mode),
+       m_endtime(0.f),
+       m_localtime(start),
+       m_blendframe(0.f),
+       m_blendstart(0.f),
+       m_speed(playback_speed),
+       m_pose(NULL),
+       m_blendpose(NULL),
+       m_sg_contr(NULL),
+       m_done(false)
+{
+       m_starttime = KX_GetActiveEngine()->GetFrameTime();
+       m_action = (bAction*)KX_GetActiveScene()->GetLogicManager()->GetActionByName(name);
+
+       if (!m_action) printf("Failed to load action: %s\n", name);
+
+       if (m_obj->GetGameObjectType() != SCA_IObject::OBJ_ARMATURE)
+       {
+               // Create an SG_Controller
+               m_sg_contr = BL_CreateIPO(m_action, m_obj, KX_GetActiveScene()->GetSceneConverter());
+               m_obj->GetSGNode()->AddSGController(m_sg_contr);
+               m_sg_contr->SetObject(m_obj->GetSGNode());
+               InitIPO();
+       }
+
+}
+
+BL_Action::~BL_Action()
+{
+       if (m_pose)
+               game_free_pose(m_pose);
+       if (m_blendpose)
+               game_free_pose(m_blendpose);
+       if (m_sg_contr)
+       {
+               m_obj->GetSGNode()->RemoveSGController(m_sg_contr);
+               delete m_sg_contr;
+       }
+}
+
+void BL_Action::InitIPO()
+{
+               // Initialize the IPO
+               m_sg_contr->SetOption(SG_Controller::SG_CONTR_IPO_RESET, true);
+               m_sg_contr->SetOption(SG_Controller::SG_CONTR_IPO_IPO_AS_FORCE, false);
+               m_sg_contr->SetOption(SG_Controller::SG_CONTR_IPO_IPO_ADD, false);
+               m_sg_contr->SetOption(SG_Controller::SG_CONTR_IPO_LOCAL, false);
+}
+
+float BL_Action::GetFrame()
+{
+       return m_localtime;
+}
+
+void BL_Action::SetFrame(float frame)
+{
+       float dt;
+
+       // 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);
+
+       // We don't set m_localtime directly since it's recalculated
+       // in the next update. So, we modify the value (m_starttime) 
+       // used to calculate m_localtime the next time SetLocalTime() is called.
+
+       dt = frame-m_startframe;
+
+       if (m_endframe < m_startframe)
+               dt = -dt;
+
+       m_starttime -= dt / (KX_KetsjiEngine::GetAnimFrameRate()*m_speed);
+}
+
+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::Update(float curtime)
+{
+       // Don't bother if we're done with the animation
+       if (m_done)
+               return;
+
+       curtime -= KX_KetsjiEngine::GetSuspendedDelta();
+
+       SetLocalTime(curtime);
+
+       // 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 && m_sg_contr)
+                       InitIPO();
+       }
+
+       if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
+       {
+               bPose* prev_pose = NULL;
+               BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj;
+               obj->GetPose(&m_pose);
+
+               // Save the old pose if we need to do some layer blending
+               if (m_blendmode != ACT_BLEND_NONE)
+                       obj->GetMRDPose(&prev_pose);
+
+               // Extract the pose from the action
+               {
+                       struct PointerRNA id_ptr;
+                       Object *arm = obj->GetArmatureObject();
+                       bPose *temp = arm->pose;
+
+                       arm->pose = m_pose;
+                       RNA_id_pointer_create((ID*)arm, &id_ptr);
+                       animsys_evaluate_action(&id_ptr, m_action, NULL, m_localtime);
+
+                       arm->pose = temp;
+               }
+
+               // Handle blending between layers
+               switch(m_blendmode)
+               {
+               case ACT_BLEND_MIX:
+                       game_blend_poses(m_pose, prev_pose, 0.5f);
+                       break;
+               case ACT_BLEND_NONE:
+               default:
+                       break;
+               }
+
+               // Handle blending between actions
+               if (m_blendin && m_blendframe<m_blendin)
+               {
+                       if (!m_blendpose)
+                       {
+                               obj->GetMRDPose(&m_blendpose);
+                               m_blendstart = curtime;
+                       }
+
+                       // Calculate weight
+                       float weight = 1.f - (m_blendframe/m_blendin);
+                       game_blend_poses(m_pose, m_blendpose, weight);
+
+                       // Bump the blend frame
+                       m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate();
+
+                       // Clamp
+                       if (m_blendframe>m_blendin)
+                               m_blendframe = m_blendin;
+               }
+               else
+               {
+                       if (m_blendpose)
+                       {
+                               game_free_pose(m_blendpose);
+                               m_blendpose = NULL;
+                       }
+               }
+
+               obj->SetPose(m_pose);
+
+               obj->SetActiveAction(NULL, 0, curtime);
+
+               if (prev_pose)
+                       game_free_pose(prev_pose);
+       }
+       else
+       {
+               InitIPO();
+               m_sg_contr->SetSimulatedTime(m_localtime);
+               m_obj->GetSGNode()->UpdateWorldData(m_localtime);
+               m_obj->UpdateTransform();
+       }
+}
diff --git a/source/gameengine/Ketsji/BL_Action.h b/source/gameengine/Ketsji/BL_Action.h
new file mode 100644 (file)
index 0000000..f7d0feb
--- /dev/null
@@ -0,0 +1,109 @@
+/**
+ * $Id$
+ *
+ * ***** 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): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BL_ACTION
+#define __BL_ACTION
+
+#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 PointerRNA *m_ptrrna;
+       class SG_Controller *m_sg_contr;
+       class KX_GameObject* m_obj;
+
+       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_speed;
+
+       short m_playmode;
+       short m_blendmode;
+
+       bool m_done;
+
+       void InitIPO();
+       void SetLocalTime(float curtime);
+public:
+       BL_Action(class KX_GameObject* gameobj,
+                       const char* name,
+                       float start,
+                       float end,
+                       float blendin,
+                       short play_mode,
+                       short blend_mode,
+                       float playback_speed);
+       ~BL_Action();
+
+       bool IsDone() {return m_done;}
+       void Update(float curtime);
+
+       // Accessors
+       float GetFrame();
+
+       // Mutators
+       void SetFrame(float frame);
+
+       enum 
+       {
+               ACT_MODE_PLAY = 0,
+               ACT_MODE_LOOP,
+               ACT_MODE_PING_PONG,
+               ACT_MODE_MAX,
+       };
+
+       enum
+       {
+               ACT_BLEND_NONE = 0,
+               ACT_BLEND_MIX,
+               ACT_BLEND_MAX,
+       };
+
+#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
+
diff --git a/source/gameengine/Ketsji/BL_ActionManager.cpp b/source/gameengine/Ketsji/BL_ActionManager.cpp
new file mode 100644 (file)
index 0000000..2570cc1
--- /dev/null
@@ -0,0 +1,103 @@
+/**
+ * $Id$
+ *
+ * ***** 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): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "BL_ActionManager.h"
+
+BL_ActionManager::BL_ActionManager()
+{
+       for (int i=0; i<MAX_ACTION_LAYERS; ++i)
+               m_layers[i] = 0;
+}
+
+BL_ActionManager::~BL_ActionManager()
+{
+       for (int i=0; i<MAX_ACTION_LAYERS; ++i)
+               if (m_layers[i])
+                       StopAction(i);
+}
+
+float BL_ActionManager::GetActionFrame(short layer)
+{
+       if (m_layers[layer])
+               return m_layers[layer]->GetFrame();
+
+       return 0.f;
+}
+
+void BL_ActionManager::SetActionFrame(short layer, float frame)
+{
+       if (m_layers[layer])
+               m_layers[layer]->SetFrame(frame);
+}
+
+void BL_ActionManager::PlayAction(class KX_GameObject* gameobj,
+                                                               const char* name,
+                                                               float start,
+                                                               float end,
+                                                               short layer,
+                                                               float blendin,
+                                                               short play_mode,
+                                                               short blend_mode,
+                                                               float playback_speed)
+{
+       // Remove a currently running action on this layer if there is one
+       if (m_layers[layer])
+               StopAction(layer);
+
+       // Create a new action
+       m_layers[layer] = new BL_Action(gameobj, name, start, end, blendin, play_mode, blend_mode, playback_speed);
+}
+
+void BL_ActionManager::StopAction(short layer)
+{
+       delete m_layers[layer];
+       m_layers[layer] = 0;
+}
+
+bool BL_ActionManager::IsActionDone(short layer)
+{
+       if (m_layers[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])
+               {
+                       if (m_layers[i]->IsDone())
+                               StopAction(i);
+                       else
+                               m_layers[i]->Update(curtime);
+               }
+       }
+}
diff --git a/source/gameengine/Ketsji/BL_ActionManager.h b/source/gameengine/Ketsji/BL_ActionManager.h
new file mode 100644 (file)
index 0000000..32e6ce8
--- /dev/null
@@ -0,0 +1,70 @@
+/**
+ * $Id$
+ *
+ * ***** 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): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BL_ACTIONMANAGER
+#define __BL_ACTIONMANAGER
+
+#include "BL_Action.h"
+
+#define MAX_ACTION_LAYERS 4
+
+class BL_ActionManager
+{
+private:
+       BL_Action* m_layers[MAX_ACTION_LAYERS];
+
+public:
+       BL_ActionManager();
+       ~BL_ActionManager();
+
+       void PlayAction(class KX_GameObject* gameobj,
+                                       const char* name,
+                                       float start,
+                                       float end,
+                                       short layer=0,
+                                       float blendin=0.f,
+                                       short play_mode=0,
+                                       short blend_mode=0,
+                                       float playback_speed=1.f);
+       
+       float GetActionFrame(short layer);
+       void SetActionFrame(short layer, float frame);
+
+       void StopAction(short layer);
+       bool IsActionDone(short layer);
+       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
+
index a6339439beaf3297dcea44c02b7e274f314b98a2..6fe793bd4753c6124a7fbe99ffb32635e31d1344 100644 (file)
@@ -29,25 +29,26 @@ set(INC
        ../../../intern/string
        ../../../intern/guardedalloc
        ../../../intern/container
-       ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer 
+       ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer
        ../../../source/gameengine/Converter
        ../../../source/gameengine/BlenderRoutines
        ../../../source/blender/imbuf
        ../../../intern/moto/include
-       ../../../source/gameengine/Ketsji 
+       ../../../source/gameengine/Ketsji
        ../../../source/blender/blenlib
        ../../../source/blender/blenfont
        ../../../source/blender/blenkernel
        ../../../source/blender/python
        ../../../source/blender/python/generic
-       ../../../source/blender 
-       ../../../source/blender/makesdna 
-       ../../../source/gameengine/Rasterizer 
+       ../../../source/blender
+       ../../../source/blender/makesdna
+       ../../../source/blender/makesrna
+       ../../../source/gameengine/Rasterizer
        ../../../source/gameengine/GameLogic
-       ../../../source/gameengine/Expressions 
+       ../../../source/gameengine/Expressions
        ../../../source/gameengine/Ketsji/KXNetwork
        ../../../source/gameengine/Network
-       ../../../source/gameengine/SceneGraph 
+       ../../../source/gameengine/SceneGraph
        ../../../source/gameengine/Physics/common
        ../../../source/gameengine/Network/LoopBackNetwork
        ../../../intern/audaspace/intern
@@ -60,6 +61,8 @@ set(INC_SYS
 )
 
 set(SRC
+       BL_Action.cpp
+       BL_ActionManager.cpp
        BL_BlenderShader.cpp
        BL_Material.cpp
        BL_Shader.cpp
@@ -129,6 +132,8 @@ set(SRC
        KX_WorldInfo.cpp
        KX_WorldIpoController.cpp
 
+       BL_Action.h
+       BL_ActionManager.h
        KX_ArmatureSensor.h
        KX_BlenderMaterial.h
        KX_BulletPhysicsController.h
index 47d83c16659b255bf291c9f116366b201ddff83b..0ea775e3fbc8135dddf35227795ccf2aea369294 100644 (file)
@@ -74,6 +74,8 @@ typedef unsigned long uint_ptr;
 #include "SCA_IController.h"
 #include "NG_NetworkScene.h" //Needed for sendMessage()
 
+#include "BL_ActionManager.h"
+
 #include "PyObjectPlus.h" /* python stuff */
 
 // This file defines relationships between parents and children
@@ -121,6 +123,8 @@ KX_GameObject::KX_GameObject(
        KX_NormalParentRelation * parent_relation = 
                KX_NormalParentRelation::New();
        m_pSGNode->SetParentRelation(parent_relation);
+
+       m_actionManager = new BL_ActionManager();
 };
 
 
@@ -154,6 +158,10 @@ KX_GameObject::~KX_GameObject()
        {
                delete m_pGraphicController;
        }
+       if (m_actionManager)
+       {
+               delete m_actionManager;
+       }
 #ifdef WITH_PYTHON
        if (m_attr_dict) {
                PyDict_Clear(m_attr_dict); /* incase of circular refs or other weird cases */
@@ -344,6 +352,43 @@ void KX_GameObject::RemoveParent(KX_Scene *scene)
        }
 }
 
+void KX_GameObject::PlayAction(const char* name,
+                                                               float start,
+                                                               float end,
+                                                               short layer,
+                                                               float blendin,
+                                                               short play_mode,
+                                                               short blend_mode,
+                                                               float playback_speed)
+{
+       m_actionManager->PlayAction(this, name, start, end, layer, blendin, play_mode, blend_mode, playback_speed);
+}
+
+void KX_GameObject::StopAction(short layer)
+{
+       m_actionManager->StopAction(layer);
+}
+
+bool KX_GameObject::IsActionDone(short layer)
+{
+       return m_actionManager->IsActionDone(layer);
+}
+
+void KX_GameObject::UpdateActionManager(float curtime)
+{
+       m_actionManager->Update(curtime);
+}
+
+float KX_GameObject::GetActionFrame(short layer)
+{
+       return m_actionManager->GetActionFrame(layer);
+}
+
+void KX_GameObject::SetActionFrame(short layer, float frame)
+{
+       m_actionManager->SetActionFrame(layer, frame);
+}
+
 void KX_GameObject::ProcessReplica()
 {
        SCA_IObject::ProcessReplica();
@@ -353,6 +398,7 @@ void KX_GameObject::ProcessReplica()
        m_pSGNode = NULL;
        m_pClient_info = new KX_ClientObjectInfo(*m_pClient_info);
        m_pClient_info->m_gameobject = this;
+       m_actionManager = new BL_ActionManager();
        m_state = 0;
 
 #ifdef WITH_PYTHON
@@ -1497,6 +1543,8 @@ PyMethodDef KX_GameObject::Methods[] = {
        KX_PYMETHODTABLE_O(KX_GameObject, getDistanceTo),
        KX_PYMETHODTABLE_O(KX_GameObject, getVectTo),
        KX_PYMETHODTABLE(KX_GameObject, sendMessage),
+
+       KX_PYMETHODTABLE_KEYWORDS(KX_GameObject, playAction),
        
        // dict style access for props
        {"get",(PyCFunction) KX_GameObject::sPyget, METH_VARARGS},
@@ -2975,6 +3023,43 @@ KX_PYMETHODDEF_DOC_VARARGS(KX_GameObject, sendMessage,
        Py_RETURN_NONE;
 }
 
+KX_PYMETHODDEF_DOC(KX_GameObject, playAction,
+       "playAction(name, start_frame, end_frame, layer=0, blendin=0, play_mode=ACT_MODE_PLAY, blend_mode=ACT_BLEND_NONE, speed=1.0)\n"
+       "plays an action\n")
+{
+       const char* name;
+       float start, end, blendin=0.f, speed=1.f;
+       short layer=0;
+       short play_mode=0, blend_mode=0;
+
+       static const char *kwlist[] = {"name", "start_frame", "end_frame", "layer", "blendin", "play_mode", "blend_mode", "speed", NULL};
+
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "sff|hfhhf", const_cast<char**>(kwlist),
+                                                                       &name, &start, &end, &layer, &blendin, &play_mode, &blend_mode, &speed))
+               return NULL;
+
+       if (layer < 0 || layer > MAX_ACTION_LAYERS)
+       {
+               printf("KX_GameObject.playAction(): given layer (%d) is out of range (0 - %d), setting to 0", layer, MAX_ACTION_LAYERS-1);
+               layer = 0;
+       }
+
+       if (play_mode < 0 || play_mode > BL_Action::ACT_MODE_MAX)
+       {
+               printf("KX_GameObject.playAction(): given play_mode (%d) is out of range (0 - %d), setting to ACT_MODE_PLAY", play_mode, BL_Action::ACT_MODE_MAX-1);
+               play_mode = BL_Action::ACT_MODE_MAX;
+       }
+
+       if (blend_mode < 0 || blend_mode > BL_Action::ACT_BLEND_MAX)
+       {
+               printf("KX_GameObject.playAction(): given blend_mode (%d) is out of range (0 - %d), setting to ACT_BLEND_NONE", blend_mode, BL_Action::ACT_BLEND_MAX-1);
+               blend_mode = BL_Action::ACT_BLEND_NONE;
+       }
+
+       PlayAction(name, start, end, layer, blendin, play_mode, blend_mode, speed);
+
+       Py_RETURN_NONE;
+}
 /* dict style access */
 
 
index 50fbebe1341d86b66d215ae330bbebe98b0b9c5b..48d290d289a988756173880cc5b29df1638b428a 100644 (file)
@@ -63,6 +63,7 @@ class RAS_MeshObject;
 class KX_IPhysicsController;
 class PHY_IGraphicController;
 class PHY_IPhysicsEnvironment;
+class BL_ActionManager;
 struct Object;
 
 #ifdef WITH_PYTHON
@@ -112,6 +113,9 @@ protected:
        SG_Node*                                                        m_pSGNode;
 
        MT_CmMatrix4x4                                          m_OpenGL_4x4Matrix;
+
+       // The action manager is used to play/stop/update actions
+       BL_ActionManager*                               m_actionManager;
        
 public:
        bool                                                            m_isDeformable;
@@ -198,6 +202,51 @@ public:
         */                     
        void RemoveParent(KX_Scene *scene);
 
+       /*********************************
+        * Animation API
+        *********************************/
+
+       /**
+        * Adds an action to the object's action manager
+        */
+       void PlayAction(const char* name,
+                                       float start,
+                                       float end,
+                                       short layer=0,
+                                       float blendin=0.f,
+                                       short play_mode=0,
+                                       short blend_mode=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);
+
+       /**
+        * Remove an action from the object's action manager
+        */
+       void StopAction(short layer);
+
+       /**
+        * Check if an action has finished playing
+        */
+       bool IsActionDone(short layer);
+
+       /**
+        * Kick the object's action manager
+        */
+       void UpdateActionManager(float curtime);
+
+       /*********************************
+        * End Animation API
+        *********************************/
+
        /**
         * Construct a game object. This class also inherits the 
         * default constructors - use those with care!
@@ -853,6 +902,8 @@ public:
        KX_PYMETHOD_DOC_O(KX_GameObject,getVectTo);
        KX_PYMETHOD_DOC_VARARGS(KX_GameObject, sendMessage);
        KX_PYMETHOD_VARARGS(KX_GameObject, ReinstancePhysicsMesh);
+
+       KX_PYMETHOD_DOC(KX_GameObject, playAction);
        
        /* Dict access */
        KX_PYMETHOD_VARARGS(KX_GameObject,get);
index 28dc660037c5046cc04ba5a5399d18d56393035f..27bf5d19b14b66700e6818aacf898448281cdfac 100644 (file)
@@ -1506,6 +1506,9 @@ void KX_Scene::LogicBeginFrame(double curtime)
 
 void KX_Scene::LogicUpdateFrame(double curtime, bool frame)
 {
+       // Update any animations
+       for (int i=0; i<GetObjectList()->GetCount(); ++i)
+               ((KX_GameObject*)GetObjectList()->GetValue(i))->UpdateActionManager(curtime);
        m_logicmgr->UpdateFrame(curtime, frame);
 }
 
index 086422627247e1c6735bf20aeea98339f8810169..da6361952e03a74edeb328e8d774f9a4f2042a91 100644 (file)
@@ -14,7 +14,7 @@ incs += ' #intern/audaspace/intern #source/gameengine/Converter'
 incs += ' #source/gameengine/BlenderRoutines #source/blender/imbuf #intern/moto/include'
 incs += ' #source/gameengine/Ketsji #source/gameengine/Ketsji/KXNetwork #source/blender/blenlib #source/blender/blenfont'
 incs += ' #source/blender/blenkernel #source/blender #source/blender/editors/include'
-incs += ' #source/blender/makesdna #source/blender/python #source/gameengine/Rasterizer'
+incs += ' #source/blender/makesdna #source/blender/makesrna #source/blender/python #source/gameengine/Rasterizer'
 incs += ' #source/gameengine/GameLogic #source/gameengine/Expressions #source/gameengine/Network'
 incs += ' #source/gameengine/SceneGraph #source/gameengine/Physics/common'
 incs += ' #source/gameengine/Physics/Dummy'
@@ -34,7 +34,7 @@ if env['WITH_BF_PYTHON']:
 
 if env['WITH_BF_FFMPEG']:
     defs.append('WITH_FFMPEG')
-    
+
 if env['OURPLATFORM'] in ('win32-vc', 'win64-vc', 'win32-mingw'):
     if env['BF_DEBUG']:
         defs.append('_DEBUG') # for Python
index 3064e6662b9d29d1146a31c24063963f527f6a8d..b22d210984d627c52f8093eaf1137da153338836 100644 (file)
@@ -34,6 +34,8 @@
 #include "SG_IObject.h"
 #include "SG_Controller.h"
 
+#include <algorithm>
+
 SG_Stage gSG_Stage = SG_STAGE_UNKNOWN;
 
 SG_IObject::
@@ -71,6 +73,16 @@ AddSGController(
 
        void                            
 SG_IObject::
+RemoveSGController(
+       SG_Controller* cont
+) {
+       SGControllerList::iterator contit;
+
+       m_SGcontrollers.erase(std::remove(m_SGcontrollers.begin(), m_SGcontrollers.end(), cont));
+}
+
+       void
+SG_IObject::
 RemoveAllControllers(
 ) { 
        m_SGcontrollers.clear(); 
index 26e317bdcd98417cef7649eb564d8f6df83e8652..e709699c08abc437713f133a0f2963cf58f967d2 100644 (file)
@@ -180,6 +180,16 @@ public:
                SG_Controller* cont
        );
 
+       /**
+        * Remove a pointer to a controller from this node.
+        * This does not delete the controller itself! Be careful to
+        * avoid memory leaks.
+        */
+               void
+       RemoveSGController(
+               SG_Controller* cont
+       );
+
        /** 
         * Clear the array of pointers to controllers associated with 
         * this node. This does not delete the controllers themselves!