Added 'position hint' to packages, used to specify the order of the packages in a package list;
Added 'pack type', intended for playtesting (random boosters/starters); Added 'default(_image)' property to ImageStyle, and added the frame fillers for magic; Added blurring and bold printing (rather hacky) to the text rendering functions (used for "double click to add image" text); Added 'symmetric overlay' combine mode, which will look really nice for hybrids; Moved the watermark choices from the game to an include file in magic-watermarks; Working on a replacement for the image scripting system that plays nicer with the rest of the code. In particular, it will be possible to compare generated images quickly, so they can be updated continuously. This is a work in progress, currently there are two versions of everything. git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@327 0fc631ac-6414-0410-93d0-97cfa31319b6
@@ -529,6 +529,7 @@ type:
|
||||
string: string
|
||||
boolean: boolean
|
||||
color: color
|
||||
image: image
|
||||
nil: nothing
|
||||
|
||||
# Symbol editor shapes
|
||||
|
||||
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,3 @@
|
||||
mse version: 0.3.2
|
||||
full name: Magic The Gathering, placeholder images
|
||||
version: 2007.05.09
|
||||
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,18 @@
|
||||
|
||||
# default image if there is none
|
||||
default_image := {
|
||||
"/magic-default-image.mse-include/" +
|
||||
if input == "white" then "white.jpg"
|
||||
else if input == "blue" then "blue.jpg"
|
||||
else if input == "red" then "red.jpg"
|
||||
else if input == "black" then "black.jpg"
|
||||
else if input == "green" then "green.jpg"
|
||||
else if input == "land 1 color white" then "white.jpg"
|
||||
else if input == "land 1 color blue" then "blue.jpg"
|
||||
else if input == "land 1 color red" then "red.jpg"
|
||||
else if input == "land 1 color black" then "black.jpg"
|
||||
else if input == "land 1 color green" then "green.jpg"
|
||||
else if is_artifact() then "artifact.jpg"
|
||||
else if is_colorless() then "colorless.jpg"
|
||||
else "multicolor.jpg"
|
||||
}
|
||||
|
After Width: | Height: | Size: 7.9 KiB |
@@ -3,6 +3,7 @@ game: magic
|
||||
full name: Extended Art
|
||||
short name: Extended Art
|
||||
icon: card-sample.png
|
||||
position hint: 007
|
||||
|
||||
card width: 375
|
||||
card height: 523
|
||||
@@ -14,6 +15,7 @@ card dpi: 150
|
||||
init script:
|
||||
# Load blend scripts for hybrids/multicolors
|
||||
include file: magic-blends.mse-include/blend-scripts
|
||||
include file: magic-default-image.mse-include/scripts
|
||||
|
||||
# Should hybrids have a grey name?
|
||||
mask_hybrid_with_land := { styling.grey_hybrid_name }
|
||||
@@ -154,6 +156,7 @@ card style:
|
||||
width: 311
|
||||
height: 376
|
||||
z index: 1
|
||||
default: {default_image(card.card_color)}
|
||||
|
||||
############################# Card type
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ game: magic
|
||||
full name: FPM's Flip Magic
|
||||
short name: FPM Flip
|
||||
icon: card-sample.png
|
||||
position hint: 402
|
||||
|
||||
card width: 375
|
||||
card height: 523
|
||||
|
||||
@@ -3,6 +3,7 @@ game: magic
|
||||
full name: FPM's Normal Magic
|
||||
short name: FPM Normal
|
||||
icon: card-sample.png
|
||||
position hint: 401
|
||||
|
||||
card width: 375
|
||||
card height: 523
|
||||
|
||||
@@ -3,6 +3,7 @@ game: magic
|
||||
full name: FPM's Promo Magic
|
||||
short name: FPM Promo
|
||||
icon: card-sample.png
|
||||
position hint: 404
|
||||
|
||||
card width: 375
|
||||
card height: 523
|
||||
|
||||
@@ -3,6 +3,7 @@ game: magic
|
||||
full name: FPM's Split Magic
|
||||
short name: FPM Split
|
||||
icon: card-sample.png
|
||||
position hint: 403
|
||||
|
||||
card width: 523
|
||||
card height: 375
|
||||
|
||||
@@ -3,6 +3,7 @@ game: magic
|
||||
full name: FPM's Token Magic
|
||||
short name: FPM Token
|
||||
icon: card-sample.png
|
||||
position hint: 421
|
||||
|
||||
card width: 375
|
||||
card height: 523
|
||||
|
||||
@@ -3,6 +3,7 @@ game: magic
|
||||
short name: Flip Cards
|
||||
full name: Modern flip cards
|
||||
icon: card-sample.png
|
||||
position hint: 002
|
||||
|
||||
card width: 375
|
||||
card height: 523
|
||||
@@ -17,6 +18,7 @@ card dpi: 150
|
||||
init script:
|
||||
# Load blend scripts for hybrids/multicolors
|
||||
include file: magic-blends.mse-include/blend-scripts
|
||||
include file: magic-default-image.mse-include/scripts
|
||||
|
||||
# Should hybrids have a grey name?
|
||||
# Not supported (yet)
|
||||
@@ -185,6 +187,7 @@ card style:
|
||||
width: 311
|
||||
height: 182
|
||||
z index: 10
|
||||
default: {default_image(card.card_color)}
|
||||
|
||||
############################# Card type
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ game: magic
|
||||
short name: Promotional
|
||||
full name: Large image
|
||||
icon: card-sample.png
|
||||
position hint: 004
|
||||
|
||||
card width: 375
|
||||
card height: 523
|
||||
@@ -13,6 +14,7 @@ card dpi: 150
|
||||
init script:
|
||||
# Load blend scripts for hybrids/multicolors
|
||||
include file: magic-blends.mse-include/blend-scripts
|
||||
include file: magic-default-image.mse-include/scripts
|
||||
|
||||
# Should hybrids have a grey name?
|
||||
mask_hybrid_with_land := { styling.grey_hybrid_name }
|
||||
@@ -162,6 +164,7 @@ card style:
|
||||
width: 311
|
||||
height: 408
|
||||
z index: 1
|
||||
default: {default_image(card.card_color)}
|
||||
|
||||
############################# Card type
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ game: magic
|
||||
short name: Split Cards
|
||||
full name: Modern split cards
|
||||
icon: card-sample.png
|
||||
position hint: 003
|
||||
|
||||
card width: 523
|
||||
card height: 375
|
||||
@@ -16,6 +17,7 @@ card dpi: 150
|
||||
init script:
|
||||
# Load blend scripts for hybrids/multicolors
|
||||
include file: magic-blends.mse-include/blend-scripts
|
||||
include file: magic-default-image.mse-include/scripts
|
||||
|
||||
# Should hybrids have a grey name?
|
||||
mask_hybrid_with_land := { styling.grey_hybrid_name }
|
||||
@@ -185,6 +187,7 @@ card style:
|
||||
width: 216
|
||||
height: 159
|
||||
z index: 1
|
||||
default: {default_image(card.card_color)}
|
||||
|
||||
image 2:
|
||||
left: 279
|
||||
@@ -192,6 +195,7 @@ card style:
|
||||
width: 216
|
||||
height: 159
|
||||
z index: 1
|
||||
default: {default_image(card.card_color_2)}
|
||||
|
||||
############################# Card type
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ game: magic
|
||||
short name: Modern style
|
||||
full name: After 8th edition
|
||||
icon: card-sample.png
|
||||
position hint: 001
|
||||
|
||||
version: 2007-05-05
|
||||
depends on:
|
||||
@@ -21,6 +22,7 @@ card dpi: 150
|
||||
init script:
|
||||
# Load blend scripts for hybrids/multicolors
|
||||
include file: magic-blends.mse-include/blend-scripts
|
||||
include file: magic-default-image.mse-include/scripts
|
||||
|
||||
# Should hybrids have a grey name?
|
||||
mask_hybrid_with_land := { styling.grey_hybrid_name }
|
||||
@@ -53,6 +55,7 @@ init script:
|
||||
else rgb(0,0,0)
|
||||
}
|
||||
|
||||
|
||||
############################################################## Extra style options
|
||||
|
||||
styling field:
|
||||
@@ -125,6 +128,7 @@ card style:
|
||||
right width: 17
|
||||
top width: 17
|
||||
bottom width: 18
|
||||
#mask: border-mask.png
|
||||
z index: -1
|
||||
card color:
|
||||
left: 0
|
||||
@@ -179,6 +183,7 @@ card style:
|
||||
width: 311
|
||||
height: 228
|
||||
z index: 1
|
||||
default: {default_image(card.card_color)}
|
||||
|
||||
############################# Card type
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ game: magic
|
||||
short name: Tokens
|
||||
full name: Old style
|
||||
icon: card-sample.png
|
||||
position hint: 121
|
||||
|
||||
card width: 312
|
||||
card height: 444
|
||||
|
||||
@@ -9,6 +9,7 @@ game: magic
|
||||
short name: Old style
|
||||
full name: Before 8th edition
|
||||
icon: card-sample.png
|
||||
position hint: 101
|
||||
|
||||
card width: 312
|
||||
card height: 444
|
||||
|
||||
@@ -3,6 +3,7 @@ game: magic
|
||||
short name: Planeshifted
|
||||
full name: Planar Chaos Timeshifts
|
||||
icon: card-sample.png
|
||||
position hint: 011
|
||||
|
||||
card width: 375
|
||||
card height: 523
|
||||
|
||||
@@ -3,6 +3,7 @@ game: magic
|
||||
short name: Textless
|
||||
full name: Modern style
|
||||
icon: card-sample.png
|
||||
position hint: 006
|
||||
|
||||
card width: 375
|
||||
card height: 523
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# The watermark choices
|
||||
# Included by a game file
|
||||
|
||||
choice: none
|
||||
choice:
|
||||
name: mana symbol
|
||||
choice: white
|
||||
choice: blue
|
||||
choice: black
|
||||
choice: red
|
||||
choice: green
|
||||
choice: snow
|
||||
choice:
|
||||
name: guild symbol
|
||||
choice: Azorius Senate (W/U)
|
||||
choice: House Dimir (U/B)
|
||||
choice: Cult of Rakdos (B/R)
|
||||
choice: Gruul Clans (R/G)
|
||||
choice: Selesnya Conclave (G/W)
|
||||
choice: Orzhov Syndicate (W/B)
|
||||
choice: The Izzet (U/R)
|
||||
choice: The Golgari (B/G)
|
||||
choice: Boros Legion (R/W)
|
||||
choice: The Simic (G/U)
|
||||
choice:
|
||||
name: xander hybrid mana
|
||||
choice: B/R
|
||||
choice: U/B
|
||||
choice: B/G
|
||||
choice: R/G
|
||||
choice: G/U
|
||||
choice: U/R
|
||||
choice: W/B
|
||||
choice: G/W
|
||||
choice: R/W
|
||||
choice: W/U
|
||||
@@ -3,6 +3,7 @@ short name: Magic
|
||||
full name: Magic the Gathering
|
||||
icon: card-back.png
|
||||
version: 2007-05-05
|
||||
position hint: 1
|
||||
|
||||
############################################################## Functions & filters
|
||||
|
||||
@@ -618,39 +619,7 @@ card field:
|
||||
type: choice
|
||||
name: watermark
|
||||
icon: stats/watermark.png
|
||||
choice: none
|
||||
choice:
|
||||
name: mana symbol
|
||||
choice: white
|
||||
choice: blue
|
||||
choice: black
|
||||
choice: red
|
||||
choice: green
|
||||
choice: snow
|
||||
choice:
|
||||
name: guild symbol
|
||||
choice: Azorius Senate (W/U)
|
||||
choice: House Dimir (U/B)
|
||||
choice: Cult of Rakdos (B/R)
|
||||
choice: Gruul Clans (R/G)
|
||||
choice: Selesnya Conclave (G/W)
|
||||
choice: Orzhov Syndicate (W/B)
|
||||
choice: The Izzet (U/R)
|
||||
choice: The Golgari (B/G)
|
||||
choice: Boros Legion (R/W)
|
||||
choice: The Simic (G/U)
|
||||
choice:
|
||||
name: xander hybrid mana
|
||||
choice: B/R
|
||||
choice: U/B
|
||||
choice: B/G
|
||||
choice: R/G
|
||||
choice: G/U
|
||||
choice: U/R
|
||||
choice: W/B
|
||||
choice: G/W
|
||||
choice: R/W
|
||||
choice: W/U
|
||||
include file: magic-watermarks.mse-include/watermark-names
|
||||
description: A watermark for below the textbox, this can be a big mana symbol used on basic lands, or a guild symbol
|
||||
|
||||
############################# PT
|
||||
@@ -669,6 +638,7 @@ card field:
|
||||
name: ptsymbols
|
||||
choice: shieldsword
|
||||
editable: false
|
||||
save value: false
|
||||
show statistics: false
|
||||
card field:
|
||||
type: text
|
||||
@@ -848,39 +818,7 @@ card field:
|
||||
card field:
|
||||
type: choice
|
||||
name: watermark 2
|
||||
choice: none
|
||||
choice:
|
||||
name: mana symbol
|
||||
choice: white
|
||||
choice: blue
|
||||
choice: black
|
||||
choice: red
|
||||
choice: green
|
||||
choice: snow
|
||||
choice:
|
||||
name: xander hybrid mana
|
||||
choice: B/R
|
||||
choice: U/B
|
||||
choice: B/G
|
||||
choice: R/G
|
||||
choice: G/U
|
||||
choice: U/R
|
||||
choice: W/B
|
||||
choice: G/W
|
||||
choice: R/W
|
||||
choice: W/U
|
||||
choice:
|
||||
name: guild symbol
|
||||
choice: Azorius Senate (W/U)
|
||||
choice: House Dimir (U/B)
|
||||
choice: Cult of Rakdos (B/R)
|
||||
choice: Gruul Clans (R/G)
|
||||
choice: Selesnya Conclave (G/W)
|
||||
choice: Orzhov Syndicate (W/B)
|
||||
choice: The Izzet (U/R)
|
||||
choice: The Golgari (B/G)
|
||||
choice: Boros Legion (R/W)
|
||||
choice: The Simic (G/U)
|
||||
include file: magic-watermarks.mse-include/watermark-names
|
||||
description: A watermark for below the textbox, this can be a big mana symbol used on basic lands, a special symbol, or a guild symbol
|
||||
card field:
|
||||
type: text
|
||||
@@ -899,6 +837,7 @@ card field:
|
||||
name: ptsymbols 2
|
||||
choice: shieldsword
|
||||
editable: false
|
||||
save value: false
|
||||
show statistics: false
|
||||
card field:
|
||||
type: text
|
||||
@@ -1053,25 +992,36 @@ statistics dimension:
|
||||
|
||||
|
||||
|
||||
############################################################## Add multiple cards
|
||||
|
||||
#set template:
|
||||
# name: Base set (??? cards)
|
||||
#set template:
|
||||
# name: Expansion set (134 cards)
|
||||
#set template:
|
||||
# name: 5 color cycle
|
||||
# field: rarity
|
||||
#set template:
|
||||
# name: 3 rarities cycle
|
||||
|
||||
############################################################## Card packs
|
||||
|
||||
#pack:
|
||||
# name: Base set
|
||||
# pack type:
|
||||
#pack:
|
||||
# name:
|
||||
#pack:
|
||||
# name: Booster
|
||||
# pack type: random
|
||||
# card type:
|
||||
# amount: 1
|
||||
# filter: rarity = "rare"
|
||||
# card type:
|
||||
# amount: 3
|
||||
# filter: rarity = "uncommon"
|
||||
# card type:
|
||||
# amount: 11
|
||||
# filter: rarity = "common"
|
||||
pack type:
|
||||
name: Starter pack
|
||||
pack type:
|
||||
name: Booster pack
|
||||
card type:
|
||||
name: Rare
|
||||
amount: 1
|
||||
filter: card.rarity = "rare"
|
||||
card type:
|
||||
name: Uncommon
|
||||
amount: 3
|
||||
filter: card.rarity = "uncommon"
|
||||
card type:
|
||||
name: Common
|
||||
amount: 11
|
||||
filter: card.rarity = "common"
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
short name: Vanguard
|
||||
full name: Magic Vanguard
|
||||
icon: card-sample.png
|
||||
position hint: 2
|
||||
|
||||
# Author : Wolfwood
|
||||
# Most stuff is copy/pasted from magic.mse-game
|
||||
|
||||
@@ -3,6 +3,7 @@ game: vs
|
||||
short name: Promotional
|
||||
full name: Extended Art Promo
|
||||
icon: card-sample.png
|
||||
position hint: 2
|
||||
|
||||
card width: 375
|
||||
card height: 523
|
||||
|
||||
@@ -3,6 +3,7 @@ game: vs
|
||||
short name: Standard
|
||||
full name: Normal VS cards
|
||||
icon: card-sample.png
|
||||
position hint: 1
|
||||
|
||||
card width: 375
|
||||
card height: 523
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
mse version: 0.3.1
|
||||
short name: VS System
|
||||
icon: card-back.png
|
||||
position hint: 3
|
||||
|
||||
############################################################## Functions & filters
|
||||
## Copied and Pasted from magic-new.mse-style/style, with a few modifications
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
mse version: 0.3.1
|
||||
short name: Yu-Gi-Oh!
|
||||
icon: card-back.png
|
||||
position hint: 4
|
||||
|
||||
############################################################## Functions & filters
|
||||
## Copied and Pasted from vs.mse-game, with a few modifications
|
||||
|
||||
@@ -24,17 +24,24 @@ String ValueAction::getName(bool to_undo) const {
|
||||
|
||||
// ----------------------------------------------------------------------------- : Simple
|
||||
|
||||
/// Swap the value in a Value object with a new one
|
||||
inline void swap_value(ChoiceValue& a, ChoiceValue ::ValueType& b) { swap(a.value, b); }
|
||||
inline void swap_value(MultipleChoiceValue& a, MultipleChoiceValue::ValueType& b) { swap(a.value, b); }
|
||||
inline void swap_value(ColorValue& a, ColorValue ::ValueType& b) { swap(a.value, b); }
|
||||
inline void swap_value(ImageValue& a, ImageValue ::ValueType& b) { swap(a.filename, b); a.last_update.update(); }
|
||||
inline void swap_value(SymbolValue& a, SymbolValue ::ValueType& b) { swap(a.filename, b); a.last_update.update(); }
|
||||
inline void swap_value(TextValue& a, TextValue ::ValueType& b) { swap(a.value, b); a.last_update.update(); }
|
||||
|
||||
/// A ValueAction that swaps between old and new values
|
||||
template <typename T, bool ALLOW_MERGE>
|
||||
class SimpleValueAction : public ValueAction {
|
||||
public:
|
||||
inline SimpleValueAction(const shared_ptr<T>& value, const typename T::ValueType& new_value, typename T::ValueType T::*member)
|
||||
inline SimpleValueAction(const shared_ptr<T>& value, const typename T::ValueType& new_value)
|
||||
: ValueAction(value), new_value(new_value)
|
||||
, member(member)
|
||||
{}
|
||||
|
||||
virtual void perform(bool to_undo) {
|
||||
swap(static_cast<T&>(*valueP).*member, new_value);
|
||||
swap_value(static_cast<T&>(*valueP), new_value);
|
||||
valueP->onAction(*this, to_undo); // notify value
|
||||
}
|
||||
|
||||
@@ -52,14 +59,13 @@ class SimpleValueAction : public ValueAction {
|
||||
|
||||
private:
|
||||
typename T::ValueType new_value;
|
||||
typename T::ValueType T::*member;
|
||||
};
|
||||
|
||||
ValueAction* value_action(const ChoiceValueP& value, const Defaultable<String>& new_value) { return new SimpleValueAction<ChoiceValue, true> (value, new_value, &ChoiceValue::value); }
|
||||
ValueAction* value_action(const MultipleChoiceValueP& value, const Defaultable<String>& new_value) { return new SimpleValueAction<MultipleChoiceValue, false>(value, new_value, &MultipleChoiceValue::value); }
|
||||
ValueAction* value_action(const ColorValueP& value, const Defaultable<Color>& new_value) { return new SimpleValueAction<ColorValue, true> (value, new_value, &ColorValue::value); }
|
||||
ValueAction* value_action(const ImageValueP& value, const FileName& new_value) { return new SimpleValueAction<ImageValue, false>(value, new_value, &ImageValue::filename); }
|
||||
ValueAction* value_action(const SymbolValueP& value, const FileName& new_value) { return new SimpleValueAction<SymbolValue, false>(value, new_value, &SymbolValue::filename); }
|
||||
ValueAction* value_action(const ChoiceValueP& value, const Defaultable<String>& new_value) { return new SimpleValueAction<ChoiceValue, true> (value, new_value); }
|
||||
ValueAction* value_action(const MultipleChoiceValueP& value, const Defaultable<String>& new_value) { return new SimpleValueAction<MultipleChoiceValue, false>(value, new_value); }
|
||||
ValueAction* value_action(const ColorValueP& value, const Defaultable<Color>& new_value) { return new SimpleValueAction<ColorValue, true> (value, new_value); }
|
||||
ValueAction* value_action(const ImageValueP& value, const FileName& new_value) { return new SimpleValueAction<ImageValue, false>(value, new_value); }
|
||||
ValueAction* value_action(const SymbolValueP& value, const FileName& new_value) { return new SimpleValueAction<SymbolValue, false>(value, new_value); }
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Text
|
||||
@@ -74,8 +80,7 @@ TextValueAction::TextValueAction(const TextValueP& value, size_t start, size_t e
|
||||
String TextValueAction::getName(bool to_undo) const { return name; }
|
||||
|
||||
void TextValueAction::perform(bool to_undo) {
|
||||
swap(value().value, new_value);
|
||||
value().last_update.update();
|
||||
swap_value(value(), new_value);
|
||||
swap(selection_end, new_selection_end);
|
||||
valueP->onAction(*this, to_undo); // notify value
|
||||
}
|
||||
|
||||
@@ -26,11 +26,13 @@ IMPLEMENT_REFLECTION(ImageField) {
|
||||
IMPLEMENT_REFLECTION(ImageStyle) {
|
||||
REFLECT_BASE(Style);
|
||||
REFLECT_N("mask", mask_filename);
|
||||
REFLECT_N("default", default_image);
|
||||
}
|
||||
|
||||
bool ImageStyle::update(Context& ctx) {
|
||||
return Style ::update(ctx)
|
||||
| mask_filename.update(ctx);
|
||||
| mask_filename.update(ctx)
|
||||
| default_image.update(ctx);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : ImageValue
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <util/prec.hpp>
|
||||
#include <data/field.hpp>
|
||||
#include <script/scriptable.hpp>
|
||||
#include <script/image.hpp>
|
||||
|
||||
// ----------------------------------------------------------------------------- : ImageField
|
||||
|
||||
@@ -38,6 +39,7 @@ class ImageStyle : public Style {
|
||||
DECLARE_STYLE_TYPE(Image);
|
||||
|
||||
Scriptable<String> mask_filename; ///< Filename for a mask image
|
||||
ScriptableImage2 default_image; ///< Placeholder
|
||||
|
||||
virtual bool update(Context&);
|
||||
|
||||
@@ -53,7 +55,8 @@ class ImageValue : public Value {
|
||||
inline ImageValue(const ImageFieldP& field) : Value(field) {}
|
||||
|
||||
typedef FileName ValueType;
|
||||
ValueType filename; ///< Filename of the image (in the current package), or ""
|
||||
ValueType filename; ///< Filename of the image (in the current package), or ""
|
||||
Age last_update; ///< When was the image last changed?
|
||||
|
||||
virtual String toString() const;
|
||||
|
||||
|
||||
@@ -29,11 +29,11 @@ IMPLEMENT_REFLECTION(SymbolStyle) {
|
||||
REFLECT(variations);
|
||||
}
|
||||
|
||||
SymbolStyle::Variation::Variation()
|
||||
SymbolVariation::SymbolVariation()
|
||||
: border_radius(0.05)
|
||||
{}
|
||||
|
||||
IMPLEMENT_REFLECTION(SymbolStyle::Variation) {
|
||||
IMPLEMENT_REFLECTION(SymbolVariation) {
|
||||
REFLECT(name);
|
||||
REFLECT(border_radius);
|
||||
REFLECT_NAMELESS(filter);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <script/scriptable.hpp>
|
||||
|
||||
DECLARE_POINTER_TYPE(SymbolFilter);
|
||||
DECLARE_POINTER_TYPE(SymbolVariation);
|
||||
|
||||
// ----------------------------------------------------------------------------- : SymbolField
|
||||
|
||||
@@ -39,18 +40,16 @@ class SymbolStyle : public Style {
|
||||
inline SymbolStyle(const SymbolFieldP& field) : Style(field) {}
|
||||
DECLARE_STYLE_TYPE(Symbol);
|
||||
|
||||
class Variation;
|
||||
typedef shared_ptr<Variation> VariationP;
|
||||
vector<VariationP> variations; ///< Different variantions of the same symbol
|
||||
vector<SymbolVariationP> variations; ///< Different variantions of the same symbol
|
||||
|
||||
private:
|
||||
DECLARE_REFLECTION();
|
||||
};
|
||||
|
||||
/// Styling for a symbol variation, defines color, border, etc.
|
||||
class SymbolStyle::Variation {
|
||||
class SymbolVariation {
|
||||
public:
|
||||
Variation();
|
||||
SymbolVariation();
|
||||
String name; ///< Name of this variation
|
||||
SymbolFilterP filter; ///< Filter to color the symbol
|
||||
double border_radius; ///< Border radius for the symbol
|
||||
@@ -66,7 +65,8 @@ class SymbolValue : public Value {
|
||||
DECLARE_HAS_FIELD(Symbol)
|
||||
|
||||
typedef FileName ValueType;
|
||||
ValueType filename; ///< Filename of the symbol (in the current package)
|
||||
ValueType filename; ///< Filename of the symbol (in the current package)
|
||||
Age last_update; ///< When was the symbol last changed?
|
||||
|
||||
virtual String toString() const;
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <data/field.hpp>
|
||||
#include <data/keyword.hpp>
|
||||
#include <data/statistics.hpp>
|
||||
#include <data/pack.hpp>
|
||||
#include <util/io/package_manager.hpp>
|
||||
#include <script/script.hpp>
|
||||
|
||||
@@ -47,6 +48,7 @@ IMPLEMENT_REFLECTION(Game) {
|
||||
REFLECT(card_fields);
|
||||
REFLECT(statistics_dimensions);
|
||||
REFLECT(statistics_categories);
|
||||
REFLECT(pack_types);
|
||||
REFLECT(has_keywords);
|
||||
REFLECT(keyword_modes);
|
||||
REFLECT(keyword_parameter_types);
|
||||
|
||||
@@ -20,6 +20,7 @@ DECLARE_POINTER_TYPE(Style);
|
||||
DECLARE_POINTER_TYPE(Game);
|
||||
DECLARE_POINTER_TYPE(StatsDimension);
|
||||
DECLARE_POINTER_TYPE(StatsCategory);
|
||||
DECLARE_POINTER_TYPE(PackType);
|
||||
DECLARE_POINTER_TYPE(KeywordParam);
|
||||
DECLARE_POINTER_TYPE(KeywordMode);
|
||||
DECLARE_POINTER_TYPE(Keyword);
|
||||
@@ -40,6 +41,7 @@ class Game : public Packaged {
|
||||
vector<FieldP> card_fields; ///< Fields on each card
|
||||
vector<StatsDimensionP> statistics_dimensions; ///< (Additional) statistics dimensions
|
||||
vector<StatsCategoryP> statistics_categories; ///< (Additional) statistics categories
|
||||
vector<PackTypeP> pack_types; ///< Types of random card packs to generate
|
||||
|
||||
bool has_keywords; ///< Does this game use keywords?
|
||||
vector<KeywordParamP> keyword_parameter_types;///< Types of keyword parameters
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||
//| Copyright: (C) 2001 - 2007 Twan van Laarhoven |
|
||||
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||
//+----------------------------------------------------------------------------+
|
||||
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <data/pack.hpp>
|
||||
|
||||
// ----------------------------------------------------------------------------- : PackType
|
||||
|
||||
PackType::PackType()
|
||||
: enabled(true)
|
||||
{}
|
||||
|
||||
IMPLEMENT_REFLECTION(PackType) {
|
||||
REFLECT(name);
|
||||
REFLECT(enabled);
|
||||
REFLECT(card_types);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : CardType
|
||||
|
||||
IMPLEMENT_REFLECTION(CardType) {
|
||||
REFLECT(name);
|
||||
REFLECT(amount);
|
||||
REFLECT(filter);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||
//| Copyright: (C) 2001 - 2007 Twan van Laarhoven |
|
||||
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||
//+----------------------------------------------------------------------------+
|
||||
|
||||
#ifndef HEADER_DATA_PACK
|
||||
#define HEADER_DATA_PACK
|
||||
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <util/prec.hpp>
|
||||
#include <util/reflect.hpp>
|
||||
#include <script/scriptable.hpp>
|
||||
|
||||
DECLARE_POINTER_TYPE(CardType);
|
||||
DECLARE_POINTER_TYPE(Card);
|
||||
class Set;
|
||||
|
||||
// ----------------------------------------------------------------------------- : PackType
|
||||
|
||||
/// A card pack description for playtesting
|
||||
class PackType {
|
||||
public:
|
||||
PackType();
|
||||
|
||||
String name; ///< Name of this pack
|
||||
vector<CardTypeP> card_types; ///< Cards in this pack
|
||||
Scriptable<bool> enabled; ///< Is this pack enabled?
|
||||
|
||||
/// Generate a random pack of cards
|
||||
void generate(Set& set, vector<CardP>& out);
|
||||
|
||||
private:
|
||||
DECLARE_REFLECTION();
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : CardType
|
||||
|
||||
/// A card type description for playtesting
|
||||
class CardType {
|
||||
public:
|
||||
String name; ///< Name of this type of cards
|
||||
Scriptable<int> amount; ///< Number of cards of this type
|
||||
OptionalScript filter; ///< Filter to select this type of cards
|
||||
private:
|
||||
DECLARE_REFLECTION();
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
#endif
|
||||
@@ -38,6 +38,7 @@ IMPLEMENT_REFLECTION_ENUM(ImageCombine) {
|
||||
VALUE_N("or", COMBINE_OR);
|
||||
VALUE_N("xor", COMBINE_XOR);
|
||||
VALUE_N("shadow", COMBINE_SHADOW);
|
||||
VALUE_N("symmetric overlay",COMBINE_SYMMETRIC_OVERLAY);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Combining functions
|
||||
@@ -81,6 +82,7 @@ COMBINE_FUN(COMBINE_AND, a & b )
|
||||
COMBINE_FUN(COMBINE_OR, a | b )
|
||||
COMBINE_FUN(COMBINE_XOR, a ^ b )
|
||||
COMBINE_FUN(COMBINE_SHADOW, (b * a * a) / (255 * 255) )
|
||||
COMBINE_FUN(COMBINE_SYMMETRIC_OVERLAY, (Combine<COMBINE_OVERLAY>::f(a,b) + Combine<COMBINE_OVERLAY>::f(b,a)) / 2 )
|
||||
|
||||
// ----------------------------------------------------------------------------- : Combining
|
||||
|
||||
@@ -131,6 +133,7 @@ void combine_image(Image& a, const Image& b, ImageCombine combine) {
|
||||
DISPATCH(COMBINE_OR);
|
||||
DISPATCH(COMBINE_XOR);
|
||||
DISPATCH(COMBINE_SHADOW);
|
||||
DISPATCH(COMBINE_SYMMETRIC_OVERLAY);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||
//| Copyright: (C) 2001 - 2007 Twan van Laarhoven |
|
||||
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||
//+----------------------------------------------------------------------------+
|
||||
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <gfx/generated_image.hpp>
|
||||
#include <util/io/package.hpp>
|
||||
#include <util/error.hpp>
|
||||
#include <data/symbol.hpp>
|
||||
#include <data/field/symbol.hpp>
|
||||
#include <render/symbol/filter.hpp>
|
||||
#include <gui/util.hpp> // load_resource_image
|
||||
|
||||
// ----------------------------------------------------------------------------- : GeneratedImage
|
||||
|
||||
ScriptType GeneratedImage::type() const { return SCRIPT_IMAGE; }
|
||||
String GeneratedImage::typeName() const { return _TYPE_("image"); }
|
||||
|
||||
// ----------------------------------------------------------------------------- : LinearBlendImage
|
||||
|
||||
Image LinearBlendImage::generate(const Options& opt) const {
|
||||
Image img = image1->generate(opt);
|
||||
linear_blend(img, image2->generate(opt), x1, y1, x2, y2);
|
||||
return img;
|
||||
}
|
||||
ImageCombine LinearBlendImage::combine() const {
|
||||
return image1->combine();
|
||||
}
|
||||
bool LinearBlendImage::operator == (const GeneratedImage& that) const {
|
||||
const LinearBlendImage* that2 = dynamic_cast<const LinearBlendImage*>(&that);
|
||||
return that2 && *image1 == *that2->image1
|
||||
&& *image2 == *that2->image2
|
||||
&& x1 == that2->x1 && y1 == that2->y1
|
||||
&& x2 == that2->x2 && y2 == that2->y2;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : MaskedBlendImage
|
||||
|
||||
Image MaskedBlendImage::generate(const Options& opt) const {
|
||||
Image img = light->generate(opt);
|
||||
mask_blend(img, dark->generate(opt), mask->generate(opt));
|
||||
return img;
|
||||
}
|
||||
ImageCombine MaskedBlendImage::combine() const {
|
||||
return light->combine();
|
||||
}
|
||||
bool MaskedBlendImage::operator == (const GeneratedImage& that) const {
|
||||
const MaskedBlendImage* that2 = dynamic_cast<const MaskedBlendImage*>(&that);
|
||||
return that2 && *light == *that2->light
|
||||
&& *dark == *that2->dark
|
||||
&& *mask == *that2->mask;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : CombineBlendImage
|
||||
|
||||
Image CombineBlendImage::generate(const Options& opt) const {
|
||||
Image img = image1->generate(opt);
|
||||
combine_image(img, image2->generate(opt), image_combine);
|
||||
return img;
|
||||
}
|
||||
ImageCombine CombineBlendImage::combine() const {
|
||||
return image1->combine();
|
||||
}
|
||||
bool CombineBlendImage::operator == (const GeneratedImage& that) const {
|
||||
const CombineBlendImage* that2 = dynamic_cast<const CombineBlendImage*>(&that);
|
||||
return that2 && *image1 == *that2->image1
|
||||
&& *image2 == *that2->image2
|
||||
&& image_combine == that2->image_combine;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : SetMaskImage
|
||||
|
||||
Image SetMaskImage::generate(const Options& opt) const {
|
||||
Image img = image->generate(opt);
|
||||
set_alpha(img, mask->generate(opt));
|
||||
return img;
|
||||
}
|
||||
ImageCombine SetMaskImage::combine() const {
|
||||
return image->combine();
|
||||
}
|
||||
bool SetMaskImage::operator == (const GeneratedImage& that) const {
|
||||
const SetMaskImage* that2 = dynamic_cast<const SetMaskImage*>(&that);
|
||||
return that2 && *image == *that2->image
|
||||
&& *mask == *that2->mask;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : SetCombineImage
|
||||
|
||||
Image SetCombineImage::generate(const Options& opt) const {
|
||||
return image->generate(opt);
|
||||
}
|
||||
ImageCombine SetCombineImage::combine() const {
|
||||
return image->combine();
|
||||
}
|
||||
bool SetCombineImage::operator == (const GeneratedImage& that) const {
|
||||
const SetCombineImage* that2 = dynamic_cast<const SetCombineImage*>(&that);
|
||||
return that2 && *image == *that2->image
|
||||
&& image_combine == that2->image_combine;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : PackagedImage
|
||||
|
||||
Image PackagedImage::generate(const Options& opt) const {
|
||||
// TODO : use opt.width and opt.height?
|
||||
// open file from package
|
||||
if (!opt.package) throw ScriptError(_("Can only load images in a context where an image is expected"));
|
||||
InputStreamP file = opt.package->openIn(filename);
|
||||
Image img;
|
||||
if (img.LoadFile(*file)) {
|
||||
if (img.HasMask()) img.InitAlpha(); // we can't handle masks
|
||||
return img;
|
||||
} else {
|
||||
throw ScriptError(_("Unable to load image '") + filename + _("' from '" + opt.package->name() + _("'")));
|
||||
}
|
||||
}
|
||||
bool PackagedImage::operator == (const GeneratedImage& that) const {
|
||||
const PackagedImage* that2 = dynamic_cast<const PackagedImage*>(&that);
|
||||
return that2 && filename == that2->filename;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : BuiltInImage
|
||||
|
||||
Image BuiltInImage::generate(const Options& opt) const {
|
||||
// TODO : use opt.width and opt.height?
|
||||
Image img = load_resource_image(name);
|
||||
if (!img.Ok()) {
|
||||
throw ScriptError(_("There is no build in image '") + name + _("'"));
|
||||
}
|
||||
return img;
|
||||
}
|
||||
bool BuiltInImage::operator == (const GeneratedImage& that) const {
|
||||
const BuiltInImage* that2 = dynamic_cast<const BuiltInImage*>(&that);
|
||||
return that2 && name == that2->name;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : SymbolToImage
|
||||
|
||||
Image SymbolToImage::generate(const Options& opt) const {
|
||||
// TODO : use opt.width and opt.height?
|
||||
if (!opt.symbol_package) throw ScriptError(_("Can only load images in a context where an image is expected"));
|
||||
SymbolP the_symbol;
|
||||
if (filename.empty()) {
|
||||
the_symbol = default_symbol();
|
||||
} else {
|
||||
the_symbol = opt.symbol_package->readFile<SymbolP>(filename);
|
||||
}
|
||||
return render_symbol(the_symbol, *variation->filter, variation->border_radius);
|
||||
}
|
||||
bool SymbolToImage::operator == (const GeneratedImage& that) const {
|
||||
const SymbolToImage* that2 = dynamic_cast<const SymbolToImage*>(&that);
|
||||
return that2 && filename == that2->filename
|
||||
&& age == that2->age
|
||||
&& variation == that2->variation;
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||
//| Copyright: (C) 2001 - 2007 Twan van Laarhoven |
|
||||
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||
//+----------------------------------------------------------------------------+
|
||||
|
||||
#ifndef HEADER_GFX_GENERATED_IMAGE
|
||||
#define HEADER_GFX_GENERATED_IMAGE
|
||||
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <util/prec.hpp>
|
||||
#include <util/age.hpp>
|
||||
#include <gfx/gfx.hpp>
|
||||
#include <script/value.hpp>
|
||||
|
||||
DECLARE_INTRUSIVE_POINTER_TYPE(GeneratedImage);
|
||||
DECLARE_POINTER_TYPE(SymbolVariation);
|
||||
class Package;
|
||||
|
||||
// ----------------------------------------------------------------------------- : GeneratedImage
|
||||
|
||||
/// An image that is generated from a script.
|
||||
/** The actual generation is independend of the script execution
|
||||
*/
|
||||
class GeneratedImage : public ScriptValue {
|
||||
public:
|
||||
/// Options for generating the image
|
||||
struct Options {
|
||||
Options(int width = 0, int height = 0, Package* package = nullptr, Package* symbol_package = nullptr, PreserveAspect preserve_aspect = ASPECT_STRETCH, bool saturate = false)
|
||||
: width(width), height(height), preserve_aspect(preserve_aspect), saturate(saturate), package(package), symbol_package(symbol_package)
|
||||
{}
|
||||
|
||||
int width, height; ///< Width to force the image to, or 0 to keep the width of the input
|
||||
PreserveAspect preserve_aspect;
|
||||
bool saturate;
|
||||
Package* package; ///< Package to load images from
|
||||
Package* symbol_package; ///< Package to load symbols from
|
||||
};
|
||||
|
||||
/// Generate the image
|
||||
virtual Image generate(const Options&) const = 0;
|
||||
/// How must the image be combined with the background?
|
||||
virtual ImageCombine combine() const { return COMBINE_NORMAL; }
|
||||
/// Equality should mean that every pixel in the generated images is the same if the same options are used
|
||||
virtual bool operator == (const GeneratedImage& that) const = 0;
|
||||
inline bool operator != (const GeneratedImage& that) const { return !(*this == that); }
|
||||
|
||||
virtual ScriptType type() const;
|
||||
virtual String typeName() const;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : LinearBlendImage
|
||||
|
||||
/// An image generator that linearly blends two other images
|
||||
class LinearBlendImage : public GeneratedImage {
|
||||
public:
|
||||
inline LinearBlendImage(const GeneratedImageP& image1, const GeneratedImageP& image2, double x1, double y1, double x2, double y2)
|
||||
: image1(image1), image2(image2), x1(x1), y1(y1), x2(x2), y2(y2)
|
||||
{}
|
||||
virtual Image generate(const Options& opt) const;
|
||||
virtual ImageCombine combine() const;
|
||||
virtual bool operator == (const GeneratedImage& that) const;
|
||||
private:
|
||||
GeneratedImageP image1, image2;
|
||||
double x1, y1, x2, y2;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : MaskedBlendImage
|
||||
|
||||
/// An image generator that blends two other images using a third as a mask
|
||||
class MaskedBlendImage : public GeneratedImage {
|
||||
public:
|
||||
inline MaskedBlendImage(const GeneratedImageP& light, const GeneratedImageP& dark, const GeneratedImageP& mask)
|
||||
: light(light), dark(dark), mask(mask)
|
||||
{}
|
||||
virtual Image generate(const Options& opt) const;
|
||||
virtual ImageCombine combine() const;
|
||||
virtual bool operator == (const GeneratedImage& that) const;
|
||||
private:
|
||||
GeneratedImageP light, dark, mask;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : CombineBlendImage
|
||||
|
||||
/// An image generator that blends two other images using an ImageCombine function
|
||||
class CombineBlendImage : public GeneratedImage {
|
||||
public:
|
||||
inline CombineBlendImage(const GeneratedImageP& image1, const GeneratedImageP& image2, ImageCombine image_combine)
|
||||
: image1(image1), image2(image2), image_combine(image_combine)
|
||||
{}
|
||||
virtual Image generate(const Options& opt) const;
|
||||
virtual ImageCombine combine() const;
|
||||
virtual bool operator == (const GeneratedImage& that) const;
|
||||
private:
|
||||
GeneratedImageP image1, image2;
|
||||
ImageCombine image_combine;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : SetMaskImage
|
||||
|
||||
/// Change the alpha channel of an image
|
||||
class SetMaskImage : public GeneratedImage {
|
||||
public:
|
||||
inline SetMaskImage(const GeneratedImageP& image, const GeneratedImageP& mask)
|
||||
: image(image), mask(mask)
|
||||
{}
|
||||
virtual Image generate(const Options& opt) const;
|
||||
virtual ImageCombine combine() const;
|
||||
virtual bool operator == (const GeneratedImage& that) const;
|
||||
private:
|
||||
GeneratedImageP image, mask;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : SetCombineImage
|
||||
|
||||
/// Change the combine mode
|
||||
class SetCombineImage : public GeneratedImage {
|
||||
public:
|
||||
inline SetCombineImage(const GeneratedImageP& image, ImageCombine image_combine)
|
||||
: image(image), image_combine(image_combine)
|
||||
{}
|
||||
virtual Image generate(const Options& opt) const;
|
||||
virtual ImageCombine combine() const;
|
||||
virtual bool operator == (const GeneratedImage& that) const;
|
||||
private:
|
||||
GeneratedImageP image;
|
||||
ImageCombine image_combine;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : PackagedImage
|
||||
|
||||
/// Load an image from a file in a package
|
||||
class PackagedImage : public GeneratedImage {
|
||||
public:
|
||||
inline PackagedImage(const String& filename)
|
||||
: filename(filename)
|
||||
{}
|
||||
virtual Image generate(const Options& opt) const;
|
||||
virtual bool operator == (const GeneratedImage& that) const;
|
||||
private:
|
||||
String filename;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : BuiltInImage
|
||||
|
||||
/// Return a built in image
|
||||
class BuiltInImage : public GeneratedImage {
|
||||
public:
|
||||
inline BuiltInImage(const String& name)
|
||||
: name(name)
|
||||
{}
|
||||
virtual Image generate(const Options& opt) const;
|
||||
virtual bool operator == (const GeneratedImage& that) const;
|
||||
private:
|
||||
String name;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : SymbolToImage
|
||||
|
||||
/// Use a symbol as an image
|
||||
class SymbolToImage : public GeneratedImage {
|
||||
public:
|
||||
inline SymbolToImage(const String& filename, Age age, const SymbolVariationP& variation)
|
||||
: filename(filename), age(age), variation(variation)
|
||||
{}
|
||||
virtual Image generate(const Options& opt) const;
|
||||
virtual bool operator == (const GeneratedImage& that) const;
|
||||
private:
|
||||
String filename;
|
||||
Age age; ///< Age the symbol was last updated
|
||||
SymbolVariationP variation;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
#endif
|
||||
@@ -48,7 +48,7 @@ void sharp_resample_and_clip(const Image& img_in, Image& img_out, wxRect rect, i
|
||||
* rect = rectangle to draw in
|
||||
* (wc,hc) = the corner where drawing should begin, (0,0) for top-left, (1,1) for bottom-right
|
||||
*/
|
||||
void draw_resampled_text(DC& dc, const RealRect& rect, int wc, int hc, int angle, const String& text);
|
||||
void draw_resampled_text(DC& dc, const RealRect& rect, int wc, int hc, int angle, const String& text, int blur_radius = 0, int repeat = 1);
|
||||
|
||||
// scaling factor to use when drawing resampled text
|
||||
extern const int text_scaling;
|
||||
@@ -107,6 +107,7 @@ enum ImageCombine
|
||||
, COMBINE_OR
|
||||
, COMBINE_XOR
|
||||
, COMBINE_SHADOW
|
||||
, COMBINE_SYMMETRIC_OVERLAY
|
||||
};
|
||||
|
||||
/// Combine image b onto image a using some combining function.
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <util/error.hpp>
|
||||
#include <gui/util.hpp> // clearDC_black
|
||||
|
||||
void blur_image(const Image& img_in, Image& img_out);
|
||||
|
||||
// ----------------------------------------------------------------------------- : Resampled text
|
||||
|
||||
// scaling factor to use when drawing resampled text
|
||||
@@ -69,13 +71,35 @@ void downsample_to_alpha(Image& img_in, Image& img_out) {
|
||||
}*/
|
||||
}
|
||||
|
||||
// simple blur
|
||||
int blur_alpha_pixel(Byte* in, int x, int y, int width, int height) {
|
||||
return (2 * ( in[0]) + // center
|
||||
(x == 0 ? in[0] : in[-1]) + // left
|
||||
(y == 0 ? in[0] : in[-width]) + // up
|
||||
(x == width - 1 ? in[0] : in[1]) + // right
|
||||
(y == height - 1 ? in[0] : in[width]) // down
|
||||
) / 6;
|
||||
}
|
||||
|
||||
// TODO: move me?
|
||||
void blur_image_alpha(Image& img) {
|
||||
int width = img.GetWidth(), height = img.GetHeight();
|
||||
Byte* data = img.GetAlpha();
|
||||
for (int y = 0 ; y < height ; ++y) {
|
||||
for (int x = 0 ; x < width ; ++x) {
|
||||
*data = blur_alpha_pixel(data, x, y, width, height);
|
||||
++data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw text by first drawing it using a larger font and then downsampling it
|
||||
// optionally rotated by an angle
|
||||
// (w2,h2) = size of text
|
||||
// (wc,hc) = the corner where drawing should begin, (0,0) for top-left, (1,1) for bottom-right
|
||||
void draw_resampled_text(DC& dc, const RealRect& rect, int wc, int hc, int angle, const String& text) {
|
||||
// enlarge slightly
|
||||
int w = static_cast<int>(rect.width) + 1, h = static_cast<int>(rect.height) + 1;
|
||||
void draw_resampled_text(DC& dc, const RealRect& rect, int wc, int hc, int angle, const String& text, int blur_radius, int repeat) {
|
||||
// enlarge slightly; some fonts are larger then the GetTextExtent tells us (especially italic fonts)
|
||||
int w = static_cast<int>(rect.width) + 3 + 2 * blur_radius, h = static_cast<int>(rect.height) + 1 + 2 * blur_radius;
|
||||
// determine sub-pixel position
|
||||
int xi = static_cast<int>(rect.x), yi = static_cast<int>(rect.y);
|
||||
int xsub = static_cast<int>(text_scaling * (rect.x - xi)), ysub = static_cast<int>(text_scaling * (rect.y - yi));
|
||||
@@ -87,7 +111,7 @@ void draw_resampled_text(DC& dc, const RealRect& rect, int wc, int hc, int angle
|
||||
// now draw the text
|
||||
mdc.SetFont(dc.GetFont());
|
||||
mdc.SetTextForeground(*wxWHITE);
|
||||
mdc.DrawRotatedText(text, wc * w * text_scaling + xsub, hc * h * text_scaling + ysub, angle);
|
||||
mdc.DrawRotatedText(text, (wc * w + blur_radius) * text_scaling + xsub, (hc * h + blur_radius) * text_scaling + ysub, angle);
|
||||
// get image
|
||||
mdc.SelectObject(wxNullBitmap);
|
||||
Image img_large = buffer.ConvertToImage();
|
||||
@@ -95,7 +119,14 @@ void draw_resampled_text(DC& dc, const RealRect& rect, int wc, int hc, int angle
|
||||
Image img_small(w, h, false);
|
||||
fill_image(img_small, dc.GetTextForeground());
|
||||
downsample_to_alpha(img_large, img_small);
|
||||
// blur
|
||||
for (int i = 0 ; i < blur_radius ; ++i) {
|
||||
blur_image_alpha(img_small);
|
||||
}
|
||||
// step 3. draw to dc
|
||||
dc.DrawBitmap(img_small, xi + static_cast<int>(wc * (rect.width - w)), yi + static_cast<int>(hc * (rect.height - h)));
|
||||
for (int i = 0 ; i < repeat ; ++i) {
|
||||
dc.DrawBitmap(img_small, xi + static_cast<int>(wc * (rect.width - w)) - blur_radius,
|
||||
yi + static_cast<int>(hc * (rect.height - h)) - blur_radius);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,16 @@ void PackageList::drawItem(DC& dc, int x, int y, size_t item, bool selected) {
|
||||
dc.DrawText(d.package->full_name, (int)text_pos.x, (int)text_pos.y + 130);
|
||||
}
|
||||
|
||||
struct PackageList::ComparePackagePosHint {
|
||||
bool operator () (const PackageData& a, const PackageData& b) {
|
||||
// use position_hints to determine order
|
||||
if (a.package->position_hint < b.package->position_hint) return true;
|
||||
if (a.package->position_hint > b.package->position_hint) return false;
|
||||
// ensure a deterministic order: use the names
|
||||
return a.package->name() < b.package->name();
|
||||
}
|
||||
};
|
||||
|
||||
void PackageList::showData(const String& pattern) {
|
||||
// clear
|
||||
packages.clear();
|
||||
@@ -75,6 +85,8 @@ void PackageList::showData(const String& pattern) {
|
||||
// Next package
|
||||
f = wxFindNextFile();
|
||||
}
|
||||
// sort list
|
||||
sort(packages.begin(), packages.end(), ComparePackagePosHint());
|
||||
// update list
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ class PackageList : public GalleryList {
|
||||
PackagedP package;
|
||||
Bitmap image;
|
||||
};
|
||||
struct ComparePackagePosHint;
|
||||
/// The displayed packages
|
||||
vector<PackageData> packages;
|
||||
};
|
||||
|
||||
@@ -496,6 +496,7 @@ int blur_pixel(Byte* in, int x, int y, int width, int height) {
|
||||
) / 6;
|
||||
}
|
||||
|
||||
// TODO: move me
|
||||
void blur_image(const Image& img_in, Image& img_out) {
|
||||
int width = img_in.GetWidth(), height = img_in.GetHeight();
|
||||
assert(img_out.GetWidth() == width && img_out.GetHeight() == height);
|
||||
|
||||
@@ -1690,6 +1690,12 @@
|
||||
<File
|
||||
RelativePath=".\data\locale.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\data\pack.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\data\pack.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\data\statistics.cpp">
|
||||
</File>
|
||||
@@ -2129,6 +2135,12 @@
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\gfx\generated_image.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\gfx\generated_image.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\gfx\gfx.hpp">
|
||||
</File>
|
||||
@@ -2939,10 +2951,10 @@
|
||||
RelativePath="..\conversion-todo.txt">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\data\en.mse-locale\locale">
|
||||
RelativePath="..\data\nl.mse-locale\locale">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\data\nl.mse-locale\locale">
|
||||
RelativePath="..\data\en.mse-locale\locale">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\main.cpp">
|
||||
|
||||
@@ -32,11 +32,25 @@ void ImageValueViewer::draw(RotatedDC& dc) {
|
||||
handle_error(e, false, false); // don't handle now, we are in onPaint
|
||||
}
|
||||
}
|
||||
// if there is no image, generate a placeholder, only if there is enough room for it
|
||||
if (!bitmap.Ok() && style().width > 40) {
|
||||
bitmap = imagePlaceholder(dc, (int)dc.trS(style().width), (int)dc.trS(style().height), viewer.drawEditing());
|
||||
// if there is no image, generate a placeholder
|
||||
if (!bitmap.Ok()) {
|
||||
UInt w = (UInt)dc.trS(style().width), h = (UInt)dc.trS(style().height);
|
||||
loadMask(dc);
|
||||
if (alpha_mask) alpha_mask->setAlpha(bitmap);
|
||||
if (style().default_image.isReady()) {
|
||||
// we have a script to use for the default image
|
||||
Image img = style().default_image.generate(GeneratedImage::Options(w, h, viewer.stylesheet.get(), &getSet()));
|
||||
if (viewer.drawEditing()) {
|
||||
bitmap = imagePlaceholder(dc, w, h, img, viewer.drawEditing());
|
||||
if (alpha_mask) alpha_mask->setAlpha(bitmap);
|
||||
} else {
|
||||
if (alpha_mask) alpha_mask->setAlpha(img);
|
||||
bitmap = Bitmap(img);
|
||||
}
|
||||
} else if (style().width > 40) {
|
||||
// still not okay, use a checkered image, but only if there is enough room for it
|
||||
bitmap = imagePlaceholder(dc, w, h, wxNullImage, viewer.drawEditing());
|
||||
if (alpha_mask) alpha_mask->setAlpha(bitmap);
|
||||
}
|
||||
}
|
||||
// draw image, if any
|
||||
if (bitmap.Ok()) {
|
||||
@@ -65,7 +79,7 @@ void ImageValueViewer::onValueChange() {
|
||||
|
||||
void ImageValueViewer::onStyleChange() {
|
||||
bitmap = Bitmap();
|
||||
alpha_mask = AlphaMaskP();
|
||||
alpha_mask = AlphaMaskP(); // TODO: only reload whatever has changed
|
||||
}
|
||||
|
||||
void ImageValueViewer::loadMask(const Rotation& rot) const {
|
||||
@@ -82,15 +96,29 @@ void ImageValueViewer::loadMask(const Rotation& rot) const {
|
||||
}
|
||||
}
|
||||
|
||||
Bitmap ImageValueViewer::imagePlaceholder(const Rotation& rot, UInt w, UInt h, bool editing) {
|
||||
// is an image very light?
|
||||
bool very_light(const Image& image) {
|
||||
int w = image.GetWidth(), h = image.GetHeight();
|
||||
if (w*h<1) return false;
|
||||
Byte* data = image.GetData();
|
||||
int middle = w / 2 + (h*w) / 2;
|
||||
int total = (int)data[3 * middle] + (int)data[3 * middle + 1] + (int)data[3 * middle + 2];
|
||||
return total >= 210 * 3;
|
||||
}
|
||||
|
||||
Bitmap ImageValueViewer::imagePlaceholder(const Rotation& rot, UInt w, UInt h, const Image& background, bool editing) {
|
||||
// Bitmap and memory dc
|
||||
Bitmap bmp(w, h, 24);
|
||||
wxMemoryDC mdc;
|
||||
mdc.SelectObject(bmp);
|
||||
RealRect rect(0,0,w,h);
|
||||
RotatedDC dc(mdc, 0, rect, 1.0, QUALITY_AA);
|
||||
// Draw checker background
|
||||
draw_checker(dc, rect);
|
||||
// Draw (checker) background
|
||||
if (background.Ok()) {
|
||||
dc.DrawImage(background, RealPoint(0,0));
|
||||
} else {
|
||||
draw_checker(dc, rect);
|
||||
}
|
||||
// Draw text
|
||||
if (editing) {
|
||||
// only when in editor mode
|
||||
@@ -99,8 +127,12 @@ Bitmap ImageValueViewer::imagePlaceholder(const Rotation& rot, UInt w, UInt h, b
|
||||
RealSize rs = dc.GetTextExtent(_("double click to load image"));
|
||||
if (rs.width <= w - 10 && rs.height < h - 10) {
|
||||
// text fits
|
||||
dc.SetTextForeground(*wxBLACK);
|
||||
dc.DrawText(_("double click to load image"), align_in_rect(ALIGN_MIDDLE_CENTER, rs, rect));
|
||||
RealPoint pos = align_in_rect(ALIGN_MIDDLE_CENTER, rs, rect);
|
||||
bool black_on_white = !background.Ok() || very_light(background);
|
||||
dc.SetTextForeground(black_on_white ? *wxWHITE : *wxBLACK);
|
||||
dc.DrawText(_("double click to load image"), pos, 2, 4); // blurred
|
||||
dc.SetTextForeground(black_on_white ? *wxBLACK : *wxWHITE);
|
||||
dc.DrawText(_("double click to load image"), pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ class ImageValueViewer : public ValueViewer {
|
||||
void loadMask(const Rotation& rot) const;
|
||||
|
||||
/// Generate a placeholder image
|
||||
static Bitmap imagePlaceholder(const Rotation& rot, UInt w, UInt h, bool editing);
|
||||
static Bitmap imagePlaceholder(const Rotation& rot, UInt w, UInt h, const Image& background, bool editing);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <gui/util.hpp> // draw_checker
|
||||
#include <util/error.hpp>
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(SymbolStyle::VariationP);
|
||||
DECLARE_TYPEOF_COLLECTION(SymbolVariationP);
|
||||
|
||||
// ----------------------------------------------------------------------------- : SymbolValueViewer
|
||||
|
||||
|
||||
@@ -17,7 +17,11 @@
|
||||
#include <render/symbol/filter.hpp>
|
||||
#include <gui/util.hpp> // load_resource_image
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(SymbolStyle::VariationP);
|
||||
#include <gfx/generated_image.hpp>
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(SymbolVariationP);
|
||||
|
||||
bool parse_enum(const String&, ImageCombine& out);
|
||||
|
||||
// ----------------------------------------------------------------------------- : Macros
|
||||
|
||||
@@ -32,6 +36,84 @@ template <> inline ScriptImageP from_script<ScriptImageP>(const ScriptValueP& va
|
||||
|
||||
#define SCRIPT_IMAGE_PARAM_UP_TO_DATE(name) script_image_up_to_date(ctx.getVariable(_(#name)))
|
||||
|
||||
// ----------------------------------------------------------------------------- : Utility
|
||||
|
||||
// TODO : use this system
|
||||
|
||||
template <> inline GeneratedImageP from_script<GeneratedImageP>(const ScriptValueP& value) {
|
||||
return image_from_script(value);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Image functions
|
||||
|
||||
SCRIPT_FUNCTION(linear_blend2) {
|
||||
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 new_intrusive6<LinearBlendImage>(image1, image2, x1,y1, x2,y2);
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(masked_blend2) {
|
||||
SCRIPT_PARAM(GeneratedImageP, light);
|
||||
SCRIPT_PARAM(GeneratedImageP, dark);
|
||||
SCRIPT_PARAM(GeneratedImageP, mask);
|
||||
return new_intrusive3<MaskedBlendImage>(light, dark, mask);
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(combine_blend2) {
|
||||
SCRIPT_PARAM(String, combine);
|
||||
SCRIPT_PARAM(GeneratedImageP, image1);
|
||||
SCRIPT_PARAM(GeneratedImageP, image2);
|
||||
ImageCombine image_combine;
|
||||
if (!parse_enum(combine, image_combine)) {
|
||||
throw ScriptError(_("Not a valid combine mode: '") + combine + _("'"));
|
||||
}
|
||||
return new_intrusive3<CombineBlendImage>(image1, image2, image_combine);
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(set_mask2) {
|
||||
SCRIPT_PARAM(GeneratedImageP, image);
|
||||
SCRIPT_PARAM(GeneratedImageP, mask);
|
||||
return new_intrusive2<SetMaskImage>(image, mask);
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(set_combine2) {
|
||||
SCRIPT_PARAM(String, combine);
|
||||
SCRIPT_PARAM(GeneratedImageP, input);
|
||||
ImageCombine image_combine;
|
||||
if (!parse_enum(combine, image_combine)) {
|
||||
throw ScriptError(_("Not a valid combine mode: '") + combine + _("'"));
|
||||
}
|
||||
return new_intrusive2<SetCombineImage>(input, image_combine);
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(symbol_variation2) {
|
||||
// find symbol
|
||||
SCRIPT_PARAM(ValueP, symbol);
|
||||
SymbolValueP value = dynamic_pointer_cast<SymbolValue>(symbol);
|
||||
SCRIPT_PARAM(String, variation);
|
||||
// find style
|
||||
SCRIPT_PARAM(Set*, set);
|
||||
SCRIPT_OPTIONAL_PARAM_(CardP, card);
|
||||
SymbolStyleP style = dynamic_pointer_cast<SymbolStyle>(set->stylesheetFor(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 new_intrusive3<SymbolToImage>(value->filename, value->last_update, v);
|
||||
}
|
||||
}
|
||||
throw ScriptError(_("Variation of symbol not found ('") + variation + _("')"));
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(built_in_image2) {
|
||||
SCRIPT_PARAM(String, input);
|
||||
return new_intrusive1<BuiltInImage>(input);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Image functions
|
||||
|
||||
SCRIPT_IMAGE_FUNCTION(linear_blend) {
|
||||
@@ -62,6 +144,22 @@ SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
||||
);
|
||||
}
|
||||
|
||||
SCRIPT_IMAGE_FUNCTION(combine_blend) {
|
||||
SCRIPT_PARAM(String, combine);
|
||||
SCRIPT_PARAM(ScriptImageP, image1);
|
||||
SCRIPT_PARAM(ScriptImageP, image2);
|
||||
if (!parse_enum(combine, image1->combine)) {
|
||||
throw ScriptError(_("Not a valid combine mode: '") + combine + _("'"));
|
||||
}
|
||||
combine_image(image1->image, image2->image, image1->combine);
|
||||
return image1;
|
||||
SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
||||
SCRIPT_RETURN(
|
||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(image1) &&
|
||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(image2)
|
||||
);
|
||||
}
|
||||
|
||||
SCRIPT_IMAGE_FUNCTION(set_mask) {
|
||||
SCRIPT_PARAM(ScriptImageP, image);
|
||||
SCRIPT_PARAM(ScriptImageP, mask);
|
||||
@@ -74,8 +172,6 @@ SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
||||
);
|
||||
}
|
||||
|
||||
bool parse_enum(const String&, ImageCombine& out);
|
||||
|
||||
SCRIPT_IMAGE_FUNCTION(set_combine) {
|
||||
SCRIPT_PARAM(String, combine);
|
||||
SCRIPT_PARAM(ScriptImageP, input);
|
||||
@@ -136,6 +232,7 @@ SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
||||
void init_script_image_functions(Context& ctx) {
|
||||
ctx.setVariable(_("linear blend"), script_linear_blend);
|
||||
ctx.setVariable(_("masked blend"), script_masked_blend);
|
||||
ctx.setVariable(_("combine blend"), script_combine_blend);
|
||||
ctx.setVariable(_("set mask"), script_set_mask);
|
||||
ctx.setVariable(_("set combine"), script_set_combine);
|
||||
ctx.setVariable(_("symbol variation"), script_symbol_variation);
|
||||
|
||||
@@ -14,6 +14,58 @@
|
||||
|
||||
IMPLEMENT_DYNAMIC_ARG(Package*, load_images_from, nullptr);
|
||||
|
||||
// ----------------------------------------------------------------------------- : Utility
|
||||
|
||||
// convert any script value to a GeneratedImageP
|
||||
GeneratedImageP image_from_script(const ScriptValueP& value) {
|
||||
if (value->type() == SCRIPT_STRING) {
|
||||
return new_intrusive1<PackagedImage>(value->toString());
|
||||
} else {
|
||||
GeneratedImageP img = dynamic_pointer_cast<GeneratedImage>(value);
|
||||
if (!img) throw ScriptError(_ERROR_2_("can't convert", value->typeName(), _TYPE_("image")));
|
||||
return img;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : ScriptableImage2
|
||||
|
||||
Image ScriptableImage2::generate(const GeneratedImage::Options& options, bool cache) const {
|
||||
if (!isReady()) {
|
||||
// error, return blank image
|
||||
Image i(1,1);
|
||||
i.InitAlpha();
|
||||
i.SetAlpha(0,0,0);
|
||||
return i;
|
||||
}
|
||||
if (cached.Ok() && cached.GetWidth() == options.width && cached.GetHeight() == options.height) {
|
||||
return cached;
|
||||
}
|
||||
Image img = value->generate(options);
|
||||
if (cache) cached = img;
|
||||
return img;
|
||||
}
|
||||
|
||||
ImageCombine ScriptableImage2::combine() const {
|
||||
if (!isReady()) return COMBINE_NORMAL;
|
||||
return value->combine();
|
||||
}
|
||||
|
||||
bool ScriptableImage2::update(Context& ctx) {
|
||||
if (!isScripted()) return false;
|
||||
GeneratedImageP new_value = image_from_script(script.invoke(ctx));
|
||||
if (!new_value || !value || *new_value != *value) {
|
||||
value = new_value;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : ScriptImage
|
||||
|
||||
ScriptType ScriptImage::type() const { return SCRIPT_IMAGE; }
|
||||
@@ -160,3 +212,31 @@ template <> void Writer::handle(const ScriptableImage& s) {
|
||||
template <> void GetDefaultMember::handle(const ScriptableImage& s) {
|
||||
handle(s.script.unparsed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Reflection
|
||||
|
||||
// we need some custom io, because the behaviour is different for each of Reader/Writer/GetMember
|
||||
|
||||
template <> void Reader::handle(ScriptableImage2& s) {
|
||||
handle(s.script.unparsed);
|
||||
if (starts_with(s.script.unparsed, _("script:"))) {
|
||||
s.script.unparsed = s.script.unparsed.substr(7);
|
||||
s.script.parse(*this);
|
||||
} else if (s.script.unparsed.find_first_of('{') != String::npos) {
|
||||
s.script.parse(*this, true);
|
||||
} else {
|
||||
// script is a constant function
|
||||
s.script.script = new_intrusive<Script>();
|
||||
s.script.script->addInstruction(I_PUSH_CONST, s.script.unparsed);
|
||||
s.script.script->addInstruction(I_RET);
|
||||
}
|
||||
}
|
||||
template <> void Writer::handle(const ScriptableImage2& s) {
|
||||
handle(s.script.unparsed);
|
||||
}
|
||||
template <> void GetDefaultMember::handle(const ScriptableImage2& s) {
|
||||
handle(s.script.unparsed);
|
||||
}
|
||||
|
||||
@@ -13,13 +13,60 @@
|
||||
#include <util/age.hpp>
|
||||
#include <util/dynamic_arg.hpp>
|
||||
#include <script/scriptable.hpp>
|
||||
#include <gfx/gfx.hpp>
|
||||
//%%#include <gfx/gfx.hpp>
|
||||
#include <gfx/generated_image.hpp>
|
||||
|
||||
class Package;
|
||||
DECLARE_INTRUSIVE_POINTER_TYPE(ScriptImage);
|
||||
DECLARE_INTRUSIVE_POINTER_TYPE(ScriptImage); //%% OLD
|
||||
DECLARE_INTRUSIVE_POINTER_TYPE(GeneratedImage); //%% OLD
|
||||
|
||||
// ----------------------------------------------------------------------------- : ScriptableImage
|
||||
|
||||
/// An image that can also be scripted
|
||||
/** Differs from Scriptable<Image> in that:
|
||||
* - A script is always used
|
||||
* - Age is checked, chached images are used if possible
|
||||
* - The image can be scaled
|
||||
*/
|
||||
class ScriptableImage2 {
|
||||
public:
|
||||
inline ScriptableImage2() {}
|
||||
inline ScriptableImage2(const String& script) : script(script) {}
|
||||
|
||||
/// Is there an image set?
|
||||
inline bool isScripted() const { return script; }
|
||||
/// Is there an image generator available?
|
||||
inline bool isReady() const { return value; }
|
||||
|
||||
/// Generate an image.
|
||||
Image generate(const GeneratedImage::Options& options, bool cache = false) const;
|
||||
/// How should images be combined with the background?
|
||||
ImageCombine combine() const;
|
||||
|
||||
/// Update the script, returns true if the value has changed
|
||||
bool update(Context& ctx);
|
||||
|
||||
inline void initDependencies(Context& ctx, const Dependency& dep) const {
|
||||
script.initDependencies(ctx, dep);
|
||||
}
|
||||
|
||||
private:
|
||||
OptionalScript script; ///< The script, not really optional
|
||||
GeneratedImageP value; ///< The image generator
|
||||
mutable Image cached; ///< The cached actual image
|
||||
|
||||
DECLARE_REFLECTION();
|
||||
};
|
||||
|
||||
/// Missing for now
|
||||
inline ScriptValueP to_script(const ScriptableImage2&) { return script_nil; }
|
||||
|
||||
/// Convert a script value to a GeneratedImageP
|
||||
GeneratedImageP image_from_script(const ScriptValueP& value);
|
||||
|
||||
// ----------------------------------------------------------------------------- : ScriptableImage
|
||||
//%% OLD
|
||||
|
||||
DECLARE_DYNAMIC_ARG(Package*, load_images_from);
|
||||
|
||||
/// An image, returned by a script function
|
||||
|
||||
@@ -37,6 +37,8 @@ class Age {
|
||||
|
||||
/// Compare two ages, smaller means earlier
|
||||
inline bool operator < (Age a) const { return age < a.age; }
|
||||
/// Compare two ages
|
||||
inline bool operator == (Age a) const { return age == a.age; }
|
||||
|
||||
/// A number corresponding to the age
|
||||
inline AtomicIntEquiv get() const { return age; }
|
||||
|
||||
@@ -412,12 +412,14 @@ IMPLEMENT_REFLECTION(Packaged) {
|
||||
REFLECT(short_name);
|
||||
REFLECT(full_name);
|
||||
REFLECT_N("icon", icon_filename);
|
||||
REFLECT(position_hint);
|
||||
REFLECT(version);
|
||||
REFLECT_N("depends ons", dependencies); // hack for singular_form
|
||||
}
|
||||
|
||||
Packaged::Packaged()
|
||||
: fully_loaded(true)
|
||||
: position_hint(100000)
|
||||
, fully_loaded(true)
|
||||
{}
|
||||
|
||||
InputStreamP Packaged::openIconFile() {
|
||||
|
||||
@@ -198,6 +198,7 @@ class Packaged : public Package {
|
||||
String full_name; ///< Name of this package, for menus etc.
|
||||
String icon_filename; ///< Filename of icon to use in package lists
|
||||
vector<PackageDependencyP> dependencies; ///< Dependencies of this package
|
||||
int position_hint; ///< A hint for the package list
|
||||
|
||||
/// Get an input stream for the package icon, if there is any
|
||||
InputStreamP openIconFile();
|
||||
|
||||
@@ -122,7 +122,7 @@ void Reader::readLine(bool in_string) {
|
||||
return;
|
||||
}
|
||||
key = line.substr(indent, pos - indent);
|
||||
if (!in_string && starts_with(key, _(" "))) {
|
||||
if (!ignore_invalid && !in_string && starts_with(key, _(" "))) {
|
||||
warning(_("key: '") + key + _("' starts with a space; only use TABs for indentation!"));
|
||||
// try to fix up: 8 spaces is a tab
|
||||
while (starts_with(key, _(" "))) {
|
||||
|
||||
@@ -124,12 +124,12 @@ RotatedDC::RotatedDC(DC& dc, const Rotation& rotation, RenderQuality quality)
|
||||
|
||||
// ----------------------------------------------------------------------------- : RotatedDC : Drawing
|
||||
|
||||
void RotatedDC::DrawText (const String& text, const RealPoint& pos) {
|
||||
void RotatedDC::DrawText (const String& text, const RealPoint& pos, int blur_radius, int boldness) {
|
||||
if (text.empty()) return;
|
||||
if (quality == QUALITY_AA) {
|
||||
RealRect r(pos, GetTextExtent(text));
|
||||
RealRect r_ext = trNoNeg(r);
|
||||
draw_resampled_text(dc, r_ext, revX(), revY(), angle, text);
|
||||
draw_resampled_text(dc, r_ext, revX(), revY(), angle, text, blur_radius, boldness);
|
||||
} else if (quality == QUALITY_SUB_PIXEL) {
|
||||
RealPoint p_ext = tr(pos)*text_scaling;
|
||||
double usx,usy;
|
||||
|
||||
@@ -138,7 +138,7 @@ class RotatedDC : public Rotation {
|
||||
|
||||
// --------------------------------------------------- : Drawing
|
||||
|
||||
void DrawText (const String& text, const RealPoint& pos);
|
||||
void DrawText (const String& text, const RealPoint& pos, int blur_radius = 0, int boldness = 1);
|
||||
/// Draw abitmap, it must already be zoomed!
|
||||
void DrawBitmap(const Bitmap& bitmap, const RealPoint& pos);
|
||||
/// Draw an image using the given combining mode, the image must already be zoomed!
|
||||
|
||||
@@ -111,6 +111,41 @@ inline shared_ptr<T> new_shared9(const A0& a0, const A1& a1, const A2& a2, const
|
||||
inline intrusive_ptr<T> new_intrusive2(const A0& a0, const A1& a1) {
|
||||
return intrusive_ptr<T>(new T(a0, a1));
|
||||
}
|
||||
/// Allocate a new intrusive-pointed object, given three arguments to pass to the ctor of T
|
||||
template <typename T, typename A0, typename A1, typename A2>
|
||||
inline intrusive_ptr<T> new_intrusive3(const A0& a0, const A1& a1, const A2& a2) {
|
||||
return intrusive_ptr<T>(new T(a0, a1, a2));
|
||||
}
|
||||
/// Allocate a new intrusive-pointed object, given four arguments to pass to the ctor of T
|
||||
template <typename T, typename A0, typename A1, typename A2, typename A3>
|
||||
inline intrusive_ptr<T> new_intrusive4(const A0& a0, const A1& a1, const A2& a2, const A3& a3) {
|
||||
return intrusive_ptr<T>(new T(a0, a1, a2, a3));
|
||||
}
|
||||
/// Allocate a new intrusive-pointed object, given five arguments to pass to the ctor of T
|
||||
template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4>
|
||||
inline intrusive_ptr<T> new_intrusive5(const A0& a0, const A1& a1, const A2& a2, const A3& a3, const A4& a4) {
|
||||
return intrusive_ptr<T>(new T(a0, a1, a2, a3, a4));
|
||||
}
|
||||
/// Allocate a new intrusive-pointed object, given six arguments to pass to the ctor of T
|
||||
template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5>
|
||||
inline intrusive_ptr<T> new_intrusive6(const A0& a0, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) {
|
||||
return intrusive_ptr<T>(new T(a0, a1, a2, a3, a4, a5));
|
||||
}
|
||||
/// Allocate a new intrusive-pointed object, given seven arguments to pass to the ctor of T
|
||||
template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
|
||||
inline intrusive_ptr<T> new_intrusive7(const A0& a0, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) {
|
||||
return intrusive_ptr<T>(new T(a0, a1, a2, a3, a4, a5, a6));
|
||||
}
|
||||
/// Allocate a new intrusive-pointed object, given eight arguments to pass to the ctor of T
|
||||
template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7>
|
||||
inline intrusive_ptr<T> new_intrusive8(const A0& a0, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7) {
|
||||
return intrusive_ptr<T>(new T(a0, a1, a2, a3, a4, a5, a6, a7));
|
||||
}
|
||||
/// Allocate a new intrusive-pointed object, given nine arguments to pass to the ctor of T
|
||||
template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8>
|
||||
inline intrusive_ptr<T> new_intrusive9(const A0& a0, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8) {
|
||||
return intrusive_ptr<T>(new T(a0, a1, a2, a3, a4, a5, a6, a7, a8));
|
||||
}
|
||||
|
||||
/// Base class for objects wishing to use intrusive_ptrs
|
||||
class IntrusivePtrBase {
|
||||
@@ -144,6 +179,12 @@ inline shared_ptr<T> new_shared9(const A0& a0, const A1& a1, const A2& a2, const
|
||||
#define new_intrusive1 new_shared1
|
||||
#define new_intrusive2 new_shared2
|
||||
#define new_intrusive3 new_shared3
|
||||
#define new_intrusive4 new_shared4
|
||||
#define new_intrusive5 new_shared5
|
||||
#define new_intrusive6 new_shared6
|
||||
#define new_intrusive7 new_shared7
|
||||
#define new_intrusive8 new_shared8
|
||||
#define new_intrusive9 new_shared9
|
||||
|
||||
class IntrusivePtrBase {
|
||||
public:
|
||||
|
||||