Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

Using AEGP_StartUndoGroup / EndUndo to force an asynchronous re-render

New Here ,
Aug 14, 2014 Aug 14, 2014

I need to make an asynchronous call (from other thread) that forces re-render. I've read on this forum that introducing something into the undo stack it is forced to re-render.

I'm totally newbie to AE SDK so my idea was to store a pointer to the AEGP_UtilitySuite1 in that thread.

I saved it from the ParamsSetup

AEGP_SuiteHandler suites(in_data->pica_basicP);

suites.CommandSuite1());

And in the asynchronous function I call

suite->AEGP_StartUndoGroup("TEST UNDO");

suite->AEGP_EndUndoGroup();

But unfortunatly I had no luck and nothing is added to the undo stack.

I know that the good way should be use NULL as parameter to avoid place it into the undo stack and only re-render but I used that string to test if it is taken in account.

Thank you in advance, I'm driving nuts with this!

F.

TOPICS
SDK
1.5K
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Aug 14, 2014 Aug 14, 2014

hi mescobar! welcome to the forum!

many good people have gone nuts in this forum over the years.

i'd like to start with a moment of silence in their honor.

ok.

off the top of my head, i don't know of a direct way of forcing a re-render

from a thread other than the main.

i also don't know of undo groups causing a re-render.

however, i can think of one trick.

AEGP_CauseIdleRoutinesToBeCalled(), is thread safe, and can be called at

any time from any thread.

(you have to acquire it from the main thread, but once you have the suite,

you're free to use it whenever you want)

if you had an AEGP with an idle hook, that hook will get called asap after

yopu call for the idle routines. the idle call is in the main thread, and

now you can use a multitude of methods to trigger a re-render.

(simplest one being changing a param value)

i hope this solution is relevant to your situation.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Aug 15, 2014 Aug 15, 2014

One minute for all them, they have all my respect!

Sounds nice, in fact I managed to register an iddle hook but since I look like this one http://i.imgur.com/xVyoSl.jpg

I don't imagine how to send the params[] to modify one of them or how to send the input to create a NULL undo etc

Regards and thank you so much for your advices!

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Aug 15, 2014 Aug 15, 2014

you'll want to change params using AEGP_SetStreamValue().

look at the "project dumper" sample project to see how to access streams.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Aug 15, 2014 Aug 15, 2014

OMG I start to feel sick :S

It looks that this needs more data I don't have

  ERR(suites.StreamSuite2()->AEGP_SetStreamValue(S_my_id, text_streamH, &val));

I can grab a pointer to the Pica so getting the suites is trivial but reusing some forum code I did this:

  AEGP_StreamRefH new_streamH = NULL;

  AEGP_StreamValue    val;

  AEFX_CLR_STRUCT(val);  

  suites.StreamSuite2()->AEGP_SetStreamValue(SLIDER_DISK_ID,new_streamH,&val);

Being SLIDER_DISK_ID my id (I reused the noise example) but the only thing I had was a crash

In other hand

  ERR(suites.UtilitySuite3()->AEGP_StartUndoGroup("AAA"));

  ERR(suites.UtilitySuite3()->AEGP_EndUndoGroup());

doesn't make nothing for me (it is called since I've tracked it with messageboxes9

I'm really thankful for your help!

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Aug 15, 2014 Aug 15, 2014

lets break it down.

ERR(suites.StreamSuite2()->AEGP_SetStreamValue(S_my_id, streamH, &val));

S_my_id:

generally speaking, when you register an AEGP you get this id and you're

supposed to use it in all your calls.

just pass a NULL instead.

val:

in this structure, you should put the new value of the param you wish to

affect.

streamH:

ahhh... ain't the the tricky one...

you have to acquire that one, and it is the key to accessing a parameter.'

to get it, you need to use AEGP_GetEffectStreamByIndex().

that function takes the param index as an argument.

BUT, to use that function you must have a valid AEGP_EffectRefH.

to get the effect ref, you have to call AEGP_GetLayerEffectByIndex();

to use that function you must have a valid AEGP_LayerH.

to get a valid AEGP_LayerH you should use PF_GetEffectLayer() in the

effect, and pass that handle to the AEGP.

how do you get the effect index? that's a bit more complex. for practice

sake, test with only one effect on your layer, and use index 0.

now that you have all that data, you can access any of your effect's params

and read/write them.

it seems scary, but it's really no biggie once you get the hang of it.

again, i advise you to look at the "project dumper" sample, and see how all

of that stuff is implemented there.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Aug 16, 2014 Aug 16, 2014

Ohhh I forget to say that my test was not a AEGP but an Effect (I used noise example as base)

That's why I don't have access to several of that funcions, anyway for the future readers you can get the ID by using this:

  AEGP_SuiteHandler suites(in_dataP->pica_basicP);

  AEGP_GlobalRefcon globalRef=NULL;

  const A_char* pluginName = "MYPLUGINNAME";

  suites.UtilitySuite5()->AEGP_RegisterWithAEGP( globalRef, pluginName, &pluginID );


I'll continue working on this but unfortunatly I didn't manage to call AEGP_GetEffectStreamByIndex.

AE seems to be really really complex on it's SDK

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Aug 16, 2014 Aug 16, 2014

ok ok ok....

let's tae it from the top.

yes, there are effects and AEGPs.

effects are applied to layers, and AEGPs serve as "facilities" for general

purposes.

the suites offer both access to AE's opaque data, as well as some

processing tools.

AEGP_GetNewStreamValue() is as example of a suite function accessing opaque

data.

AEGP_TransformWorld() is an example of a suite offering some processing

tools.

AEGP_GetEffectLayer() is an example for a suite giving utilities.

(PF stands for "Plug-in Filter", AEGP stand for "After Effects General

Plugin)

now,

most of these suites, can be used on both effects and AEGPs. really AE

doesn't care.

you also don't have to get a plug-in id to use functions that take it as an

argument. you can just pass a NULL.

some suite functions, only apply either AEGPs or effects specifically. that

doesn't mean you can't call the function from the wrong sort of plug-in,

but you'll requite valid data that's not normally available to the wrong

sort.

for example, calling AEGP_GetEffectLayer() needs the effect_ref, available

only in an effect's in_data. if you pass that data to an AEGP, you can call

this function, as long as that data is valid. (and it's valid only during a

call to the effect)

idle_hook, for instance, can only be assigned to an AEGP (to the best of my

knowledge).

even if you get it to call your effect (which i don't think is possible),

the call won't be associated with any specific instance.

the closest you can get, is creating a custom comp window UI, which while

the effect is selected in the effects window, will call your effect at idle

times with an "event".

but perhaps we're diving in too deep.

what exactly are your needs for causing a render?

what is the nature of that separate thread which decides on the re-render?

do you have to have an IMMEDIATE re-render? or do you just want to tell an

effect it needs to change?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Aug 18, 2014 Aug 18, 2014

Finally I managed to do it using Idle ,yes it works with Effects plug-ins!

Just as documentation for future readers:

AEGP_EffectRefH meH;

AEGP_StreamRefH streamH ;

suites.PFInterfaceSuite1()->AEGP_GetNewEffectForEffect(pluginID, mEffectRef, &meH);

if(meH)

{

   (suites.StreamSuite2()->AEGP_GetNewEffectStreamByIndex(pluginID, meH, SLIDER_DISK_ID, &streamH));

   if (streamH)

    {

       ERR(suites.DynamicStreamSuite2()->AEGP_SetDynamicStreamFlag(streamH, AEGP_DynStreamFlag_HIDDEN, TRUE, TRUE));

       ERR(suites.StreamSuite2()->AEGP_SetStreamValue(pluginID,streamH,&val));

       ERR(suites.StreamSuite2()->AEGP_DisposeStream(streamH));

   }

   ERR(suites.EffectSuite2()->AEGP_DisposeEffect(meH));

}

In fact the only thing I didn't manage to do was PF_PUI_NO_ECW_UI since I wanna make a hidden slider that is change on Idle to force re-render, on that iddle I can hide it using

ERR(suites.DynamicStreamSuite2()->AEGP_SetDynamicStreamFlag(streamH, AEGP_DynStreamFlag_HIDDEN, TRUE, TRUE));

But if the idle hook is not called it is visible

Let's continue exploring AE SDK!

Thank you so much for your help shachar!

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Aug 18, 2014 Aug 18, 2014

wow. i didn't know you can register an idle hook from an effect! nice!

anyways, put your invisibility code in the updateParamsUI() function. (and

make sure your effect responds to that call in the entryPointFunction, and

also set the SEND_UPDATE_PAMAS_UI flag during global setup)

that function is called on numerous occasions, including when the effect is

first displayed, so your param will be invisible always.

i have a question for you.

when the idle function is called, and you call getNewEffectForEffect(),

which instance get's associated? i would imagine that call wouldn't belong

to any instance.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Aug 18, 2014 Aug 18, 2014

I've tried to add PF_OutFlag_SEND_UPDATE_PARAMS_UI to my global flags but AE claims something like this:

has global outflags mismatch.

Code flags are xxxx and PiPL are XXXXX  << EDIT I FORGET TO EDIT THE .r, comming from other sdks I don't found a logic reason to make this twice


Obviously without that PF_Cmd_UPDATE_PARAMS_UI is not called

About getNewEffectForEffect I've stored pluginID and mEffectRef in a global var so probably you are right, I need to figure some workarounds for this when I have finished the basic functions.

Regards!

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Aug 18, 2014 Aug 18, 2014

as for the mismatch, your plug-in has a resource file.

it's probably names

pluginnamePipl.r

in it there are some basic definitions for the plugin.

when AE scans the plug-ins folder it doesn't launch the plug-ins. it only

reads data from that resource file.

one of the definitions in that file is the sum of all global flags.

it has to match the sum you're reporting in outflags and outflags2 you're

setting during global setup.

after you change the resource file, you have to clean and rebuild your

project, as that file get's updated in the build only if it's compiled

version (.rc file) doesn't exist. cleaning the project erases the .rc file,

so the build generates a new one with the updated values.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Aug 18, 2014 Aug 18, 2014

You are really fast! I already edited the reply!

Next task for me how to save custom data per "intance" let's go to the mud again!

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Aug 18, 2014 Aug 18, 2014

well, here comes some bad news... (but with a solution)

as you already know, the key to access your effect data is through an

AEGP_EffectRefH.

unfortunately, this ref has a very short life span. you can't keep it from

a call to your plug-in, and expect it to work after that call has ended.

when you reach your idle hook, a kept effect ref will be invalid.

same goes for the mEffectRef you keep. if it's working, it a miracle. you

can't rely on it. (as far as i know)

some data has a longer life span. AEGP_LayerH, AEGP_CompH, and AEGP_ItemH

can outlast the call in which they were created.

i can't tell you if it's 100% safe, but i'm using these outside a call's

scope regularly.

the only full solution would be to store the item id for the comp, the

layer id for the layer, and the effect index on that layer.

then when seeking the effect at idle time, look for a project item with a

matching id, get the compH from it, look for a layer with a matching id,

get the layerH from it, then look at the effect at the stored index, and

see if it's indeed yours. (you can check it's match name to make sure)

yup.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Aug 28, 2014 Aug 28, 2014

After some deserved hollidays I've come back with more forces!

Thank you for your reply again it looks to work I mean the AEGP_LayerH, AEGP_CompH, and AEGP_ItemH.

Now continuing with my experiments I did this:

  AEGP_LayerH activeLay = NULL;

  ERR(suites.PFInterfaceSuite1()->AEGP_GetEffectLayer(mEffectRef,&activeLay));              

  AEGP_ItemH item = NULL;

  ERR(suites.LayerSuite5()->AEGP_GetLayerSourceItem(activeLay, &item));

  A_Time mTime;

  ERR(suites.ItemSuite5()->AEGP_GetItemCurrentTime(item,&mTime));

  mTime.value=150;

  ERR(suites.ItemSuite8()->AEGP_SetItemCurrentTime(item,&mTime));

It works partially since it changes the time (and in fact I can see that mTime is set propertly on *getCurrent*

but unfortunatly it is always moved to the 0 time.

Really really weird.

Thank you!

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Aug 28, 2014 Aug 28, 2014
LATEST

Upps my bad, get current time always return scale=1 value=0

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines