The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
part.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2016 by Ignacio R. Morelle <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /**
16  * @file
17  * Storyscreen parts and floating images representation.
18  */
19 
20 #include "global.hpp"
21 #include "asserts.hpp"
22 #include "log.hpp"
23 #include "resources.hpp"
24 #include "storyscreen/part.hpp"
25 
26 #include "config.hpp"
27 #include "game_data.hpp"
29 #include "game_events/manager.hpp"
30 #include "game_events/pump.hpp"
31 #include "image.hpp"
33 #include "util.hpp"
34 #include "variable.hpp"
35 #include "video.hpp"
36 
37 namespace storyscreen {
38 
40  : file_()
41  , x_(0)
42  , y_(0)
43  , delay_(0)
44  , autoscaled_(false)
45  , centered_(false)
46 {
47  this->assign(fi);
48 }
49 
51  : file_(cfg["file"])
52  , x_(cfg["x"])
53  , y_(cfg["y"])
54  , delay_(cfg["delay"])
55  , autoscaled_(cfg["scaled"].to_bool())
56  , centered_(cfg["centered"].to_bool())
57 {
58 }
59 
61 {
62  if(&fi == this)
63  return;
64 
65  file_ = fi.file_; x_ = fi.x_; y_ = fi.y_; delay_ = fi.delay_;
67 }
68 
69 floating_image::render_input floating_image::get_render_input(double xscale, double yscale, SDL_Rect& dst_rect) const
70 {
71 #ifdef SDL_GPU
72  render_input ri = {
73  {0,0,0,0},
74  file_.empty() ? sdl::timage() : image::get_texture(file_)
75  };
76 
77  if(!ri.image.null()) {
78  if(autoscaled_) {
79  ri.image.set_scale(xscale, yscale);
80  }
81 
82  ri.rect.x = static_cast<int>(x_*xscale) + dst_rect.x;
83  ri.rect.y = static_cast<int>(y_*yscale) + dst_rect.y;
84  ri.rect.w = ri.image.width();
85  ri.rect.h = ri.image.height();
86 
87  if(centered_) {
88  ri.rect.x -= ri.rect.w / 2;
89  ri.rect.y -= ri.rect.h / 2;
90  }
91  }
92  return ri;
93 #else
94  render_input ri = {
95  {0,0,0,0},
96  file_.empty() ? nullptr : image::get_image(file_)
97  };
98 
99  if(!ri.image.null()) {
100  if(autoscaled_) {
101  ri.image = scale_surface(
102  ri.image,
103  static_cast<int>(ri.image->w * xscale),
104  static_cast<int>(ri.image->h * yscale)
105  );
106  }
107 
108  ri.rect.x = static_cast<int>(x_*xscale) + dst_rect.x;
109  ri.rect.y = static_cast<int>(y_*yscale) + dst_rect.y;
110  ri.rect.w = ri.image->w;
111  ri.rect.h = ri.image->h;
112 
113  if(centered_) {
114  ri.rect.x -= ri.rect.w / 2;
115  ri.rect.y -= ri.rect.h / 2;
116  }
117  }
118  return ri;
119 #endif
120 }
121 
123  : scale_horizontally_(true)
124  , scale_vertically_(true)
125  , tile_horizontally_(false)
126  , tile_vertically_(false)
127  , keep_aspect_ratio_(true)
128  , is_base_layer_(false)
129  , image_file_()
130 {}
131 
133  : scale_horizontally_(true)
134  , scale_vertically_(true)
135  , tile_horizontally_(false)
136  , tile_vertically_(false)
137  , keep_aspect_ratio_(true)
138  , is_base_layer_(false)
139  , image_file_()
140 {
141  if(cfg.has_attribute("image")) {
142  image_file_ = cfg["image"].str();
143  }
144  if(cfg.has_attribute("scale")) {
145  scale_vertically_ = cfg["scale"].to_bool(true);
146  scale_horizontally_ = cfg["scale"].to_bool(true);
147  } else {
148  if(cfg.has_attribute("scale_vertically")) {
149  scale_vertically_ = cfg["scale_vertically"].to_bool(true);
150  }
151  if(cfg.has_attribute("scale_horizontally")) {
152  scale_horizontally_ = cfg["scale_horizontally"].to_bool(true);
153  }
154  }
155  if(cfg.has_attribute("tile")) {
156  tile_vertically_ = cfg["tile"].to_bool(false);
157  tile_horizontally_ = cfg["tile"].to_bool(false);
158  } else {
159  if(cfg.has_attribute("tile_vertically")) {
160  tile_vertically_ = cfg["tile_vertically"].to_bool(false);
161  }
162  if(cfg.has_attribute("tile_horizontally")) {
163  tile_horizontally_ = cfg["tile_horizontally"].to_bool(false);
164  }
165  }
166  if(cfg.has_attribute("keep_aspect_ratio")) {
167  keep_aspect_ratio_ = cfg["keep_aspect_ratio"].to_bool(true);
168  }
169  if(cfg.has_attribute("base_layer")) {
170  is_base_layer_ = cfg["base_layer"].to_bool(false);
171  }
172 }
173 
174 part::part(const vconfig &part_cfg)
175  : show_title_()
176  , text_()
177  , text_title_()
178  , text_block_loc_(part::BLOCK_BOTTOM)
179  , title_alignment_(part::TEXT_LEFT)
180  , music_()
181  , sound_()
182  , background_layers_()
183  , floating_images_()
184 {
185  resolve_wml(part_cfg);
186 }
187 
189 {
190  if(s.empty() != true) {
191  if(s == "top") {
192  return part::BLOCK_TOP;
193  }
194  else if (s == "middle") {
195  return part::BLOCK_MIDDLE;
196  }
197  }
198  return part::BLOCK_BOTTOM;
199 }
200 
202 {
203  if(s.empty() != true) {
204  if(s == "right") {
205  return part::TEXT_RIGHT;
206  }
207  else if(s == "center") {
208  return part::TEXT_CENTERED;
209  }
210  }
211  return part::TEXT_LEFT;
212 }
213 
214 void part::resolve_wml(const vconfig &cfg)
215 {
216  if(cfg.null()) {
217  return;
218  }
219 
220  // Converts shortcut syntax to members of [background_layer]
221  background_layer bl;
222 
223  if(cfg.has_attribute("background")) {
224  bl.set_file(cfg["background"].str());
225  }
226  if(cfg.has_attribute("scale_background")) {
227  bl.set_scale_horizontally(cfg["scale_background"].to_bool(true));
228  bl.set_scale_vertically(cfg["scale_background"].to_bool(true));
229  } else {
230  if(cfg.has_attribute("scale_background_vertically")) {
231  bl.set_scale_vertically(cfg["scale_background_vertically"].to_bool(true));
232  }
233  if(cfg.has_attribute("scale_background_horizontally")) {
234  bl.set_scale_horizontally(cfg["scale_background_horizontally"].to_bool(true));
235  }
236  }
237  if(cfg.has_attribute("tile_background")) {
238  bl.set_tile_horizontally(cfg["tile_background"].to_bool(false));
239  bl.set_tile_vertically(cfg["tile_background"].to_bool(false));
240  } else {
241  if(cfg.has_attribute("tile_background_vertically")) {
242  bl.set_tile_vertically(cfg["tile_background_vertically"].to_bool(false));
243  }
244  if(cfg.has_attribute("tile_background_horizontally")) {
245  bl.set_tile_vertically(cfg["tile_background_horizontally"].to_bool(false));
246  }
247  }
248  if(cfg.has_attribute("keep_aspect_ratio")) {
249  bl.set_keep_aspect_ratio(cfg["keep_aspect_ratio"].to_bool(true));
250  }
251  background_layers_.push_back(bl);
252 
253 
254  if(cfg.has_attribute("show_title")) {
255  show_title_ = cfg["show_title"].to_bool();
256  }
257  if(cfg.has_attribute("story")) {
258  text_ = cfg["story"].str();
259  }
260  if(cfg.has_attribute("title")) {
261  text_title_ = cfg["title"].str();
262  if(!cfg.has_attribute("show_title")) {
263  show_title_ = true;
264  }
265  }
266  if(cfg.has_attribute("text_layout")) {
267  text_block_loc_ = string_tblock_loc(cfg["text_layout"]);
268  }
269  if(cfg.has_attribute("title_alignment")) {
270  title_alignment_ = string_title_align(cfg["title_alignment"]);
271  }
272  if(cfg.has_attribute("music")) {
273  music_ = cfg["music"].str();
274  }
275  if(cfg.has_attribute("sound")) {
276  sound_ = cfg["sound"].str();
277  }
278 
279  // Execution flow/branching/[image]
280  for(vconfig::all_children_iterator i = cfg.ordered_begin(); i != cfg.ordered_end(); ++ i) {
281  // i->first and i->second are goddamn temporaries; do not make references
282  const std::string key = i->first;
283  const vconfig node = i->second;
284 
285  // [background_layer]
286  if (key == "background_layer") {
287  background_layers_.push_back(node.get_parsed_config());
288  }
289  // [image]
290  else if(key == "image") {
291  floating_images_.push_back(node.get_parsed_config());
292  }
293  // [if]
294  else if(key == "if") {
295  // check if the [if] tag has a [then] child;
296  // if we try to execute a non-existing [then], we get a segfault
298  if (node.has_child("then")) {
299  resolve_wml(node.child("then"));
300  }
301  }
302  // condition not passed, check [elseif] and [else]
303  else {
304  // get all [elseif] children and set a flag
305  vconfig::child_list elseif_children = node.get_children("elseif");
306  bool elseif_flag = false;
307  // for each [elseif]: test if it has a [then] child
308  // if the condition matches, execute [then] and raise flag
309  for (vconfig::child_list::const_iterator elseif = elseif_children.begin(); elseif != elseif_children.end(); ++elseif) {
310  if (game_events::conditional_passed(*elseif)) {
311  if (elseif->has_child("then")) {
312  resolve_wml(elseif->child("then"));
313  }
314  elseif_flag = true;
315  break;
316  }
317  }
318  // if we have an [else] tag and no [elseif] was successful (flag not raised), execute it
319  if (node.has_child("else") && !elseif_flag) {
320  resolve_wml(node.child("else"));
321  }
322  }
323  }
324  // [switch]
325  else if(key == "switch") {
326  const std::string var_name = node["variable"];
327  const std::string var_actual_value = resources::gamedata->get_variable_const(var_name);
328  bool case_not_found = true;
329 
330  for(vconfig::all_children_iterator j = node.ordered_begin(); j != node.ordered_end(); ++j) {
331  if(j->first != "case") continue;
332 
333  // Enter all matching cases.
334  const std::string var_expected_value = (j->second)["value"];
335  if(var_actual_value == var_expected_value) {
336  case_not_found = false;
337  resolve_wml(j->second);
338  }
339  }
340 
341  if(case_not_found) {
342  for(vconfig::all_children_iterator j = node.ordered_begin(); j != node.ordered_end(); ++j) {
343  if(j->first != "else") continue;
344 
345  // Enter all elses.
346  resolve_wml(j->second);
347  }
348  }
349  }
350  // [deprecated_message]
351  else if(key == "deprecated_message") {
352  // Won't appear until the scenario start event finishes.
353  lg::wml_error() << node["message"] << '\n';
354  }
355  // [wml_message]
356  else if(key == "wml_message") {
357  // As with [deprecated_message],
358  // it won't appear until the scenario start event is complete.
359  resources::game_events->pump().put_wml_message(node["logger"], node["message"], node["in_chat"].to_bool(false));
360  }
361  }
362 }
363 
364 } // end namespace storyscreen
365 
surface get_image(const image::locator &i_locator, TYPE type)
function to get the surface corresponding to an image.
Definition: image.cpp:878
std::string music_
Definition: part.hpp:350
void set_keep_aspect_ratio(bool b)
Sets whether the aspect ratio should be preserved.
Definition: part.hpp:200
tformula< unsigned > x_
The x coordinate of the rectangle.
Definition: canvas.cpp:682
Center of the screen.
Definition: part.hpp:254
bool null() const
Definition: utils.hpp:104
Storyscreen parts and floating images representation.
vconfig child(const std::string &key) const
Returns a child of *this whose key is key.
Definition: variable.cpp:243
SDL_Rect rect
Corrected rectangle for rendering surf.
Definition: part.hpp:45
config get_parsed_config() const
Definition: variable.cpp:131
all_children_iterator ordered_end() const
Definition: variable.cpp:403
Center on the topmost edge of the screen.
Definition: part.hpp:264
std::string text_
Definition: part.hpp:345
static TEXT_ALIGNMENT string_title_align(const std::string &s)
Definition: part.cpp:201
surface scale_surface(const surface &surf, int w, int h)
Definition: utils.cpp:443
Bottom of the screen.
Definition: part.hpp:255
render_input get_render_input(double xscale, double yscale, SDL_Rect &dst_rect) const
Gets a render_input object for use by the rendering code after applying any geometric transformations...
Definition: part.cpp:69
tformula< t_string > text_
The text to draw.
Definition: canvas.cpp:1268
-file util.hpp
Definitions for the interface to Wesnoth Markup Language (WML).
void set_tile_vertically(bool b)
Sets whether the layer should be tiled vertically.
Definition: part.hpp:186
Top-left corner.
Definition: part.hpp:263
game_data * gamedata
Definition: resources.cpp:22
BLOCK_LOCATION text_block_loc_
Definition: part.hpp:347
bool null() const
Definition: variable.hpp:66
void set_file(const std::string &str)
Sets the path to the image file.
Definition: part.hpp:228
virtual config::attribute_value get_variable_const(const std::string &varname) const
returns a blank attribute value if varname is no valid variable name.
Definition: game_data.cpp:75
child_list get_children(const std::string &key) const
Definition: variable.cpp:181
Represents and contains information about image labels used in story screen parts.
Definition: part.hpp:40
void set_tile_horizontally(bool b)
Sets whether the layer should be tiled horizontally.
Definition: part.hpp:172
background_layer()
Constructor.
Definition: part.cpp:122
bool has_child(const std::string &key) const
Returns whether or not *this has a child whose key is key.
Definition: variable.cpp:270
TEXT_ALIGNMENT title_alignment_
Definition: part.hpp:348
Templates and utility-routines for strings and numbers.
std::vector< background_layer > background_layers_
Definition: part.hpp:353
game_events::manager * game_events
Definition: resources.cpp:24
Represents and contains information about a single storyscreen part.
Definition: part.hpp:244
std::vector< floating_image > floating_images_
Definition: part.hpp:354
std::string sound_
Definition: part.hpp:351
void resolve_wml(const vconfig &cfg)
Takes care of initializing and branching properties.
Definition: part.cpp:214
Define conditionals for the game's events mechanism, a.k.a.
static BLOCK_LOCATION string_tblock_loc(const std::string &s)
Definition: part.cpp:188
std::string text_title_
Definition: part.hpp:346
Top of the screen.
Definition: part.hpp:253
std::stringstream & wml_error()
Use this logger to send errors due to deprecated WML.
Definition: log.cpp:262
void assign(const floating_image &fi)
Copy constructor and operator=() implementation details.
Definition: part.cpp:60
bool show_title_
Definition: part.hpp:344
Define the game's event mechanism.
size_t i
Definition: function.cpp:1057
tformula< unsigned > y_
The y coordinate of the rectangle.
Definition: canvas.cpp:682
game_events::t_pump & pump()
Definition: manager.cpp:194
bool conditional_passed(const vconfig &cond)
floating_image(const config &cfg)
WML-based constructor.
Definition: part.cpp:50
Top-right corner.
Definition: part.hpp:265
bool has_attribute(const std::string &key) const
Definition: config.cpp:514
part(const vconfig &part_cfg)
Constructs a storyscreen part from a managed WML node.
Definition: part.cpp:174
A variable-expanding proxy for the config class.
Definition: variable.hpp:36
Standard logging facilities (interface).
std::vector< vconfig > child_list
Definition: variable.hpp:71
void set_scale_horizontally(bool b)
Sets whether the layer should be scaled horizontally.
Definition: part.hpp:144
surface image
Surface, scaled if required.
Definition: part.hpp:49
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
TEXT_ALIGNMENT
Currently used to indicate where the page title should be placed.
Definition: part.hpp:262
GLdouble s
Definition: glew.h:1358
void set_scale_vertically(bool b)
Sets whether the layer should be scaled vertically.
Definition: part.hpp:158
void put_wml_message(const std::string &logger, const std::string &message, bool in_chat)
Helper function which determines whether a wml_message text can really be pushed into the wml_message...
Definition: pump.cpp:458
GLsizei const GLcharARB ** string
Definition: glew.h:4503
bool has_attribute(const std::string &key) const
< Synonym for operator[]
Definition: variable.hpp:92
all_children_iterator ordered_begin() const
In-order iteration over all children.
Definition: variable.cpp:398
BLOCK_LOCATION
Currently used to indicate where the text block should be placed.
Definition: part.hpp:252