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 "effects/effect_factory.h"
29 
30 #include <iostream>
31 #include <sstream>
32 #include <vector>
33 
34 #include "effects/blind_effect.h"
35 #include "effects/fade_effect.h"
36 #include "effects/scroll_on_scroll_off.h"
37 #include "effects/wipe_effect.h"
38 #include "libreallive/gameexe.h"
39 #include "machine/rlmachine.h"
40 #include "systems/base/graphics_system.h"
41 #include "systems/base/surface.h"
42 #include "systems/base/system.h"
43 #include "systems/base/system_error.h"
44 #include "utilities/exception.h"
45 #include "utilities/graphics.h"
46 
47 // -----------------------------------------------------------------------
48 // EffectFactory
49 // -----------------------------------------------------------------------
50 
BuildFromSEL(RLMachine & machine,std::shared_ptr<Surface> src,std::shared_ptr<Surface> dst,int selNum)51 Effect* EffectFactory::BuildFromSEL(RLMachine& machine,
52                                     std::shared_ptr<Surface> src,
53                                     std::shared_ptr<Surface> dst,
54                                     int selNum) {
55   std::vector<int> sel_params = GetSELEffect(machine, selNum);
56 
57   return Build(machine,
58                src,
59                dst,
60                sel_params[6],
61                sel_params[7],
62                sel_params[8],
63                sel_params[9],
64                sel_params[10],
65                sel_params[11],
66                sel_params[12],
67                sel_params[13],
68                sel_params[15]);
69 }
70 
Build(RLMachine & machine,std::shared_ptr<Surface> src,std::shared_ptr<Surface> dst,int time,int style,int direction,int interpolation,int xsize,int ysize,int a,int b,int c)71 Effect* EffectFactory::Build(RLMachine& machine,
72                              std::shared_ptr<Surface> src,
73                              std::shared_ptr<Surface> dst,
74                              int time,
75                              int style,
76                              int direction,
77                              int interpolation,
78                              int xsize,
79                              int ysize,
80                              int a,
81                              int b,
82                              int c) {
83   Size screen_size = machine.system().graphics().screen_size();
84 
85   // Ensure that both of our images are on the graphics card so we don't
86   // stutter during the loop. These can be NULL in unit tests.
87   if (src)
88     src->EnsureUploaded();
89   if (dst)
90     dst->EnsureUploaded();
91 
92   // There is a completely ridiculous number of transitions here! Damn
93   // you, VisualArts, for making something so simple sounding so
94   // confusing and hard to implement!
95   switch (style) {
96     case 10:
97       return BuildWipeEffect(
98           machine, src, dst, screen_size, time, direction, interpolation);
99     // We have the bunch of similar effects that are all implemented by
100     // ScrollSquashSlideBaseEffect
101     case 15:
102     case 16:
103     case 17:
104     case 18:
105     case 20:
106     case 21: {
107       ScrollSquashSlideDrawer* drawer = BuildScrollSquashSlideDrawer(direction);
108       ScrollSquashSlideEffectTypeBase* effect =
109           BuildScrollSquashSlideTypeBase(style);
110       return new ScrollSquashSlideBaseEffect(
111           machine, src, dst, drawer, effect, screen_size, time);
112     }
113     case 120:
114       return BuildBlindEffect(
115           machine, src, dst, screen_size, time, direction, xsize, ysize);
116     case 0:
117     case 50:
118     default:
119       return new FadeEffect(machine, src, dst, screen_size, time);
120   }
121 }
122 
123 // -----------------------------------------------------------------------
124 // Private methods
125 // -----------------------------------------------------------------------
126 
127 // Which direction we wipe in
128 enum ScreenDirection {
129   TOP_TO_BOTTOM = 0,  // From the top to the bottom
130   BOTTOM_TO_TOP = 1,  // From the bottom to the top
131   LEFT_TO_RIGHT = 2,  // From left to right
132   RIGHT_TO_LEFT = 3   // From right to left
133 };
134 
BuildWipeEffect(RLMachine & machine,std::shared_ptr<Surface> src,std::shared_ptr<Surface> dst,const Size & screen_size,int time,int direction,int interpolation)135 Effect* EffectFactory::BuildWipeEffect(RLMachine& machine,
136                                        std::shared_ptr<Surface> src,
137                                        std::shared_ptr<Surface> dst,
138                                        const Size& screen_size,
139                                        int time,
140                                        int direction,
141                                        int interpolation) {
142   switch (direction) {
143     case TOP_TO_BOTTOM:
144       return new WipeTopToBottomEffect(
145           machine, src, dst, screen_size, time, interpolation);
146     case BOTTOM_TO_TOP:
147       return new WipeBottomToTopEffect(
148           machine, src, dst, screen_size, time, interpolation);
149     case LEFT_TO_RIGHT:
150       return new WipeLeftToRightEffect(
151           machine, src, dst, screen_size, time, interpolation);
152     case RIGHT_TO_LEFT:
153       return new WipeRightToLeftEffect(
154           machine, src, dst, screen_size, time, interpolation);
155     default:
156       std::cerr << "WARNING! Unsupported direction " << direction
157                 << " in EffectFactory::buildWipeEffect. Returning Top to"
158                 << " Bottom effect." << std::endl;
159       return new WipeTopToBottomEffect(
160           machine, src, dst, screen_size, time, interpolation);
161   }
162 }
163 
BuildBlindEffect(RLMachine & machine,std::shared_ptr<Surface> src,std::shared_ptr<Surface> dst,const Size & screen_size,int time,int direction,int xsize,int ysize)164 Effect* EffectFactory::BuildBlindEffect(RLMachine& machine,
165                                         std::shared_ptr<Surface> src,
166                                         std::shared_ptr<Surface> dst,
167                                         const Size& screen_size,
168                                         int time,
169                                         int direction,
170                                         int xsize,
171                                         int ysize) {
172   // RL does something really weird: if the wrong xsize/ysize was set
173   // (the correct one is zero), it uses the other.
174   switch (direction) {
175     case TOP_TO_BOTTOM:
176       if (xsize == 0 && ysize > 0)
177         xsize = ysize;
178       return new BlindTopToBottomEffect(
179           machine, src, dst, screen_size, time, xsize);
180     case BOTTOM_TO_TOP:
181       if (xsize == 0 && ysize > 0)
182         xsize = ysize;
183       return new BlindBottomToTopEffect(
184           machine, src, dst, screen_size, time, xsize);
185     case LEFT_TO_RIGHT:
186       if (ysize == 0 && xsize > 0)
187         ysize = xsize;
188       return new BlindLeftToRightEffect(
189           machine, src, dst, screen_size, time, ysize);
190     case RIGHT_TO_LEFT:
191       if (ysize == 0 && xsize > 0)
192         ysize = xsize;
193       return new BlindRightToLeftEffect(
194           machine, src, dst, screen_size, time, ysize);
195 
196     default:
197       std::cerr << "WARNING! Unsupported direction " << direction
198                 << " in EffectFactory::buildWipeEffect. Returning Top to"
199                 << " Bottom effect." << std::endl;
200       if (xsize == 0 && ysize > 0)
201         xsize = ysize;
202       return new BlindTopToBottomEffect(
203           machine, src, dst, screen_size, time, xsize);
204   }
205 }
206 
BuildScrollSquashSlideDrawer(int drawerType)207 ScrollSquashSlideDrawer* EffectFactory::BuildScrollSquashSlideDrawer(
208     int drawerType) {
209   switch (drawerType) {
210     case TOP_TO_BOTTOM:
211       return new TopToBottomDrawer;
212     case BOTTOM_TO_TOP:
213       return new BottomToTopDrawer;
214     case LEFT_TO_RIGHT:
215       return new LeftToRightDrawer;
216     case RIGHT_TO_LEFT:
217       return new RightToLeftDrawer;
218     default:
219       std::cerr << "WARNING! Unsupported direction " << drawerType
220                 << " in EffectFactory::buildWipeEffect. Returning Top to"
221                 << " Bottom effect." << std::endl;
222       return new TopToBottomDrawer;
223   }
224 }
225 
BuildScrollSquashSlideTypeBase(int style)226 ScrollSquashSlideEffectTypeBase* EffectFactory::BuildScrollSquashSlideTypeBase(
227     int style) {
228   switch (style) {
229     case 15:
230       return new ScrollOnScrollOff;
231     case 16:
232       return new ScrollOnSquashOff;
233     case 17:
234       return new SquashOnScrollOff;
235     case 18:
236       return new SquashOnSquashOff;
237     case 20:
238       return new SlideOn;
239     case 21:
240       return new SlideOff;
241     default:
242       throw SystemError(
243           "Impossible style number in "
244           "EffectFactory::buildScrollSquashSlideTypeBase");
245   }
246 }
247