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