After Effects Plug-in の種類
大まかにわけると以下の2つ。
After Effects General Plug-in (AEGP) | AEGP API を使用して色々できる ・メニューの追加 ・ プロジェクトへのアイテム、コンポジションなどの追加、削除 など色々できる。 |
effect Plug-in | レンダリング関連 |
リファレンスをみると、1つのプラグインに両方を含めることもできる模様。
ここでは基本的な AEGP Plug-in を制作する際のとっかかりについて説明する。
プラグインプロパティリスト(PiPL)の編集
サンプル ProjDumper の ProjDumper_PiPL.r をみると以下のようになっている。
#include "AEConfig.h"
#ifndef AE_OS_WIN
#include "AE_General.r"
#endif
resource 'PiPL' (16000) {
{ /* array properties: 7 elements */
/* [1] */
Kind {
AEGP
},
/* [2] */
Name {
"ProjDumper"
},
/* [3] */
Category {
"General Plugin"
},
/* [4] */
Version {
196608
},
/* [5] */
#ifdef AE_OS_WIN
#ifdef AE_PROC_INTELx64
CodeWin64X86 {"EntryPointFunc"},
#endif
#else
#ifdef AE_OS_MAC
CodeMacIntel64 {"EntryPointFunc"},
CodeMacARM64 {"EntryPointFunc"},
#endif
#endif
}
};
プラグインの動作に関する基本情報を提供するリソースで、Name、Version 辺りを制作するプラグイン用に書き換えて使用するばよさそう。
このリソースは古いもので、現在は、Command Selectors ー Global Selectors などに置き換わっているようですが PiPL の動作と一致している必要があるようなのでまだ必要なのでしょう。
EntryPointFunc() 関数の実装
起動時に1度だけ呼び出される関数(PiPLで指定)。主に次のような事を行う。
発行されたプラグインIDの保存(何かの機能を使用する際に渡す必要があることが多い)
AEGP_GlobalRefcon の保存(suitesの元になる。基本的にこれを元に suites を作成し各機能にアクセスする)
メニューのコマンドIDの生成と保存、メニュー追加(メニューが実行された時にどのコマンドなのかを判定したりするのに使用)
各フック関数の登録
以下、 ProjDumper の EntryPointFunc() に説明を加えたもの。
登録できるフック関数などは他にもいろいろあるので RegisterSuite のヘッダやリファレンスを参照。
A_Err
EntryPointFunc(
struct SPBasicSuite *pica_basicP, /* >> */
A_long major_versionL, /* >> */
A_long minor_versionL, /* >> */
AEGP_PluginID aegp_plugin_id, /* >> */
AEGP_GlobalRefcon *global_refconP) /* << */
{
A_Err err = A_Err_NONE;
// 発行されたプラグインIDの保存
S_my_id = aegp_plugin_id;
// AEGP_GlobalRefcon の保存
sP = pica_basicP;
// suites の作成(基本的に各機能へのアクセスは suites を介して行う
AEGP_SuiteHandler suites(pica_basicP);
// コマンドIDの生成と保存、メニュー追加
ERR(suites.CommandSuite1()->AEGP_GetUniqueCommand(&S_dump_proj_cmd));
ERR(suites.CommandSuite1()->AEGP_InsertMenuCommand(S_dump_proj_cmd, "ProjDumper", AEGP_Menu_EDIT, AEGP_MENU_INSERT_SORTED));
ERR(suites.CommandSuite1()->AEGP_GetUniqueCommand(&S_other_cmd));
ERR(suites.CommandSuite1()->AEGP_InsertMenuCommand(S_other_cmd, "ProjDumper: Make Cuter", AEGP_Menu_EDIT, AEGP_MENU_INSERT_AT_BOTTOM));
// コマンドが実行された時に呼び出される関数を登録
ERR(suites.RegisterSuite5()->AEGP_RegisterCommandHook( S_my_id,
AEGP_HP_BeforeAE,
AEGP_Command_ALL,
CommandHook,
NULL));
// メニューがアップデートされた時に呼び出される関数を登録
ERR(suites.RegisterSuite5()->AEGP_RegisterUpdateMenuHook(S_my_id, UpdateMenuHook, NULL));
return err;
}
CommandHook()、UpdateMenuHook()の実装
static A_Err
CommandHook(
AEGP_GlobalRefcon plugin_refconPV, /* >> */
AEGP_CommandRefcon refconPV, /* >> */
AEGP_Command command, /* >> */
AEGP_HookPriority hook_priority, /* >> */
A_Boolean already_handledB, /* >> */
A_Boolean *handledPB) /* << */
{
A_Err err = A_Err_NONE;
AEGP_SuiteHandler suites(sP);
*handledPB = FALSE;
// コマンドIDでどのコマンドが実行されたかを判定し、処理を行う
if ((command == S_dump_proj_cmd) || (command == S_other_cmd)) {
if (command == S_dump_proj_cmd) {
err = DumpProj(); // DumpProj処理を行う
*handledPB = TRUE; // コマンドが処理された
} else if (command == S_other_cmd) {
err = MakeCuter(); // MakeCuter処理を行う
*handledPB = TRUE; // コマンドが処理された
}
}
return err;
}
static A_Err
UpdateMenuHook(
AEGP_GlobalRefcon plugin_refconPV, /* >> */
AEGP_UpdateMenuRefcon refconPV, /* >> */
AEGP_WindowType active_window) /* >> */
{
A_Err err = A_Err_NONE;
AEGP_SuiteHandler suites(sP);
if (S_dump_proj_cmd) {
// メニューを有効化
err = suites.CommandSuite1()->AEGP_EnableCommand(S_dump_proj_cmd);
}
if (!err && S_other_cmd) {
AEGP_ItemH active_itemH;
// アクティブアイテムがある場合だけメニューを有効化
ERR(suites.ItemSuite6()->AEGP_GetActiveItem(&active_itemH));
if (!err && active_itemH) {
ERR(suites.CommandSuite1()->AEGP_EnableCommand(S_other_cmd));
ERR(suites.CommandSuite1()->AEGP_CheckMarkMenuCommand(S_other_cmd, TRUE));
}
} else {
ERR(suites.CommandSuite1()->AEGP_CheckMarkMenuCommand(S_other_cmd, FALSE));
}
return err;
}
ここまでくればある程度C++やAfterEffectsの知識があればいろいろ作れるはず。