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 "modules/module_grp.h"
29
30 #include <boost/algorithm/string.hpp>
31 #include <functional>
32 #include <iostream>
33 #include <string>
34 #include <vector>
35
36 #include "effects/effect.h"
37 #include "effects/effect_factory.h"
38 #include "libreallive/bytecode.h"
39 #include "libreallive/expression.h"
40 #include "libreallive/gameexe.h"
41 #include "long_operations/wait_long_operation.h"
42 #include "long_operations/zoom_long_operation.h"
43 #include "machine/general_operations.h"
44 #include "machine/rlmachine.h"
45 #include "machine/rloperation.h"
46 #include "machine/rloperation/argc_t.h"
47 #include "machine/rloperation/complex_t.h"
48 #include "machine/rloperation/default_value.h"
49 #include "machine/rloperation/rect_t.h"
50 #include "machine/rloperation/rgb_colour_t.h"
51 #include "machine/rloperation/special_t.h"
52 #include "systems/base/colour.h"
53 #include "systems/base/graphics_stack_frame.h"
54 #include "systems/base/graphics_system.h"
55 #include "systems/base/surface.h"
56 #include "systems/base/system.h"
57 #include "systems/base/text_system.h"
58 #include "utilities/graphics.h"
59
60 using std::get;
61
62 namespace fs = boost::filesystem;
63
64 namespace {
65
66 // Constant names used in the graphics stack.
67 const std::string GRP_ALLOC = "allocDC";
68 const std::string GRP_WIPE = "wipe";
69 const std::string GRP_COPY = "copy";
70 const std::string GRP_DISPLAY = "display";
71 const std::string GRP_LOAD = "grpLoad";
72 const std::string GRP_OPEN = "grpOpen";
73 const std::string GRP_OPENBG = "grpOpenBg";
74
blitDC1toDC0(RLMachine & machine)75 void blitDC1toDC0(RLMachine& machine) {
76 GraphicsSystem& graphics = machine.system().graphics();
77
78 std::shared_ptr<Surface> src = graphics.GetDC(1);
79 std::shared_ptr<Surface> dst = graphics.GetDC(0);
80
81 // Blit DC1 onto DC0, with full opacity, and end the operation
82 src->BlitToSurface(*dst, src->GetRect(), dst->GetRect(), 255);
83
84 // Mark that the background should be DC0 instead of the Haikei.
85 graphics.set_graphics_background(BACKGROUND_DC0);
86
87 // Promote the objects if we're in normal mode. If we're restoring the
88 // graphics stack, we already have our layers promoted.
89 if (!machine.replaying_graphics_stack())
90 graphics.ClearAndPromoteObjects();
91 }
92
93 // Performs half the grunt work of a recOpen command; Copies DC0 to DC1, loads
94 // a graphics file, and then composites that file to DC1.
95 //
96 // Kanon uses the recOpen('?', ...) form for rendering Last Regrets. This isn't
97 // documented in the rldev manual, and we must check for that case.
loadImageToDC1(RLMachine & machine,std::string name,const Rect & srcRect,const Point & dest,int opacity,bool useAlpha)98 void loadImageToDC1(RLMachine& machine,
99 std::string name,
100 const Rect& srcRect,
101 const Point& dest,
102 int opacity,
103 bool useAlpha) {
104 GraphicsSystem& graphics = machine.system().graphics();
105
106 if (name != "?") {
107 if (name == "???")
108 name = graphics.default_grp_name();
109
110 std::shared_ptr<Surface> dc0 = graphics.GetDC(0);
111 std::shared_ptr<Surface> dc1 = graphics.GetDC(1);
112
113 // Inclusive ranges are a monstrosity to computer people
114 Size size = srcRect.size() + Size(1, 1);
115
116 dc0->BlitToSurface(*dc1, dc0->GetRect(), dc0->GetRect(), 255);
117
118 // Load the section of the image file on top of dc1
119 std::shared_ptr<const Surface> surface(
120 graphics.GetSurfaceNamedAndMarkViewed(machine, name));
121 surface->BlitToSurface(*graphics.GetDC(1),
122 Rect(srcRect.origin(), size),
123 Rect(dest, size),
124 opacity,
125 useAlpha);
126 }
127 }
128
loadDCToDC1(RLMachine & machine,int srcDc,const Rect & srcRect,const Point & dest,int opacity)129 void loadDCToDC1(RLMachine& machine,
130 int srcDc,
131 const Rect& srcRect,
132 const Point& dest,
133 int opacity) {
134 GraphicsSystem& graphics = machine.system().graphics();
135 std::shared_ptr<Surface> dc1 = graphics.GetDC(1);
136 std::shared_ptr<Surface> src = graphics.GetDC(srcDc);
137
138 // Inclusive ranges are a monstrosity to computer people
139 Size size = srcRect.size() + Size(1, 1);
140
141 src->BlitToSurface(
142 *dc1, Rect(srcRect.origin(), size), Rect(dest, size), opacity, false);
143 }
144
performEffect(RLMachine & machine,const std::shared_ptr<Surface> & src,const std::shared_ptr<Surface> & dst,int selnum)145 void performEffect(RLMachine& machine,
146 const std::shared_ptr<Surface>& src,
147 const std::shared_ptr<Surface>& dst,
148 int selnum) {
149 if (!machine.replaying_graphics_stack()) {
150 LongOperation* lop = EffectFactory::BuildFromSEL(machine, src, dst, selnum);
151 machine.PushLongOperation(lop);
152 }
153 }
154
performEffect(RLMachine & machine,const std::shared_ptr<Surface> & src,const std::shared_ptr<Surface> & dst,int time,int style,int direction,int interpolation,int xsize,int ysize,int a,int b,int c)155 void performEffect(RLMachine& machine,
156 const std::shared_ptr<Surface>& src,
157 const std::shared_ptr<Surface>& dst,
158 int time,
159 int style,
160 int direction,
161 int interpolation,
162 int xsize,
163 int ysize,
164 int a,
165 int b,
166 int c) {
167 if (!machine.replaying_graphics_stack()) {
168 LongOperation* lop = EffectFactory::Build(machine,
169 src,
170 dst,
171 time,
172 style,
173 direction,
174 interpolation,
175 xsize,
176 ysize,
177 a,
178 b,
179 c);
180 machine.PushLongOperation(lop);
181 }
182 }
183
184 // We don't hide text windows when replaying the stack because hiding the
185 // window won't be undone like it normally is!
performHideAllTextWindows(RLMachine & machine)186 void performHideAllTextWindows(RLMachine& machine) {
187 if (!machine.replaying_graphics_stack()) {
188 machine.system().text().HideAllTextWindows();
189 }
190 }
191
192 // Common code to all the openBg commands.
OpenBgPrelude(RLMachine & machine,const std::string & filename)193 void OpenBgPrelude(RLMachine& machine, const std::string& filename) {
194 if (!boost::starts_with(filename, "?")) {
195 GraphicsSystem& graphics = machine.system().graphics();
196 graphics.set_default_grp_name(filename);
197
198 // Only clear the stack when we are the command setting the background.
199 graphics.ClearStack();
200 }
201 }
202
203 // Implements op<1:Grp:00015, 0>, fun allocDC('DC', 'width', 'height').
204 //
205 // Allocates a blank width * height bitmap in dc. Any DC apart from DC 0 may be
206 // allocated thus, although DC 1 is never given a size smaller than the screen
207 // resolution. Any previous contents of dc are erased.
208 struct allocDC
209 : public RLOpcode<IntConstant_T, IntConstant_T, IntConstant_T> {
operator ()__anon19ca9ffc0111::allocDC210 void operator()(RLMachine& machine, int dc, int width, int height) {
211 machine.system().graphics().AllocateDC(dc, Size(width, height));
212 }
213 };
214
215 // Implements op<1:Grp:00031, 0>, fun wipe('DC', 'r', 'g', 'b')
216 //
217 // Fills dc with the colour indicated by the given RGB triplet.
218 struct wipe : public RLOpcode<IntConstant_T,
219 IntConstant_T,
220 IntConstant_T,
221 IntConstant_T> {
operator ()__anon19ca9ffc0111::wipe222 void operator()(RLMachine& machine, int dc, int r, int g, int b) {
223 machine.system().graphics().GetDC(dc)->Fill(RGBAColour(r, g, b));
224 }
225 };
226
227 struct shake : public RLOpcode<IntConstant_T> {
operator ()__anon19ca9ffc0111::shake228 void operator()(RLMachine& machine, int spec) {
229 machine.system().graphics().QueueShakeSpec(spec);
230
231 WaitLongOperation* wait_op = new WaitLongOperation(machine);
232 wait_op->BreakOnEvent(std::bind(StopShaking, std::ref(machine)));
233 machine.PushLongOperation(wait_op);
234 }
235
StopShaking__anon19ca9ffc0111::shake236 static bool StopShaking(RLMachine& machine) {
237 return machine.system().graphics().IsShaking() == false;
238 }
239 };
240
241 // -----------------------------------------------------------------------
242 // {grp,rec}Load Commands
243 // -----------------------------------------------------------------------
244
245 // Implements the {grp,rec}(Mask)?Load family of functions.
246 //
247 // Loads filename into dc; note that filename may not be '???'.
248 //
249 // Since this function deals with the entire screen (and therefore doesn't need
250 // to worry about the difference between grp/rec coordinate space), we write
251 // one function for both versions.
252 struct load_1
253 : public RLOpcode<StrConstant_T, IntConstant_T, DefaultIntValue_T<255>> {
254 bool use_alpha_;
load_1__anon19ca9ffc0111::load_1255 explicit load_1(bool in) : use_alpha_(in) {}
256
operator ()__anon19ca9ffc0111::load_1257 void operator()(RLMachine& machine, string filename, int dc, int opacity) {
258 GraphicsSystem& graphics = machine.system().graphics();
259
260 std::shared_ptr<const Surface> surface(
261 graphics.GetSurfaceNamedAndMarkViewed(machine, filename));
262
263 if (dc != 0 && dc != 1) {
264 graphics.AllocateDC(dc, surface->GetSize());
265 }
266
267 surface->BlitToSurface(*graphics.GetDC(dc),
268 surface->GetRect(),
269 surface->GetRect(),
270 opacity,
271 use_alpha_);
272 }
273 };
274
275 // Implements op<1:Grp:00050, 3>, fun grpLoad(strC 'filename', 'DC',
276 // 'x1', 'y1', 'x2', 'y2', 'dx', 'dy', 'alpha').
277 //
278 // Loads filename into dc; note that filename may not be '???'. Using this
279 // form, the given area of the bitmap is loaded at the given location.
280 template <typename SPACE>
281 struct load_3 : public RLOpcode<StrConstant_T,
282 IntConstant_T,
283 Rect_T<SPACE>,
284 Point_T,
285 DefaultIntValue_T<255>> {
286 bool use_alpha_;
load_3__anon19ca9ffc0111::load_3287 explicit load_3(bool in) : use_alpha_(in) {}
288
operator ()__anon19ca9ffc0111::load_3289 void operator()(RLMachine& machine,
290 string filename,
291 int dc,
292 Rect srcRect,
293 Point dest,
294 int opacity) {
295 GraphicsSystem& graphics = machine.system().graphics();
296 std::shared_ptr<const Surface> surface(
297 graphics.GetSurfaceNamedAndMarkViewed(machine, filename));
298
299 Rect destRect = Rect(dest, srcRect.size());
300
301 if (dc != 0 && dc != 1) {
302 graphics.SetMinimumSizeForDC(dc, surface->GetSize());
303 }
304
305 surface->BlitToSurface(
306 *graphics.GetDC(dc), srcRect, destRect, opacity, use_alpha_);
307 }
308 };
309
310 // -----------------------------------------------------------------------
311 // {grp,rec}Display
312 // -----------------------------------------------------------------------
313
314 struct display_1
315 : public RLOpcode<IntConstant_T, IntConstant_T, IntConstant_T> {
operator ()__anon19ca9ffc0111::display_1316 void operator()(RLMachine& machine, int dc, int effectNum, int opacity) {
317 Rect src;
318 Point dest;
319 GetSELPointAndRect(machine, effectNum, src, dest);
320
321 GraphicsSystem& graphics = machine.system().graphics();
322
323 std::shared_ptr<Surface> before = graphics.RenderToSurface();
324
325 loadDCToDC1(machine, dc, src, dest, opacity);
326 blitDC1toDC0(machine);
327
328 std::shared_ptr<Surface> after = graphics.RenderToSurface();
329 performEffect(machine, after, before, effectNum);
330 }
331 };
332
333 struct display_0 : public RLOpcode<IntConstant_T, IntConstant_T> {
334 display_1 delegate_;
335
operator ()__anon19ca9ffc0111::display_0336 void operator()(RLMachine& machine, int dc, int effectNum) {
337 std::vector<int> selEffect = GetSELEffect(machine, effectNum);
338 delegate_(machine, dc, effectNum, selEffect.at(14));
339 }
340 };
341
342 template <typename SPACE>
343 struct display_3 : public RLOpcode<IntConstant_T,
344 IntConstant_T,
345 Rect_T<SPACE>,
346 Point_T,
347 IntConstant_T> {
operator ()__anon19ca9ffc0111::display_3348 void operator()(RLMachine& machine,
349 int dc,
350 int effectNum,
351 Rect srcRect,
352 Point dest,
353 int opacity) {
354 GraphicsSystem& graphics = machine.system().graphics();
355
356 std::shared_ptr<Surface> before = graphics.RenderToSurface();
357
358 loadDCToDC1(machine, dc, srcRect, dest, opacity);
359 blitDC1toDC0(machine);
360
361 std::shared_ptr<Surface> after = graphics.RenderToSurface();
362 performEffect(machine, after, before, effectNum);
363 }
364 };
365
366 template <typename SPACE>
367 struct display_2
368 : public RLOpcode<IntConstant_T, IntConstant_T, Rect_T<SPACE>, Point_T> {
operator ()__anon19ca9ffc0111::display_2369 void operator()(RLMachine& machine,
370 int dc,
371 int effectNum,
372 Rect src_rect,
373 Point dest) {
374 int opacity = GetSELEffect(machine, effectNum).at(14);
375 display_3<SPACE>()(machine, dc, effectNum, src_rect, dest, opacity);
376 }
377 };
378
379 template <typename SPACE>
380 struct display_4 : public RLOpcode<IntConstant_T,
381 Rect_T<SPACE>,
382 Point_T,
383 IntConstant_T,
384 IntConstant_T,
385 IntConstant_T,
386 IntConstant_T,
387 IntConstant_T,
388 IntConstant_T,
389 IntConstant_T,
390 IntConstant_T,
391 IntConstant_T,
392 IntConstant_T> {
operator ()__anon19ca9ffc0111::display_4393 void operator()(RLMachine& machine,
394 int dc,
395 Rect srcRect,
396 Point dest,
397 int time,
398 int style,
399 int direction,
400 int interpolation,
401 int xsize,
402 int ysize,
403 int a,
404 int b,
405 int opacity,
406 int c) {
407 GraphicsSystem& graphics = machine.system().graphics();
408
409 std::shared_ptr<Surface> before = graphics.RenderToSurface();
410
411 loadDCToDC1(machine, dc, srcRect, dest, opacity);
412 blitDC1toDC0(machine);
413
414 std::shared_ptr<Surface> after = graphics.RenderToSurface();
415 performEffect(machine,
416 after,
417 before,
418 time,
419 style,
420 direction,
421 interpolation,
422 xsize,
423 ysize,
424 a,
425 b,
426 c);
427 }
428 };
429
430 // -----------------------------------------------------------------------
431 // {grp,rec}Open
432 // -----------------------------------------------------------------------
433
434 // Implements op<1:Grp:00076, 1>, fun grpOpen(strC 'filename', '#SEL',
435 // 'opacity').
436 //
437 // Load and display a bitmap. |filename| is loaded into DC1 with opacity
438 // |opacity|, and then is passed off to whatever transition effect, which will
439 // perform some intermediary steps and then render DC1 to DC0.
440 //
441 // TODO(erg): factor out the common code between grpOpens!
442 struct open_1
443 : public RLOpcode<StrConstant_T, IntConstant_T, IntConstant_T> {
444 bool use_alpha_;
open_1__anon19ca9ffc0111::open_1445 explicit open_1(bool in) : use_alpha_(in) {}
446
operator ()__anon19ca9ffc0111::open_1447 void operator()(RLMachine& machine,
448 string filename,
449 int effectNum,
450 int opacity) {
451 Rect src;
452 Point dest;
453 GetSELPointAndRect(machine, effectNum, src, dest);
454
455 GraphicsSystem& graphics = machine.system().graphics();
456 std::shared_ptr<Surface> before = graphics.RenderToSurface();
457
458 loadImageToDC1(machine, filename, src, dest, opacity, use_alpha_);
459 blitDC1toDC0(machine);
460
461 std::shared_ptr<Surface> after = graphics.RenderToSurface();
462 performEffect(machine, after, before, effectNum);
463 performHideAllTextWindows(machine);
464 }
465 };
466
467 // Implements op<1:Grp:00076, 0>, fun grpOpen(strC 'filename', '\#SEL').
468 //
469 // Load and display a bitmap. |filename| is loaded into DC1, and then is passed
470 // off to whatever transition effect, which will perform some intermediary
471 // steps and then render DC1 to DC0.
472 struct open_0 : public RLOpcode<StrConstant_T, IntConstant_T> {
473 open_1 delegate_;
open_0__anon19ca9ffc0111::open_0474 explicit open_0(bool in) : delegate_(in) {}
475
operator ()__anon19ca9ffc0111::open_0476 void operator()(RLMachine& machine, string filename, int effectNum) {
477 std::vector<int> selEffect = GetSELEffect(machine, effectNum);
478 delegate_(machine, filename, effectNum, selEffect[14]);
479 }
480 };
481
482 template <typename SPACE>
483 struct open_3 : public RLOpcode<StrConstant_T,
484 IntConstant_T,
485 Rect_T<SPACE>,
486 Point_T,
487 IntConstant_T> {
488 bool use_alpha_;
open_3__anon19ca9ffc0111::open_3489 explicit open_3(bool in) : use_alpha_(in) {}
490
operator ()__anon19ca9ffc0111::open_3491 void operator()(RLMachine& machine,
492 string filename,
493 int effectNum,
494 Rect srcRect,
495 Point dest,
496 int opacity) {
497 GraphicsSystem& graphics = machine.system().graphics();
498
499 std::shared_ptr<Surface> before = graphics.RenderToSurface();
500
501 // Kanon uses the recOpen('?', ...) form for rendering Last Regrets. This
502 // isn't documented in the rldev manual.
503 loadImageToDC1(machine, filename, srcRect, dest, opacity, use_alpha_);
504 blitDC1toDC0(machine);
505
506 std::shared_ptr<Surface> after = graphics.RenderToSurface();
507 performEffect(machine, after, before, effectNum);
508 performHideAllTextWindows(machine);
509 }
510 };
511
512 // Implements op<1:Grp:00076, 1>, fun grpOpen(strC 'filename', '\#SEL',
513 // 'opacity').
514 //
515 // Load and display a bitmap. |filename| is loaded into DC1 with opacity
516 // |opacity|, and then is passed off to whatever transition effect, which will
517 // perform some intermediary steps and then render DC1 to DC0.
518 template <typename SPACE>
519 struct open_2
520 : public RLOpcode<StrConstant_T, IntConstant_T, Rect_T<SPACE>, Point_T> {
521 open_3<SPACE> delegate_;
open_2__anon19ca9ffc0111::open_2522 explicit open_2(bool in) : delegate_(in) {}
523
operator ()__anon19ca9ffc0111::open_2524 void operator()(RLMachine& machine,
525 string filename,
526 int effectNum,
527 Rect src,
528 Point dest) {
529 int opacity = GetSELEffect(machine, effectNum).at(14);
530 delegate_(machine, filename, effectNum, src, dest, opacity);
531 }
532 };
533
534 template <typename SPACE>
535 struct open_4 : public RLOpcode<StrConstant_T,
536 Rect_T<SPACE>,
537 Point_T,
538 IntConstant_T,
539 IntConstant_T,
540 IntConstant_T,
541 IntConstant_T,
542 IntConstant_T,
543 IntConstant_T,
544 IntConstant_T,
545 IntConstant_T,
546 IntConstant_T,
547 IntConstant_T> {
548 bool use_alpha_;
open_4__anon19ca9ffc0111::open_4549 explicit open_4(bool in) : use_alpha_(in) {}
550
operator ()__anon19ca9ffc0111::open_4551 void operator()(RLMachine& machine,
552 string fileName,
553 Rect srcRect,
554 Point dest,
555 int time,
556 int style,
557 int direction,
558 int interpolation,
559 int xsize,
560 int ysize,
561 int a,
562 int b,
563 int opacity,
564 int c) {
565 GraphicsSystem& graphics = machine.system().graphics();
566
567 std::shared_ptr<Surface> before = graphics.RenderToSurface();
568
569 // Kanon uses the recOpen('?', ...) form for rendering Last Regrets. This
570 // isn't documented in the rldev manual.
571 loadImageToDC1(machine, fileName, srcRect, dest, opacity, use_alpha_);
572 blitDC1toDC0(machine);
573
574 std::shared_ptr<Surface> after = graphics.RenderToSurface();
575 performEffect(machine,
576 after,
577 before,
578 time,
579 style,
580 direction,
581 interpolation,
582 xsize,
583 ysize,
584 a,
585 b,
586 c);
587 performHideAllTextWindows(machine);
588 }
589 };
590
591 struct openBg_1
592 : public RLOpcode<StrConstant_T, IntConstant_T, IntConstant_T> {
operator ()__anon19ca9ffc0111::openBg_1593 void operator()(RLMachine& machine,
594 string fileName,
595 int effectNum,
596 int opacity) {
597 GraphicsSystem& graphics = machine.system().graphics();
598 Rect srcRect;
599 Point destPoint;
600 GetSELPointAndRect(machine, effectNum, srcRect, destPoint);
601
602 OpenBgPrelude(machine, fileName);
603
604 std::shared_ptr<Surface> before = graphics.RenderToSurface();
605
606 loadImageToDC1(machine, fileName, srcRect, destPoint, opacity, false);
607 blitDC1toDC0(machine);
608
609 std::shared_ptr<Surface> after = graphics.RenderToSurface();
610 performEffect(machine, after, before, effectNum);
611 performHideAllTextWindows(machine);
612 }
613 };
614
615 struct openBg_0 : public RLOpcode<StrConstant_T, IntConstant_T> {
616 openBg_1 delegate_;
617
operator ()__anon19ca9ffc0111::openBg_0618 void operator()(RLMachine& machine, string filename, int effectNum) {
619 std::vector<int> selEffect = GetSELEffect(machine, effectNum);
620 delegate_(machine, filename, effectNum, selEffect[14]);
621 }
622 };
623
624 template <typename SPACE>
625 struct openBg_3 : public RLOpcode<StrConstant_T,
626 IntConstant_T,
627 Rect_T<SPACE>,
628 Point_T,
629 IntConstant_T> {
630 bool use_alpha_;
openBg_3__anon19ca9ffc0111::openBg_3631 explicit openBg_3(bool in) : use_alpha_(in) {}
632
operator ()__anon19ca9ffc0111::openBg_3633 void operator()(RLMachine& machine,
634 string fileName,
635 int effectNum,
636 Rect srcRect,
637 Point destPt,
638 int opacity) {
639 GraphicsSystem& graphics = machine.system().graphics();
640 OpenBgPrelude(machine, fileName);
641
642 // Set the long operation for the correct transition long operation
643 std::shared_ptr<Surface> before = graphics.RenderToSurface();
644
645 loadImageToDC1(machine, fileName, srcRect, destPt, opacity, use_alpha_);
646 blitDC1toDC0(machine);
647
648 std::shared_ptr<Surface> after = graphics.RenderToSurface();
649 performEffect(machine, after, before, effectNum);
650 performHideAllTextWindows(machine);
651 }
652 };
653
654 template <typename SPACE>
655 struct openBg_2
656 : public RLOpcode<StrConstant_T, IntConstant_T, Rect_T<SPACE>, Point_T> {
657 openBg_3<SPACE> delegate_;
openBg_2__anon19ca9ffc0111::openBg_2658 explicit openBg_2(bool in) : delegate_(in) {}
659
operator ()__anon19ca9ffc0111::openBg_2660 void operator()(RLMachine& machine,
661 string fileName,
662 int effectNum,
663 Rect srcRect,
664 Point destPt) {
665 std::vector<int> selEffect = GetSELEffect(machine, effectNum);
666 delegate_(machine, fileName, effectNum, srcRect, destPt, selEffect[14]);
667 }
668 };
669
670 template <typename SPACE>
671 struct openBg_4 : public RLOpcode<StrConstant_T,
672 Rect_T<SPACE>,
673 Point_T,
674 IntConstant_T,
675 IntConstant_T,
676 IntConstant_T,
677 IntConstant_T,
678 IntConstant_T,
679 IntConstant_T,
680 IntConstant_T,
681 IntConstant_T,
682 IntConstant_T,
683 IntConstant_T> {
684 bool use_alpha_;
openBg_4__anon19ca9ffc0111::openBg_4685 explicit openBg_4(bool in) : use_alpha_(in) {}
686
operator ()__anon19ca9ffc0111::openBg_4687 void operator()(RLMachine& machine,
688 string fileName,
689 Rect srcRect,
690 Point destPt,
691 int time,
692 int style,
693 int direction,
694 int interpolation,
695 int xsize,
696 int ysize,
697 int a,
698 int b,
699 int opacity,
700 int c) {
701 GraphicsSystem& graphics = machine.system().graphics();
702 OpenBgPrelude(machine, fileName);
703
704 // Set the long operation for the correct transition long operation
705 std::shared_ptr<Surface> before = graphics.RenderToSurface();
706
707 loadImageToDC1(machine, fileName, srcRect, destPt, opacity, use_alpha_);
708 blitDC1toDC0(machine);
709
710 // Render the screen to a temporary
711 std::shared_ptr<Surface> after = graphics.RenderToSurface();
712 performEffect(machine,
713 after,
714 before,
715 time,
716 style,
717 direction,
718 interpolation,
719 xsize,
720 ysize,
721 a,
722 b,
723 c);
724 performHideAllTextWindows(machine);
725 }
726 };
727
728 // -----------------------------------------------------------------------
729 // {grp,rec}Copy
730 // -----------------------------------------------------------------------
731 template <typename SPACE>
732 struct copy_3 : public RLOpcode<Rect_T<SPACE>,
733 IntConstant_T,
734 Point_T,
735 IntConstant_T,
736 DefaultIntValue_T<255>> {
737 bool use_alpha_;
copy_3__anon19ca9ffc0111::copy_3738 explicit copy_3(bool in) : use_alpha_(in) {}
739
operator ()__anon19ca9ffc0111::copy_3740 void operator()(RLMachine& machine,
741 Rect srcRect,
742 int src,
743 Point destPoint,
744 int dst,
745 int opacity) {
746 // Copying to self is a noop
747 if (src == dst)
748 return;
749
750 GraphicsSystem& graphics = machine.system().graphics();
751
752 std::shared_ptr<Surface> sourceSurface = graphics.GetDC(src);
753
754 if (dst != 0 && dst != 1) {
755 graphics.SetMinimumSizeForDC(dst, srcRect.size());
756 }
757
758 sourceSurface->BlitToSurface(*graphics.GetDC(dst),
759 srcRect,
760 Rect(destPoint, srcRect.size()),
761 opacity,
762 use_alpha_);
763 }
764 };
765
766 struct copy_1
767 : public RLOpcode<IntConstant_T, IntConstant_T, DefaultIntValue_T<255>> {
768 bool use_alpha_;
copy_1__anon19ca9ffc0111::copy_1769 explicit copy_1(bool in) : use_alpha_(in) {}
770
operator ()__anon19ca9ffc0111::copy_1771 void operator()(RLMachine& machine, int src, int dst, int opacity) {
772 // Copying to self is a noop
773 if (src == dst)
774 return;
775
776 GraphicsSystem& graphics = machine.system().graphics();
777
778 std::shared_ptr<Surface> sourceSurface = graphics.GetDC(src);
779
780 if (dst != 0 && dst != 1) {
781 graphics.SetMinimumSizeForDC(dst, sourceSurface->GetSize());
782 }
783
784 sourceSurface->BlitToSurface(*graphics.GetDC(dst),
785 sourceSurface->GetRect(),
786 sourceSurface->GetRect(),
787 opacity,
788 use_alpha_);
789 }
790 };
791
792 // -----------------------------------------------------------------------
793 // {grp,rec}Fill
794 // -----------------------------------------------------------------------
795
796 struct fill_0 : public RLOpcode<IntConstant_T, RGBColour_T> {
operator ()__anon19ca9ffc0111::fill_0797 void operator()(RLMachine& machine, int dc, RGBAColour colour) {
798 // Justification: Maiden Halo uses fill(x, 0, 0, 0) as a synanom for clear
799 // and since it uses haikei, the DC0 needs to be transparent.
800 if (colour.r() == 0 && colour.g() == 0 && colour.b() == 0)
801 colour.set_alpha(0);
802
803 machine.system().graphics().GetDC(dc)->Fill(colour);
804 }
805 };
806
807 struct fill_1 : public RLOpcode<IntConstant_T, RGBMaybeAColour_T> {
operator ()__anon19ca9ffc0111::fill_1808 void operator()(RLMachine& machine, int dc, RGBAColour colour) {
809 machine.system().graphics().GetDC(dc)->Fill(colour);
810 }
811 };
812
813 template <typename SPACE>
814 struct fill_3
815 : public RLOpcode<Rect_T<SPACE>, IntConstant_T, RGBMaybeAColour_T> {
operator ()__anon19ca9ffc0111::fill_3816 void operator()(RLMachine& machine,
817 Rect destRect,
818 int dc,
819 RGBAColour colour) {
820 machine.system().graphics().GetDC(dc)->Fill(colour, destRect);
821 }
822 };
823
824 struct invert_1 : public RLOpcode<IntConstant_T> {
operator ()__anon19ca9ffc0111::invert_1825 void operator()(RLMachine& machine, int dc) {
826 std::shared_ptr<Surface> surface = machine.system().graphics().GetDC(dc);
827 surface->Invert(surface->GetRect());
828 }
829 };
830
831 template <typename SPACE>
832 struct invert_3 : public RLOpcode<Rect_T<SPACE>, IntConstant_T> {
operator ()__anon19ca9ffc0111::invert_3833 void operator()(RLMachine& machine, Rect rect, int dc) {
834 machine.system().graphics().GetDC(dc)->Invert(rect);
835 }
836 };
837
838 struct mono_1 : public RLOpcode<IntConstant_T> {
operator ()__anon19ca9ffc0111::mono_1839 void operator()(RLMachine& machine, int dc) {
840 std::shared_ptr<Surface> surface = machine.system().graphics().GetDC(dc);
841 surface->Mono(surface->GetRect());
842 }
843 };
844
845 template <typename SPACE>
846 struct mono_3 : public RLOpcode<Rect_T<SPACE>, IntConstant_T> {
operator ()__anon19ca9ffc0111::mono_3847 void operator()(RLMachine& machine, Rect rect, int dc) {
848 machine.system().graphics().GetDC(dc)->Mono(rect);
849 }
850 };
851
852 struct colour_1 : public RLOpcode<IntConstant_T, RGBColour_T> {
operator ()__anon19ca9ffc0111::colour_1853 void operator()(RLMachine& machine, int dc, RGBAColour colour) {
854 std::shared_ptr<Surface> surface = machine.system().graphics().GetDC(dc);
855 surface->ApplyColour(colour.rgb(), surface->GetRect());
856 }
857 };
858
859 template <typename SPACE>
860 struct colour_2
861 : public RLOpcode<Rect_T<SPACE>, IntConstant_T, RGBColour_T> {
operator ()__anon19ca9ffc0111::colour_2862 void operator()(RLMachine& machine, Rect rect, int dc, RGBAColour colour) {
863 std::shared_ptr<Surface> surface = machine.system().graphics().GetDC(dc);
864 surface->ApplyColour(colour.rgb(), rect);
865 }
866 };
867
868 struct light_1 : public RLOpcode<IntConstant_T, IntConstant_T> {
operator ()__anon19ca9ffc0111::light_1869 void operator()(RLMachine& machine, int dc, int level) {
870 std::shared_ptr<Surface> surface = machine.system().graphics().GetDC(dc);
871 surface->ApplyColour(RGBColour(level, level, level), surface->GetRect());
872 }
873 };
874
875 template <typename SPACE>
876 struct light_2
877 : public RLOpcode<Rect_T<SPACE>, IntConstant_T, IntConstant_T> {
operator ()__anon19ca9ffc0111::light_2878 void operator()(RLMachine& machine, Rect rect, int dc, int level) {
879 std::shared_ptr<Surface> surface = machine.system().graphics().GetDC(dc);
880 surface->ApplyColour(RGBColour(level, level, level), rect);
881 }
882 };
883
884 // -----------------------------------------------------------------------
885 // {grp,rec}Fade
886 // -----------------------------------------------------------------------
887
888 template <typename SPACE>
889 struct fade_7
890 : public RLOpcode<Rect_T<SPACE>, RGBColour_T, DefaultIntValue_T<0>> {
operator ()__anon19ca9ffc0111::fade_7891 void operator()(RLMachine& machine, Rect rect, RGBAColour colour, int time) {
892 GraphicsSystem& graphics = machine.system().graphics();
893 std::shared_ptr<Surface> before = graphics.RenderToSurface();
894 graphics.GetDC(0)->Fill(colour, rect);
895 std::shared_ptr<Surface> after = graphics.RenderToSurface();
896
897 if (time > 0) {
898 performEffect(machine, after, before, time, 0, 0, 0, 0, 0, 0, 0, 0);
899 }
900 }
901 };
902
903 template <typename SPACE>
904 struct fade_5
905 : public RLOpcode<Rect_T<SPACE>, IntConstant_T, DefaultIntValue_T<0>> {
906 fade_7<SPACE> delegate_;
907
operator ()__anon19ca9ffc0111::fade_5908 void operator()(RLMachine& machine, Rect rect, int colour_num, int time) {
909 Gameexe& gexe = machine.system().gameexe();
910 const std::vector<int>& rgb = gexe("COLOR_TABLE", colour_num).ToIntVector();
911 delegate_(machine, rect, RGBAColour(rgb), time);
912 }
913 };
914
915 struct fade_3 : public RLOpcode<RGBColour_T, DefaultIntValue_T<0>> {
916 fade_7<rect_impl::REC> delegate_;
917
operator ()__anon19ca9ffc0111::fade_3918 void operator()(RLMachine& machine, RGBAColour colour, int time) {
919 Size screen_size = machine.system().graphics().screen_size();
920 delegate_(machine, Rect(0, 0, screen_size), colour, time);
921 }
922 };
923
924 struct fade_1 : public RLOpcode<IntConstant_T, DefaultIntValue_T<0>> {
925 fade_7<rect_impl::REC> delegate_;
926
operator ()__anon19ca9ffc0111::fade_1927 void operator()(RLMachine& machine, int colour_num, int time) {
928 Size screen_size = machine.system().graphics().screen_size();
929 Gameexe& gexe = machine.system().gameexe();
930 const std::vector<int>& rgb = gexe("COLOR_TABLE", colour_num).ToIntVector();
931 delegate_(machine, Rect(0, 0, screen_size), RGBAColour(rgb), time);
932 }
933 };
934
935 // -----------------------------------------------------------------------
936 // {grp,rec}StretchBlit
937 // -----------------------------------------------------------------------
938 template <typename SPACE>
939 struct stretchBlit_1 : public RLOpcode<Rect_T<SPACE>,
940 IntConstant_T,
941 Rect_T<SPACE>,
942 IntConstant_T,
943 DefaultIntValue_T<255>> {
944 bool use_alpha_;
stretchBlit_1__anon19ca9ffc0111::stretchBlit_1945 explicit stretchBlit_1(bool in) : use_alpha_(in) {}
946
operator ()__anon19ca9ffc0111::stretchBlit_1947 void operator()(RLMachine& machine,
948 Rect src_rect,
949 int src,
950 Rect dst_rect,
951 int dst,
952 int opacity) {
953 // Copying to self is a noop
954 if (src == dst)
955 return;
956
957 GraphicsSystem& graphics = machine.system().graphics();
958 std::shared_ptr<Surface> sourceSurface = graphics.GetDC(src);
959
960 if (dst != 0 && dst != 1) {
961 graphics.SetMinimumSizeForDC(dst, sourceSurface->GetSize());
962 }
963
964 sourceSurface->BlitToSurface(
965 *graphics.GetDC(dst), src_rect, dst_rect, opacity, use_alpha_);
966 }
967 };
968
969 template <typename SPACE>
970 struct zoom : public RLOpcode<Rect_T<SPACE>,
971 Rect_T<SPACE>,
972 IntConstant_T,
973 Rect_T<SPACE>,
974 IntConstant_T> {
operator ()__anon19ca9ffc0111::zoom975 void operator()(RLMachine& machine,
976 Rect frect,
977 Rect trect,
978 int srcDC,
979 Rect drect,
980 int time) {
981 GraphicsSystem& gs = machine.system().graphics();
982 gs.set_graphics_background(BACKGROUND_DC0);
983
984 LongOperation* zoomOp = new ZoomLongOperation(
985 machine, gs.GetDC(0), gs.GetDC(srcDC), frect, trect, drect, time);
986 BlitAfterEffectFinishes* blitOp = new BlitAfterEffectFinishes(
987 zoomOp, gs.GetDC(srcDC), gs.GetDC(0), trect, drect);
988 machine.PushLongOperation(blitOp);
989 }
990 };
991
992 // -----------------------------------------------------------------------
993 // {grp,rec}multi
994 // -----------------------------------------------------------------------
995
996 // Defines the fairly complex parameter definition for the list of functions to
997 // call in a {grp,rec}Multi command.
998 typedef Argc_T<Special_T<
999 DefaultSpecialMapper,
1000 // 0:copy(strC 'filename')
1001 StrConstant_T,
1002 // 1:copy(strC 'filename', 'effect')
1003 Complex_T<StrConstant_T, IntConstant_T>,
1004 // 2:copy(strC 'filename', 'effect', 'alpha')
1005 Complex_T<StrConstant_T, IntConstant_T, IntConstant_T>,
1006 // 3:area(strC 'filename', 'x1', 'y1', 'x2', 'y2', 'dx', 'dy')
1007 Complex_T<StrConstant_T,
1008 IntConstant_T,
1009 IntConstant_T,
1010 IntConstant_T,
1011 IntConstant_T,
1012 IntConstant_T,
1013 IntConstant_T>,
1014 // 4:area(strC 'filename', 'x1', 'y1', 'x2', 'y2', 'dx', 'dy', 'alpha')
1015 Complex_T<StrConstant_T,
1016 IntConstant_T,
1017 IntConstant_T,
1018 IntConstant_T,
1019 IntConstant_T,
1020 IntConstant_T,
1021 IntConstant_T,
1022 IntConstant_T>>> MultiCommand;
1023
1024 // -----------------------------------------------------------------------
1025
1026 // Defines the weird multi commands. I will be the first to admit that the
1027 // following is fairly difficult to read; it comes from the quagmire of
1028 // composing Special_T and ComplexX_T templates.
1029 //
1030 // In the end, this operation struct simply Dispatches the Special/Complex
1031 // commands to functions and other operation structs that are clearer in
1032 // purpose.
1033
1034 // All work is applied to DC 1.
1035 const int MULTI_TARGET_DC = 1;
1036
1037 template <typename SPACE>
1038 struct multi_command {
1039 void handleMultiCommands(RLMachine& machine,
1040 const MultiCommand::type& commands);
1041 };
1042
1043 template <typename SPACE>
handleMultiCommands(RLMachine & machine,const MultiCommand::type & commands)1044 void multi_command<SPACE>::handleMultiCommands(
1045 RLMachine& machine,
1046 const MultiCommand::type& commands) {
1047 for (MultiCommand::type::const_iterator it = commands.begin();
1048 it != commands.end();
1049 it++) {
1050 switch (it->type) {
1051 case 0:
1052 // 0:copy(strC 'filename')
1053 if (it->first != "")
1054 load_1(true)(machine, it->first, MULTI_TARGET_DC, 255);
1055 break;
1056 case 1: {
1057 // 1:copy(strC 'filename', 'effect')
1058 if (get<0>(it->second) != "") {
1059 Rect src;
1060 Point dest;
1061 GetSELPointAndRect(machine, get<1>(it->second), src, dest);
1062
1063 load_3<SPACE>(true)(
1064 machine, get<0>(it->second), MULTI_TARGET_DC, src, dest, 255);
1065 }
1066 break;
1067 }
1068 case 2: {
1069 // 2:copy(strC 'filename', 'effect', 'alpha')
1070 if (get<0>(it->third) != "") {
1071 Rect src;
1072 Point dest;
1073 GetSELPointAndRect(machine, get<1>(it->third), src, dest);
1074
1075 load_3<SPACE>(true)(machine,
1076 get<0>(it->third),
1077 MULTI_TARGET_DC,
1078 src,
1079 dest,
1080 get<2>(it->third));
1081 }
1082 break;
1083 }
1084 case 3: {
1085 // 3:area(strC 'filename', 'x1', 'y1', 'x2', 'y2', 'dx', 'dy')
1086 if (get<0>(it->fourth) != "") {
1087 load_3<SPACE>(true)(machine,
1088 get<0>(it->fourth),
1089 MULTI_TARGET_DC,
1090 SPACE::makeRect(get<1>(it->fourth),
1091 get<2>(it->fourth),
1092 get<3>(it->fourth),
1093 get<4>(it->fourth)),
1094 Point(get<5>(it->fourth), get<6>(it->fourth)),
1095 255);
1096 }
1097 break;
1098 }
1099 case 4: {
1100 // 4:area(strC 'filename', 'x1', 'y1', 'x2', 'y2', 'dx', 'dy', 'alpha')
1101 if (get<0>(it->fifth) != "") {
1102 load_3<SPACE>(true)(machine,
1103 get<0>(it->fifth),
1104 MULTI_TARGET_DC,
1105 SPACE::makeRect(get<1>(it->fifth),
1106 get<2>(it->fifth),
1107 get<3>(it->fifth),
1108 get<4>(it->fifth)),
1109 Point(get<5>(it->fifth), get<6>(it->fifth)),
1110 get<7>(it->fifth));
1111 }
1112 break;
1113 }
1114 }
1115 }
1116 }
1117
1118 // fun grpMulti <1:Grp:00075, 4> (<strC 'filename', <'effect', MultiCommand)
1119 template <typename SPACE>
1120 struct multi_str_1 : public RLOpcode<StrConstant_T,
1121 IntConstant_T,
1122 IntConstant_T,
1123 MultiCommand>,
1124 public multi_command<SPACE> {
operator ()__anon19ca9ffc0111::multi_str_11125 void operator()(RLMachine& machine,
1126 string filename,
1127 int effect,
1128 int alpha,
1129 MultiCommand::type commands) {
1130 load_1(false)(machine, filename, MULTI_TARGET_DC, 255);
1131 multi_command<SPACE>::handleMultiCommands(machine, commands);
1132 display_0()(machine, MULTI_TARGET_DC, effect);
1133 }
1134 };
1135
1136 template <typename SPACE>
1137 struct multi_str_0
1138 : public RLOpcode<StrConstant_T, IntConstant_T, MultiCommand> {
1139 multi_str_1<SPACE> delegate_;
1140
operator ()__anon19ca9ffc0111::multi_str_01141 void operator()(RLMachine& machine,
1142 string filename,
1143 int effect,
1144 MultiCommand::type commands) {
1145 delegate_(machine, filename, effect, 255, commands);
1146 }
1147 };
1148
1149 template <typename SPACE>
1150 struct multi_dc_1 : public RLOpcode<IntConstant_T,
1151 IntConstant_T,
1152 IntConstant_T,
1153 MultiCommand>,
1154 public multi_command<SPACE> {
operator ()__anon19ca9ffc0111::multi_dc_11155 void operator()(RLMachine& machine,
1156 int dc,
1157 int effect,
1158 int alpha,
1159 MultiCommand::type commands) {
1160 copy_1(false)(machine, dc, MULTI_TARGET_DC, 255);
1161 multi_command<SPACE>::handleMultiCommands(machine, commands);
1162 display_0()(machine, MULTI_TARGET_DC, effect);
1163 }
1164 };
1165
1166 template <typename SPACE>
1167 struct multi_dc_0
1168 : public RLOpcode<IntConstant_T, IntConstant_T, MultiCommand> {
1169 multi_dc_1<SPACE> delegate_;
1170
operator ()__anon19ca9ffc0111::multi_dc_01171 void operator()(RLMachine& machine,
1172 int dc,
1173 int effect,
1174 MultiCommand::type commands) {
1175 delegate_(machine, dc, effect, 255, commands);
1176 }
1177 };
1178
1179 // Special case adapter to record every graphics command onto the "graphics
1180 // stack"
1181 class GrpStackAdapter : public RLOp_SpecialCase {
1182 public:
GrpStackAdapter(RLOperation * in)1183 explicit GrpStackAdapter(RLOperation* in) : operation(in) {}
1184
operator ()(RLMachine & machine,const libreallive::CommandElement & ff)1185 void operator()(RLMachine& machine, const libreallive::CommandElement& ff) {
1186 operation->DispatchFunction(machine, ff);
1187
1188 // Record this command's reallive bytecode form onto the graphics stack.
1189 machine.system().graphics().AddGraphicsStackCommand(
1190 ff.GetSerializedCommand(machine));
1191 }
1192
1193 private:
1194 std::unique_ptr<RLOperation> operation;
1195 };
1196
1197 } // namespace
1198
GraphicsStackMappingFun(RLOperation * op)1199 RLOperation* GraphicsStackMappingFun(RLOperation* op) {
1200 return new GrpStackAdapter(op);
1201 }
1202
GrpModule()1203 GrpModule::GrpModule() : MappedRLModule(GraphicsStackMappingFun, "Grp", 1, 33) {
1204 using rect_impl::GRP;
1205 using rect_impl::REC;
1206
1207 AddOpcode(15, 0, "allocDC", new allocDC);
1208 AddOpcode(16, 0, "FreeDC", CallFunction(&GraphicsSystem::FreeDC));
1209
1210 AddUnsupportedOpcode(20, 0, "grpLoadMask");
1211 // AddOpcode(30, 0, new grpTextout);
1212
1213 AddOpcode(31, 0, "wipe", new wipe);
1214 AddOpcode(32, 0, "shake", new shake);
1215
1216 AddOpcode(50, 0, "grpLoad", new load_1(false));
1217 AddOpcode(50, 1, "grpLoad", new load_1(false));
1218 AddOpcode(50, 2, "grpLoad", new load_3<GRP>(false));
1219 AddOpcode(50, 3, "grpLoad", new load_3<GRP>(false));
1220 AddOpcode(51, 0, "grpMaskLoad", new load_1(true));
1221 AddOpcode(51, 1, "grpMaskLoad", new load_1(true));
1222 AddOpcode(51, 2, "grpMaskLoad", new load_3<GRP>(true));
1223 AddOpcode(51, 3, "grpMaskLoad", new load_3<GRP>(true));
1224
1225 // These are grpBuffer, which is very similar to grpLoad and Haeleth
1226 // doesn't know how they differ. For now, we just assume they're
1227 // equivalent.
1228 AddOpcode(70, 0, "grpBuffer", new load_1(false));
1229 AddOpcode(70, 1, "grpBuffer", new load_1(false));
1230 AddOpcode(70, 2, "grpBuffer", new load_3<GRP>(false));
1231 AddOpcode(70, 3, "grpBuffer", new load_3<GRP>(false));
1232 AddOpcode(71, 0, "grpMaskBuffer", new load_1(true));
1233 AddOpcode(71, 1, "grpMaskBuffer", new load_1(true));
1234 AddOpcode(71, 2, "grpMaskBuffer", new load_3<GRP>(true));
1235 AddOpcode(71, 3, "grpMaskBuffer", new load_3<GRP>(true));
1236
1237 AddOpcode(72, 0, "grpDisplay", new display_0);
1238 AddOpcode(72, 1, "grpDisplay", new display_1);
1239 AddOpcode(72, 2, "grpDisplay", new display_2<GRP>());
1240 AddOpcode(72, 3, "grpDisplay", new display_3<GRP>());
1241 AddOpcode(72, 4, "grpDisplay", new display_4<GRP>());
1242
1243 AddOpcode(73, 0, "grpOpenBg", new openBg_0);
1244 AddOpcode(73, 1, "grpOpenBg", new openBg_1);
1245 AddOpcode(73, 2, "grpOpenBg", new openBg_2<GRP>(false));
1246 AddOpcode(73, 3, "grpOpenBg", new openBg_3<GRP>(false));
1247 AddOpcode(73, 4, "grpOpenBg", new openBg_4<GRP>(false));
1248
1249 AddOpcode(74, 0, "grpMaskOpen", new open_0(true));
1250 AddOpcode(74, 1, "grpMaskOpen", new open_1(true));
1251 AddOpcode(74, 2, "grpMaskOpen", new open_2<GRP>(true));
1252 AddOpcode(74, 3, "grpMaskOpen", new open_3<GRP>(true));
1253 AddOpcode(74, 4, "grpMaskOpen", new open_4<GRP>(true));
1254
1255 AddOpcode(75, 0, "grpMulti", new multi_str_0<GRP>());
1256 AddOpcode(75, 1, "grpMulti", new multi_str_1<GRP>());
1257 AddUnsupportedOpcode(75, 2, "grpMulti");
1258 AddUnsupportedOpcode(75, 3, "grpMulti");
1259 AddUnsupportedOpcode(75, 4, "grpMulti");
1260
1261 AddOpcode(76, 0, "grpOpen", new open_0(false));
1262 AddOpcode(76, 1, "grpOpen", new open_1(false));
1263 AddOpcode(76, 2, "grpOpen", new open_2<GRP>(false));
1264 AddOpcode(76, 3, "grpOpen", new open_3<GRP>(false));
1265 AddOpcode(76, 4, "grpOpen", new open_4<GRP>(false));
1266
1267 AddOpcode(77, 0, "grpMulti", new multi_dc_0<GRP>());
1268 AddOpcode(77, 1, "grpMulti", new multi_dc_1<GRP>());
1269 AddUnsupportedOpcode(77, 2, "grpMulti");
1270 AddUnsupportedOpcode(77, 3, "grpMulti");
1271 AddUnsupportedOpcode(77, 4, "grpMulti");
1272
1273 AddOpcode(100, 0, "grpCopy", new copy_1(false));
1274 AddOpcode(100, 1, "grpCopy", new copy_1(false));
1275 AddOpcode(100, 2, "grpCopy", new copy_3<GRP>(false));
1276 AddOpcode(100, 3, "grpCopy", new copy_3<GRP>(false));
1277 AddOpcode(101, 0, "grpMaskCopy", new copy_1(true));
1278 AddOpcode(101, 1, "grpMaskCopy", new copy_1(true));
1279 AddOpcode(101, 2, "grpMaskCopy", new copy_3<GRP>(true));
1280 AddOpcode(101, 3, "grpMaskCopy", new copy_3<GRP>(true));
1281
1282 AddUnsupportedOpcode(120, 5, "grpCopyWithMask");
1283 AddUnsupportedOpcode(140, 5, "grpCopyInvMask");
1284
1285 AddOpcode(201, 0, "grpFill", new fill_0);
1286 AddOpcode(201, 1, "grpFill", new fill_1);
1287 AddOpcode(201, 2, "grpFill", new fill_3<GRP>());
1288 AddOpcode(201, 3, "grpFill", new fill_3<GRP>());
1289
1290 AddOpcode(300, 0, "grpInvert", new invert_1);
1291 AddUnsupportedOpcode(300, 1, "grpInvert");
1292 AddOpcode(300, 2, "grpInvert", new invert_3<GRP>());
1293 AddUnsupportedOpcode(300, 3, "grpInvert");
1294
1295 AddOpcode(301, 0, "grpMono", new mono_1);
1296 AddUnsupportedOpcode(301, 1, "grpMono");
1297 AddOpcode(301, 2, "grpMono", new mono_3<GRP>());
1298 AddUnsupportedOpcode(301, 3, "grpMono");
1299
1300 AddOpcode(302, 0, "grpColour", new colour_1);
1301 AddOpcode(302, 1, "grpColour", new colour_2<GRP>());
1302
1303 AddOpcode(303, 0, "grpLight", new light_1);
1304 AddOpcode(303, 1, "grpLight", new light_2<GRP>());
1305
1306 AddUnsupportedOpcode(400, 0, "grpSwap");
1307 AddUnsupportedOpcode(400, 1, "grpSwap");
1308
1309 AddOpcode(401, 0, "grpStretchBlt", new stretchBlit_1<GRP>(false));
1310 AddOpcode(401, 1, "grpStretchBlt", new stretchBlit_1<GRP>(false));
1311
1312 AddOpcode(402, 0, "grpZoom", new zoom<GRP>());
1313
1314 AddOpcode(403, 0, "grpFade", new fade_1);
1315 AddOpcode(403, 1, "grpFade", new fade_1);
1316 AddOpcode(403, 2, "grpFade", new fade_3);
1317 AddOpcode(403, 3, "grpFade", new fade_3);
1318 AddOpcode(403, 4, "grpFade", new fade_5<GRP>());
1319 AddOpcode(403, 5, "grpFade", new fade_5<GRP>());
1320 AddOpcode(403, 6, "grpFade", new fade_7<GRP>());
1321 AddOpcode(403, 7, "grpFade", new fade_7<GRP>());
1322
1323 AddOpcode(409, 0, "grpMaskStretchBlt", new stretchBlit_1<GRP>(true));
1324 AddOpcode(409, 1, "grpMaskStretchBlt", new stretchBlit_1<GRP>(true));
1325
1326 AddUnsupportedOpcode(601, 0, "grpMaskAdd");
1327 AddUnsupportedOpcode(601, 1, "grpMaskAdd");
1328 AddUnsupportedOpcode(601, 2, "grpMaskAdd");
1329 AddUnsupportedOpcode(601, 3, "grpMaskAdd");
1330
1331 // -----------------------------------------------------------------------
1332
1333 AddOpcode(1050, 0, "recLoad", new load_1(false));
1334 AddOpcode(1050, 1, "recLoad", new load_1(false));
1335 AddOpcode(1050, 2, "recLoad", new load_3<REC>(false));
1336 AddOpcode(1050, 3, "recLoad", new load_3<REC>(false));
1337
1338 AddOpcode(1051, 0, "recMaskLoad", new load_1(true));
1339 AddOpcode(1051, 1, "recMaskLoad", new load_1(true));
1340 AddOpcode(1051, 2, "recMaskLoad", new load_3<REC>(true));
1341 AddOpcode(1051, 3, "recMaskLoad", new load_3<REC>(true));
1342
1343 AddOpcode(1052, 0, "recDisplay", new display_0);
1344 AddOpcode(1052, 1, "recDisplay", new display_1);
1345 AddOpcode(1052, 2, "recDisplay", new display_2<REC>());
1346 AddOpcode(1052, 3, "recDisplay", new display_3<REC>());
1347 AddOpcode(1052, 4, "recDisplay", new display_4<REC>());
1348
1349 AddOpcode(1053, 0, "recOpenBg", new openBg_0);
1350 AddOpcode(1053, 1, "recOpenBg", new openBg_1);
1351 AddOpcode(1053, 2, "recOpenBg", new openBg_2<REC>(false));
1352 AddOpcode(1053, 3, "recOpenBg", new openBg_3<REC>(false));
1353 AddOpcode(1053, 4, "recOpenBg", new openBg_4<REC>(false));
1354
1355 AddOpcode(1054, 0, "recMaskOpen", new open_0(true));
1356 AddOpcode(1054, 1, "recMaskOpen", new open_1(true));
1357 AddOpcode(1054, 2, "recMaskOpen", new open_2<REC>(true));
1358 AddOpcode(1054, 3, "recMaskOpen", new open_3<REC>(true));
1359 AddOpcode(1054, 4, "recMaskOpen", new open_4<REC>(true));
1360
1361 AddOpcode(1056, 0, "recOpen", new open_0(false));
1362 AddOpcode(1056, 1, "recOpen", new open_1(false));
1363 AddOpcode(1056, 2, "recOpen", new open_2<REC>(false));
1364 AddOpcode(1056, 3, "recOpen", new open_3<REC>(false));
1365 AddOpcode(1056, 4, "recOpen", new open_4<REC>(false));
1366
1367 AddOpcode(1055, 0, "recMulti", new multi_str_0<REC>());
1368 AddOpcode(1055, 1, "recMulti", new multi_str_1<REC>());
1369 AddUnsupportedOpcode(1055, 2, "recMulti");
1370 AddUnsupportedOpcode(1055, 3, "recMulti");
1371 AddUnsupportedOpcode(1055, 4, "recMulti");
1372
1373 AddOpcode(1057, 0, "recMulti", new multi_dc_0<REC>());
1374 AddOpcode(1057, 1, "recMulti", new multi_dc_1<REC>());
1375 AddUnsupportedOpcode(1057, 2, "recMulti");
1376 AddUnsupportedOpcode(1057, 3, "recMulti");
1377 AddUnsupportedOpcode(1057, 4, "recMulti");
1378
1379 AddOpcode(1100, 0, "recCopy", new copy_1(false));
1380 AddOpcode(1100, 1, "recCopy", new copy_1(false));
1381 AddOpcode(1100, 2, "recCopy", new copy_3<REC>(false));
1382 AddOpcode(1100, 3, "recCopy", new copy_3<REC>(false));
1383 AddOpcode(1101, 0, "recMaskCopy", new copy_1(true));
1384 AddOpcode(1101, 1, "recMaskCopy", new copy_1(true));
1385 AddOpcode(1101, 2, "recMaskCopy", new copy_3<REC>(true));
1386 AddOpcode(1101, 3, "recMaskCopy", new copy_3<REC>(true));
1387
1388 AddOpcode(1201, 0, "recFill", new fill_0);
1389 AddOpcode(1201, 1, "recFill", new fill_1);
1390 AddOpcode(1201, 2, "recFill", new fill_3<REC>());
1391 AddOpcode(1201, 3, "recFill", new fill_3<REC>());
1392
1393 AddOpcode(1300, 0, "recInvert", new invert_1);
1394 AddUnsupportedOpcode(1300, 1, "recInvert");
1395 AddOpcode(1300, 2, "recInvert", new invert_3<REC>());
1396 AddUnsupportedOpcode(1300, 3, "recInvert");
1397
1398 AddOpcode(1301, 0, "recMono", new mono_1);
1399 AddUnsupportedOpcode(1301, 1, "recMono");
1400 AddOpcode(1301, 2, "recMono", new mono_3<REC>());
1401 AddUnsupportedOpcode(1301, 3, "recMono");
1402
1403 AddOpcode(1302, 0, "recColour", new colour_1);
1404 AddOpcode(1302, 1, "recColour", new colour_2<REC>());
1405
1406 AddOpcode(1303, 0, "recLight", new light_1);
1407 AddOpcode(1303, 1, "recLight", new light_2<REC>());
1408
1409 AddUnsupportedOpcode(1400, 0, "recSwap");
1410 AddUnsupportedOpcode(1400, 1, "recSwap");
1411
1412 AddOpcode(1401, 0, "recStretchBlt", new stretchBlit_1<REC>(false));
1413 AddOpcode(1401, 1, "recStretchBlt", new stretchBlit_1<REC>(false));
1414
1415 AddOpcode(1402, 0, "recZoom", new zoom<REC>());
1416
1417 AddOpcode(1403, 0, "recFade", new fade_1);
1418 AddOpcode(1403, 1, "recFade", new fade_1);
1419 AddOpcode(1403, 2, "recFade", new fade_3);
1420 AddOpcode(1403, 3, "recFade", new fade_3);
1421 AddOpcode(1403, 4, "recFade", new fade_5<REC>());
1422 AddOpcode(1403, 5, "recFade", new fade_5<REC>());
1423 AddOpcode(1403, 6, "recFade", new fade_7<REC>());
1424 AddOpcode(1403, 7, "recFade", new fade_7<REC>());
1425
1426 AddUnsupportedOpcode(1404, 0, "recFlash");
1427 AddUnsupportedOpcode(1404, 1, "recFlash");
1428 AddUnsupportedOpcode(1404, 2, "recFlash");
1429 AddUnsupportedOpcode(1404, 3, "recFlash");
1430
1431 AddUnsupportedOpcode(1406, 0, "recPan");
1432 AddUnsupportedOpcode(1407, 0, "recShift");
1433 AddUnsupportedOpcode(1408, 0, "recSlide");
1434 AddOpcode(1409, 0, "recMaskStretchBlt", new stretchBlit_1<REC>(true));
1435 AddOpcode(1409, 1, "recMaskStretchBlt", new stretchBlit_1<REC>(true));
1436 }
1437
1438 // @}
1439
1440 // -----------------------------------------------------------------------
1441
ReplayGraphicsStackCommand(RLMachine & machine,const std::deque<std::string> & stack)1442 void ReplayGraphicsStackCommand(RLMachine& machine,
1443 const std::deque<std::string>& stack) {
1444 try {
1445 for (auto const& command : stack) {
1446 if (command != "") {
1447 // Parse the string as a chunk of Reallive bytecode.
1448 libreallive::ConstructionData cdata(0, libreallive::pointer_t());
1449 libreallive::BytecodeElement* element =
1450 libreallive::BytecodeElement::Read(
1451 command.c_str(), command.c_str() + command.size(), cdata);
1452 libreallive::CommandElement* command =
1453 dynamic_cast<libreallive::CommandElement*>(element);
1454 if (command) {
1455 machine.ExecuteCommand(*command);
1456 }
1457 }
1458 }
1459 }
1460 catch (std::exception& e) {
1461 std::cerr << "Error while replaying graphics stack: " << e.what()
1462 << std::endl;
1463 return;
1464 }
1465 }
1466
1467 // -----------------------------------------------------------------------
1468
ReplayDepricatedGraphicsStackVector(RLMachine & machine,const std::vector<GraphicsStackFrame> & gstack)1469 void ReplayDepricatedGraphicsStackVector(
1470 RLMachine& machine,
1471 const std::vector<GraphicsStackFrame>& gstack) {
1472 for (auto const& frame : gstack) {
1473 try {
1474 if (frame.name() == GRP_LOAD) {
1475 if (frame.hasTargetCoordinates()) {
1476 load_3<rect_impl::REC>(frame.mask())(machine,
1477 frame.filename(),
1478 frame.targetDC(),
1479 frame.sourceRect(),
1480 frame.targetPoint(),
1481 frame.opacity());
1482 } else {
1483 // Older versions of rlvm didn't record the mask bit, so make sure we
1484 // check for that since we don't want to break old save games.
1485 bool mask = (frame.hasMask() ? frame.mask() : true);
1486 load_1 loader(mask);
1487 loader(machine, frame.filename(), frame.targetDC(), frame.opacity());
1488 }
1489 } else if (frame.name() == GRP_OPEN) {
1490 // open is just a load + an animation.
1491 loadImageToDC1(machine,
1492 frame.filename(),
1493 frame.sourceRect(),
1494 frame.targetPoint(),
1495 frame.opacity(),
1496 frame.mask());
1497 blitDC1toDC0(machine);
1498 } else if (frame.name() == GRP_COPY) {
1499 if (frame.hasSourceCoordinates()) {
1500 copy_3<rect_impl::REC>(frame.mask())(machine,
1501 frame.sourceRect(),
1502 frame.sourceDC(),
1503 frame.targetPoint(),
1504 frame.targetDC(),
1505 frame.opacity());
1506 } else {
1507 copy_1(frame.mask())(
1508 machine, frame.sourceDC(), frame.targetDC(), frame.opacity());
1509 }
1510 } else if (frame.name() == GRP_DISPLAY) {
1511 loadDCToDC1(machine,
1512 frame.sourceDC(),
1513 frame.sourceRect(),
1514 frame.targetPoint(),
1515 frame.opacity());
1516 blitDC1toDC0(machine);
1517 } else if (frame.name() == GRP_OPENBG) {
1518 loadImageToDC1(machine,
1519 frame.filename(),
1520 frame.sourceRect(),
1521 frame.targetPoint(),
1522 frame.opacity(),
1523 false);
1524 blitDC1toDC0(machine);
1525 } else if (frame.name() == GRP_ALLOC) {
1526 Point target = frame.targetPoint();
1527 allocDC()(machine, frame.targetDC(), target.x(), target.y());
1528 } else if (frame.name() == GRP_WIPE) {
1529 wipe()(machine, frame.targetDC(), frame.r(), frame.g(), frame.b());
1530 }
1531 }
1532 catch (rlvm::Exception& e) {
1533 std::cerr << "WARNING: Error while thawing graphics stack: "
1534 << e.what() << std::endl;
1535 }
1536 }
1537 }
1538