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) 2009 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 #include "modules/module_bgr.h"
28
29 #include <boost/algorithm/string.hpp>
30 #include <boost/filesystem.hpp>
31 #include <iostream>
32 #include <string>
33
34 #include "effects/effect.h"
35 #include "effects/effect_factory.h"
36 #include "machine/general_operations.h"
37 #include "machine/rlmachine.h"
38 #include "machine/rloperation.h"
39 #include "machine/rloperation/argc_t.h"
40 #include "machine/rloperation/complex_t.h"
41 #include "machine/rloperation/special_t.h"
42 #include "modules/module_grp.h"
43 #include "systems/base/colour.h"
44 #include "systems/base/graphics_system.h"
45 #include "systems/base/hik_renderer.h"
46 #include "systems/base/hik_script.h"
47 #include "systems/base/surface.h"
48 #include "systems/base/system.h"
49 #include "utilities/graphics.h"
50
51 namespace fs = boost::filesystem;
52 using boost::iends_with;
53
54 // Working theory of how this module works: The haikei module is one backing
55 // surface and (optionally) a HIK script. Games like AIR and the Maiden Halo
56 // demo use just the surface with a combination of bgrMulti and
57 // bgrLoadHaikei. OTOH, ALMA and planetarian use HIK scripts and the whole
58 // point of HIK scripts is to manipulate the backing surface on a timer that's
59 // divorced from the main interpreter loop.
60
61 namespace {
62
63 struct bgrLoadHaikei_blank : public RLOpcode<IntConstant_T> {
operator ()__anon0d5ae00e0111::bgrLoadHaikei_blank64 void operator()(RLMachine& machine, int sel) {
65 GraphicsSystem& graphics = machine.system().graphics();
66 graphics.set_default_bgr_name("");
67 graphics.SetHikRenderer(NULL);
68 graphics.set_graphics_background(BACKGROUND_HIK);
69
70 std::shared_ptr<Surface> before = graphics.RenderToSurface();
71 graphics.GetHaikei()->Fill(RGBAColour::Clear());
72
73 if (!machine.replaying_graphics_stack())
74 graphics.ClearAndPromoteObjects();
75
76 std::shared_ptr<Surface> after = graphics.RenderToSurface();
77
78 LongOperation* effect =
79 EffectFactory::BuildFromSEL(machine, after, before, sel);
80 machine.PushLongOperation(effect);
81 }
82 };
83
84 struct bgrLoadHaikei_main : RLOpcode<StrConstant_T, IntConstant_T> {
operator ()__anon0d5ae00e0111::bgrLoadHaikei_main85 void operator()(RLMachine& machine, std::string filename, int sel) {
86 System& system = machine.system();
87 GraphicsSystem& graphics = system.graphics();
88 graphics.set_default_bgr_name(filename);
89 graphics.set_graphics_background(BACKGROUND_HIK);
90
91 // bgrLoadHaikei clears the stack.
92 graphics.ClearStack();
93
94 fs::path path = system.FindFile(filename, HIK_FILETYPES);
95 if (iends_with(path.string(), "hik")) {
96 if (!machine.replaying_graphics_stack())
97 graphics.ClearAndPromoteObjects();
98
99 graphics.SetHikRenderer(new HIKRenderer(
100 system, graphics.GetHIKScript(system, filename, path)));
101 } else {
102 std::shared_ptr<Surface> before = graphics.RenderToSurface();
103
104 if (!path.empty()) {
105 std::shared_ptr<const Surface> source(
106 graphics.GetSurfaceNamedAndMarkViewed(machine, filename));
107 std::shared_ptr<Surface> haikei = graphics.GetHaikei();
108 source->BlitToSurface(
109 *haikei, source->GetRect(), source->GetRect(), 255, true);
110 }
111
112 // Promote the objects if we're in normal mode. If we're restoring the
113 // graphics stack, we already have our layers promoted.
114 if (!machine.replaying_graphics_stack())
115 graphics.ClearAndPromoteObjects();
116
117 std::shared_ptr<Surface> after = graphics.RenderToSurface();
118
119 LongOperation* effect =
120 EffectFactory::BuildFromSEL(machine, after, before, sel);
121 machine.PushLongOperation(effect);
122 }
123 }
124 };
125
126 struct bgrLoadHaikei_wtf
127 : RLOpcode<StrConstant_T, IntConstant_T, IntConstant_T, IntConstant_T> {
operator ()__anon0d5ae00e0111::bgrLoadHaikei_wtf128 void operator()(RLMachine& machine,
129 std::string filename,
130 int sel,
131 int a,
132 int b) {
133 bgrLoadHaikei_main()(machine, filename, sel);
134 }
135 };
136
137 struct bgrLoadHaikei_wtf2 : RLOpcode<StrConstant_T,
138 IntConstant_T,
139 IntConstant_T,
140 IntConstant_T,
141 IntConstant_T,
142 IntConstant_T> {
operator ()__anon0d5ae00e0111::bgrLoadHaikei_wtf2143 void operator()(RLMachine& machine,
144 string filename,
145 int sel,
146 int a,
147 int b,
148 int c,
149 int d) {
150 // cerr << "Filename: " << filename
151 // << "(a: " << a << ", b: " << b << ", c: " << c << ", d: " << d <<
152 // ")"
153 // << endl;
154 bgrLoadHaikei_main()(machine, filename, sel);
155 }
156 };
157
158 // -----------------------------------------------------------------------
159
160 typedef Argc_T<Special_T<
161 DefaultSpecialMapper,
162 // 0:copy(strC 'filename')
163 StrConstant_T,
164 // 1:DUMMY. Unknown.
165 Complex_T<StrConstant_T, IntConstant_T>,
166 // 2:copy(strC 'filename', '?')
167 Complex_T<StrConstant_T, IntConstant_T>,
168 // 3:DUMMY. Unknown.
169 Complex_T<StrConstant_T, IntConstant_T>,
170 // 4:copy(strC, '?', '?')
171 Complex_T<StrConstant_T, IntConstant_T, IntConstant_T>>> BgrMultiCommand;
172
173 struct bgrMulti_1
174 : public RLOpcode<StrConstant_T, IntConstant_T, BgrMultiCommand> {
175 public:
operator ()__anon0d5ae00e0111::bgrMulti_1176 void operator()(RLMachine& machine,
177 string filename,
178 int effectNum,
179 BgrMultiCommand::type commands) {
180 GraphicsSystem& graphics = machine.system().graphics();
181
182 // Get the state of the world before we do any processing.
183 std::shared_ptr<Surface> before = graphics.RenderToSurface();
184
185 graphics.set_graphics_background(BACKGROUND_HIK);
186
187 // May need to use current background.
188 if (filename == "???")
189 filename = graphics.default_bgr_name();
190
191 // Load "filename" as the background.
192 std::shared_ptr<const Surface> surface(
193 graphics.GetSurfaceNamedAndMarkViewed(machine, filename));
194 surface->BlitToSurface(
195 *graphics.GetHaikei(), surface->GetRect(), surface->GetRect(), 255, true);
196
197 // TODO(erg): Unsure about the alpha in these implementation.
198 for (BgrMultiCommand::type::const_iterator it = commands.begin();
199 it != commands.end();
200 it++) {
201 switch (it->type) {
202 case 0: {
203 // 0:copy(strC 'filename')
204 surface = graphics.GetSurfaceNamedAndMarkViewed(machine, it->first);
205 surface->BlitToSurface(*graphics.GetHaikei(),
206 surface->GetRect(),
207 surface->GetRect(),
208 255,
209 true);
210 break;
211 }
212 case 2: {
213 // 2:copy(strC 'filename', '?')
214 Rect srcRect;
215 Point dest;
216 GetSELPointAndRect(machine, std::get<1>(it->third), srcRect, dest);
217
218 surface =
219 graphics.GetSurfaceNamedAndMarkViewed(machine,
220 std::get<0>(it->third));
221 Rect destRect = Rect(dest, srcRect.size());
222 surface->BlitToSurface(
223 *graphics.GetHaikei(), srcRect, destRect, 255, true);
224 break;
225 }
226 default: {
227 std::cerr << "Don't know what to do with a type " << it->type
228 << " in bgrMulti_1" << std::endl;
229 break;
230 }
231 }
232 }
233
234 // Promote the objects if we're in normal mode. If we're restoring the
235 // graphics stack, we already have our layers promoted.
236 if (!machine.replaying_graphics_stack())
237 graphics.ClearAndPromoteObjects();
238
239 std::shared_ptr<Surface> after = graphics.RenderToSurface();
240 LongOperation* effect =
241 EffectFactory::BuildFromSEL(machine, after, before, effectNum);
242 machine.PushLongOperation(effect);
243 }
244 };
245
246 struct bgrNext : public RLOpcode<> {
operator ()__anon0d5ae00e0111::bgrNext247 void operator()(RLMachine& machine) {
248 HIKRenderer* renderer = machine.system().graphics().hik_renderer();
249 if (renderer) {
250 renderer->NextAnimationFrame();
251 }
252 }
253 };
254
255 struct bgrSetXOffset : public RLOpcode<IntConstant_T> {
operator ()__anon0d5ae00e0111::bgrSetXOffset256 void operator()(RLMachine& machine, int offset) {
257 HIKRenderer* renderer = machine.system().graphics().hik_renderer();
258 if (renderer) {
259 renderer->set_x_offset(offset);
260 }
261 }
262 };
263
264 struct bgrSetYOffset : public RLOpcode<IntConstant_T> {
operator ()__anon0d5ae00e0111::bgrSetYOffset265 void operator()(RLMachine& machine, int offset) {
266 HIKRenderer* renderer = machine.system().graphics().hik_renderer();
267 if (renderer) {
268 renderer->set_y_offset(offset);
269 }
270 }
271 };
272
273 struct bgrPreloadScript : public RLOpcode<IntConstant_T, StrConstant_T> {
operator ()__anon0d5ae00e0111::bgrPreloadScript274 void operator()(RLMachine& machine, int slot, string name) {
275 System& system = machine.system();
276 fs::path path = system.FindFile(name, HIK_FILETYPES);
277 if (iends_with(path.string(), "hik")) {
278 system.graphics().PreloadHIKScript(system, slot, name, path);
279 }
280 }
281 };
282
283 } // namespace
284
285 // -----------------------------------------------------------------------
286
BgrModule()287 BgrModule::BgrModule() : MappedRLModule(GraphicsStackMappingFun, "Bgr", 1, 40) {
288 AddOpcode(10, 0, "bgrLoadHaikei", new bgrLoadHaikei_blank);
289 AddOpcode(10, 1, "bgrLoadHaikei", new bgrLoadHaikei_main);
290 AddOpcode(10, 2, "bgrLoadHaikei", new bgrLoadHaikei_wtf);
291 AddOpcode(10, 3, "bgrLoadHaikei", new bgrLoadHaikei_wtf2);
292
293 AddUnsupportedOpcode(100, 0, "bgrMulti");
294 AddOpcode(100, 1, "bgrMulti", new bgrMulti_1);
295
296 AddOpcode(1000, 0, "bgrNext", new bgrNext);
297
298 AddOpcode(1104, 0, "bgrSetXOffset", new bgrSetXOffset);
299 AddOpcode(1105, 0, "bgrSetYOffset", new bgrSetYOffset);
300
301 AddOpcode(2000, 0, "bgrPreloadScript", new bgrPreloadScript);
302 AddOpcode(2001,
303 0,
304 "bgrClearPreloadedScript",
305 CallFunction(&GraphicsSystem::ClearPreloadedHIKScript));
306 AddOpcode(2002,
307 0,
308 "bgrClearAllPreloadedScripts",
309 CallFunction(&GraphicsSystem::ClearAllPreloadedHIKScripts));
310 }
311