A lua greenhorn's question

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

Moderators: Víctor Paredes, Belgarath, slowtiger

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

Post by Rudiger »

I thought of one restriction, unfortunately. For the point channels, you're going to need access to the mesh which comes from moho and not the layer. Similarly, for bone channels. You might have to compromise and have a tool button that does the synchronization between your floating window and the actual timeline.
stefman
Posts: 75
Joined: Mon Jul 20, 2009 6:46 pm

Post by stefman »

Rudiger,

in order to understand things better I tried to apply the principles of your "RT_UtilityWindow" in the "lm_layertrail.lua" script (/scripts/menu/layer effects).

I tried to use your method for changing it to modeless.
So, I changed the code at lines 101 - 108 from:
function LM_LayerTrail:Run(moho)
self.startFrame = 1
self.endFrame = moho.document:EndFrame()

local dlog = LM_LayerTrailDialog:new(moho)
if (dlog:DoModal() == LM.GUI.MSG_CANCEL) then
return
end

to:

function LM_LayerTrail:Run(moho)
self.startFrame = 1
self.endFrame = moho.document:EndFrame()
self.moho = moho

local dlog = LM_LayerTrailDialog:new(moho)
dlog:DoModeless()
end

But, the result is that the script even doesn't appear anymore in the script list.:?
Do you know what's going wrong?

Of course I could have set the window to modeless by keeping all the code and just changing
if (dlog:DoModal() == LM.GUI.MSG_CANCEL) then
return
to
if (dlog:DoModeless() == LM.GUI.MSG_CANCEL) then
return
But, I wanted to recreate your structure in order to integrate a button at the next step.

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

Post by Rudiger »

Hi Stefman,

The reason that the script isn't showing up all is probably that it has a syntax error and there is a bug in version 6.0 that makes it not report lua syntax errors properly.

I suspect you've got one too many ends. Since you got rid of the "if(dlog:DoModal() == LM... ...then" line you have to get rid of the corresponding "end" statement. Don't forget that any other code in the run function will have to be moved to its own function so you can run it when a button is pressed not when the script is first run.
User avatar
heyvern
Posts: 7035
Joined: Fri Sep 02, 2005 4:49 am

Post by heyvern »

Rudiger wrote:OK, I had a look at the lm_star.lua script and it looks like the moho object is already embedded in the dialog! IE on line 55 is says "d.moho = moho". This means any dialog method can access the scripting interface simply by using self.moho.
Good grief... I'm an idiot. :oops: There it was... passed from the crazy dialog box. Forest for the trees. ;)

Funny... I sort of tried that but it didn't work. I think because I tried to make another GLOBAL variable equal to "moho"! This is what caused AS to crash. "d.moho" is only passed as a LOCAL variable. If I pass moho to other functions using a local variable it works without crashing!!!

Thanks DUDE!!! My brain thanks you to. ;)

-vern
stefman
Posts: 75
Joined: Mon Jul 20, 2009 6:46 pm

Post by stefman »

Rudiger wrote: I suspect you've got one too many ends. Since you got rid of the "if(dlog:DoModal() == LM... ...then" line you have to get rid of the corresponding "end" statement.

Rudiger, thank you very much!


Indeed, there was one "end" too much.
Now, the script appears properly in the menu and the window also opens well.

I managed to integrate the button, to create the message and I created an own function for the code that was remaining underneath.

The isolated code for the run function is as follows:
function LM_LayerTrail:Run(moho)
self.startFrame = moho.document:StartFrame()
self.endFrame = moho.document:EndFrame()
self.moho = moho


local dlog = LM_LayerTrailDialog:new(moho)
dlog:DoModeless()
end
(I kept the definitions of self.startFrame and self.endFrame in that function because the display needs them to update themselves when the window opens.) This works fine. The window opens properly.

I put the remaining code into a new function which is triggered by the button.
The triggering works fine but I think there are things in this function which shouldn't be there.

When pushing the button the lua console shows this error message:

attempt to index global 'moho' (a nil value)

This is the code of my bearish function:
function LM_LayerTrail:ButtonAction(parent)

moho.document:PrepUndo(nil)
moho.document:SetDirty()

local parentLayer = moho.layer
local layer = moho:CreateNewLayer(MOHO.LT_VECTOR)
layer:SetName("Layer Trail")
local mesh = moho:Mesh()
if (mesh == nil) then
return
end

local startFrame = self.startFrame
local endFrame = self.endFrame
local curFrame = moho.frame
local m = LM.Matrix:new_local()
local origM = LM.Matrix:new_local()
local vec = LM.Vector2:new_local()
local origin = parentLayer:Origin()

-- first, create a curve with a new point for each frame of movement
local dashedOn = true
for frame = startFrame, endFrame do
moho:SetCurFrame(frame)
parentLayer:GetFullTransform(frame, m, nil)
vec:Set(origin)
m:Transform(vec)
if (frame == startFrame) then
mesh:AddLonePoint(vec, 0)
else
mesh:AppendPoint(vec, 0)
mesh:SelectNone()
local id = mesh:CountPoints() - 1
mesh:Point(id).fSelected = true
mesh:Point(id - 1).fSelected = true
if (self.dashed) then
if (dashedOn) then
moho:CreateShape(false, layer:CurFrame(), false)
end
else
moho:CreateShape(false, layer:CurFrame(), false)
end
mesh:Point(0).fParent = -1
mesh:Point(mesh:CountPoints() - 1).fParent = -1
dashedOn = not dashedOn
end
end

mesh:SelectNone()

-- next, compensate these points for any movement higher up in the hierarchy
-- examples: the target layer is part of a group with motion of its own, or is attached to a bone
layer:GetFullTransform(0, origM, nil)
for frame = startFrame, endFrame do
layer:GetFullTransform(frame, m, nil)
m:Invert()
for i = 0, mesh:CountPoints() - 1 do
vec:Set(mesh:Point(i).fAnimPos:GetValue(0))
origM:Transform(vec)
m:Transform(vec)
mesh:Point(i).fAnimPos:SetValue(frame, vec)
end
end

moho:SetCurFrame(curFrame)
end
The error message referes to line 3
moho.document:PrepUndo(nil)
Well, I managed to resolve the problem at line 3 by putting code back to the run function. This worked fine until
local curFrame = moho.frame

AS didn't know what to do with it (a nil value). But, I managed it by creating a self object.


But, now I'm stuck at
local origin = parentLayer:Origin()

Do you know why he doesn't find this value and what I could do? Or, am I completely wrong when doing all this?

stefman
stefman
Posts: 75
Joined: Mon Jul 20, 2009 6:46 pm

Post by stefman »

Vern,

I have to advance very slowly to understand what I'm doing. That's why I remain on the lm_layertrail script at the moment.

The star script remains too abstract for me yet.
But, did you manage to make it work with a separated button?

stefman
User avatar
heyvern
Posts: 7035
Joined: Fri Sep 02, 2005 4:49 am

Post by heyvern »

Not yet but I sort of know how to do it now.

The dialog box creation is the key to it. You have to create all the variables there that you need IN the dialog box widgets. So... if you need the LAYER to do stuff to it, create a variable for the layer in the dialog box:

Code: Select all

d.moho = moho
d.myLayer = moho.layer
If you try to use the "self.moho" anywhere in the script, AS will crash. But I can use the "self.myLayer" variable without a crash. So the trick is to create those variables in the dialog box creation at the top of the script. I haven't had a chance yet to take this further BUT it should work now because I was able to access the layer name and print it out using a button in the dialog box. This means the layer contents like bones, or points is accessible from that button.

-vern
Rudiger
Posts: 786
Joined: Sun Dec 18, 2005 2:25 am

Post by Rudiger »

heyvern wrote: If you try to use the "self.moho" anywhere in the script, AS will crash. But I can use the "self.myLayer" variable without a crash. So the trick is to create those variables in the dialog box creation at the top of the script. I haven't had a chance yet to take this further BUT it should work now because I was able to access the layer name and print it out using a button in the dialog box. This means the layer contents like bones, or points is accessible from that button.

-vern
If only, but not quite. Skeleton() and Mesh() are both methods of moho and not layer, so you will have to store them in the dialog as well. If you really want a floating layer-independent window, you would really require a fresh moho variable to be supplied to the handle_message method each time it's called.
stefman
Posts: 75
Joined: Mon Jul 20, 2009 6:46 pm

Post by stefman »

Rudiger,

is your answer refering to my code question from 4 posts ago?
Sorry, but, I don't know how to resolve my problem in the lm_layertrail script.:roll:

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

Post by Rudiger »

Hi Stefman,

Basically, when you store moho inside your script object, you are only storing the address of the interface, not the interface itself. What happens is that after the script is run and the modeless dialog is created, the interface that moho points to is no longer valid, so that's why AnimeStudio crashes if you try and do things like self.moho.layer or self.moho:Mesh(). However, static functions like self.moho:LayerAsGroup() seemed to be OK.

So that means you have to replace moho in your function with self.moho and things like layer and mesh you also have to pre-store in self before you create the dialog.
stefman
Posts: 75
Joined: Mon Jul 20, 2009 6:46 pm

Post by stefman »

Thank you Rudiger;

But, I still didn't get it work.

As 'self.moho.layer' doesn't work I don't know how I have to modify
local parentLayer = moho.layer
in order to be used in this line of the 'ButtonAction' function:
local origin = parentLayer:Origin()
How can I integrate 'self.moho:LayerAsGroup()' into that?
Or, did you mention this just as an example?

stefman
User avatar
heyvern
Posts: 7035
Joined: Fri Sep 02, 2005 4:49 am

Post by heyvern »

Look at the top of the script, any menu script that has a dialog box.

You see where it has the:

Code: Select all

function LM_BoneSoundDialog:new(moho)
	local d = LM.GUI.SimpleDialog(MOHO.Localize("/Scripts/Menu/BoneSound/Title=Bone Audio Wiggle"), LM_BoneSoundDialog)
	local l = d:GetLayout()

	d.moho = moho
"d" is passed to the dialog box. It is a "table" that has all of those variables stored in it that reference the elements you need. So if you need "moho.layer" then create a variable in the table in the dialog creation:

Code: Select all

d.layer = moho.layer
Then you could use "self.layer".

I am still very confused how and what can be accessed in a modeless dialog box. I seriously doubt a full fledged timeline or comprehensive gizmo can be done this way. For example if the modeless window is open and you select a different layer in the layer palette is the "moho.layer" updated? That layer object is defined with the layer selected... if you can't access "moho" after the dialog is open how do you get channel info from any other layers?

-vern
stefman
Posts: 75
Joined: Mon Jul 20, 2009 6:46 pm

Post by stefman »

Thank you Vern.

But I unforunately still don't get it done.

In the local "LM_LayerTrailDialog" function I integrated:
d.layer = moho.layer


And this part of the code I added the first bolt line to define "self.moho" again and replaced "moho.layer" with "self.layer" in the second bolt line.

But, I still get the nil value in the third bolt line.:?
-- **************************************************
-- The guts of this script
-- **************************************************

function LM_LayerTrail:Run(moho)
self.startFrame = moho.document:StartFrame()
self.endFrame = moho.document:EndFrame()
self.moho = moho
self.curFrame = moho.frame
self.layer = moho.layer


moho.document:PrepUndo(nil)
moho.document:SetDirty()

local dlog = LM_LayerTrailDialog:new(moho)
dlog:DoModeless()

local parentLayer = self.layer
local layer = moho:CreateNewLayer(MOHO.LT_VECTOR)
layer:SetName("Layer Trail")
local mesh = moho:Mesh()
if (mesh == nil) then
return
end
end


function LM_LayerTrail:ButtonAction(parent)

local startFrame = self.startFrame
local endFrame = self.endFrame
local curFrame = self.curFrame
local m = LM.Matrix:new_local()
local origM = LM.Matrix:new_local()
local vec = LM.Vector2:new_local()
local origin = parentLayer:Origin()

-- first, create a curve with a new point for each frame of movement
local dashedOn = true
for frame = startFrame, endFrame do
moho:SetCurFrame(frame)
parentLayer:GetFullTransform(frame, m, nil)
vec:Set(origin)
m:Transform(vec)
if (frame == startFrame) then
mesh:AddLonePoint(vec, 0)
else
mesh:AppendPoint(vec, 0)
mesh:SelectNone()
local id = mesh:CountPoints() - 1
mesh:Point(id).fSelected = true
mesh:Point(id - 1).fSelected = true
if (self.dashed) then
if (dashedOn) then
moho:CreateShape(false, layer:CurFrame(), false)
end
else
moho:CreateShape(false, layer:CurFrame(), false)
end
mesh:Point(0).fParent = -1
mesh:Point(mesh:CountPoints() - 1).fParent = -1
dashedOn = not dashedOn
end
end

mesh:SelectNone()

-- next, compensate these points for any movement higher up in the hierarchy
-- examples: the target layer is part of a group with motion of its own, or is attached to a bone
layer:GetFullTransform(0, origM, nil)
for frame = startFrame, endFrame do
layer:GetFullTransform(frame, m, nil)
m:Invert()
for i = 0, mesh:CountPoints() - 1 do
vec:Set(mesh:Point(i).fAnimPos:GetValue(0))
origM:Transform(vec)
m:Transform(vec)
mesh:Point(i).fAnimPos:SetValue(frame, vec)
end
end

moho:SetCurFrame(curFrame)
end


Do you know what I am doing wrong?

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

Post by Rudiger »

Try moving "local parentLayer = self.layer" to ButtonAction() somewhere before "local origin = parentLayer:Origin()".
stefman
Posts: 75
Joined: Mon Jul 20, 2009 6:46 pm

Post by stefman »

Yes, thanks Rudiger. That worked.

Now I'm stuck again.

Does anyone know how I could replace 'moho' in this line?

Code: Select all

moho:SetCurFrame(frame)
I'm lost because self.moho makes crash all.

stefman
Post Reply