Trying to Make Work 'BlendActions()' Function, with any Luck

Moho allows users to write new tools and plugins. Discuss scripting ideas and problems here.

Moderators: Víctor Paredes, Belgarath, slowtiger

User avatar
Rai López
Posts: 2292
Joined: Sun Aug 08, 2004 1:41 pm
Location: Spain
Contact:

Trying to Make Work 'BlendActions()' Function, with any Luck

Post by Rai López »

Hi, just in case someone knows, or have a better understanding of this kind of raw type of documentation... I'm in troubles trying to take advantage of this "promising" function, documented in the last ASP scripting interface as follows:

Code: Select all

void BlendPoses @ BlendActions(int32 frame, int32 numToBlend, LM_String names[numToBlend], real percentages[numToBlend]);
Which seems clearly intended to morph between several actions in an "straightforward" way (?), and that is exactly what I'd need to do right now... but I'm trying to feed it in all the ways I can imagine in basis of the sparse documentation "clues", and all I'm getting until now are all kind of Lua Console errors and AS crashes...

This (and all the variants that have passed through my mind), applied to a vector layer with two actions named "A" and "E", is what I have been basically trying all the afternoon:

Code: Select all

function LayerScript(moho)
	local actionNames = {["A"] = 0.5, ["E"] = 0.25}
	local percentages = {0.5, 0.25}
	--local nActions = layer:CountActions()

	if (moho.frame == 1) then
		moho.layer:BlendActions(1, 2, actionNames, percentages)
	end
end
As you see, I'm basically trying to feed the function (in the mos T&E way) with the values I think it could need according to the above Scripting Interface info and the Lua Console errors/clues that I've been getting on the way... as I said, with no results. This are my guesses in detail:

BlendActions(the frame where blending will take place (1 in this case), the number of morphs involved? (2 in this case), a string key based table with the names of the actions involved (A, E), a table with the weights to be applied for each of the previous values (0.5, 0.25))

Hmmm, maybe only Mike could say, but I lose nothing for ask here before... Of course, all is temporally and too much simplified, in order to try to make it works first in it's most simple way, but apart of that... do someone see any logical (or illogical) on this? Or... do you think this function is intended to be used in other way, like inside a "for" loop (what I've tried too with no results either) or something? I suspect that the problem well could be in the way I'm providing tables to the function, but the truth is that I don't know what more I could try and I'm totally lost with all this in general... so well, thank you very much in advance for any help.


PS: BTW, I have been testing it in the "Layer Script" fashion/way to avoid as much as possible the "Alt+F5" (of the dead), but I've been testing it lately as a part of a tool, just in case it could have something to do with crashes, and nothing seems to change.
...
Rudiger
Posts: 786
Joined: Sun Dec 18, 2005 2:25 am

Post by Rudiger »

Wow, you are braver than I am. Just the mere sight of LM_String had me running for the hills :)!

If it could possibly work, I would imagine it just wants straight indexed tables for both names and percentages, so I would try:
name = {'A', 'E'} and percentages = {0.5, 0.25}.

Like I said, I can't see it working on account of there being no way to convert a lua string to the LM_String type and I've also never seen a function that can take a Lua table as a parameter before, but please let me know if you have any luck :).
User avatar
Rai López
Posts: 2292
Joined: Sun Aug 08, 2004 1:41 pm
Location: Spain
Contact:

Post by Rai López »

...Hey! Just the MAN I had in mind :)

Thank you on first place! I'm not in front of AS right now but, of course, I'm thinking on it... so here are some quick thoughts:

Not sure what the "LM_String" value/parameter (whatever!) will have especially, but for some reason it called my attention at some point too and, now that you say that, I couldn't be more intrigued... Anyway, in my last tries, insted using simple strings like "A" or "E", I started to fill the table like this:

Code: Select all

local actionNames = {[moho.layer:ActionName(0)] = 0.5, [moho.layer:ActionName(1)] = 0.25}

That, theoretically, should fill the table keys with an appropriate "LM_String" value, isn't?? But it didn't make any difference at first sight (although it's hard to ensure at this point, when anything could be the problem). About fill that 4th function value (LM_String names[numToBlend]) with a table like you suggest: name = {'A', 'E'}, wouldn't be that table values automatically indexed as: name[1] = 'A', name[2] = 'B' and so? I mean, with a numerical key? If so, I think the function won't accept it, cause it seems to expect something like a table which keys be a string type, and that's the reason for I tried to feed it with a table constructed like that: ["A"] = 0.5 (adding the "= 0.5" part just to make valid the construction). Anyway, I just can't wait to go home to continue the "trial & erroring", although I'm not sure if I have reasons to be very hopeful at this point in time :(

...But I agree that the function is curious to say the least! And only the possibility of make it works as it (theoretically) should work, will worth the invested time (?), or I hope so... Well, THANKS for not leave me alone on this! :) Of course, I'll comment any curious thing that I could get... Fingers crossed! (Yeah) It[seems]'s all about luck...


EDIT: And talking about (bad) luck... I've just seen in the scripting interface, that the "ActionName(int32 id)" doesn't return any "LM_String" value as I thought but a "const char" string type one:

Code: Select all

const char *PoseName @ ActionName(int32 id);
Hmmm... really (really!) I've no idea of the difference between them but, for your words, I'd say that the "LM_String" is nothing good and I wonder (and wonder) why... and my guess: is it something like a specially formatted string in an internal/unexposed way or something so? But If so... why the hell a user exposed function would require something like that?? It wouldn't make too much sense... :cry:
...
Rudiger
Posts: 786
Joined: Sun Dec 18, 2005 2:25 am

Post by Rudiger »

Hi Ramon,

I emailed Mike about the LM_String thing, and apparently you can create your own LM_String objects after all!

You just do:

Code: Select all

local lm_string = LM.String:new_local("Action 1")
I couldn't find it documented anywhere, but I assume there's a way of extracting the normal string value from it as well.

Anyway, I gave it a go, and got the following code to work:

Code: Select all

moho.layer:BlendActions(moho.frame, 2, {LM.String:new_local('A'), LM.String:new_local('B')}, {1.0, 1.0})
By the way, you do know this is just the same function as the Animation -> Blend Morphs... menu item, right :)? I just thought I would mention it in case you are expecting something different like relative blending or something.
User avatar
Rai López
Posts: 2292
Joined: Sun Aug 08, 2004 1:41 pm
Location: Spain
Contact:

Post by Rai López »

Rudiger, still no words... I've seen your reply this morning just before go to work and, after that, I simply though that my working day would never ends... But here I am, testing it and seeing it with my own eyes, just some hours after that I thought I had lost (almost) all hope, and I was trying to convince myself (without too much success, BTW) to close the chapter, turn the page/leaf, or whatever you say...

About the golden function, what can I say? It's simply, simply amazing! :D And for some reason (double sudden luck?) it seems to be intended to work exactly in the way I imagined/needed, mixing the morphs and writing the keys for the involved channels on the fly and showing results in real time, simply a dream! :) Apart of that, all this seems to reveal (or throw some light on at least) one of those big and ancient AS mysteries, the "LM_String" one, and that is something to remember foreeever and eeever and eveeer...

Hmmm, well, now I think that the only thing missing here is is a giant (no font size of bold effect will made bigger) thank you. Of course, all this will delay the release of my (still delayed by itself, as usually...) tool, but I think it'll worth :)


Thanks again & greetings,
Ramón López.
...
Breinmeester
Posts: 306
Joined: Thu May 13, 2010 2:01 pm

Post by Breinmeester »

Would it be possible to implement this code without it setting a keyframe on the timeline? I mean in a sort of preview mode like the Blend Morphs dialogue box before you 'Ok' it.
User avatar
funksmaname
Posts: 3174
Joined: Tue May 29, 2007 11:31 am
Location: New Zealand

Post by funksmaname »

Breinmeester - that's how Rudiger's morphdials work when in 'real time morphdials' mode...
Breinmeester
Posts: 306
Joined: Thu May 13, 2010 2:01 pm

Post by Breinmeester »

No, he uses a different technique. He calculates the point data himself.
Rudiger
Posts: 786
Joined: Sun Dec 18, 2005 2:25 am

Post by Rudiger »

Breinmeester wrote:Would it be possible to implement this code without it setting a keyframe on the timeline? I mean in a sort of preview mode like the Blend Morphs dialogue box before you 'Ok' it.
I think I know what you mean.

There's no way of stopping the function from dropping down a key for the current frame, but you could make your embedded script instantly delete the key, but keep the position of the points.
Breinmeester
Posts: 306
Joined: Thu May 13, 2010 2:01 pm

Post by Breinmeester »

Hey Rudiger! Thanks for helping out.

Probaply your solution would delete any keys that were there before, right?
Also, the actions I'm trying to blend are on a group layer and effects several child layers. I don't want to simply delete all the keys of the parent and child layers on the current frame, because some channels are not effected by the actions and I need to keep whatever keys are on those channels for the current frame.

How would I script it so it knows what channels to delete a key on?

Maybe I could make an action called "delete" where it has keys on all the channels that need keys deleted for the parent and all child layers. This way the script could check if there's a key on a certain channel of the "delete" action and delete keys of the corresponding channel on the main timeline for the current frame.
But that would probaply slow an already pretty slow script down enormously...

What do you think?
Rudiger
Posts: 786
Joined: Sun Dec 18, 2005 2:25 am

Post by Rudiger »

Breinmeester wrote:Hey Rudiger! Thanks for helping out.

Probaply your solution would delete any keys that were there before, right?
Also, the actions I'm trying to blend are on a group layer and effects several child layers. I don't want to simply delete all the keys of the parent and child layers on the current frame, because some channels are not effected by the actions and I need to keep whatever keys are on those channels for the current frame.

How would I script it so it knows what channels to delete a key on?

Maybe I could make an action called "delete" where it has keys on all the channels that need keys deleted for the parent and all child layers. This way the script could check if there's a key on a certain channel of the "delete" action and delete keys of the corresponding channel on the main timeline for the current frame.
But that would probaply slow an already pretty slow script down enormously...

What do you think?
Your idea gave me an even better idea. Why don't you just create a new temporary action to use as a sort of scratchpad before you start. Then BlendMorph could put all the keys it wants to in there without interfering with any keys you may already have on the main timeline. You can then use the key information to apply the morphs in real time and then just simply delete the action when you are done.
Breinmeester
Posts: 306
Joined: Thu May 13, 2010 2:01 pm

Post by Breinmeester »

Wow, that sounds pretty nifty! You've got a sound brain in yer head!

How would you do this:
Rudiger wrote:You can then use the key information to apply the morphs in real time (...)
How would you preview an action without it setting a key? The InsertAction() command sets a key as well.
Rudiger
Posts: 786
Joined: Sun Dec 18, 2005 2:25 am

Post by Rudiger »

Why, thank you. Just a shame it has no off switch :?.

Anyway, you would probably want to do something like...

Code: Select all

for i = 0, mesh:CountPoints()-1 do
    local point = mesh:Point(i)
    point.fPos = point.fAnimPos:GetValue(moho.frame)
end
Breinmeester
Posts: 306
Joined: Thu May 13, 2010 2:01 pm

Post by Breinmeester »

Ok, I appologize in advance, but I'm a complete novice in lua scripting.

What's the difference between fAnimPos, fPos and fTempPos?
And I'm guessing I would have to ActivateAction("scratchpad") first, right?

Thanks.
Rudiger
Posts: 786
Joined: Sun Dec 18, 2005 2:25 am

Post by Rudiger »

As I understand it, fPos is the current position of the point, fTempPos is for temporarily storing the position value while it is being calculated, and fAnimPos is the point's position animation channel. So fPos and fTempPos are each single Vector2 objects, whereas fAnimPos can be thought of as a list of Vector2 objects, one for each frame.

That's right about needing to activate the action first, so the full thing would be:

Code: Select all

local frame = moho.frame
local layer = moho.layer

layer:ActivateAction("scratchpad")
layer:BlendActions(frame, 2, {LM.String:new_local('A'), LM.String:new_local('B')}, {1.0, 1.0}) 

for i = 0, mesh:CountPoints()-1 do
    local point = mesh:Point(i)
    -- You may also only want to set the position if the point has a key for this frame, like so:
    if point:fAnimPos:HasKey(frame) then
        point.fPos = point.fAnimPos:GetValue(frame)
    end
end 

layer:ActivateAction(nil)
layer:DeleteAction("scratchpad")
Post Reply