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