1 // -*- Mode: C++; tab-width:2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi:tw=80:et:ts=2:sts=2
3 //
4 // -----------------------------------------------------------------------
5 //
6 // This file is part of RLVM, a RealLive virtual machine clone.
7 //
8 // -----------------------------------------------------------------------
9 //
10 // Copyright (C) 2006, 2007 Elliot Glaysher
11 //
12 // This program is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation; either version 3 of the License, or
15 // (at your option) any later version.
16 //
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with this program; if not, write to the Free Software
24 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
25 //
26 // -----------------------------------------------------------------------
27 
28 #include <boost/archive/text_iarchive.hpp>
29 #include <boost/archive/text_oarchive.hpp>
30 
31 // -----------------------------------------------------------------------
32 
33 #include "systems/base/graphics_object.h"
34 
35 #include <boost/serialization/scoped_ptr.hpp>
36 #include <boost/serialization/shared_ptr.hpp>
37 
38 #include <algorithm>
39 #include <iostream>
40 #include <numeric>
41 #include <sstream>
42 #include <string>
43 #include <vector>
44 
45 #include "systems/base/graphics_object_data.h"
46 #include "systems/base/object_mutator.h"
47 #include "utilities/exception.h"
48 
49 const int DEFAULT_TEXT_SIZE = 14;
50 const int DEFAULT_TEXT_XSPACE = 0;
51 const int DEFAULT_TEXT_YSPACE = 0;
52 const int DEFAULT_TEXT_CHAR_COUNT = 0;
53 const int DEFAULT_TEXT_COLOUR = 0;
54 const int DEFAULT_TEXT_SHADOWCOLOUR = -1;
55 
56 const int DEFAULT_DRIFT_COUNT = 1;
57 const int DEFAULT_DRIFT_USE_ANIMATION = 0;
58 const int DEFAULT_DRIFT_START_PATTERN = 0;
59 const int DEFAULT_DRIFT_END_PATTERN = 0;
60 const int DEFAULT_DRIFT_ANIMATION_TIME = 0;
61 const int DEFAULT_DRIFT_YSPEED = 1000;
62 const int DEFAULT_DRIFT_PERIOD = 0;
63 const int DEFAULT_DRIFT_AMPLITUDE = 0;
64 const int DEFAULT_DRIFT_USE_DRIFT = 0;
65 const int DEFAULT_DRIFT_UNKNOWN_PROP = 0;
66 const int DEFAULT_DRIFT_DRIFTSPEED = 0;
67 const Rect DEFAULT_DRIFT_AREA = Rect(Point(-1, -1), Size(-1, -1));
68 
69 const int DEFAULT_DIGITS_VALUE = 0;
70 const int DEFAULT_DIGITS_DIGITS = 0;
71 const int DEFAULT_DIGITS_ZERO = 0;
72 const int DEFAULT_DIGITS_SIGN = 0;
73 const int DEFAULT_DIGITS_PACK = 0;
74 const int DEFAULT_DIGITS_SPACE = 0;
75 
76 const int DEFAULT_BUTTON_IS_BUTTON = 0;
77 const int DEFAULT_BUTTON_ACTION = 0;
78 const int DEFAULT_BUTTON_SE = -1;
79 const int DEFAULT_BUTTON_GROUP = 0;
80 const int DEFAULT_BUTTON_NUMBER = 0;
81 const int DEFAULT_BUTTON_STATE = 0;
82 const bool DEFAULT_BUTTON_USING_OVERRIDES = 0;
83 const int DEFAULT_BUTTON_PATTERN_OVERRIDE = 0;
84 const int DEFAULT_BUTTON_X_OFFSET = 0;
85 const int DEFAULT_BUTTON_Y_OFFSET = 0;
86 
87 const Rect EMPTY_CLIP = Rect(Point(0, 0), Size(-1, -1));
88 
89 const boost::shared_ptr<GraphicsObject::Impl> GraphicsObject::s_empty_impl(
90     new GraphicsObject::Impl);
91 
92 // -----------------------------------------------------------------------
93 // GraphicsObject::TextProperties
94 // -----------------------------------------------------------------------
TextProperties()95 GraphicsObject::Impl::TextProperties::TextProperties()
96     : text_size(DEFAULT_TEXT_SIZE),
97       xspace(DEFAULT_TEXT_XSPACE),
98       yspace(DEFAULT_TEXT_YSPACE),
99       char_count(DEFAULT_TEXT_CHAR_COUNT),
100       colour(DEFAULT_TEXT_COLOUR),
101       shadow_colour(DEFAULT_TEXT_SHADOWCOLOUR) {}
102 
DriftProperties()103 GraphicsObject::Impl::DriftProperties::DriftProperties()
104     : count(DEFAULT_DRIFT_COUNT),
105       use_animation(DEFAULT_DRIFT_USE_ANIMATION),
106       start_pattern(DEFAULT_DRIFT_START_PATTERN),
107       end_pattern(DEFAULT_DRIFT_END_PATTERN),
108       total_animation_time_ms(DEFAULT_DRIFT_ANIMATION_TIME),
109       yspeed(DEFAULT_DRIFT_YSPEED),
110       period(DEFAULT_DRIFT_PERIOD),
111       amplitude(DEFAULT_DRIFT_AMPLITUDE),
112       use_drift(DEFAULT_DRIFT_USE_DRIFT),
113       unknown_drift_property(DEFAULT_DRIFT_UNKNOWN_PROP),
114       driftspeed(DEFAULT_DRIFT_DRIFTSPEED),
115       drift_area(DEFAULT_DRIFT_AREA) {}
116 
DigitProperties()117 GraphicsObject::Impl::DigitProperties::DigitProperties()
118     : value(DEFAULT_DIGITS_VALUE),
119       digits(DEFAULT_DIGITS_DIGITS),
120       zero(DEFAULT_DIGITS_ZERO),
121       sign(DEFAULT_DIGITS_SIGN),
122       pack(DEFAULT_DIGITS_PACK),
123       space(DEFAULT_DIGITS_SPACE) {}
124 
ButtonProperties()125 GraphicsObject::Impl::ButtonProperties::ButtonProperties()
126     : is_button(DEFAULT_BUTTON_IS_BUTTON),
127       action(DEFAULT_BUTTON_ACTION),
128       se(DEFAULT_BUTTON_SE),
129       group(DEFAULT_BUTTON_GROUP),
130       button_number(DEFAULT_BUTTON_NUMBER),
131       state(DEFAULT_BUTTON_STATE),
132       using_overides(DEFAULT_BUTTON_USING_OVERRIDES),
133       pattern_override(DEFAULT_BUTTON_PATTERN_OVERRIDE),
134       x_offset_override(DEFAULT_BUTTON_X_OFFSET),
135       y_offset_override(DEFAULT_BUTTON_Y_OFFSET) {}
136 
137 // -----------------------------------------------------------------------
138 // GraphicsObject
139 // -----------------------------------------------------------------------
GraphicsObject()140 GraphicsObject::GraphicsObject() : impl_(s_empty_impl) {}
141 
GraphicsObject(const GraphicsObject & rhs)142 GraphicsObject::GraphicsObject(const GraphicsObject& rhs) : impl_(rhs.impl_) {
143   if (rhs.object_data_) {
144     object_data_.reset(rhs.object_data_->Clone());
145     object_data_->set_owned_by(*this);
146   } else {
147     object_data_.reset();
148   }
149 
150   for (auto const& mutator : rhs.object_mutators_)
151     object_mutators_.emplace_back(mutator->Clone());
152 }
153 
~GraphicsObject()154 GraphicsObject::~GraphicsObject() { DeleteObjectMutators(); }
155 
operator =(const GraphicsObject & obj)156 GraphicsObject& GraphicsObject::operator=(const GraphicsObject& obj) {
157   DeleteObjectMutators();
158   impl_ = obj.impl_;
159 
160   if (obj.object_data_) {
161     object_data_.reset(obj.object_data_->Clone());
162     object_data_->set_owned_by(*this);
163   } else {
164     object_data_.reset();
165   }
166 
167   for (auto const& mutator : obj.object_mutators_)
168     object_mutators_.emplace_back(mutator->Clone());
169 
170   return *this;
171 }
172 
SetObjectData(GraphicsObjectData * obj)173 void GraphicsObject::SetObjectData(GraphicsObjectData* obj) {
174   object_data_.reset(obj);
175   object_data_->set_owned_by(*this);
176 }
177 
SetVisible(const int in)178 void GraphicsObject::SetVisible(const int in) {
179   MakeImplUnique();
180   impl_->visible_ = in;
181 }
182 
SetX(const int x)183 void GraphicsObject::SetX(const int x) {
184   MakeImplUnique();
185   impl_->x_ = x;
186 }
187 
SetY(const int y)188 void GraphicsObject::SetY(const int y) {
189   MakeImplUnique();
190   impl_->y_ = y;
191 }
192 
GetXAdjustmentSum() const193 int GraphicsObject::GetXAdjustmentSum() const {
194   return std::accumulate(impl_->adjust_x_, impl_->adjust_x_ + 8, 0);
195 }
196 
SetXAdjustment(int idx,int x)197 void GraphicsObject::SetXAdjustment(int idx, int x) {
198   MakeImplUnique();
199   impl_->adjust_x_[idx] = x;
200 }
201 
GetYAdjustmentSum() const202 int GraphicsObject::GetYAdjustmentSum() const {
203   return std::accumulate(impl_->adjust_y_, impl_->adjust_y_ + 8, 0);
204 }
205 
SetYAdjustment(int idx,int y)206 void GraphicsObject::SetYAdjustment(int idx, int y) {
207   MakeImplUnique();
208   impl_->adjust_y_[idx] = y;
209 }
210 
SetVert(const int vert)211 void GraphicsObject::SetVert(const int vert) {
212   MakeImplUnique();
213   impl_->whatever_adjust_vert_operates_on_ = vert;
214 }
215 
SetOriginX(const int x)216 void GraphicsObject::SetOriginX(const int x) {
217   MakeImplUnique();
218   impl_->origin_x_ = x;
219 }
220 
SetOriginY(const int y)221 void GraphicsObject::SetOriginY(const int y) {
222   MakeImplUnique();
223   impl_->origin_y_ = y;
224 }
225 
SetRepOriginX(const int x)226 void GraphicsObject::SetRepOriginX(const int x) {
227   MakeImplUnique();
228   impl_->rep_origin_x_ = x;
229 }
230 
SetRepOriginY(const int y)231 void GraphicsObject::SetRepOriginY(const int y) {
232   MakeImplUnique();
233   impl_->rep_origin_y_ = y;
234 }
235 
SetWidth(const int in)236 void GraphicsObject::SetWidth(const int in) {
237   MakeImplUnique();
238   impl_->width_ = in;
239 }
240 
SetHeight(const int in)241 void GraphicsObject::SetHeight(const int in) {
242   MakeImplUnique();
243   impl_->height_ = in;
244 }
245 
SetHqWidth(const int in)246 void GraphicsObject::SetHqWidth(const int in) {
247   MakeImplUnique();
248   impl_->hq_width_ = in;
249 }
250 
SetHqHeight(const int in)251 void GraphicsObject::SetHqHeight(const int in) {
252   MakeImplUnique();
253   impl_->hq_height_ = in;
254 }
255 
GetWidthScaleFactor() const256 float GraphicsObject::GetWidthScaleFactor() const {
257   return (impl_->width_ / 100.0f) * (impl_->hq_width_ / 1000.0f);
258 }
259 
GetHeightScaleFactor() const260 float GraphicsObject::GetHeightScaleFactor() const {
261   return (impl_->height_ / 100.0f) * (impl_->hq_height_ / 1000.0f);
262 }
263 
SetRotation(const int in)264 void GraphicsObject::SetRotation(const int in) {
265   MakeImplUnique();
266   impl_->rotation_ = in;
267 }
268 
PixelWidth() const269 int GraphicsObject::PixelWidth() const {
270   // Calculate out the pixel width of the current object taking in the
271   // width() scaling.
272   if (has_object_data())
273     return object_data_->PixelWidth(*this);
274   else
275     return 0;
276 }
277 
PixelHeight() const278 int GraphicsObject::PixelHeight() const {
279   if (has_object_data())
280     return object_data_->PixelHeight(*this);
281   else
282     return 0;
283 }
284 
GetPattNo() const285 int GraphicsObject::GetPattNo() const {
286   if (GetButtonUsingOverides())
287     return GetButtonPatternOverride();
288 
289   return impl_->patt_no_;
290 }
291 
SetPattNo(const int in)292 void GraphicsObject::SetPattNo(const int in) {
293   MakeImplUnique();
294   impl_->patt_no_ = in;
295 }
296 
SetMono(const int in)297 void GraphicsObject::SetMono(const int in) {
298   MakeImplUnique();
299   impl_->mono_ = in;
300 }
301 
SetInvert(const int in)302 void GraphicsObject::SetInvert(const int in) {
303   MakeImplUnique();
304   impl_->invert_ = in;
305 }
306 
SetLight(const int in)307 void GraphicsObject::SetLight(const int in) {
308   MakeImplUnique();
309   impl_->light_ = in;
310 }
311 
SetTint(const RGBColour & colour)312 void GraphicsObject::SetTint(const RGBColour& colour) {
313   MakeImplUnique();
314   impl_->tint_ = colour;
315 }
316 
SetTintRed(const int in)317 void GraphicsObject::SetTintRed(const int in) {
318   MakeImplUnique();
319   impl_->tint_.set_red(in);
320 }
321 
SetTintGreen(const int in)322 void GraphicsObject::SetTintGreen(const int in) {
323   MakeImplUnique();
324   impl_->tint_.set_green(in);
325 }
326 
SetTintBlue(const int in)327 void GraphicsObject::SetTintBlue(const int in) {
328   MakeImplUnique();
329   impl_->tint_.set_blue(in);
330 }
331 
SetColour(const RGBAColour & colour)332 void GraphicsObject::SetColour(const RGBAColour& colour) {
333   MakeImplUnique();
334   impl_->colour_ = colour;
335 }
336 
SetColourRed(const int in)337 void GraphicsObject::SetColourRed(const int in) {
338   MakeImplUnique();
339   impl_->colour_.set_red(in);
340 }
341 
SetColourGreen(const int in)342 void GraphicsObject::SetColourGreen(const int in) {
343   MakeImplUnique();
344   impl_->colour_.set_green(in);
345 }
346 
SetColourBlue(const int in)347 void GraphicsObject::SetColourBlue(const int in) {
348   MakeImplUnique();
349   impl_->colour_.set_blue(in);
350 }
351 
SetColourLevel(const int in)352 void GraphicsObject::SetColourLevel(const int in) {
353   MakeImplUnique();
354   impl_->colour_.set_alpha(in);
355 }
356 
SetCompositeMode(const int in)357 void GraphicsObject::SetCompositeMode(const int in) {
358   MakeImplUnique();
359   impl_->composite_mode_ = in;
360 }
361 
SetScrollRateX(const int x)362 void GraphicsObject::SetScrollRateX(const int x) {
363   MakeImplUnique();
364   impl_->scroll_rate_x_ = x;
365 }
366 
SetScrollRateY(const int y)367 void GraphicsObject::SetScrollRateY(const int y) {
368   MakeImplUnique();
369   impl_->scroll_rate_y_ = y;
370 }
371 
SetZOrder(const int in)372 void GraphicsObject::SetZOrder(const int in) {
373   MakeImplUnique();
374   impl_->z_order_ = in;
375 }
376 
SetZLayer(const int in)377 void GraphicsObject::SetZLayer(const int in) {
378   MakeImplUnique();
379   impl_->z_layer_ = in;
380 }
381 
SetZDepth(const int in)382 void GraphicsObject::SetZDepth(const int in) {
383   MakeImplUnique();
384   impl_->z_depth_ = in;
385 }
386 
GetComputedAlpha() const387 int GraphicsObject::GetComputedAlpha() const {
388   int alpha = impl_->alpha_;
389   for (int i = 0; i < 8; ++i)
390     alpha = (alpha * impl_->adjust_alpha_[i]) / 255;
391   return alpha;
392 }
393 
SetAlpha(const int alpha)394 void GraphicsObject::SetAlpha(const int alpha) {
395   MakeImplUnique();
396   impl_->alpha_ = alpha;
397 }
398 
SetAlphaAdjustment(int idx,int alpha)399 void GraphicsObject::SetAlphaAdjustment(int idx, int alpha) {
400   MakeImplUnique();
401   impl_->adjust_alpha_[idx] = alpha;
402 }
403 
ClearClipRect()404 void GraphicsObject::ClearClipRect() {
405   MakeImplUnique();
406   impl_->clip_ = EMPTY_CLIP;
407 }
408 
SetClipRect(const Rect & rect)409 void GraphicsObject::SetClipRect(const Rect& rect) {
410   MakeImplUnique();
411   impl_->clip_ = rect;
412 }
413 
ClearOwnClipRect()414 void GraphicsObject::ClearOwnClipRect() {
415   MakeImplUnique();
416   impl_->own_clip_ = EMPTY_CLIP;
417 }
418 
SetOwnClipRect(const Rect & rect)419 void GraphicsObject::SetOwnClipRect(const Rect& rect) {
420   MakeImplUnique();
421   impl_->own_clip_ = rect;
422 }
423 
GetObjectData()424 GraphicsObjectData& GraphicsObject::GetObjectData() {
425   if (object_data_) {
426     return *object_data_;
427   } else {
428     throw rlvm::Exception("null object data");
429   }
430 }
431 
SetWipeCopy(const int wipe_copy)432 void GraphicsObject::SetWipeCopy(const int wipe_copy) {
433   MakeImplUnique();
434   impl_->wipe_copy_ = wipe_copy;
435 }
436 
SetTextText(const std::string & utf8str)437 void GraphicsObject::SetTextText(const std::string& utf8str) {
438   MakeImplUnique();
439   impl_->MakeSureHaveTextProperties();
440   impl_->text_properties_->value = utf8str;
441 }
442 
GetTextText() const443 const std::string& GraphicsObject::GetTextText() const {
444   static const std::string empty = "";
445 
446   if (impl_->text_properties_)
447     return impl_->text_properties_->value;
448   else
449     return empty;
450 }
451 
GetTextSize() const452 int GraphicsObject::GetTextSize() const {
453   if (impl_->text_properties_)
454     return impl_->text_properties_->text_size;
455   else
456     return DEFAULT_TEXT_SIZE;
457 }
458 
GetTextXSpace() const459 int GraphicsObject::GetTextXSpace() const {
460   if (impl_->text_properties_)
461     return impl_->text_properties_->xspace;
462   else
463     return DEFAULT_TEXT_XSPACE;
464 }
465 
GetTextYSpace() const466 int GraphicsObject::GetTextYSpace() const {
467   if (impl_->text_properties_)
468     return impl_->text_properties_->yspace;
469   else
470     return DEFAULT_TEXT_YSPACE;
471 }
472 
GetTextCharCount() const473 int GraphicsObject::GetTextCharCount() const {
474   if (impl_->text_properties_)
475     return impl_->text_properties_->char_count;
476   else
477     return DEFAULT_TEXT_CHAR_COUNT;
478 }
479 
GetTextColour() const480 int GraphicsObject::GetTextColour() const {
481   if (impl_->text_properties_)
482     return impl_->text_properties_->colour;
483   else
484     return DEFAULT_TEXT_COLOUR;
485 }
486 
GetTextShadowColour() const487 int GraphicsObject::GetTextShadowColour() const {
488   if (impl_->text_properties_)
489     return impl_->text_properties_->shadow_colour;
490   else
491     return DEFAULT_TEXT_SHADOWCOLOUR;
492 }
493 
SetTextOps(int size,int xspace,int yspace,int char_count,int colour,int shadow)494 void GraphicsObject::SetTextOps(int size,
495                                 int xspace,
496                                 int yspace,
497                                 int char_count,
498                                 int colour,
499                                 int shadow) {
500   MakeImplUnique();
501 
502   impl_->MakeSureHaveTextProperties();
503   impl_->text_properties_->text_size = size;
504   impl_->text_properties_->xspace = xspace;
505   impl_->text_properties_->yspace = yspace;
506   impl_->text_properties_->char_count = char_count;
507   impl_->text_properties_->colour = colour;
508   impl_->text_properties_->shadow_colour = shadow;
509 }
510 
SetDriftOpts(int count,int use_animation,int start_pattern,int end_pattern,int total_animation_time_ms,int yspeed,int period,int amplitude,int use_drift,int unknown_drift_property,int driftspeed,Rect driftarea)511 void GraphicsObject::SetDriftOpts(int count,
512                                   int use_animation,
513                                   int start_pattern,
514                                   int end_pattern,
515                                   int total_animation_time_ms,
516                                   int yspeed,
517                                   int period,
518                                   int amplitude,
519                                   int use_drift,
520                                   int unknown_drift_property,
521                                   int driftspeed,
522                                   Rect driftarea) {
523   MakeImplUnique();
524 
525   impl_->MakeSureHaveDriftProperties();
526   impl_->drift_properties_->count = count;
527   impl_->drift_properties_->use_animation = use_animation;
528   impl_->drift_properties_->start_pattern = start_pattern;
529   impl_->drift_properties_->end_pattern = end_pattern;
530   impl_->drift_properties_->total_animation_time_ms = total_animation_time_ms;
531   impl_->drift_properties_->yspeed = yspeed;
532   impl_->drift_properties_->period = period;
533   impl_->drift_properties_->amplitude = amplitude;
534   impl_->drift_properties_->use_drift = use_drift;
535   impl_->drift_properties_->unknown_drift_property = unknown_drift_property;
536   impl_->drift_properties_->driftspeed = driftspeed;
537   impl_->drift_properties_->drift_area = driftarea;
538 }
539 
GetDriftParticleCount() const540 int GraphicsObject::GetDriftParticleCount() const {
541   if (impl_->drift_properties_)
542     return impl_->drift_properties_->count;
543   else
544     return DEFAULT_DRIFT_COUNT;
545 }
546 
GetDriftUseAnimation() const547 int GraphicsObject::GetDriftUseAnimation() const {
548   if (impl_->drift_properties_)
549     return impl_->drift_properties_->use_animation;
550   else
551     return DEFAULT_DRIFT_USE_ANIMATION;
552 }
553 
GetDriftStartPattern() const554 int GraphicsObject::GetDriftStartPattern() const {
555   if (impl_->drift_properties_)
556     return impl_->drift_properties_->start_pattern;
557   else
558     return DEFAULT_DRIFT_START_PATTERN;
559 }
560 
GetDriftEndPattern() const561 int GraphicsObject::GetDriftEndPattern() const {
562   if (impl_->drift_properties_)
563     return impl_->drift_properties_->end_pattern;
564   else
565     return DEFAULT_DRIFT_END_PATTERN;
566 }
567 
GetDriftAnimationTime() const568 int GraphicsObject::GetDriftAnimationTime() const {
569   if (impl_->drift_properties_)
570     return impl_->drift_properties_->total_animation_time_ms;
571   else
572     return DEFAULT_DRIFT_ANIMATION_TIME;
573 }
574 
GetDriftYSpeed() const575 int GraphicsObject::GetDriftYSpeed() const {
576   if (impl_->drift_properties_)
577     return impl_->drift_properties_->yspeed;
578   else
579     return DEFAULT_DRIFT_YSPEED;
580 }
581 
GetDriftPeriod() const582 int GraphicsObject::GetDriftPeriod() const {
583   if (impl_->drift_properties_)
584     return impl_->drift_properties_->period;
585   else
586     return DEFAULT_DRIFT_PERIOD;
587 }
588 
GetDriftAmplitude() const589 int GraphicsObject::GetDriftAmplitude() const {
590   if (impl_->drift_properties_)
591     return impl_->drift_properties_->amplitude;
592   else
593     return DEFAULT_DRIFT_AMPLITUDE;
594 }
595 
GetDriftUseDrift() const596 int GraphicsObject::GetDriftUseDrift() const {
597   if (impl_->drift_properties_)
598     return impl_->drift_properties_->use_drift;
599   else
600     return DEFAULT_DRIFT_USE_DRIFT;
601 }
602 
GetDriftUnknown() const603 int GraphicsObject::GetDriftUnknown() const {
604   if (impl_->drift_properties_)
605     return impl_->drift_properties_->unknown_drift_property;
606   else
607     return DEFAULT_DRIFT_UNKNOWN_PROP;
608 }
609 
GetDriftDriftSpeed() const610 int GraphicsObject::GetDriftDriftSpeed() const {
611   if (impl_->drift_properties_)
612     return impl_->drift_properties_->driftspeed;
613   else
614     return DEFAULT_DRIFT_UNKNOWN_PROP;
615 }
616 
GetDriftArea() const617 Rect GraphicsObject::GetDriftArea() const {
618   if (impl_->drift_properties_)
619     return impl_->drift_properties_->drift_area;
620   else
621     return Rect();
622 }
623 
SetDigitValue(int value)624 void GraphicsObject::SetDigitValue(int value) {
625   MakeImplUnique();
626   impl_->MakeSureHaveDigitProperties();
627   impl_->digit_properties_->value = value;
628 }
629 
SetDigitOpts(int digits,int zero,int sign,int pack,int space)630 void GraphicsObject::SetDigitOpts(int digits,
631                                   int zero,
632                                   int sign,
633                                   int pack,
634                                   int space) {
635   MakeImplUnique();
636 
637   impl_->MakeSureHaveDigitProperties();
638   impl_->digit_properties_->digits = digits;
639   impl_->digit_properties_->zero = zero;
640   impl_->digit_properties_->sign = sign;
641   impl_->digit_properties_->pack = pack;
642   impl_->digit_properties_->space = space;
643 }
644 
GetDigitValue() const645 int GraphicsObject::GetDigitValue() const {
646   if (impl_->digit_properties_)
647     return impl_->digit_properties_->value;
648   else
649     return DEFAULT_DIGITS_VALUE;
650 }
651 
GetDigitDigits() const652 int GraphicsObject::GetDigitDigits() const {
653   if (impl_->digit_properties_)
654     return impl_->digit_properties_->digits;
655   else
656     return DEFAULT_DIGITS_DIGITS;
657 }
658 
GetDigitZero() const659 int GraphicsObject::GetDigitZero() const {
660   if (impl_->digit_properties_)
661     return impl_->digit_properties_->zero;
662   else
663     return DEFAULT_DIGITS_ZERO;
664 }
665 
GetDigitSign() const666 int GraphicsObject::GetDigitSign() const {
667   if (impl_->digit_properties_)
668     return impl_->digit_properties_->sign;
669   else
670     return DEFAULT_DIGITS_SIGN;
671 }
672 
GetDigitPack() const673 int GraphicsObject::GetDigitPack() const {
674   if (impl_->digit_properties_)
675     return impl_->digit_properties_->pack;
676   else
677     return DEFAULT_DIGITS_PACK;
678 }
679 
GetDigitSpace() const680 int GraphicsObject::GetDigitSpace() const {
681   if (impl_->digit_properties_)
682     return impl_->digit_properties_->space;
683   else
684     return DEFAULT_DIGITS_SPACE;
685 }
686 
SetButtonOpts(int action,int se,int group,int button_number)687 void GraphicsObject::SetButtonOpts(int action,
688                                    int se,
689                                    int group,
690                                    int button_number) {
691   MakeImplUnique();
692   impl_->MakeSureHaveButtonProperties();
693   impl_->button_properties_->is_button = true;
694   impl_->button_properties_->action = action;
695   impl_->button_properties_->se = se;
696   impl_->button_properties_->group = group;
697   impl_->button_properties_->button_number = button_number;
698 }
699 
SetButtonState(int state)700 void GraphicsObject::SetButtonState(int state) {
701   MakeImplUnique();
702   impl_->MakeSureHaveButtonProperties();
703   impl_->button_properties_->state = state;
704 }
705 
IsButton() const706 int GraphicsObject::IsButton() const {
707   if (impl_->button_properties_)
708     return impl_->button_properties_->is_button;
709   else
710     return DEFAULT_BUTTON_IS_BUTTON;
711 }
712 
GetButtonAction() const713 int GraphicsObject::GetButtonAction() const {
714   if (impl_->button_properties_)
715     return impl_->button_properties_->action;
716   else
717     return DEFAULT_BUTTON_ACTION;
718 }
719 
GetButtonSe() const720 int GraphicsObject::GetButtonSe() const {
721   if (impl_->button_properties_)
722     return impl_->button_properties_->se;
723   else
724     return DEFAULT_BUTTON_SE;
725 }
726 
GetButtonGroup() const727 int GraphicsObject::GetButtonGroup() const {
728   if (impl_->button_properties_)
729     return impl_->button_properties_->group;
730   else
731     return DEFAULT_BUTTON_GROUP;
732 }
733 
GetButtonNumber() const734 int GraphicsObject::GetButtonNumber() const {
735   if (impl_->button_properties_)
736     return impl_->button_properties_->button_number;
737   else
738     return DEFAULT_BUTTON_NUMBER;
739 }
740 
GetButtonState() const741 int GraphicsObject::GetButtonState() const {
742   if (impl_->button_properties_)
743     return impl_->button_properties_->state;
744   else
745     return DEFAULT_BUTTON_STATE;
746 }
747 
SetButtonOverrides(int override_pattern,int override_x_offset,int override_y_offset)748 void GraphicsObject::SetButtonOverrides(int override_pattern,
749                                         int override_x_offset,
750                                         int override_y_offset) {
751   MakeImplUnique();
752   impl_->MakeSureHaveButtonProperties();
753   impl_->button_properties_->using_overides = true;
754   impl_->button_properties_->pattern_override = override_pattern;
755   impl_->button_properties_->x_offset_override = override_x_offset;
756   impl_->button_properties_->y_offset_override = override_y_offset;
757 }
758 
ClearButtonOverrides()759 void GraphicsObject::ClearButtonOverrides() {
760   MakeImplUnique();
761   impl_->MakeSureHaveButtonProperties();
762   impl_->button_properties_->using_overides = false;
763 }
764 
GetButtonUsingOverides() const765 bool GraphicsObject::GetButtonUsingOverides() const {
766   if (impl_->button_properties_)
767     return impl_->button_properties_->using_overides;
768   else
769     return DEFAULT_BUTTON_USING_OVERRIDES;
770 }
771 
GetButtonPatternOverride() const772 int GraphicsObject::GetButtonPatternOverride() const {
773   if (impl_->button_properties_)
774     return impl_->button_properties_->pattern_override;
775   else
776     return DEFAULT_BUTTON_PATTERN_OVERRIDE;
777 }
778 
GetButtonXOffsetOverride() const779 int GraphicsObject::GetButtonXOffsetOverride() const {
780   if (impl_->button_properties_)
781     return impl_->button_properties_->x_offset_override;
782   else
783     return DEFAULT_BUTTON_X_OFFSET;
784 }
785 
GetButtonYOffsetOverride() const786 int GraphicsObject::GetButtonYOffsetOverride() const {
787   if (impl_->button_properties_)
788     return impl_->button_properties_->y_offset_override;
789   else
790     return DEFAULT_BUTTON_Y_OFFSET;
791 }
792 
AddObjectMutator(std::unique_ptr<ObjectMutator> mutator)793 void GraphicsObject::AddObjectMutator(std::unique_ptr<ObjectMutator> mutator) {
794   MakeImplUnique();
795 
796   // If there's a currently running mutator that matches the incoming mutator,
797   // we ignore the incoming mutator. Kud Wafter's ED relies on this behavior.
798   for (std::unique_ptr<ObjectMutator>& mutator_ptr : object_mutators_) {
799     if (mutator_ptr->OperationMatches(mutator->repr(), mutator->name())) {
800       return;
801     }
802   }
803 
804   object_mutators_.push_back(std::move(mutator));
805 }
806 
IsMutatorRunningMatching(int repno,const std::string & name)807 bool GraphicsObject::IsMutatorRunningMatching(int repno,
808                                               const std::string& name) {
809   for (auto const& mutator : object_mutators_) {
810     if (mutator->OperationMatches(repno, name))
811       return true;
812   }
813 
814   return false;
815 }
816 
EndObjectMutatorMatching(RLMachine & machine,int repno,const std::string & name,int speedup)817 void GraphicsObject::EndObjectMutatorMatching(RLMachine& machine,
818                                               int repno,
819                                               const std::string& name,
820                                               int speedup) {
821   if (speedup == 0) {
822     std::vector<std::unique_ptr<ObjectMutator>>::iterator it =
823         object_mutators_.begin();
824     while (it != object_mutators_.end()) {
825       if ((*it)->OperationMatches(repno, name)) {
826         (*it)->SetToEnd(machine, *this);
827         it = object_mutators_.erase(it);
828       } else {
829         ++it;
830       }
831     }
832   } else if (speedup == 1) {
833     // This is explicitly a noop.
834   } else {
835     std::cerr << "Warning: We only do immediate endings in "
836               << "EndObjectMutatorMatching(). Unsupported speedup " << speedup
837               << std::endl;
838   }
839 }
840 
GetMutatorNames() const841 std::vector<std::string> GraphicsObject::GetMutatorNames() const {
842   std::vector<std::string> names;
843 
844   for (auto& mutator : object_mutators_) {
845     std::ostringstream oss;
846     oss << mutator->name();
847     if (mutator->repr() != -1)
848       oss << "/" << mutator->repr();
849     names.push_back(oss.str());
850   }
851 
852   return names;
853 }
854 
MakeImplUnique()855 void GraphicsObject::MakeImplUnique() {
856   if (!impl_.unique()) {
857     impl_.reset(new Impl(*impl_));
858   }
859 }
860 
DeleteObjectMutators()861 void GraphicsObject::DeleteObjectMutators() {
862   object_mutators_.clear();
863 }
864 
Render(int objNum,const GraphicsObject * parent,std::ostream * tree)865 void GraphicsObject::Render(int objNum,
866                             const GraphicsObject* parent,
867                             std::ostream* tree) {
868   if (object_data_ && visible()) {
869     if (tree) {
870       *tree << "Object #" << objNum << ":" << std::endl;
871     }
872 
873     object_data_->Render(*this, parent, tree);
874   }
875 }
876 
FreeObjectData()877 void GraphicsObject::FreeObjectData() {
878   object_data_.reset();
879   DeleteObjectMutators();
880 }
881 
InitializeParams()882 void GraphicsObject::InitializeParams() {
883   impl_ = s_empty_impl;
884   DeleteObjectMutators();
885 }
886 
FreeDataAndInitializeParams()887 void GraphicsObject::FreeDataAndInitializeParams() {
888   object_data_.reset();
889   impl_ = s_empty_impl;
890   DeleteObjectMutators();
891 }
892 
Execute(RLMachine & machine)893 void GraphicsObject::Execute(RLMachine& machine) {
894   if (object_data_) {
895     object_data_->Execute(machine);
896   }
897 
898   // Run each mutator. If it returns true, remove it.
899   std::vector<std::unique_ptr<ObjectMutator>>::iterator it =
900       object_mutators_.begin();
901   while (it != object_mutators_.end()) {
902     if ((**it)(machine, *this)) {
903       it = object_mutators_.erase(it);
904     } else {
905       ++it;
906     }
907   }
908 }
909 
910 template <class Archive>
serialize(Archive & ar,unsigned int version)911 void GraphicsObject::serialize(Archive& ar, unsigned int version) {
912   ar& impl_& object_data_;
913 }
914 
915 // -----------------------------------------------------------------------
916 
917 template void GraphicsObject::serialize<boost::archive::text_oarchive>(
918     boost::archive::text_oarchive& ar,
919     unsigned int version);
920 
921 template void GraphicsObject::serialize<boost::archive::text_iarchive>(
922     boost::archive::text_iarchive& ar,
923     unsigned int version);
924 
925 // -----------------------------------------------------------------------
926 // GraphicsObject::Impl
927 // -----------------------------------------------------------------------
Impl()928 GraphicsObject::Impl::Impl()
929     : visible_(false),
930       x_(0),
931       y_(0),
932       whatever_adjust_vert_operates_on_(0),
933       origin_x_(0),
934       origin_y_(0),
935       rep_origin_x_(0),
936       rep_origin_y_(0),
937 
938       // Width and height are percentages
939       width_(100),
940       height_(100),
941       hq_width_(1000),
942       hq_height_(1000),
943       rotation_(0),
944       patt_no_(0),
945       alpha_(255),
946       clip_(EMPTY_CLIP),
947       own_clip_(EMPTY_CLIP),
948       mono_(0),
949       invert_(0),
950       light_(0),
951       // Do the rest later.
952       tint_(RGBColour::Black()),
953       colour_(RGBAColour::Clear()),
954       composite_mode_(0),
955       scroll_rate_x_(0),
956       scroll_rate_y_(0),
957       z_order_(0),
958       z_layer_(0),
959       z_depth_(0),
960       wipe_copy_(0) {
961   // Regretfully, we can't do this in the initializer list.
962   std::fill(adjust_x_, adjust_x_ + 8, 0);
963   std::fill(adjust_y_, adjust_y_ + 8, 0);
964   std::fill(adjust_alpha_, adjust_alpha_ + 8, 255);
965 }
966 
Impl(const Impl & rhs)967 GraphicsObject::Impl::Impl(const Impl& rhs)
968     : visible_(rhs.visible_),
969       x_(rhs.x_),
970       y_(rhs.y_),
971       whatever_adjust_vert_operates_on_(rhs.whatever_adjust_vert_operates_on_),
972       origin_x_(rhs.origin_x_),
973       origin_y_(rhs.origin_y_),
974       rep_origin_x_(rhs.rep_origin_x_),
975       rep_origin_y_(rhs.rep_origin_y_),
976       width_(rhs.width_),
977       height_(rhs.height_),
978       hq_width_(rhs.hq_width_),
979       hq_height_(rhs.hq_height_),
980       rotation_(rhs.rotation_),
981       patt_no_(rhs.patt_no_),
982       alpha_(rhs.alpha_),
983       clip_(rhs.clip_),
984       own_clip_(rhs.own_clip_),
985       mono_(rhs.mono_),
986       invert_(rhs.invert_),
987       light_(rhs.light_),
988       tint_(rhs.tint_),
989       colour_(rhs.colour_),
990       composite_mode_(rhs.composite_mode_),
991       scroll_rate_x_(rhs.scroll_rate_x_),
992       scroll_rate_y_(rhs.scroll_rate_y_),
993       z_order_(rhs.z_order_),
994       z_layer_(rhs.z_layer_),
995       z_depth_(rhs.z_depth_),
996       wipe_copy_(0) {
997   if (rhs.text_properties_)
998     text_properties_.reset(new TextProperties(*rhs.text_properties_));
999   if (rhs.drift_properties_)
1000     drift_properties_.reset(new DriftProperties(*rhs.drift_properties_));
1001   if (rhs.digit_properties_)
1002     digit_properties_.reset(new DigitProperties(*rhs.digit_properties_));
1003   if (rhs.button_properties_)
1004     button_properties_.reset(new ButtonProperties(*rhs.button_properties_));
1005 
1006   std::copy(rhs.adjust_x_, rhs.adjust_x_ + 8, adjust_x_);
1007   std::copy(rhs.adjust_y_, rhs.adjust_y_ + 8, adjust_y_);
1008   std::copy(rhs.adjust_alpha_, rhs.adjust_alpha_ + 8, adjust_alpha_);
1009 }
1010 
~Impl()1011 GraphicsObject::Impl::~Impl() {}
1012 
operator =(const GraphicsObject::Impl & rhs)1013 GraphicsObject::Impl& GraphicsObject::Impl::operator=(
1014     const GraphicsObject::Impl& rhs) {
1015   if (this != &rhs) {
1016     visible_ = rhs.visible_;
1017     x_ = rhs.x_;
1018     y_ = rhs.y_;
1019 
1020     std::copy(rhs.adjust_x_, rhs.adjust_x_ + 8, adjust_x_);
1021     std::copy(rhs.adjust_y_, rhs.adjust_y_ + 8, adjust_y_);
1022     std::copy(rhs.adjust_alpha_, rhs.adjust_alpha_ + 8, adjust_alpha_);
1023 
1024     whatever_adjust_vert_operates_on_ = rhs.whatever_adjust_vert_operates_on_;
1025     origin_x_ = rhs.origin_x_;
1026     origin_y_ = rhs.origin_y_;
1027     rep_origin_x_ = rhs.rep_origin_x_;
1028     rep_origin_y_ = rhs.rep_origin_y_;
1029     width_ = rhs.width_;
1030     height_ = rhs.height_;
1031     hq_width_ = rhs.hq_width_;
1032     hq_height_ = rhs.hq_height_;
1033     rotation_ = rhs.rotation_;
1034 
1035     patt_no_ = rhs.patt_no_;
1036     alpha_ = rhs.alpha_;
1037     clip_ = rhs.clip_;
1038     own_clip_ = rhs.own_clip_;
1039     mono_ = rhs.mono_;
1040     invert_ = rhs.invert_;
1041     light_ = rhs.light_;
1042     tint_ = rhs.tint_;
1043 
1044     colour_ = rhs.colour_;
1045 
1046     composite_mode_ = rhs.composite_mode_;
1047     scroll_rate_x_ = rhs.scroll_rate_x_;
1048     scroll_rate_y_ = rhs.scroll_rate_y_;
1049     z_order_ = rhs.z_order_;
1050     z_layer_ = rhs.z_layer_;
1051     z_depth_ = rhs.z_depth_;
1052 
1053     if (rhs.text_properties_)
1054       text_properties_.reset(new TextProperties(*rhs.text_properties_));
1055     if (rhs.drift_properties_)
1056       drift_properties_.reset(new DriftProperties(*rhs.drift_properties_));
1057     if (rhs.digit_properties_)
1058       digit_properties_.reset(new DigitProperties(*rhs.digit_properties_));
1059     if (rhs.button_properties_)
1060       button_properties_.reset(new ButtonProperties(*rhs.button_properties_));
1061 
1062     wipe_copy_ = rhs.wipe_copy_;
1063   }
1064 
1065   return *this;
1066 }
1067 
MakeSureHaveTextProperties()1068 void GraphicsObject::Impl::MakeSureHaveTextProperties() {
1069   if (!text_properties_) {
1070     text_properties_.reset(new Impl::TextProperties());
1071   }
1072 }
1073 
MakeSureHaveDriftProperties()1074 void GraphicsObject::Impl::MakeSureHaveDriftProperties() {
1075   if (!drift_properties_) {
1076     drift_properties_.reset(new Impl::DriftProperties());
1077   }
1078 }
1079 
MakeSureHaveDigitProperties()1080 void GraphicsObject::Impl::MakeSureHaveDigitProperties() {
1081   if (!digit_properties_) {
1082     digit_properties_.reset(new Impl::DigitProperties());
1083   }
1084 }
1085 
MakeSureHaveButtonProperties()1086 void GraphicsObject::Impl::MakeSureHaveButtonProperties() {
1087   if (!button_properties_) {
1088     button_properties_.reset(new Impl::ButtonProperties());
1089   }
1090 }
1091 
1092 // boost::serialization support
1093 template <class Archive>
serialize(Archive & ar,unsigned int version)1094 void GraphicsObject::Impl::serialize(Archive& ar, unsigned int version) {
1095   ar& visible_& x_& y_& whatever_adjust_vert_operates_on_& origin_x_& origin_y_&
1096       rep_origin_x_& rep_origin_y_& width_& height_& rotation_& patt_no_&
1097           alpha_& clip_& mono_& invert_& tint_& colour_& composite_mode_&
1098               text_properties_& wipe_copy_;
1099 
1100   if (version > 0) {
1101     ar& drift_properties_;
1102   }
1103 
1104   if (version > 1) {
1105     ar& digit_properties_;
1106   }
1107 
1108   if (version > 2) {
1109     ar& adjust_x_& adjust_y_& adjust_alpha_;
1110   }
1111 
1112   if (version > 3) {
1113     ar& hq_width_& hq_height_& button_properties_;
1114   }
1115 
1116   if (version > 4) {
1117     ar& own_clip_;
1118   }
1119 
1120   if (version > 5) {
1121     ar& z_order_& z_layer_& z_depth_;
1122   }
1123 
1124   if (version < 7) {
1125     // Before version 7, tint and colour were set incorrectly. Therefore the
1126     // vast majority of values in save games were set incorrectly. Oops. Set to
1127     // the default here.
1128     tint_ = RGBColour::Black();
1129     colour_ = RGBAColour::Clear();
1130   }
1131 }
1132 
1133 // -----------------------------------------------------------------------
1134 
1135 // Explicit instantiations for text archives (since we hide the
1136 // implementation)
1137 
1138 template void GraphicsObject::Impl::serialize<boost::archive::text_oarchive>(
1139     boost::archive::text_oarchive& ar,
1140     unsigned int version);
1141 
1142 template void GraphicsObject::Impl::serialize<boost::archive::text_iarchive>(
1143     boost::archive::text_iarchive& ar,
1144     unsigned int version);
1145 
1146 // -----------------------------------------------------------------------
1147 // GraphicsObject::Impl::TextProperties
1148 // -----------------------------------------------------------------------
1149 template <class Archive>
serialize(Archive & ar,unsigned int version)1150 void GraphicsObject::Impl::TextProperties::serialize(Archive& ar,
1151                                                      unsigned int version) {
1152   ar& value& text_size& xspace& yspace& char_count& colour& shadow_colour;
1153 }
1154 
1155 // -----------------------------------------------------------------------
1156 
1157 // Explicit instantiations for text archives (since we hide the
1158 // implementation)
1159 
1160 template void GraphicsObject::Impl::TextProperties::serialize<
1161     boost::archive::text_oarchive>(boost::archive::text_oarchive& ar,
1162                                    unsigned int version);
1163 
1164 template void GraphicsObject::Impl::TextProperties::serialize<
1165     boost::archive::text_iarchive>(boost::archive::text_iarchive& ar,
1166                                    unsigned int version);
1167 
1168 // -----------------------------------------------------------------------
1169 // GraphicsObject::Impl::DirftProperties
1170 // -----------------------------------------------------------------------
1171 template <class Archive>
serialize(Archive & ar,unsigned int version)1172 void GraphicsObject::Impl::DriftProperties::serialize(Archive& ar,
1173                                                       unsigned int version) {
1174   ar& count& use_animation& start_pattern& end_pattern& total_animation_time_ms&
1175       yspeed& period& amplitude& use_drift& unknown_drift_property& driftspeed&
1176           drift_area;
1177 }
1178 
1179 // -----------------------------------------------------------------------
1180 
1181 template void GraphicsObject::Impl::DriftProperties::serialize<
1182     boost::archive::text_oarchive>(boost::archive::text_oarchive& ar,
1183                                    unsigned int version);
1184 
1185 template void GraphicsObject::Impl::DriftProperties::serialize<
1186     boost::archive::text_iarchive>(boost::archive::text_iarchive& ar,
1187                                    unsigned int version);
1188 
1189 // -----------------------------------------------------------------------
1190 // GraphicsObject::Impl::DigitProperties
1191 // -----------------------------------------------------------------------
1192 template <class Archive>
serialize(Archive & ar,unsigned int version)1193 void GraphicsObject::Impl::DigitProperties::serialize(Archive& ar,
1194                                                       unsigned int version) {
1195   ar& value& digits& zero& sign& pack& space;
1196 }
1197 
1198 // -----------------------------------------------------------------------
1199 
1200 template void GraphicsObject::Impl::DigitProperties::serialize<
1201     boost::archive::text_oarchive>(boost::archive::text_oarchive& ar,
1202                                    unsigned int version);
1203 
1204 template void GraphicsObject::Impl::DigitProperties::serialize<
1205     boost::archive::text_iarchive>(boost::archive::text_iarchive& ar,
1206                                    unsigned int version);
1207 
1208 // -----------------------------------------------------------------------
1209 // GraphicsObject::Impl::ButtonProperties
1210 // -----------------------------------------------------------------------
1211 template <class Archive>
serialize(Archive & ar,unsigned int version)1212 void GraphicsObject::Impl::ButtonProperties::serialize(Archive& ar,
1213                                                        unsigned int version) {
1214   // The override values are stuck here because I'm not sure about
1215   // initialization otherwise.
1216   ar& is_button& action& se& group& button_number& state& using_overides&
1217       pattern_override& x_offset_override& y_offset_override;
1218 }
1219 
1220 // -----------------------------------------------------------------------
1221 
1222 template void GraphicsObject::Impl::ButtonProperties::serialize<
1223     boost::archive::text_oarchive>(boost::archive::text_oarchive& ar,
1224                                    unsigned int version);
1225 
1226 template void GraphicsObject::Impl::ButtonProperties::serialize<
1227     boost::archive::text_iarchive>(boost::archive::text_iarchive& ar,
1228                                    unsigned int version);
1229