/* ----------------------------------------------------------------------------- This source file is part of OpenSpace3D For the latest info, see http://www.openspace3d.com Copyright (c) 2012 I-maginer This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA, or go to http://www.gnu.org/copyleft/lesser.txt ----------------------------------------------------------------------------- */ struct PlugPosBlend = [ PPOSEBLEND_inst : PInstance, PPOSEBLEND_animList : [[I V3Danim] r1], PPOSEBLEND_heaviestAnimList : [[V3Danim F] r1], PPOSEBLEND_lighterAnimList : [V3Danim r1], PPOSEBLEND_fSpeed : F, PPOSEBLEND_iNumAnim : I, PPOSEBLEND_iNumAnimblended : I, PPOSEBLEND_iTick : I ]mkPlugPosBlend;; fun loadAnimations(inst)= let nil -> ndata in let 0 -> i in ( let getPluginInstanceParam inst (strcat "animation_" (itoa i)) -> elem in while (elem != nil) do ( let V3DgetAnimationByName c3dXsession elem -> anim in ( V3DsetAnimationWeight anim 0.0; set ndata = [i anim]::ndata; ); set i = i + 1; set elem = getPluginInstanceParam inst (strcat "animation_" (itoa i)); ); revertlist ndata; );; fun deleteOb(inst, panimstr)= setPluginInstanceCbPreRender inst nil; let sizelist panimstr.PPOSEBLEND_animList -> numanimations in let 0 -> i in while (i < numanimations) do ( let switch panimstr.PPOSEBLEND_animList i -> animation in ( V3DstopAnimation animation; V3DenableAnimation animation 0; ); set i = i + 1; ); 0;; fun sortWeights(elt1, elt2)= let elt1 -> [pos1 val1] in let elt2 -> [pos2 val2] in val1 >. val2;; fun cbBlendAnim(inst, view3d, panimstr)= let 1 -> heavierFinished in let 1 -> lighterFinished in let (itof (_tickcount - panimstr.PPOSEBLEND_iTick)) -> deltatime in ( //fade in or out heavier animations let 0 -> i in let panimstr.PPOSEBLEND_iNumAnimblended -> size in while (i < size) do ( let nth_list panimstr.PPOSEBLEND_heaviestAnimList i -> [animation animationweight] in let V3DgetAnimationWeight animation -> animationcurrentweight in if (animationcurrentweight >=. animationweight) then ( let animationcurrentweight -. (deltatime /. panimstr.PPOSEBLEND_fSpeed) -> nweight in ( V3DsetAnimationWeight animation (SO3MathsClampValue nweight 0.0 1.0); if (V3DgetAnimationState animation) then nil else V3DplayAnimation animation; if (nweight <=. animationweight) || (!V3DgetAnimationState animation) then ( if (V3DgetAnimationLoop animation) then nil else V3DpauseAnimation animation; ) else ( set heavierFinished = 0; ); ) ) else ( let animationcurrentweight +. (deltatime /. panimstr.PPOSEBLEND_fSpeed) -> nweight in ( V3DsetAnimationWeight animation (SO3MathsClampValue nweight 0.0 1.0); if (V3DgetAnimationState animation) then nil else V3DplayAnimation animation; if (nweight >=. animationweight) || (!V3DgetAnimationState animation) then ( if (V3DgetAnimationLoop animation) then nil else V3DpauseAnimation animation; ) else ( set heavierFinished = 0; ); ); ); set i = i + 1; ); //fade out lighter animations at speed * 2 let 0 -> i in let panimstr.PPOSEBLEND_iNumAnim - panimstr.PPOSEBLEND_iNumAnimblended -> size in while (i < size) do ( let nth_list panimstr.PPOSEBLEND_lighterAnimList i -> animation in let V3DgetAnimationWeight animation -> animationcurrentweight in if (animationcurrentweight <=. 0.0) then nil else ( let animationcurrentweight -. (deltatime /. (panimstr.PPOSEBLEND_fSpeed)) -> nweight in ( V3DsetAnimationWeight animation (SO3MathsClampValue nweight 0.0 1.0); if (V3DgetAnimationState animation) then nil else V3DplayAnimation animation; if (nweight <=. 0.0) || (!V3DgetAnimationState animation) then ( if (V3DgetAnimationLoop animation) then nil else V3DpauseAnimation animation; ) else ( set lighterFinished = 0; ); ); ); set i = i + 1; ); set panimstr.PPOSEBLEND_iTick = _tickcount; if !(heavierFinished && lighterFinished) then nil else ( setPluginInstanceCbPreRender inst nil; ); ); 0;; fun cbInjectWeight(inst, from, action, param, rep, panimstr) = let hd (strextr param) -> lweight in let sizelist lweight -> numparams in if numparams != panimstr.PPOSEBLEND_iNumAnim then nil else let nil -> nlist in ( // The input vector contain weight data for each animation, so we can go further // First, add an index indicating the target animation for each weight. let 0 -> i in while (i < numparams) do ( let nth_list lweight i -> animationweight in set nlist = [i (atof animationweight)]::nlist; set i = i + 1; ); // Next, sort the list by weight values. set nlist = sortlist nlist @sortWeights; let splitList nlist panimstr.PPOSEBLEND_iNumAnimblended -> [nl1 nl2] in ( // Finally, take the n heaviest anim that will fadein. set panimstr.PPOSEBLEND_heaviestAnimList = nil; let 0 -> i in let panimstr.PPOSEBLEND_iNumAnimblended -> size in while (i < size) do ( let nth_list nl1 i -> [index animationweight] in let switch panimstr.PPOSEBLEND_animList index -> animation in set panimstr.PPOSEBLEND_heaviestAnimList = [animation animationweight]::panimstr.PPOSEBLEND_heaviestAnimList; set i = i + 1; ); // Put the other anims in the lighter anim list, they will be fade out at speed*2 set panimstr.PPOSEBLEND_lighterAnimList = nil; let 0 -> i in let panimstr.PPOSEBLEND_iNumAnim - panimstr.PPOSEBLEND_iNumAnimblended -> size in while (i < size) do ( let nth_list nl2 i -> [index animationweight] in let switch panimstr.PPOSEBLEND_animList index -> animation in set panimstr.PPOSEBLEND_lighterAnimList = animation::panimstr.PPOSEBLEND_lighterAnimList; set i = i + 1; ); // Reset counter set panimstr.PPOSEBLEND_iTick = _tickcount; // Set pre-render callback setPluginInstanceCbPreRender inst mkfun3 @cbBlendAnim panimstr; ); ); 0;; fun newOb(inst)= let atof (getPluginInstanceParam inst "transitionSpeed") -> transitionspeed in let if transitionspeed == nil then 200.0 else transitionspeed -> transitionspeed in let atoi (getPluginInstanceParam inst "numAnimBlended") -> numanimblended in let if numanimblended == nil then 2 else numanimblended -> numanimblended in let loadAnimations inst -> animations in let (sizelist animations) -> numanimations in ( let mkPlugPosBlend [inst nil nil nil nil nil nil nil] -> plipsyncstr in ( set plipsyncstr.PPOSEBLEND_animList = animations; set plipsyncstr.PPOSEBLEND_fSpeed = transitionspeed; set plipsyncstr.PPOSEBLEND_iNumAnim = numanimations; set plipsyncstr.PPOSEBLEND_iNumAnimblended = numanimblended; set plipsyncstr.PPOSEBLEND_iTick = 0; PluginRegisterAction inst "Inject weight" mkfun6 @cbInjectWeight plipsyncstr; setPluginInstanceCbDel inst mkfun2 @deleteOb plipsyncstr; ); ); 0;; fun IniPlug(file)= PlugRegister @newOb nil; setPluginEditor @dynamicedit; 0;;