Files
MagicSetEditor2/src/script/functions/image.cpp
T
GenevensiS 436c437189 add compiler directives
add compiler directives
2025-12-30 01:18:04 +01:00

323 lines
12 KiB
C++

//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make card games |
//| Copyright: (C) Twan van Laarhoven and the other MSE developers |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <script/functions/functions.hpp>
#include <script/functions/util.hpp>
#include <script/image.hpp>
// used by the functions
#include <data/set.hpp>
#include <data/card.hpp>
#include <data/stylesheet.hpp>
#include <data/symbol.hpp>
#include <data/field/symbol.hpp>
#include <data/format/formats.hpp>
#include <gfx/generated_image.hpp>
#include <render/symbol/filter.hpp>
void parse_enum(const String&, ImageCombine& out);
// ----------------------------------------------------------------------------- : Utility
SCRIPT_FUNCTION(to_image) {
SCRIPT_PARAM_C(GeneratedImageP, input);
return input;
}
SCRIPT_FUNCTION(to_card_image) {
SCRIPT_PARAM(Set*, set);
SCRIPT_PARAM(CardP, input);
SCRIPT_PARAM_DEFAULT(double, zoom, 100.0);
SCRIPT_PARAM_DEFAULT(Degrees, angle, 0.0);
SCRIPT_PARAM_DEFAULT(double, bleed, 0.0);
SCRIPT_PARAM_DEFAULT(bool, use_user_settings, false);
if (use_user_settings) {
// Use the User's Preferences for Export Zoom, Angle and Bleed settings.
Settings::ExportSettings card_settings = settings.exportSettingsFor(set->stylesheetFor(input));
zoom = card_settings.zoom;
angle = card_settings.angle_radians;
bleed = card_settings.bleed_pixels;
} else {
// Use the provided (or defaulted) Zoom, Angle and Bleed.
zoom = zoom / 100.0;
angle = deg_to_rad(angle);
}
return make_intrusive<ArbitraryImage>(export_image(set, input, true, zoom, angle, bleed));
}
SCRIPT_FUNCTION(import_image) {
SCRIPT_PARAM(Set*, set);
SCRIPT_PARAM(String, input);
return make_intrusive<ImportedImage>(set, input);
}
SCRIPT_FUNCTION(download_image) {
SCRIPT_PARAM(Set*, set);
SCRIPT_PARAM(String, input);
return make_intrusive<DownloadedImage>(set, input);
}
// ----------------------------------------------------------------------------- : Image functions
SCRIPT_FUNCTION(width_of) {
SCRIPT_PARAM(Set*, set);
SCRIPT_PARAM(GeneratedImageP, input);
Image image = input->generate(GeneratedImage::Options(0, 0, set->stylesheet.get()));
SCRIPT_RETURN(image.GetWidth());
}
SCRIPT_FUNCTION(height_of) {
SCRIPT_PARAM(Set*, set);
SCRIPT_PARAM(GeneratedImageP, input);
Image image = input->generate(GeneratedImage::Options(0, 0, set->stylesheet.get()));
SCRIPT_RETURN(image.GetHeight());
}
SCRIPT_FUNCTION(dimensions_of) {
SCRIPT_PARAM(Set*, set);
SCRIPT_PARAM(GeneratedImageP, input);
Image image = input->generate(GeneratedImage::Options(0, 0, set->stylesheet.get()));
ScriptCustomCollectionP ret(new ScriptCustomCollection());
ret->value.push_back(to_script(image.GetWidth()));
ret->value.push_back(to_script(image.GetHeight()));
return ret;
}
SCRIPT_FUNCTION(insert_image) {
SCRIPT_PARAM(GeneratedImageP, base_image);
SCRIPT_PARAM(GeneratedImageP, inserted_image);
SCRIPT_PARAM(int, offset_x);
SCRIPT_PARAM(int, offset_y);
SCRIPT_OPTIONAL_PARAM_(Color, background_color);
return make_intrusive<InsertedImage>(base_image, inserted_image, offset_x, offset_y, background_color);
}
SCRIPT_FUNCTION(linear_blend) {
SCRIPT_PARAM(GeneratedImageP, image1);
SCRIPT_PARAM(GeneratedImageP, image2);
SCRIPT_PARAM(double, x1); SCRIPT_PARAM(double, y1);
SCRIPT_PARAM(double, x2); SCRIPT_PARAM(double, y2);
return make_intrusive<LinearBlendImage>(image1, image2, x1,y1, x2,y2);
}
SCRIPT_FUNCTION(masked_blend) {
SCRIPT_PARAM(GeneratedImageP, light);
SCRIPT_PARAM(GeneratedImageP, dark);
SCRIPT_PARAM(GeneratedImageP, mask);
return make_intrusive<MaskedBlendImage>(light, dark, mask);
}
SCRIPT_FUNCTION(combine_blend) {
SCRIPT_PARAM(String, combine);
SCRIPT_PARAM(GeneratedImageP, image1);
SCRIPT_PARAM(GeneratedImageP, image2);
ImageCombine image_combine;
parse_enum(combine, image_combine);
return make_intrusive<CombineBlendImage>(image1, image2, image_combine);
}
SCRIPT_FUNCTION(set_mask) {
SCRIPT_PARAM(GeneratedImageP, image);
SCRIPT_PARAM(GeneratedImageP, mask);
return make_intrusive<SetMaskImage>(image, mask);
}
SCRIPT_FUNCTION(set_alpha) {
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_PARAM(double, alpha);
return make_intrusive<SetAlphaImage>(input, alpha);
}
SCRIPT_FUNCTION(set_combine) {
SCRIPT_PARAM(String, combine);
SCRIPT_PARAM_C(GeneratedImageP, input);
ImageCombine image_combine;
parse_enum(combine, image_combine);
return make_intrusive<SetCombineImage>(input, image_combine);
}
SCRIPT_FUNCTION(saturate) {
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_PARAM(double, amount);
return make_intrusive<SaturateImage>(input, amount);
}
SCRIPT_FUNCTION(invert_image) {
SCRIPT_PARAM_C(GeneratedImageP, input);
return make_intrusive<InvertImage>(input);
}
SCRIPT_FUNCTION(recolor_image) {
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_OPTIONAL_PARAM(Color, red) {
SCRIPT_PARAM(Color, green);
SCRIPT_PARAM(Color, blue);
SCRIPT_PARAM_DEFAULT(Color, white, Color(255,255,255));
return make_intrusive<RecolorImage2>(input,red,green,blue,white);
} else {
SCRIPT_PARAM(Color, color);
return make_intrusive<RecolorImage>(input,color);
}
}
SCRIPT_FUNCTION(enlarge) {
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_PARAM(double, border_size);
return make_intrusive<EnlargeImage>(input, border_size);
}
SCRIPT_FUNCTION(add_bleed_edge) {
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_PARAM_DEFAULT(double, horizontal_size, -1.0);
SCRIPT_PARAM_DEFAULT(double, vertical_size, -1.0);
SCRIPT_OPTIONAL_PARAM_(Color, background_color);
return make_intrusive<BleedEdgedImage>(input, horizontal_size, vertical_size, background_color);
}
SCRIPT_FUNCTION(resize_image) {
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_PARAM(int, width);
SCRIPT_PARAM(int, height);
return make_intrusive<ResizeImage>(input, width, height);
}
SCRIPT_FUNCTION(crop) {
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_PARAM(int, width);
SCRIPT_PARAM(int, height);
SCRIPT_PARAM(double, offset_x);
SCRIPT_PARAM(double, offset_y);
return make_intrusive<CropImage>(input, width, height, offset_x, offset_y);
}
SCRIPT_FUNCTION(flip_horizontal) {
SCRIPT_PARAM_C(GeneratedImageP, input);
return make_intrusive<FlipImageHorizontal>(input);
}
SCRIPT_FUNCTION(flip_vertical) {
SCRIPT_PARAM_C(GeneratedImageP, input);
return make_intrusive<FlipImageVertical>(input);
}
SCRIPT_FUNCTION(rotate) {
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_PARAM(Degrees, angle);
return make_intrusive<RotateImage>(input,deg_to_rad(angle));
}
SCRIPT_FUNCTION(drop_shadow) {
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_OPTIONAL_PARAM_(double, offset_x);
SCRIPT_OPTIONAL_PARAM_(double, offset_y);
SCRIPT_OPTIONAL_PARAM_(double, alpha);
SCRIPT_OPTIONAL_PARAM_(double, blur_radius);
SCRIPT_OPTIONAL_PARAM_(Color, color);
return make_intrusive<DropShadowImage>(input, offset_x, offset_y, alpha, blur_radius, color);
}
SCRIPT_FUNCTION(symbol_variation) {
// find symbol
SCRIPT_PARAM(ScriptValueP, symbol); // TODO: change to input?
ScriptObject<ValueP>* valueO = dynamic_cast<ScriptObject<ValueP>*>(symbol.get());
SymbolValue* value = valueO ? dynamic_cast<SymbolValue*>(valueO->getValue().get()) : nullptr;
LocalFileName filename;
if (value) {
filename = value->filename;
} else if (valueO) {
throw ScriptErrorConversion(valueO->typeName(), _TYPE_("symbol" ));
} else {
filename = LocalFileName::fromReadString(symbol->toString());
}
// known variation?
SCRIPT_OPTIONAL_PARAM_(String, variation)
if (value && variation_) {
// find style
SCRIPT_PARAM(Set*, set);
SCRIPT_OPTIONAL_PARAM_(CardP, card);
SymbolStyleP style = dynamic_pointer_cast<SymbolStyle>(set->stylesheetForP(card)->styleFor(value->fieldP));
if (!style) throw InternalError(_("Symbol value has a style of the wrong type"));
// find variation
FOR_EACH(v, style->variations) {
if (v->name == variation) {
// found it
return make_intrusive<SymbolToImage>(value, filename, value->last_update, v);
}
}
throw ScriptError(_("Variation of symbol not found ('") + variation + _("')"));
} else {
// custom variation
SCRIPT_PARAM(double, border_radius);
SCRIPT_OPTIONAL_PARAM_(String, fill_type);
SymbolVariationP var(new SymbolVariation);
var->border_radius = border_radius;
if (fill_type == _("solid") || fill_type.empty()) {
SCRIPT_PARAM(Color, fill_color);
SCRIPT_PARAM(Color, border_color);
var->filter = make_intrusive<SolidFillSymbolFilter>(fill_color, border_color);
} else if (fill_type == _("linear gradient")) {
SCRIPT_PARAM(Color, fill_color_1);
SCRIPT_PARAM(Color, border_color_1);
SCRIPT_PARAM(Color, fill_color_2);
SCRIPT_PARAM(Color, border_color_2);
SCRIPT_PARAM(double, center_x);
SCRIPT_PARAM(double, center_y);
SCRIPT_PARAM(double, end_x);
SCRIPT_PARAM(double, end_y);
var->filter = make_intrusive<LinearGradientSymbolFilter>(fill_color_1, border_color_1, fill_color_2, border_color_2, center_x, center_y, end_x, end_y);
} else if (fill_type == _("radial gradient")) {
SCRIPT_PARAM(Color, fill_color_1);
SCRIPT_PARAM(Color, border_color_1);
SCRIPT_PARAM(Color, fill_color_2);
SCRIPT_PARAM(Color, border_color_2);
var->filter = make_intrusive<RadialGradientSymbolFilter>(fill_color_1, border_color_1, fill_color_2, border_color_2);
} else {
throw ScriptError(_("Unknown fill type for symbol_variation: ") + fill_type);
}
return make_intrusive<SymbolToImage>(value, filename, value ? value->last_update : Age(0), var);
}
}
SCRIPT_FUNCTION(built_in_image) {
SCRIPT_PARAM_C(String, input);
return make_intrusive<BuiltInImage>(input);
}
// ----------------------------------------------------------------------------- : Init
void init_script_image_functions(Context& ctx) {
ctx.setVariable(_("to_image"), script_to_image);
ctx.setVariable(_("to_card_image"), script_to_card_image);
ctx.setVariable(_("width_of"), script_width_of);
ctx.setVariable(_("height_of"), script_height_of);
ctx.setVariable(_("dimensions_of"), script_dimensions_of);
ctx.setVariable(_("linear_blend"), script_linear_blend);
ctx.setVariable(_("masked_blend"), script_masked_blend);
ctx.setVariable(_("combine_blend"), script_combine_blend);
ctx.setVariable(_("insert_image"), script_insert_image);
ctx.setVariable(_("set_mask"), script_set_mask);
ctx.setVariable(_("set_alpha"), script_set_alpha);
ctx.setVariable(_("set_combine"), script_set_combine);
ctx.setVariable(_("saturate"), script_saturate);
ctx.setVariable(_("invert_image"), script_invert_image);
ctx.setVariable(_("recolor_image"), script_recolor_image);
ctx.setVariable(_("enlarge"), script_enlarge);
ctx.setVariable(_("add_bleed_edge"), script_add_bleed_edge);
ctx.setVariable(_("resize_image"), script_resize_image);
ctx.setVariable(_("crop"), script_crop);
ctx.setVariable(_("flip_horizontal"), script_flip_horizontal);
ctx.setVariable(_("flip_vertical"), script_flip_vertical);
ctx.setVariable(_("rotate"), script_rotate);
ctx.setVariable(_("rotate_image"), script_rotate);
ctx.setVariable(_("drop_shadow"), script_drop_shadow);
ctx.setVariable(_("symbol_variation"), script_symbol_variation);
ctx.setVariable(_("built_in_image"), script_built_in_image);
ctx.setVariable(_("import_image"), script_import_image);
ctx.setVariable(_("download_image"), script_download_image);
}