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 "systems/base/graphics_object_data.h"
29
30 #include <ostream>
31
32 #include "systems/base/graphics_object.h"
33 #include "systems/base/graphics_object_of_file.h"
34 #include "systems/base/surface.h"
35 #include "systems/base/rect.h"
36
37 // -----------------------------------------------------------------------
38 // GraphicsObjectData
39 // -----------------------------------------------------------------------
40
GraphicsObjectData()41 GraphicsObjectData::GraphicsObjectData()
42 : after_animation_(AFTER_NONE),
43 owned_by_(NULL),
44 currently_playing_(false),
45 animation_finished_(false) {}
46
GraphicsObjectData(const GraphicsObjectData & obj)47 GraphicsObjectData::GraphicsObjectData(const GraphicsObjectData& obj)
48 : after_animation_(obj.after_animation_),
49 owned_by_(NULL),
50 currently_playing_(obj.currently_playing_),
51 animation_finished_(false) {}
52
~GraphicsObjectData()53 GraphicsObjectData::~GraphicsObjectData() {}
54
Render(const GraphicsObject & go,const GraphicsObject * parent,std::ostream * tree)55 void GraphicsObjectData::Render(const GraphicsObject& go,
56 const GraphicsObject* parent,
57 std::ostream* tree) {
58 std::shared_ptr<const Surface> surface = CurrentSurface(go);
59 if (surface) {
60 Rect src = SrcRect(go);
61 Rect dst = DstRect(go, parent);
62 int alpha = GetRenderingAlpha(go, parent);
63
64 if (go.GetButtonUsingOverides()) {
65 // Tacked on side channel that lets a ButtonObjectSelectLongOperation
66 // tweak the x/y coordinates of dst. There isn't really a better place to
67 // put this. It can't go in dstRect() because the LongOperation also
68 // consults the data from dstRect().
69 dst = Rect(dst.origin() + Size(go.GetButtonXOffsetOverride(),
70 go.GetButtonYOffsetOverride()),
71 dst.size());
72 }
73
74 if (tree) {
75 ObjectInfo(*tree);
76 *tree << " Rendering " << src << " to " << dst << std::endl;
77 if (parent) {
78 *tree << " Parent Properties: ";
79 PrintGraphicsObjectToTree(*parent, tree);
80 *tree << std::endl;
81 }
82
83 *tree << " Properties: ";
84 if (alpha != 255)
85 *tree << "(alpha=" << alpha << ") ";
86 PrintGraphicsObjectToTree(go, tree);
87 *tree << std::endl;
88
89 if (parent) {
90 *tree << " Parent Mutators: ";
91 PrintStringVector(parent->GetMutatorNames(), tree);
92 *tree << std::endl;
93 }
94
95 *tree << " Mutators: ";
96 PrintStringVector(go.GetMutatorNames(), tree);
97 *tree << std::endl;
98 }
99
100 if (parent && parent->has_own_clip_rect()) {
101 // In Little Busters, a parent clip rect is used to clip text scrolling
102 // in the battle system. rlvm has the concept of parent objects badly
103 // hacked in, and that means we can't directly apply the own clip
104 // rect. Instead we have to calculate this in terms of the screen
105 // coordinates and then apply that as a global clip rect.
106 Point parent_start(parent->x() + parent->GetXAdjustmentSum(),
107 parent->y() + parent->GetYAdjustmentSum());
108 Rect full_parent_clip =
109 Rect(parent_start + parent->own_clip_rect().origin(),
110 parent->own_clip_rect().size());
111
112 Rect clipped_dest = dst.Intersection(full_parent_clip);
113 Rect inset = dst.GetInsetRectangle(clipped_dest);
114 dst = clipped_dest;
115 src = src.ApplyInset(inset);
116
117 if (tree) {
118 *tree << " Parent Own Clipping Rect: " << parent->own_clip_rect()
119 << std::endl
120 << " After clipping: " << src << " to " << dst << std::endl;
121 }
122 }
123
124 if (go.has_own_clip_rect()) {
125 dst = dst.ApplyInset(go.own_clip_rect());
126 src = src.ApplyInset(go.own_clip_rect());
127
128 if (tree) {
129 *tree << " Internal Clipping Rect: " << go.own_clip_rect() << std::endl
130 << " After internal clipping: " << src << " to " << dst
131 << std::endl;
132 }
133 }
134
135 // Perform the object clipping.
136 if (go.has_clip_rect()) {
137 Rect clipped_dest = dst.Intersection(go.clip_rect());
138
139 // Do nothing if object falls wholly outside clip area
140 if (clipped_dest.is_empty())
141 return;
142
143 // Adjust the source rectangle
144 Rect inset = dst.GetInsetRectangle(clipped_dest);
145
146 dst = clipped_dest;
147 src = src.ApplyInset(inset);
148
149 if (tree) {
150 *tree << " Clipping Rect: " << go.clip_rect() << std::endl
151 << " After clipping: " << src << " to " << dst << std::endl;
152 }
153 }
154
155 // TODO(erg): Do we want to skip this if no alpha?
156 surface->RenderToScreenAsObject(go, src, dst, alpha);
157 }
158 }
159
LoopAnimation()160 void GraphicsObjectData::LoopAnimation() {}
161
EndAnimation()162 void GraphicsObjectData::EndAnimation() {
163 // Set first, because we may deallocate this by one of our actions
164 currently_playing_ = false;
165
166 switch (after_animation_) {
167 case AFTER_NONE:
168 animation_finished_ = true;
169 break;
170 case AFTER_CLEAR:
171 if (owned_by_)
172 owned_by_->FreeObjectData();
173 break;
174 case AFTER_LOOP: {
175 // Reset from the beginning
176 currently_playing_ = true;
177 LoopAnimation();
178 break;
179 }
180 }
181 }
182
PrintGraphicsObjectToTree(const GraphicsObject & go,std::ostream * tree)183 void GraphicsObjectData::PrintGraphicsObjectToTree(const GraphicsObject& go,
184 std::ostream* tree) {
185 if (go.mono())
186 *tree << "(mono) ";
187 if (go.invert())
188 *tree << "(invert) ";
189 if (go.light())
190 *tree << "(light=" << go.light() << ") ";
191 if (go.tint() != RGBColour::Black())
192 *tree << "(tint=" << go.tint() << ") ";
193 if (go.colour() != RGBAColour::Clear())
194 *tree << "(colour=" << go.colour() << ") ";
195 if (go.composite_mode())
196 *tree << "(composite=" << go.composite_mode() << ") ";
197 if (go.origin_x())
198 *tree << "(origin_x=" << go.origin_x() << ") ";
199 if (go.origin_y())
200 *tree << "(origin_y=" << go.origin_y() << ") ";
201 }
202
PrintStringVector(const std::vector<std::string> & names,std::ostream * tree)203 void GraphicsObjectData::PrintStringVector(
204 const std::vector<std::string>& names,
205 std::ostream* tree) {
206 bool first = true;
207
208 for (auto const& name : names) {
209 if (!first)
210 *tree << ", ";
211 else
212 first = false;
213
214 *tree << name;
215 }
216 }
217
SrcRect(const GraphicsObject & go)218 Rect GraphicsObjectData::SrcRect(const GraphicsObject& go) {
219 return CurrentSurface(go)->GetPattern(go.GetPattNo()).rect;
220 }
221
DstOrigin(const GraphicsObject & go)222 Point GraphicsObjectData::DstOrigin(const GraphicsObject& go) {
223 if (go.origin_x() || go.origin_y()) {
224 return Point(go.origin_x(), go.origin_y());
225 }
226
227 std::shared_ptr<const Surface> surface = CurrentSurface(go);
228 if (surface) {
229 return Point(surface->GetPattern(go.GetPattNo()).originX,
230 surface->GetPattern(go.GetPattNo()).originY);
231 }
232
233 return Point();
234 }
235
DstRect(const GraphicsObject & go,const GraphicsObject * parent)236 Rect GraphicsObjectData::DstRect(const GraphicsObject& go,
237 const GraphicsObject* parent) {
238 Point origin = DstOrigin(go);
239 Rect src = SrcRect(go);
240
241 int center_x =
242 go.x() + go.GetXAdjustmentSum() - origin.x() + (src.width() / 2.0f);
243 int center_y =
244 go.y() + go.GetYAdjustmentSum() - origin.y() + (src.height() / 2.0f);
245
246 float second_factor_x = 1.0f;
247 float second_factor_y = 1.0f;
248 if (parent) {
249 center_x += parent->x() + parent->GetXAdjustmentSum();
250 center_y += parent->y() + parent->GetYAdjustmentSum();
251
252 second_factor_x = parent->GetWidthScaleFactor();
253 second_factor_y = parent->GetHeightScaleFactor();
254 }
255
256 int half_real_width =
257 (src.width() * second_factor_x * go.GetWidthScaleFactor()) / 2.0f;
258 int half_real_height =
259 (src.height() * second_factor_y * go.GetHeightScaleFactor()) / 2.0f;
260
261 int xPos1 = center_x - half_real_width;
262 int yPos1 = center_y - half_real_height;
263 int xPos2 = center_x + half_real_width;
264 int yPos2 = center_y + half_real_height;
265
266 return Rect::GRP(xPos1, yPos1, xPos2, yPos2);
267 }
268
GetRenderingAlpha(const GraphicsObject & go,const GraphicsObject * parent)269 int GraphicsObjectData::GetRenderingAlpha(const GraphicsObject& go,
270 const GraphicsObject* parent) {
271 if (!parent) {
272 return go.GetComputedAlpha();
273 } else {
274 return int((parent->GetComputedAlpha() / 255.0f) *
275 (go.GetComputedAlpha() / 255.0f) * 255);
276 }
277 }
278
IsAnimation() const279 bool GraphicsObjectData::IsAnimation() const { return false; }
280
PlaySet(int set)281 void GraphicsObjectData::PlaySet(int set) {}
282
IsParentLayer() const283 bool GraphicsObjectData::IsParentLayer() const { return false; }
284