Guest User

collide.cpp

a guest
May 12th, 2013
29
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // include the header
  2. #include "collide.h"
  3.  
  4. // usefull macros to improve readability
  5. #define INDEX( Z, X, Y )    Z->data[ (X) + ((Y) * Z->width) ]
  6. #define ISWALL( Z, X, Y ) ((Z->data[ (X) + ((Y) * Z->width) ] & cWall ) > 0 )
  7.  
  8. // preprocess the map to encode some gradients for each of the tiles
  9. // to simplify the collision process
  10. void collide_preprocess( sCollideMap *map )
  11. {
  12.     // clear all gradient data
  13.     for ( uint32 i=0; i<map->width * map->height; i++ )
  14.         // gradient data occupies lower four bits
  15.         map->data[ i ] &= 0xF0;
  16.  
  17.     // horizontal process
  18.     for ( uint32 x=0; x < map->width; x++ )
  19.     {
  20.         // check if first tile is wall
  21.         int prev = ISWALL( map, x, 0 );
  22.         // vertical process
  23.         for ( uint32 y=1; y < map->height; y++ )
  24.         {
  25.             // sample the current tile
  26.             int cur = ISWALL( map, x, y );
  27.             // encode a wall gradient
  28.             switch (cur - prev)
  29.             {
  30.             case ( -1 ): INDEX( map, x, y-1 ) |= cQLower; break;
  31.             case (  1 ): INDEX( map, x, y   ) |= cQUpper; break;
  32.             }
  33.             //
  34.             prev = cur;
  35.         }
  36.     }
  37.  
  38.     // vertical process
  39.     for ( uint32 y=0; y < map->height; y++ )
  40.     {
  41.         // check if first tile is wall
  42.         int prev = ISWALL( map, 0, y );
  43.         // horozontal process
  44.         for ( uint32 x=1; x < map->width; x++ )
  45.         {
  46.             // sample the current tile
  47.             int cur = ISWALL( map, x, y );
  48.             // encode a wall gradient
  49.             switch (cur - prev)
  50.             {
  51.             case ( -1 ): INDEX( map, x-1, y ) |= cQRight; break;
  52.             case (  1 ): INDEX( map, x  , y ) |= cQLeft ; break;
  53.             }
  54.             //
  55.             prev = cur;
  56.         }
  57.     }
  58. }
  59.  
  60. // clamp integer
  61. static inline int clampi( int min, int cur, int max )
  62. {
  63.     if ( cur < min ) return min;
  64.     if ( cur > max ) return max;
  65.                      return cur;
  66. }
  67.  
  68. // absolute value integer
  69. static inline int absi( int a )
  70. {
  71.     if ( a < 0 ) return -a;
  72.                  return  a;
  73. }
  74.  
  75. //
  76. static inline int select_from_absmin( int a, int b )
  77. {
  78.     int i = a, j = b;
  79.     // compute abs
  80.     if ( a < 0 ) a = -a;
  81.     if ( b < 0 ) a = -b;
  82.     // return closest to zero
  83.     if ( a < b ) return i;
  84.                  return j;
  85. }
  86.  
  87. //
  88. bool collide_test( sCollideMap *map, sCollideObject *info )
  89. {
  90.     // a little helper to simplify the look of the code
  91.     const int ts = map->tileSize;
  92.  
  93.     // convert into map space and clamp
  94.     int x1 = clampi( 0, info->x1 / ts, map->width -1 );
  95.     int x2 = clampi( 0, info->x2 / ts, map->width -1 );
  96.     int y1 = clampi( 0, info->y1 / ts, map->height-1 );
  97.     int y2 = clampi( 0, info->y2 / ts, map->height-1 );
  98.    
  99.     // start with two 'invalid' resolution values
  100.     int dp_x = 0xFFFF, dp_y = 0xFFFF;
  101.  
  102.     // traverse all tiles in the collision area
  103.     for     ( int y=y1; y<=y2; y++ )
  104.         for ( int x=x1; x<=x2; x++ )
  105.         {
  106.             // extract this tiles value
  107.             uint8 tile = map->data[ x + y*map->width ];
  108.  
  109.             // skip if not a blocking tile
  110.             if ( (tile & cWall) == 0 )
  111.                 continue;
  112.  
  113.             // four resolution values, one for each resolution direction
  114.             int quad[4] = { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF };
  115.  
  116.             // find all of the resolutions, one for each direction
  117.             if ( (tile & cQUpper) != 0 ) quad[0] =  (y   *ts) - info->y2;
  118.             if ( (tile & cQLower) != 0 ) quad[1] = ((y+1)*ts) - info->y1;
  119.             if ( (tile & cQLeft ) != 0 ) quad[2] =  (x   *ts) - info->x2;
  120.             if ( (tile & cQRight) != 0 ) quad[3] = ((x+1)*ts) - info->x1;
  121.  
  122.             // select smallest resolution for each axis by comparison of their abs min
  123.             quad[0] = select_from_absmin( quad[0], quad[1] );
  124.             quad[2] = select_from_absmin( quad[2], quad[3] );
  125.  
  126.             // select the smallest resolving axis for this tile
  127.             if ( absi( quad[2] ) < absi( quad[0] ) )
  128.             {
  129.                 // x - axis
  130.                 // save it if smaller then our current resolution
  131.                 if ( absi( quad[2] ) < absi( dp_x ) ) dp_x = quad[2];
  132.             }
  133.             else
  134.             {
  135.                 // y - axis
  136.                 // save it if smaller then our current resolution
  137.                 if ( absi( quad[0] ) < absi( dp_y ) ) dp_y = quad[0];
  138.             }
  139.  
  140.         }
  141.  
  142.     // resolve a overlap on each axis
  143.     if ( dp_x != 0xFFFF ) info->r_x = dp_x;
  144.     if ( dp_y != 0xFFFF ) info->r_y = dp_y;
  145.  
  146.     // return true if we had a resolution
  147.     return (dp_x != 0xFFFF) || (dp_y != 0xFFFF);
  148. }
RAW Paste Data