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) 2011 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 "systems/base/hik_renderer.h"
28
29 #include <iostream>
30
31 #include "machine/rlmachine.h"
32 #include "systems/base/event_system.h"
33 #include "systems/base/graphics_system.h"
34 #include "systems/base/hik_script.h"
35 #include "systems/base/surface.h"
36 #include "systems/base/system.h"
37 #include "utilities/graphics.h"
38
LayerData(int time)39 HIKRenderer::LayerData::LayerData(int time)
40 : animation_num_(0), animation_start_time_(time) {}
41
HIKRenderer(System & system,const std::shared_ptr<const HIKScript> & script)42 HIKRenderer::HIKRenderer(System& system,
43 const std::shared_ptr<const HIKScript>& script)
44 : system_(system),
45 script_(script),
46 creation_time_(system_.event().GetTicks()),
47 x_offset_(0),
48 y_offset_(0) {
49 layer_to_animation_num_.insert(layer_to_animation_num_.begin(),
50 script->layers().size(),
51 LayerData(creation_time_));
52 }
53
~HIKRenderer()54 HIKRenderer::~HIKRenderer() {}
55
Execute(RLMachine & machine)56 void HIKRenderer::Execute(RLMachine& machine) {
57 machine.system().graphics().MarkScreenAsDirty(GUT_DRAW_HIK);
58 }
59
Render(std::ostream * tree)60 void HIKRenderer::Render(std::ostream* tree) {
61 int current_ticks = system_.event().GetTicks();
62 int time_since_creation = current_ticks - creation_time_;
63
64 if (tree) {
65 *tree << " HIK Script:" << std::endl;
66 }
67
68 int layer_num = 0;
69 for (std::vector<HIKScript::Layer>::const_iterator
70 it = script_->layers().begin();
71 it != script_->layers().end();
72 ++it, ++layer_num) {
73 // Calculate the source rectangle
74
75 Point dest_point = it->top_offset;
76 if (it->use_scrolling) {
77 dest_point += it->start_point;
78
79 Size difference = it->end_point - it->start_point;
80 int x_difference = 0;
81 int y_difference = 0;
82 if (it->x_scroll_time_ms) {
83 double x_percent = (time_since_creation % it->x_scroll_time_ms) /
84 static_cast<float>(it->x_scroll_time_ms);
85 x_difference = difference.width() * x_percent;
86 }
87 if (it->y_scroll_time_ms) {
88 double y_percent = (time_since_creation % it->y_scroll_time_ms) /
89 static_cast<float>(it->y_scroll_time_ms);
90 y_difference = difference.height() * y_percent;
91 }
92
93 dest_point += Point(x_difference, y_difference);
94 }
95
96 LayerData& layer_data = layer_to_animation_num_.at(layer_num);
97 const HIKScript::Animation* animation =
98 &it->animations.at(layer_data.animation_num_);
99 size_t frame_to_use = 0;
100 if (animation->use_multiframe_animation) {
101 int ticks_since_animation_began =
102 current_ticks - layer_data.animation_start_time_;
103
104 // Advance to the correct animation.
105 bool advanced = false;
106 while (ticks_since_animation_began > animation->total_time) {
107 switch (animation->i_30101) {
108 case 0:
109 // Don't change the animation number.
110 break;
111 case 3:
112 // Move to the next animation.
113 layer_data.animation_num_++;
114 if (layer_data.animation_num_ == it->animations.size())
115 layer_data.animation_num_ = 0;
116 break;
117 default:
118 break;
119 }
120
121 animation = &it->animations.at(layer_data.animation_num_);
122 ticks_since_animation_began -= animation->total_time;
123 advanced = true;
124 }
125
126 if (advanced)
127 layer_data.animation_start_time_ = current_ticks;
128
129 while (ticks_since_animation_began > 0) {
130 ticks_since_animation_began -=
131 animation->frames.at(frame_to_use).frame_length_ms;
132
133 if (ticks_since_animation_began > 0) {
134 frame_to_use++;
135 if (frame_to_use > animation->frames.size()) {
136 frame_to_use = 0;
137 }
138 }
139 }
140 }
141
142 const HIKScript::Frame& frame = animation->frames.at(frame_to_use);
143
144 int pattern_to_use = 0;
145 if (frame.grp_pattern != -1)
146 pattern_to_use = frame.grp_pattern;
147
148 Rect src_rect = frame.surface->GetPattern(pattern_to_use).rect;
149 src_rect =
150 Rect(src_rect.origin() + Size(x_offset_, y_offset_), src_rect.size());
151 Rect dest_rect(dest_point, src_rect.size());
152 if (it->use_clip_area)
153 ClipDestination(it->clip_area, src_rect, dest_rect);
154
155 frame.surface->RenderToScreen(src_rect, dest_rect, frame.opacity);
156
157 if (tree) {
158 *tree << " [L:" << (std::distance(script_->layers().begin(), it) + 1)
159 << "/" << script_->layers().size()
160 << ", A:" << (layer_data.animation_num_ + 1) << "/"
161 << it->animations.size() << ", F:" << (frame_to_use + 1) << "/"
162 << animation->frames.size() << ", P:" << pattern_to_use
163 << ", ??: " << animation->use_multiframe_animation << "/"
164 << animation->i_30101 << "/" << animation->i_30102
165 << ", O:" << frame.opacity << ", Image: " << frame.image << "]"
166 << std::endl;
167 }
168 }
169 }
170
NextAnimationFrame()171 void HIKRenderer::NextAnimationFrame() {
172 int time = system_.event().GetTicks();
173
174 int idx = 0;
175 for (std::vector<LayerData>::iterator it = layer_to_animation_num_.begin();
176 it != layer_to_animation_num_.end();
177 ++it, ++idx) {
178 it->animation_num_++;
179 if (it->animation_num_ == script_->layers().at(idx).animations.size())
180 it->animation_num_ = 0;
181
182 it->animation_start_time_ = time;
183 }
184 }
185