/* * This Game is distributed under the GNU GENERAL PUBLIC LICENSE * version 2. See COPYING for details. * * Copyright (C) 1999, 2000, 2001 Harry Storbacka * * Race homepage: http://race.sourceforge.net */ #include #include #include "rect.h" #include "collision.h" /* Pixel based collision detection that works ONLY on 32 bit surfaces. * Returns true if there are overlapping opaque pixels in the union rect. */ bool RaceCollision::alpha_based( CL_Surface *obj_1, CL_Surface *obj_2, int obj_1_x, int obj_1_y, int obj_2_x, int obj_2_y, int frame_1, int frame_2, RaceRect union_rect ) { CL_SurfaceProvider *provider_1 = obj_1->get_provider(); CL_SurfaceProvider *provider_2 = obj_2->get_provider(); int height_1 = provider_1->get_height(); int height_2 = provider_2->get_height(); int pitch_1 = provider_1->get_pitch(); int pitch_2 = provider_2->get_pitch(); provider_1->lock(); provider_2->lock(); unsigned char *data_1 = (unsigned char *)provider_1->get_data(); unsigned char *data_2 = (unsigned char *)provider_2->get_data(); /* * ________ * | | * | |<-- obj_1 * | ___|___ * | |XXX| | * |____|XXX| | * | |<-- obj_2 * |_______| * * ________ * | | * | | * ____|___ | <-- obj_1 * | |XXX| | * | |XXX|____| * | | * |________|<-- obj_2 * * (the positions are changed so that obj_2 is ALWAYS under.) */ data_1 += ( frame_1 * height_1 * pitch_1 ) // move to right frame + ((union_rect.y1 - obj_1_y) * pitch_1) // move to y start + ( 4 * abs(obj_1_x - union_rect.x1)); // move to x start data_2 += ( frame_2 * height_2 * pitch_2) // move to right frame + 4 * abs(obj_2_x - union_rect.x1); // move to x start for( int y = 0; y < union_rect.get_height(); y++ ) { unsigned char *obj_1_data = data_1 + y*pitch_1; unsigned char *obj_2_data = data_2 + y*pitch_2; for( int x = 0; x < union_rect.get_width(); x++ ) { if( obj_2_data[0] > 205 && obj_1_data[0] > 205 ) return true; obj_1_data+=4; obj_2_data+=4; } } provider_1->unlock(); provider_2->unlock(); return false; } bool RaceCollision::check( CL_Surface *obj_1, CL_Surface *obj_2, int obj_1_x, int obj_1_y, int obj_2_x, int obj_2_y, int frame_1=0, int frame_2=0 ) { int width_1 = obj_1->get_width(); int height_1 = obj_1->get_height(); int width_2 = obj_2->get_width(); int height_2 = obj_2->get_height(); RaceRect obj_1_rect( obj_1_x, obj_1_y, obj_1_x + width_1, obj_1_y + height_1 ); RaceRect obj_2_rect( obj_2_x, obj_2_y, obj_2_x + width_2, obj_2_y + height_2 ); if( obj_1_rect.overlapping( obj_2_rect ) ) { RaceRect union_rect = obj_1_rect.clip(obj_2_rect); if( obj_1_y < obj_2_y ) { if( alpha_based( obj_1, obj_2, obj_1_x, obj_1_y, obj_2_x, obj_2_y, frame_1, frame_2, union_rect )) return true; } else { if( alpha_based( obj_2, obj_1, obj_2_x, obj_2_y, obj_1_x, obj_1_y, frame_2, frame_1, union_rect )) return true; } } return false; } bool RaceCollision::check( CL_Surface *obj, CL_Surface *car, RaceRect obj_rect, int car_x, int car_y, int o_frame=0, int c_frame=0 ) { RaceRect car_rect( car_x, car_y, car_x + car->get_width(), car_y + car->get_height() ); if( obj_rect.overlapping( car_rect ) ) { RaceRect union_rect = obj_rect.clip(car_rect); if( obj_rect.y1 < car_y ) { if( alpha_based( obj, car, obj_rect.x1, obj_rect.y1, car_x, car_y, o_frame, c_frame, union_rect )) return true; } else { if( alpha_based( car, obj, car_x, car_y, obj_rect.x1, obj_rect.y1, c_frame, o_frame, union_rect )) return true; } } return false; }