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