Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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!
Copy link to clipboard
Copied
you'll want to change params using AEGP_SetStreamValue().
look at the "project dumper" sample project to see how to access streams.
Copy link to clipboard
Copied
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!
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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?
Copy link to clipboard
Copied
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!
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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!
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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!
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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!
Copy link to clipboard
Copied
Upps my bad, get current time always return scale=1 value=0
Find more inspiration, events, and resources on the new Adobe Community
Explore Now