#include <stdio.h>
#include <toonz_plugin.h>
#include <toonz_hostif.h>
#include <memory>
#include <cmath>
#include <vector>
#include "pixelop.hpp"
#include <utils/rect.hpp>
#include <utils/interf_holder.hpp>
#include <utils/param_traits.hpp>
#ifdef _MSC_VER
// Visual Studio is not supported __restrict for reference
#define RESTRICT
#else
#define RESTRICT __restrict
#endif
extern "C" {
TOONZ_EXPORT int toonz_plugin_init(toonz::host_interface_t *hostif);
TOONZ_EXPORT void toonz_plugin_exit();
}
toonz::host_interface_t *ifactory_ = NULL;
int toonz_plugin_init(toonz::host_interface_t *hostif)
{
printf("toonz_plugin_init()\n");
ifactory_ = hostif;
return TOONZ_OK;
}
void toonz_plugin_exit()
{
printf("toonz_plugin_exit()\n");
}
ToonzRect conv2rect(toonz::rect_t &&r)
{
return ToonzRect(r.x0, r.y0, r.x1, r.y1);
}
toonz::rect_t conv2rect(ToonzRect &&r)
{
return toonz::rect_t{r.x0, r.y0, r.x1, r.y1};
}
ToonzRect conv2rect(const toonz::rect_t &r)
{
return ToonzRect(r.x0, r.y0, r.x1, r.y1);
}
toonz::rect_t conv2rect(const ToonzRect &r)
{
return toonz::rect_t{r.x0, r.y0, r.x1, r.y1};
}
template <typename T>
void dump_value(const T &v)
{
printf("value: type:%s {%d}\n", typeid(T).name(), v);
}
template <>
void dump_value<toonz_param_traits_double_t::iovaluetype>(const toonz_param_traits_double_t::iovaluetype &v)
{
printf("value: type:%s {%g}\n", typeid(toonz_param_traits_double_t::iovaluetype).name(), v);
}
template <>
void dump_value<toonz_param_traits_range_t::iovaluetype>(const toonz_param_traits_range_t::iovaluetype &v)
{
printf("value: type:%s {%g, %g}\n", typeid(toonz_param_traits_range_t::iovaluetype).name(), v.a, v.b);
}
template <>
void dump_value<toonz_param_traits_point_t::iovaluetype>(const toonz_param_traits_point_t::iovaluetype &v)
{
printf("value: type:%s {%g, %g}\n", typeid(toonz_param_traits_point_t::iovaluetype).name(), v.x, v.y);
}
template <>
void dump_value<toonz_param_traits_color_t::iovaluetype>(const toonz_param_traits_color_t::iovaluetype &v)
{
printf("value: type:%s {%d, %d, %d, %d}\n", typeid(toonz_param_traits_color_t::iovaluetype).name(), v.c0, v.c1, v.c2, v.m);
}
template <>
void dump_value<toonz_param_traits_spectrum_t::iovaluetype>(const toonz_param_traits_spectrum_t::iovaluetype &v)
{
printf("value: type:%s {%g, %g, %g, %g, %g}\n", typeid(toonz_param_traits_spectrum_t::iovaluetype).name(), v.w, v.c0, v.c1, v.c2, v.m);
}
template <>
void dump_value<toonz_param_traits_tonecurve_t::iovaluetype>(const toonz_param_traits_tonecurve_t::iovaluetype &v)
{
printf("value: type:%s {%g, %g, %d, %d}\n", typeid(toonz_param_traits_tonecurve_t::iovaluetype).name(), v.x, v.y, v.channel, v.interp);
}
template <typename T>
bool get_and_check(toonz::node_handle_t node, const char *nm, double frame, double opt = 0)
{
auto nodeif = grab_interf<toonz::node_interface_t>(TOONZ_UUID_NODE);
auto pif = grab_interf<toonz::param_interface_t>(TOONZ_UUID_PARAM);
toonz_param_handle_t p1;
int ret;
ret = nodeif->get_param(node, nm, &p1);
printf("get_param(%s): ret:%d\n", nm, ret);
int type = 0;
int cnt = 0;
pif->get_type(p1, frame, &type, &cnt);
printf("parameter(ret:%d): name:%s (type:%d count:%d) expect:(type:%d) typesize:%ld\n", ret, nm, type, cnt, T::E, sizeof(typename T::iovaluetype));
if (type != T::E)
return false;
typename T::iovaluetype v;
ret = pif->get_value(p1, frame, &cnt, &v);
printf("get_value: ret:%d count:%d\n", ret, cnt);
dump_value<typename T::iovaluetype>(v);
return true;
}
template <>
bool get_and_check<toonz_param_traits_string_t>(toonz::node_handle_t node, const char *nm, double frame, double opt)
{
auto nodeif = grab_interf<toonz::node_interface_t>(TOONZ_UUID_NODE);
auto pif = grab_interf<toonz::param_interface_t>(TOONZ_UUID_PARAM);
toonz_param_handle_t p1;
int ret;
ret = nodeif->get_param(node, nm, &p1);
printf("get_param(%s): ret:%d\n", nm, ret);
int type = 0;
int cnt = 0;
ret = pif->get_type(p1, frame, &type, &cnt);
printf("parameter(ret:%d): name:%s (type:%d count:%d) expect:(type:%d) typesize:-\n", ret, nm, type, cnt, toonz_param_traits_string_t::E);
if (type != toonz_param_traits_string_t::E)
return false;
std::vector<toonz_param_traits_string_t::iovaluetype> v(cnt);
ret = pif->get_value(p1, frame, &cnt, v.data());
printf("get_value: ret:%d count:%d\n", ret, cnt);
//dump_value< toonz_param_traits_string_t::iovaluetype* >(v);
printf("value: type:%s {%s}\n", typeid(toonz_param_traits_string_t::iovaluetype).name(), v.begin());
return true;
}
template <>
bool get_and_check<toonz_param_traits_spectrum_t>(toonz::node_handle_t node, const char *nm, double frame, double opt)
{
auto nodeif = grab_interf<toonz::node_interface_t>(TOONZ_UUID_NODE);
auto pif = grab_interf<toonz::param_interface_t>(TOONZ_UUID_PARAM);
toonz_param_handle_t p1;
int ret;
ret = nodeif->get_param(node, nm, &p1);
printf("get_param(%s): ret:%d\n", nm, ret);
int type = 0;
int cnt = 0;
ret = pif->get_type(p1, frame, &type, &cnt);
printf("parameter(ret:%d): name:%s (type:%d count:%d) expect:(type:%d) typesize:-\n", ret, nm, type, cnt, toonz_param_traits_spectrum_t::E);
if (type != toonz_param_traits_spectrum_t::E)
return false;
toonz_param_traits_spectrum_t::iovaluetype v;
v.w = opt;
ret = pif->get_value(p1, frame, &cnt, &v);
printf("get_value: ret:%d count:%d\n", ret, cnt);
dump_value<toonz_param_traits_spectrum_t::iovaluetype>(v);
return true;
}
template <>
bool get_and_check<toonz_param_traits_tonecurve_t>(toonz::node_handle_t node, const char *nm, double frame, double opt)
{
auto nodeif = grab_interf<toonz::node_interface_t>(TOONZ_UUID_NODE);
auto pif = grab_interf<toonz::param_interface_t>(TOONZ_UUID_PARAM);
toonz_param_handle_t p1;
int ret;
ret = nodeif->get_param(node, nm, &p1);
printf("get_param(%s): ret:%d\n", nm, ret);
int type = 0;
int cnt = 0;
ret = pif->get_type(p1, frame, &type, &cnt);
printf("parameter)(ret:%d): name:%s (type:%d count:%d) expect:(type:%d) sz:-\n", ret, nm, type, cnt, toonz_param_traits_tonecurve_t::E);
if (type != toonz_param_traits_tonecurve_t::E)
return false;
std::vector<toonz_param_traits_tonecurve_t::iovaluetype> v(cnt);
ret = pif->get_value(p1, frame, &cnt, v.data());
printf("get_value: ret:%d count:%d\n", ret, cnt);
for (int i = 0; i < cnt; i++) {
dump_value<toonz_param_traits_tonecurve_t::iovaluetype>(v[i]);
}
return true;
}
void do_compute(toonz::node_handle_t node, const toonz::rendering_setting_t *rs, double frame, toonz::tile_handle_t tile)
{
printf("do_compute(): node:%p tile:%p frame:%g\n", node, tile, frame);
toonz::port_handle_t port = nullptr;
{
auto nodeif = grab_interf<toonz::node_interface_t>(TOONZ_UUID_NODE);
if (nodeif) {
int ret = nodeif->get_input_port(node, "IPort", &port);
if (ret)
printf("do_compute(): get_input_port: ret:%d\n", ret);
// test
get_and_check<toonz_param_traits_double_t>(node, "first", frame);
get_and_check<toonz_param_traits_range_t>(node, "second", frame);
get_and_check<toonz_param_traits_color_t>(node, "third", frame);
get_and_check<toonz_param_traits_point_t>(node, "fourth", frame);
get_and_check<toonz_param_traits_enum_t>(node, "fifth", frame);
get_and_check<toonz_param_traits_int_t>(node, "sixth", frame);
get_and_check<toonz_param_traits_bool_t>(node, "seventh", frame);
get_and_check<toonz_param_traits_string_t>(node, "eighth", frame);
get_and_check<toonz_param_traits_spectrum_t>(node, "ninth", frame, 0.5);
get_and_check<toonz_param_traits_tonecurve_t>(node, "tenth", frame);
get_and_check<toonz_param_traits_tonecurve_t>(node, "unknown", frame);
toonz::param_handle_t str;
nodeif->get_param(node, "eighth", &str);
toonz::param_handle_t notstr;
nodeif->get_param(node, "seventh", ¬str);
toonz::param_handle_t spec;
nodeif->get_param(node, "ninth", &spec);
auto pif = grab_interf<toonz::param_interface_t>(TOONZ_UUID_PARAM);
if (pif) {
int t, l;
pif->get_type(str, frame, &t, &l);
int sz;
std::vector<char> shortage_buf(l / 2 + 1);
int ret = pif->get_string_value(str, &sz, l / 2 + 1, shortage_buf.data());
printf("get_string_value(string): {%s} (length:%d) ret:%d\n", shortage_buf.data(), sz, ret);
ret = pif->get_string_value(notstr, &sz, l / 2 + 1, shortage_buf.data()); // must be error
printf("get_string_value(not string): sz:%d ret:%d\n", sz, ret); // size must be not changed
pif->get_type(spec, frame, &t, &l);
toonz_param_spectrum_t spc;
ret = pif->get_spectrum_value(spec, frame, 0, &spc);
printf("get_spectrum_value(spec): ret:%d\n", ret);
dump_value(spc);
ret = pif->get_spectrum_value(str, frame, 0, &spc);
printf("get_spectrum_value(str): ret:%d\n", ret); // must be error
}
}
}
int blur = 1;
auto tileif = grab_interf<toonz::tile_interface_t>(TOONZ_UUID_TILE);
auto portif = grab_interf<toonz::port_interface_t>(TOONZ_UUID_PORT);
if (port && tileif && portif) {
toonz::fxnode_handle_t fx;
portif->get_fx(port, &fx);
auto fxif = grab_interf<toonz::fxnode_interface_t>(TOONZ_UUID_FXNODE);
if (fxif) {
/* evaluate upstream's flow */
toonz::rect_t rect;
tileif->get_rectangle(tile, &rect);
toonz::rect_t inRect = conv2rect(conv2rect(rect).enlarge(blur, blur));
toonz::tile_handle_t result = nullptr;
tileif->create(&result);
fxif->compute_to_tile(fx, rs, frame, &inRect, tile, result);
/* evaluate the fx */
int x = rect.x0;
int y = rect.y0;
int lx = rect.x1 - rect.x0;
int ly = rect.y1 - rect.y0;
int sstride, dstride;
tileif->get_raw_stride(result, &sstride);
tileif->get_raw_stride(tile, &dstride);
int selement_type, delement_type;
tileif->get_element_type(result, &delement_type);
tileif->get_element_type(tile, &selement_type);
uint8_t *saddr, *daddr;
tileif->get_raw_address_unsafe(result, reinterpret_cast<void **>(&saddr));
tileif->get_raw_address_unsafe(tile, reinterpret_cast<void **>(&daddr));
printf("%f %f %f %f\n", rect.x0, rect.y0, rect.x1, rect.y1);
printf("-+ x:%d y:%d lx:%d ly:%d\n", x, y, lx, ly);
printf(" + src tile: addr:%p stride:%d type:%d\n", saddr, sstride, selement_type);
printf(" + dst tile: addr:%p stride:%d type:%d\n", daddr, dstride, delement_type);
// need compatibility check for formats
hv_kernel<uint8_t, 4>(daddr, saddr + sstride + 4, lx, ly, dstride, sstride, [](uint8_t v[4], const uint8_t *p, int stride, int xinbytes, int yinbytes) {
uint32_t l00 = *reinterpret_cast<const uint32_t *>(p + -stride - 4);
uint32_t l10 = *reinterpret_cast<const uint32_t *>(p + -stride);
uint32_t l20 = *reinterpret_cast<const uint32_t *>(p + -stride + 4);
uint32_t l01 = *reinterpret_cast<const uint32_t *>(p - 4);
uint32_t l11 = *reinterpret_cast<const uint32_t *>(p);
uint32_t l21 = *reinterpret_cast<const uint32_t *>(p + 4);
uint32_t l02 = *reinterpret_cast<const uint32_t *>(p + stride - 4);
uint32_t l12 = *reinterpret_cast<const uint32_t *>(p + stride);
uint32_t l22 = *reinterpret_cast<const uint32_t *>(p + stride + 4);
uint32_t r = 0, g = 0, b = 0, m = 0;
//printf("col:0x%08x [%d, %d]\n", l11, xinbytes, yinbytes);
/* TODO:
toonz の TPixel は char r, g, b, m; のように持っているのでそのまま uin32_t だとエンディアンが変わる.
toonz ビルド時の configuration はコンパイル時に参照できるようにしておくべきだ.
*/
m += ((l00 >> 24) & 0xff);
m += ((l10 >> 24) & 0xff);
m += ((l20 >> 24) & 0xff);
m += ((l01 >> 24) & 0xff);
m += ((l11 >> 24) & 0xff);
m += ((l21 >> 24) & 0xff);
m += ((l02 >> 24) & 0xff);
m += ((l12 >> 24) & 0xff);
m += ((l22 >> 24) & 0xff);
b += ((l00 >> 16) & 0xff);
b += ((l10 >> 16) & 0xff);
b += ((l20 >> 16) & 0xff);
b += ((l01 >> 16) & 0xff);
b += ((l11 >> 16) & 0xff);
b += ((l21 >> 16) & 0xff);
b += ((l02 >> 16) & 0xff);
b += ((l12 >> 16) & 0xff);
b += ((l22 >> 16) & 0xff);
g += ((l00 >> 8) & 0xff);
g += ((l10 >> 8) & 0xff);
g += ((l20 >> 8) & 0xff);
g += ((l01 >> 8) & 0xff);
g += ((l11 >> 8) & 0xff);
g += ((l21 >> 8) & 0xff);
g += ((l02 >> 8) & 0xff);
g += ((l12 >> 8) & 0xff);
g += ((l22 >> 8) & 0xff);
r += ((l00 >> 0) & 0xff);
r += ((l10 >> 0) & 0xff);
r += ((l20 >> 0) & 0xff);
r += ((l01 >> 0) & 0xff);
r += ((l11 >> 0) & 0xff);
r += ((l21 >> 0) & 0xff);
r += ((l02 >> 0) & 0xff);
r += ((l12 >> 0) & 0xff);
r += ((l22 >> 0) & 0xff);
v[0] = static_cast<uint8_t>(r / 9);
v[1] = static_cast<uint8_t>(g / 9);
v[2] = static_cast<uint8_t>(b / 9);
v[3] = static_cast<uint8_t>(m / 9);
});
}
}
}
int do_get_bbox(toonz::node_handle_t node, const toonz::rendering_setting_t *rs, double frame, toonz::rect_t *rect)
{
printf("do_get_bbox(): node:%p\n", node);
bool modified = false;
toonz::port_handle_t port = nullptr;
{
auto nodeif = grab_interf<toonz::node_interface_t>(TOONZ_UUID_NODE);
if (nodeif) {
int ret = nodeif->get_input_port(node, "IPort", &port);
printf("do_get_bbox(): get_input_port:%d\n", ret);
}
}
auto portif = grab_interf<toonz::port_interface_t>(TOONZ_UUID_PORT);
if (port && portif) {
int con = 0;
portif->is_connected(port, &con);
if (con) {
toonz::fxnode_handle_t fx;
portif->get_fx(port, &fx);
auto fxif = grab_interf<toonz::fxnode_interface_t>(TOONZ_UUID_FXNODE);
if (fxif) {
int ret = 0;
/* この引数の順番つらいなぁ, fx, rs, frame, rect の順だよね */
fxif->get_bbox(fx, rs, frame, rect, &ret);
/* 画素単位の値を現在の座標系に合わせる */
toonz::affine_t a = rs->affine;
double det = a.a11 * a.a22 - a.a12 * a.a21;
double scale = sqrt(fabs(det));
double blur = 1.0 / scale;
ToonzRect r = conv2rect(*rect);
r = r.enlarge(blur, blur);
*rect = conv2rect(std::move(r));
modified = true;
}
}
}
return modified;
}
param_desc_t params0_[] = {
param_desc_ctor<traits_double_t>("first", "1st", {1.0 /* default */, -1.0 /* min */, 1.0 /* max */}, "description of the first param"),
param_desc_ctor<traits_range_t>("second", "2nd", {{48.0, 64.0} /* default */, {0.0, 180.0} /* min-max */}),
param_desc_ctor<traits_color_t>("third", "3rd", {0xff, 0xff, 0xff, 0xff} /* white */),
param_desc_ctor<traits_point_t>("fourth", "4th", {{64, -64} /* default */, {-200, 200} /* min */, {-200, +200} /* max */}),
};
const char *strtbl_[] = {"tokyo", "osaka", "nagoya"};
param_desc_t params1_[] = {
param_desc_ctor<traits_enum_t>("fifth", "5th", {2, 3, strtbl_}),
param_desc_ctor<traits_int_t>("sixth", "6th", {2, -10, 10}, "this is integer"),
param_desc_ctor<traits_bool_t>("seventh", "7th", {1}),
};
toonz_param_traits_spectrum_t::valuetype points_[] = {{0.0, 1.0, 0.0, 0.0, 1.0},
{0.5, 0.5, 0.0, 0.5, 1.0},
{1.0, 0.0, 0.0, 0.5, 1.0}};
param_desc_t params2_[] = {
param_desc_ctor<traits_string_t>("eighth", "8th", {"this is sample message"}),
param_desc_ctor<traits_spectrum_t>("ninth", "9th", {0.1, 3, points_}),
param_desc_ctor<traits_tonecurve_t>("tenth", "10th", {/* tonecurve has no default */}),
};
toonz_param_group_t groups0_[] = {
param_group_ctor("Group1", sizeof(params0_) / sizeof(param_desc_t), params0_),
param_group_ctor("Group2", sizeof(params1_) / sizeof(param_desc_t), params1_),
param_group_ctor("Group3", sizeof(params2_) / sizeof(param_desc_t), params2_),
};
toonz_param_page_t pages_[] = {
param_page_ctor("Properties", sizeof(groups0_) / sizeof(toonz_param_group_t), groups0_),
};
int node_setup(toonz::node_handle_t node)
{
printf("blur: setup(): node:%p\n", node);
auto setup = grab_interf<toonz::setup_interface_t>(TOONZ_UUID_SETUP);
if (setup) {
int errcode = 0;
void *entry = NULL;
int ret = setup->set_parameter_pages_with_error(node, sizeof(pages_) / sizeof(toonz_param_page_t), pages_, &errcode, &entry);
if (ret) {
printf("setup error:0x%x reason:0x%x entry:%p\n", ret, errcode, entry);
}
setup->add_input_port(node, "IPort", TOONZ_PORT_TYPE_RASTER);
}
return 0;
}
int node_create(toonz::node_handle_t node)
{
printf("blur: create(): node:%p\n", node);
return TOONZ_OK;
}
int node_destroy(toonz::node_handle_t node)
{
printf("destroy():node:%p\n", node);
return TOONZ_OK;
}
int can_handle(toonz_node_handle_t node, const toonz_rendering_setting_t *rs, double frame)
{
printf("%s:\n", __FUNCTION__);
return TOONZ_OK;
}
size_t get_memory_requirement(toonz_node_handle_t node, const toonz_rendering_setting_t *rs, double frame, const toonz_rect_t *rect)
{
printf("%s:\n", __FUNCTION__);
return TOONZ_OK;
}
void on_new_frame(toonz_node_handle_t node, const toonz_rendering_setting_t *rs, double frame)
{
printf("%s:\n", __FUNCTION__);
}
void on_end_frame(toonz_node_handle_t node, const toonz_rendering_setting_t *rs, double frame)
{
printf("%s:\n", __FUNCTION__);
}
toonz_nodal_rasterfx_handler_t_ toonz_plugin_node_handler =
{
{1, 0}, // ver
do_compute, // do_compute
do_get_bbox, // do_get_bbox
can_handle, // can_handle
get_memory_requirement, // get_memory_requirement
on_new_frame, // on_new_frame
on_end_frame, // on_end_frame
node_create, // create
node_destroy, // destroy
node_setup};
extern "C" {
TOONZ_PLUGIN_PROBE_BEGIN(TOONZ_IF_VER(1, 0))
TOONZ_PLUGIN_PROBE_DEFINE(TOONZ_PLUGIN_VER(1, 0), "blur-plugin" /* name */, "dwango" /* vendor */, "libblur.plugin" /* identifier */, "a blur plugin for test", "http://dwango.co.jp/", TOONZ_PLUGIN_CLASS_POSTPROCESS_SLAB, &toonz_plugin_node_handler)
TOONZ_PLUGIN_PROBE_END;
}