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 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_obj.h"
29
30 #include "machine/properties.h"
31 #include "machine/rlmachine.h"
32 #include "systems/base/graphics_object.h"
33 #include "systems/base/graphics_system.h"
34 #include "systems/base/parent_graphics_object_data.h"
35 #include "systems/base/system.h"
36 #include "utilities/exception.h"
37 #include "libreallive/bytecode.h"
38
39 using libreallive::ExpressionPiece;
40
EnsureIsParentObject(GraphicsObject & parent,int size)41 void EnsureIsParentObject(GraphicsObject& parent, int size) {
42 if (parent.has_object_data()) {
43 if (parent.GetObjectData().IsParentLayer()) {
44 return;
45 }
46 }
47
48 parent.SetObjectData(new ParentGraphicsObjectData(size));
49 }
50
GetGraphicsObject(RLMachine & machine,RLOperation * op,int obj)51 GraphicsObject& GetGraphicsObject(RLMachine& machine,
52 RLOperation* op,
53 int obj) {
54 GraphicsSystem& graphics = machine.system().graphics();
55
56 int fgbg;
57 if (!op->GetProperty(P_FGBG, fgbg))
58 fgbg = OBJ_FG;
59
60 int parentobj;
61 if (op->GetProperty(P_PARENTOBJ, parentobj)) {
62 GraphicsObject& parent = graphics.GetObject(fgbg, parentobj);
63 EnsureIsParentObject(parent, graphics.GetObjectLayerSize());
64 return static_cast<ParentGraphicsObjectData&>(parent.GetObjectData())
65 .GetObject(obj);
66 } else {
67 return graphics.GetObject(fgbg, obj);
68 }
69 }
70
GetGraphicsObjects(RLMachine & machine,RLOperation * op)71 LazyArray<GraphicsObject>& GetGraphicsObjects(RLMachine& machine,
72 RLOperation* op) {
73 GraphicsSystem& graphics = machine.system().graphics();
74
75 int fgbg;
76 if (!op->GetProperty(P_FGBG, fgbg))
77 fgbg = OBJ_FG;
78
79 int parentobj;
80 if (op->GetProperty(P_PARENTOBJ, parentobj)) {
81 GraphicsObject& parent = graphics.GetObject(fgbg, parentobj);
82 EnsureIsParentObject(parent, graphics.GetObjectLayerSize());
83 return static_cast<ParentGraphicsObjectData&>(parent.GetObjectData())
84 .objects();
85 } else if (fgbg == OBJ_FG) {
86 return graphics.GetForegroundObjects();
87 } else {
88 return graphics.GetBackgroundObjects();
89 }
90 }
91
SetGraphicsObject(RLMachine & machine,RLOperation * op,int obj,GraphicsObject & gobj)92 void SetGraphicsObject(RLMachine& machine,
93 RLOperation* op,
94 int obj,
95 GraphicsObject& gobj) {
96 GraphicsSystem& graphics = machine.system().graphics();
97
98 int fgbg;
99 if (!op->GetProperty(P_FGBG, fgbg))
100 fgbg = OBJ_FG;
101
102 int parentobj;
103 if (op->GetProperty(P_PARENTOBJ, parentobj)) {
104 GraphicsObject& parent = graphics.GetObject(fgbg, parentobj);
105 EnsureIsParentObject(parent, graphics.GetObjectLayerSize());
106 static_cast<ParentGraphicsObjectData&>(parent.GetObjectData())
107 .SetObject(obj, gobj);
108 } else {
109 graphics.SetObject(fgbg, obj, gobj);
110 }
111 }
112
113 // -----------------------------------------------------------------------
114
ObjRangeAdapter(RLOperation * in)115 ObjRangeAdapter::ObjRangeAdapter(RLOperation* in) : handler(in) {}
116
~ObjRangeAdapter()117 ObjRangeAdapter::~ObjRangeAdapter() {}
118
operator ()(RLMachine & machine,const libreallive::CommandElement & ff)119 void ObjRangeAdapter::operator()(RLMachine& machine,
120 const libreallive::CommandElement& ff) {
121 const libreallive::ExpressionPiecesVector& allParameters =
122 ff.GetParsedParameters();
123
124 // Range check the data
125 if (allParameters.size() < 2)
126 throw rlvm::Exception("Less then two arguments to an objRange function!");
127
128 // BIG WARNING ABOUT THE FOLLOWING CODE: Note that we copy half of
129 // what RLOperation.DispatchFunction() does; we manually call the
130 // subclass's Dispatch() so that we can get around the automated
131 // incrementing of the instruction pointer.
132 int lowerRange = allParameters[0].GetIntegerValue(machine);
133 int upperRange = allParameters[1].GetIntegerValue(machine);
134
135 // Create a new list of expression pieces that contain a single integer at
136 // the front. We will update this integer each time through the loop below.
137 libreallive::ExpressionPiecesVector parameters;
138 parameters.reserve(allParameters.size() - 1);
139 parameters.emplace_back(
140 libreallive::ExpressionPiece::IntConstant(lowerRange));
141
142 // Copy everything after the first two items
143 libreallive::ExpressionPiecesVector::const_iterator it =
144 allParameters.begin();
145 std::advance(it, 2);
146 for (; it != allParameters.end(); ++it)
147 parameters.emplace_back(*it);
148
149 for (int i = lowerRange; i <= upperRange; ++i) {
150 parameters[0] = libreallive::ExpressionPiece::IntConstant(i);
151 handler->Dispatch(machine, parameters);
152 }
153
154 machine.AdvanceInstructionPointer();
155 }
156
RangeMappingFun(RLOperation * op)157 RLOperation* RangeMappingFun(RLOperation* op) {
158 return new ObjRangeAdapter(op);
159 }
160
161 // -----------------------------------------------------------------------
162 // ChildObjAdapter
163 // -----------------------------------------------------------------------
164
ChildObjAdapter(RLOperation * in)165 ChildObjAdapter::ChildObjAdapter(RLOperation* in) : handler(in) {}
166
~ChildObjAdapter()167 ChildObjAdapter::~ChildObjAdapter() {}
168
operator ()(RLMachine & machine,const libreallive::CommandElement & ff)169 void ChildObjAdapter::operator()(RLMachine& machine,
170 const libreallive::CommandElement& ff) {
171 const libreallive::ExpressionPiecesVector& allParameters =
172 ff.GetParsedParameters();
173
174 // Range check the data
175 if (allParameters.size() < 1)
176 throw rlvm::Exception("Less than one argument to an objLayered function!");
177
178 int objset = allParameters[0].GetIntegerValue(machine);
179
180 // Copy everything after the first item
181 libreallive::ExpressionPiecesVector::const_iterator it =
182 allParameters.begin();
183 ++it;
184 libreallive::ExpressionPiecesVector currentInstantiation(
185 it, allParameters.end());
186
187 handler->SetProperty(P_PARENTOBJ, objset);
188 handler->Dispatch(machine, currentInstantiation);
189
190 machine.AdvanceInstructionPointer();
191 }
192
ChildObjMappingFun(RLOperation * op)193 RLOperation* ChildObjMappingFun(RLOperation* op) {
194 return new ChildObjAdapter(op);
195 }
196
197 // -----------------------------------------------------------------------
198 // ChildObjRangeAdapter
199 // -----------------------------------------------------------------------
200
ChildObjRangeAdapter(RLOperation * in)201 ChildObjRangeAdapter::ChildObjRangeAdapter(RLOperation* in) : handler(in) {}
202
~ChildObjRangeAdapter()203 ChildObjRangeAdapter::~ChildObjRangeAdapter() {}
204
operator ()(RLMachine & machine,const libreallive::CommandElement & ff)205 void ChildObjRangeAdapter::operator()(RLMachine& machine,
206 const libreallive::CommandElement& ff) {
207 const libreallive::ExpressionPiecesVector& allParameters =
208 ff.GetParsedParameters();
209
210 // Range check the data
211 if (allParameters.size() < 3) {
212 throw rlvm::Exception(
213 "Less then three arguments to an objChildRange function!");
214 }
215
216 // This part is like ChildObjAdapter; the first parameter is an integer
217 // that represents the parent object.
218 int objset = allParameters[0].GetIntegerValue(machine);
219
220 // This part is like ObjRangeAdapter; the second and third parameters are
221 // integers that represent a range of child objects.
222 int lowerRange = allParameters[1].GetIntegerValue(machine);
223 int upperRange = allParameters[2].GetIntegerValue(machine);
224
225 // Create a new list of expression pieces that contain a single integer at
226 // the front. We will update this integer each time through the loop below.
227 libreallive::ExpressionPiecesVector parameters;
228 parameters.reserve(allParameters.size() - 2);
229 parameters.emplace_back(
230 libreallive::ExpressionPiece::IntConstant(lowerRange));
231
232 // Copy everything after the first three items
233 libreallive::ExpressionPiecesVector::const_iterator it =
234 allParameters.begin();
235 std::advance(it, 3);
236 for (; it != allParameters.end(); ++it)
237 parameters.emplace_back(*it);
238
239 for (int i = lowerRange; i <= upperRange; ++i) {
240 parameters[0] = libreallive::ExpressionPiece::IntConstant(i);
241
242 // Now Dispatch based on these parameters.
243 handler->SetProperty(P_PARENTOBJ, objset);
244 handler->Dispatch(machine, parameters);
245 }
246
247 machine.AdvanceInstructionPointer();
248 }
249
ChildRangeMappingFun(RLOperation * op)250 RLOperation* ChildRangeMappingFun(RLOperation* op) {
251 return new ChildObjRangeAdapter(op);
252 }
253
254 // -----------------------------------------------------------------------
255 // Obj_CallFunction
256 // -----------------------------------------------------------------------
257
Obj_CallFunction(Function f)258 Obj_CallFunction::Obj_CallFunction(Function f) : function_(f) {}
259
~Obj_CallFunction()260 Obj_CallFunction::~Obj_CallFunction() {}
261
operator ()(RLMachine & machine,int buf)262 void Obj_CallFunction::operator()(RLMachine& machine, int buf) {
263 GraphicsObject& obj = GetGraphicsObject(machine, this, buf);
264 ((obj).*(function_))();
265 }
266
267 // -----------------------------------------------------------------------
268 // Obj_SetOneIntOnObj
269 // -----------------------------------------------------------------------
270
Obj_SetOneIntOnObj(Setter s)271 Obj_SetOneIntOnObj::Obj_SetOneIntOnObj(Setter s) : setter(s) {}
272
~Obj_SetOneIntOnObj()273 Obj_SetOneIntOnObj::~Obj_SetOneIntOnObj() {}
274
operator ()(RLMachine & machine,int buf,int incoming)275 void Obj_SetOneIntOnObj::operator()(RLMachine& machine, int buf, int incoming) {
276 GraphicsObject& obj = GetGraphicsObject(machine, this, buf);
277 ((obj).*(setter))(incoming);
278
279 machine.system().graphics().mark_object_state_as_dirty();
280 }
281
282 // -----------------------------------------------------------------------
283 // Obj_SetTwoIntOnObj
284 // -----------------------------------------------------------------------
285
Obj_SetTwoIntOnObj(Setter one,Setter two)286 Obj_SetTwoIntOnObj::Obj_SetTwoIntOnObj(Setter one, Setter two)
287 : setter_one_(one), setter_two_(two) {}
288
~Obj_SetTwoIntOnObj()289 Obj_SetTwoIntOnObj::~Obj_SetTwoIntOnObj() {}
290
operator ()(RLMachine & machine,int buf,int incoming_one,int incoming_two)291 void Obj_SetTwoIntOnObj::operator()(RLMachine& machine,
292 int buf,
293 int incoming_one,
294 int incoming_two) {
295 GraphicsObject& obj = GetGraphicsObject(machine, this, buf);
296 ((obj).*(setter_one_))(incoming_one);
297 ((obj).*(setter_two_))(incoming_two);
298
299 machine.system().graphics().mark_object_state_as_dirty();
300 }
301
302 // -----------------------------------------------------------------------
303 // Obj_SetRepnoIntOnObj
304 // -----------------------------------------------------------------------
305
Obj_SetRepnoIntOnObj(Setter setter)306 Obj_SetRepnoIntOnObj::Obj_SetRepnoIntOnObj(Setter setter)
307 : setter(setter) {}
308
~Obj_SetRepnoIntOnObj()309 Obj_SetRepnoIntOnObj::~Obj_SetRepnoIntOnObj() {}
310
operator ()(RLMachine & machine,int buf,int idx,int val)311 void Obj_SetRepnoIntOnObj::operator()(RLMachine& machine,
312 int buf,
313 int idx,
314 int val) {
315 GraphicsObject& obj = GetGraphicsObject(machine, this, buf);
316 ((obj).*(setter))(idx, val);
317 machine.system().graphics().mark_object_state_as_dirty();
318 }
319