1// SuperTux
2// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17#include "object/particlesystem_interactive.hpp"
18
19#include "collision/collision.hpp"
20#include "editor/editor.hpp"
21#include "math/aatriangle.hpp"
22#include "object/tilemap.hpp"
23#include "supertux/globals.hpp"
24#include "supertux/sector.hpp"
25#include "supertux/tile.hpp"
26#include "video/drawing_context.hpp"
27#include "video/surface_batch.hpp"
28#include "video/video_system.hpp"
29#include "video/viewport.hpp"
30
31//TODO: Find a way to make rain collide with objects like bonus blocks
32// Add an option to set rain strength
33// Fix rain being "respawned" over solid tiles
34ParticleSystem_Interactive::ParticleSystem_Interactive() :
35 ParticleSystem()
36{
37 virtual_width = static_cast<float>(SCREEN_WIDTH);
38 virtual_height = static_cast<float>(SCREEN_HEIGHT);
39 if (!Editor::is_active()) {
40 z_pos = 0;
41 }
42}
43
44ParticleSystem_Interactive::ParticleSystem_Interactive(const ReaderMapping& mapping) :
45 ParticleSystem(mapping)
46{
47 virtual_width = static_cast<float>(SCREEN_WIDTH);
48 virtual_height = static_cast<float>(SCREEN_HEIGHT);
49 if (!Editor::is_active()) {
50 z_pos = 0;
51 }
52}
53
54ParticleSystem_Interactive::~ParticleSystem_Interactive()
55{
56}
57
58void
59ParticleSystem_Interactive::draw(DrawingContext& context)
60{
61 if (!enabled)
62 return;
63
64 context.push_transform();
65
66 std::unordered_map<SurfacePtr, SurfaceBatch> batches;
67 for (const auto& particle : particles) {
68 auto it = batches.find(particle->texture);
69 if (it == batches.end()) {
70 const auto& batch_it = batches.emplace(particle->texture,
71 SurfaceBatch(particle->texture));
72 batch_it.first->second.draw(particle->pos);
73 } else {
74 it->second.draw(particle->pos);
75 }
76 }
77
78 for(auto& it : batches) {
79 auto& surface = it.first;
80 auto& batch = it.second;
81 // FIXME: What is the colour used for?
82 context.color().draw_surface_batch(surface, batch.move_srcrects(),
83 batch.move_dstrects(), Color::WHITE, z_pos);
84 }
85
86 context.pop_transform();
87}
88
89int
90ParticleSystem_Interactive::collision(Particle* object, const Vector& movement)
91{
92 using namespace collision;
93
94 // calculate rectangle where the object will move
95 float x1, x2;
96 float y1, y2;
97
98 x1 = object->pos.x;
99 x2 = x1 + 32 + movement.x;
100 if (x2 < x1) {
101 x1 = x2;
102 x2 = object->pos.x;
103 }
104
105 y1 = object->pos.y;
106 y2 = y1 + 32 + movement.y;
107 if (y2 < y1) {
108 y1 = y2;
109 y2 = object->pos.y;
110 }
111 bool water = false;
112
113 // test with all tiles in this rectangle
114 int starttilex = int(x1-1) / 32;
115 int starttiley = int(y1-1) / 32;
116 int max_x = int(x2+1);
117 int max_y = int(y2+1);
118
119 Rectf dest(x1, y1, x2, y2);
120 dest.move(movement);
121 Constraints constraints;
122
123 for (const auto& solids : Sector::get().get_solid_tilemaps()) {
124 // FIXME Handle a nonzero tilemap offset
125 for (int x = starttilex; x*32 < max_x; ++x) {
126 for (int y = starttiley; y*32 < max_y; ++y) {
127 const Tile& tile = solids->get_tile(x, y);
128
129 // skip non-solid tiles, except water
130 if (! (tile.get_attributes() & (Tile::WATER | Tile::SOLID)))
131 continue;
132
133 Rectf rect = solids->get_tile_bbox(x, y);
134 if (tile.is_slope ()) { // slope tile
135 AATriangle triangle = AATriangle(rect, tile.get_data());
136
137 if (rectangle_aatriangle(&constraints, dest, triangle)) {
138 if (tile.get_attributes() & Tile::WATER)
139 water = true;
140 }
141 } else { // normal rectangular tile
142 if (intersects(dest, rect)) {
143 if (tile.get_attributes() & Tile::WATER)
144 water = true;
145 set_rectangle_rectangle_constraints(&constraints, dest, rect);
146 }
147 }
148 }
149 }
150 }
151
152 // TODO don't use magic numbers here...
153
154 // did we collide at all?
155 if (!constraints.has_constraints())
156 return -1;
157
158 const CollisionHit& hit = constraints.hit;
159 if (water) {
160 return 0; //collision with water tile - don't draw splash
161 } else {
162 if (hit.right || hit.left) {
163 return 2; //collision from right
164 } else {
165 return 1; //collision from above
166 }
167 }
168}
169
170/* EOF */
171