00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "supertux/tile.hpp"
00020
00021 #include "supertux/constants.hpp"
00022 #include "supertux/tile_set.hpp"
00023 #include "math/aatriangle.hpp"
00024 #include "video/drawing_context.hpp"
00025
00026 bool Tile::draw_editor_images = false;
00027
00028 Tile::Tile() :
00029 imagespecs(),
00030 images(),
00031 editor_imagespecs(),
00032 editor_images(),
00033 attributes(0),
00034 data(0),
00035 fps(1)
00036 {
00037 }
00038
00039 Tile::Tile(const std::vector<ImageSpec>& imagespecs_, const std::vector<ImageSpec>& editor_imagespecs_,
00040 uint32_t attributes, uint32_t data, float fps) :
00041 imagespecs(imagespecs_),
00042 images(),
00043 editor_imagespecs(editor_imagespecs_),
00044 editor_images(),
00045 attributes(attributes),
00046 data(data),
00047 fps(fps)
00048 {
00049 correct_attributes();
00050 }
00051
00052 Tile::~Tile()
00053 {
00054 }
00055
00056 void
00057 Tile::load_images()
00058 {
00059 if(images.size() == 0 && imagespecs.size() != 0)
00060 {
00061 assert(images.size() == 0);
00062 for(std::vector<ImageSpec>::iterator i = imagespecs.begin(); i != imagespecs.end(); ++i)
00063 {
00064 const ImageSpec& spec = *i;
00065
00066 SurfacePtr surface;
00067 if(spec.rect.get_width() <= 0)
00068 {
00069 surface = Surface::create(spec.file);
00070 }
00071 else
00072 {
00073 surface = Surface::create(spec.file,
00074 Rect((int) spec.rect.p1.x,
00075 (int) spec.rect.p1.y,
00076 Size((int) spec.rect.get_width(),
00077 (int) spec.rect.get_height())));
00078 }
00079 images.push_back(surface);
00080 }
00081 }
00082
00083 if(editor_images.size() == 0 && editor_imagespecs.size() != 0)
00084 {
00085 assert(editor_images.size() == 0);
00086 for(std::vector<ImageSpec>::iterator i = editor_imagespecs.begin(); i != editor_imagespecs.end(); ++i)
00087 {
00088 const ImageSpec& spec = *i;
00089
00090 SurfacePtr surface;
00091 if(spec.rect.get_width() <= 0)
00092 {
00093 surface = Surface::create(spec.file);
00094 }
00095 else
00096 {
00097 surface = Surface::create(spec.file,
00098 Rect((int) spec.rect.p1.x,
00099 (int) spec.rect.p1.y,
00100 Size((int) spec.rect.get_width(),
00101 (int) spec.rect.get_height())));
00102 }
00103 editor_images.push_back(surface);
00104 }
00105 }
00106 }
00107
00108 void
00109 Tile::draw(DrawingContext& context, const Vector& pos, int z_pos) const
00110 {
00111 if(draw_editor_images) {
00112 if(editor_images.size() > 1) {
00113 size_t frame = size_t(game_time * fps) % editor_images.size();
00114 context.draw_surface(editor_images[frame], pos, z_pos);
00115 return;
00116 } else if (editor_images.size() == 1) {
00117 context.draw_surface(editor_images[0], pos, z_pos);
00118 return;
00119 }
00120 }
00121
00122 if(images.size() > 1) {
00123 size_t frame = size_t(game_time * fps) % images.size();
00124 context.draw_surface(images[frame], pos, z_pos);
00125 } else if (images.size() == 1) {
00126 context.draw_surface(images[0], pos, z_pos);
00127 }
00128 }
00129
00130 void
00131 Tile::correct_attributes()
00132 {
00133
00134 if(!(attributes & SOLID) && (attributes & SLOPE || attributes & UNISOLID)) {
00135 attributes |= SOLID;
00136
00137 log_warning << "Tile with image " << imagespecs[0].file << " needs solid attribute." << std::endl;
00138 }
00139 }
00140
00141 void
00142 Tile::print_debug(int id) const
00143 {
00144 log_debug << " Tile: id " << id << ", data " << getData() << ", attributes " << getAttributes() << ":" << std::endl;
00145 for(std::vector<Tile::ImageSpec>::const_iterator im = editor_imagespecs.begin(); im != editor_imagespecs.end(); ++im)
00146 log_debug << " Editor Imagespec: file " << im->file << "; rect " << im->rect << std::endl;
00147 for(std::vector<Tile::ImageSpec>::const_iterator im = imagespecs.begin(); im != imagespecs.end(); ++im)
00148 log_debug << " Imagespec: file " << im->file << "; rect " << im->rect << std::endl;
00149 }
00150
00151
00152
00153
00154
00155
00156
00157 bool Tile::check_movement_unisolid (const Vector movement) const
00158 {
00159 int slope_info;
00160 double mv_x;
00161 double mv_y;
00162 double mv_tan;
00163 double slope_tan;
00164
00165
00166 if (!this->is_slope())
00167 {
00168 int dir = this->getData() & Tile::UNI_DIR_MASK;
00169
00170 return ((dir == Tile::UNI_DIR_NORTH) && (movement.y >= 0))
00171 || ((dir == Tile::UNI_DIR_SOUTH) && (movement.y <= 0))
00172 || ((dir == Tile::UNI_DIR_WEST ) && (movement.x >= 0))
00173 || ((dir == Tile::UNI_DIR_EAST ) && (movement.x <= 0));
00174 }
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184 mv_x = (double) movement.x;
00185 mv_y = (double) movement.y;
00186
00187 slope_info = this->getData();
00188 switch (slope_info & AATriangle::DIRECTION_MASK)
00189 {
00190 case AATriangle::SOUTHEAST:
00191
00192 break;
00193
00194 case AATriangle::SOUTHWEST:
00195 mv_x *= (-1.0);
00196 break;
00197
00198 case AATriangle::NORTHEAST:
00199 mv_y *= (-1.0);
00200 break;
00201
00202 case AATriangle::NORTHWEST:
00203 mv_x *= (-1.0);
00204 mv_y *= (-1.0);
00205 break;
00206 }
00207
00208
00209
00210 if ((mv_x >= 0.0) && (mv_y >= 0.0))
00211 return true;
00212
00213 else if ((mv_x <= 0.0) && (mv_y <= 0.0))
00214 return false;
00215
00216
00217 assert (mv_x != 0.0);
00218 assert (mv_y != 0.0);
00219
00220
00221 mv_tan = (-1.0) * mv_y / mv_x;
00222
00223
00224 slope_tan = 1.0;
00225 if (((slope_info & AATriangle::DEFORM_MASK) == AATriangle::DEFORM_BOTTOM)
00226 || ((slope_info & AATriangle::DEFORM_MASK) == AATriangle::DEFORM_TOP))
00227 slope_tan = 0.5;
00228 else if (((slope_info & AATriangle::DEFORM_MASK) == AATriangle::DEFORM_LEFT)
00229 || ((slope_info & AATriangle::DEFORM_MASK) == AATriangle::DEFORM_RIGHT))
00230 slope_tan = 2.0;
00231
00232
00233 if (mv_x > 0.0)
00234 {
00235 assert (mv_y < 0.0);
00236 return (mv_tan <= slope_tan);
00237 }
00238
00239 else if (mv_x < 0.0)
00240 {
00241 assert (mv_y > 0.0);
00242 return (mv_tan >= slope_tan);
00243 }
00244
00245 assert (1 != 1);
00246 return false;
00247 }
00248
00249 bool is_above_line (float l_x, float l_y, float m,
00250 float p_x, float p_y)
00251 {
00252 float interp_y = (l_y + (m * (p_x - l_x)));
00253 return (interp_y >= p_y);
00254 }
00255
00256 bool is_below_line (float l_x, float l_y, float m,
00257 float p_x, float p_y)
00258 {
00259 return !is_above_line (l_x, l_y, m, p_x, p_y);
00260 }
00261
00262
00263
00264
00265 bool Tile::check_position_unisolid (const Rectf& obj_bbox,
00266 const Rectf& tile_bbox) const
00267 {
00268 int slope_info;
00269 float tile_x;
00270 float tile_y;
00271 float gradient;
00272 float delta_x;
00273 float delta_y;
00274 float obj_x;
00275 float obj_y;
00276
00277
00278 if (!this->is_slope())
00279 {
00280 int dir = this->getData() & Tile::UNI_DIR_MASK;
00281
00282 return ((dir == Tile::UNI_DIR_NORTH) && ((obj_bbox.get_bottom() - SHIFT_DELTA) <= tile_bbox.get_top() ))
00283 || ((dir == Tile::UNI_DIR_SOUTH) && ((obj_bbox.get_top() + SHIFT_DELTA) >= tile_bbox.get_bottom()))
00284 || ((dir == Tile::UNI_DIR_WEST ) && ((obj_bbox.get_right() - SHIFT_DELTA) <= tile_bbox.get_left() ))
00285 || ((dir == Tile::UNI_DIR_EAST ) && ((obj_bbox.get_left() + SHIFT_DELTA) >= tile_bbox.get_right() ));
00286 }
00287
00288
00289
00290
00291 slope_info = this->getData();
00292 switch (slope_info
00293 & (AATriangle::DIRECTION_MASK | AATriangle::DEFORM_MASK))
00294 {
00295 case AATriangle::SOUTHWEST:
00296 case AATriangle::SOUTHWEST | AATriangle::DEFORM_TOP:
00297 case AATriangle::SOUTHWEST | AATriangle::DEFORM_LEFT:
00298 case AATriangle::NORTHEAST:
00299 case AATriangle::NORTHEAST | AATriangle::DEFORM_TOP:
00300 case AATriangle::NORTHEAST | AATriangle::DEFORM_LEFT:
00301 tile_x = tile_bbox.get_left();
00302 tile_y = tile_bbox.get_top();
00303 gradient = 1.0;
00304 break;
00305
00306 case AATriangle::SOUTHEAST:
00307 case AATriangle::SOUTHEAST | AATriangle::DEFORM_TOP:
00308 case AATriangle::SOUTHEAST | AATriangle::DEFORM_RIGHT:
00309 case AATriangle::NORTHWEST:
00310 case AATriangle::NORTHWEST | AATriangle::DEFORM_TOP:
00311 case AATriangle::NORTHWEST | AATriangle::DEFORM_RIGHT:
00312 tile_x = tile_bbox.get_right();
00313 tile_y = tile_bbox.get_top();
00314 gradient = -1.0;
00315 break;
00316
00317 case AATriangle::SOUTHEAST | AATriangle::DEFORM_BOTTOM:
00318 case AATriangle::SOUTHEAST | AATriangle::DEFORM_LEFT:
00319 case AATriangle::NORTHWEST | AATriangle::DEFORM_BOTTOM:
00320 case AATriangle::NORTHWEST | AATriangle::DEFORM_LEFT:
00321 tile_x = tile_bbox.get_left();
00322 tile_y = tile_bbox.get_bottom();
00323 gradient = -1.0;
00324 break;
00325
00326 case AATriangle::SOUTHWEST | AATriangle::DEFORM_BOTTOM:
00327 case AATriangle::SOUTHWEST | AATriangle::DEFORM_RIGHT:
00328 case AATriangle::NORTHEAST | AATriangle::DEFORM_BOTTOM:
00329 case AATriangle::NORTHEAST | AATriangle::DEFORM_RIGHT:
00330 tile_x = tile_bbox.get_right();
00331 tile_y = tile_bbox.get_bottom();
00332 gradient = 1.0;
00333 break;
00334
00335 default:
00336 assert (23 == 42);
00337 return 0;
00338 }
00339
00340
00341
00342
00343 delta_x = 1.0 * SHIFT_DELTA;
00344 delta_y = 1.0 * SHIFT_DELTA;
00345 switch (slope_info & AATriangle::DIRECTION_MASK)
00346 {
00347 case AATriangle::SOUTHWEST:
00348 delta_x *= 1.0;
00349 delta_y *= -1.0;
00350 obj_x = obj_bbox.get_left();
00351 obj_y = obj_bbox.get_bottom();
00352 break;
00353
00354 case AATriangle::SOUTHEAST:
00355 delta_x *= -1.0;
00356 delta_y *= -1.0;
00357 obj_x = obj_bbox.get_right();
00358 obj_y = obj_bbox.get_bottom();
00359 break;
00360
00361 case AATriangle::NORTHWEST:
00362 delta_x *= 1.0;
00363 delta_y *= 1.0;
00364 obj_x = obj_bbox.get_left();
00365 obj_y = obj_bbox.get_top();
00366 break;
00367
00368 case AATriangle::NORTHEAST:
00369 delta_x *= -1.0;
00370 delta_y *= 1.0;
00371 obj_x = obj_bbox.get_right();
00372 obj_y = obj_bbox.get_top();
00373 break;
00374 }
00375
00376
00377
00378 switch (slope_info & AATriangle::DEFORM_MASK)
00379 {
00380 case 0:
00381 delta_x *= .70710678118654752440;
00382 delta_y *= .70710678118654752440;
00383 break;
00384
00385 case AATriangle::DEFORM_BOTTOM:
00386 case AATriangle::DEFORM_TOP:
00387 delta_x *= .44721359549995793928;
00388 delta_y *= .89442719099991587856;
00389 gradient *= 0.5;
00390 break;
00391
00392 case AATriangle::DEFORM_LEFT:
00393 case AATriangle::DEFORM_RIGHT:
00394 delta_x *= .89442719099991587856;
00395 delta_y *= .44721359549995793928;
00396 gradient *= 2.0;
00397 break;
00398 }
00399
00400
00401
00402
00403 if (((slope_info & AATriangle::DIRECTION_MASK) == AATriangle::SOUTHWEST)
00404 || ((slope_info & AATriangle::DIRECTION_MASK) == AATriangle::SOUTHEAST))
00405 {
00406 return !is_below_line(tile_x, tile_y, gradient, obj_x + delta_x, obj_y + delta_y);
00407 }
00408
00409
00410 else
00411 {
00412 return !is_above_line (tile_x, tile_y, gradient, obj_x + delta_x, obj_y + delta_y);
00413 }
00414 }
00415
00416 bool Tile::is_solid (const Rectf& tile_bbox, const Rectf& position, const Vector& movement) const
00417 {
00418 if (!(attributes & SOLID))
00419 return false;
00420
00421 if (!(attributes & UNISOLID))
00422 return true;
00423
00424 return check_movement_unisolid (movement) &&
00425 check_position_unisolid (position, tile_bbox);
00426 }
00427
00428
00429