Advertisement
snake5

some old CCD physics DLL for a game

Oct 25th, 2013
261
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 22.63 KB | None | 0 0
  1. #define _USE_MATH_DEFINES
  2. #include <math.h>
  3. #include <string.h>
  4. #include <assert.h>
  5. #include <float.h>
  6. #include "vec2d.h"
  7.  
  8. #define PI 3.14159265358979323846f
  9.  
  10. inline float rad2deg( float x )
  11. {
  12.     return x / PI * 180;
  13. }
  14. inline float deg2rad( float x )
  15. {
  16.     return x * PI / 180;
  17. }
  18.  
  19. inline float sign( float x )
  20. {
  21.     return x == 0.0f ? 0.0f : ( x > 0.0f ? 1.0f : -1.0f );
  22. }
  23.  
  24. inline float lerp( float a, float b, float s )
  25. {
  26.     return a + ( b - a ) * s;
  27. }
  28.  
  29. template< typename _T >
  30. _T min( _T a, _T b )
  31. {
  32.     if( a < b ) return a;
  33.     else return b;
  34. }
  35.  
  36. template< typename _T >
  37. _T max( _T a, _T b )
  38. {
  39.     if( a > b ) return a;
  40.     else return b;
  41. }
  42.  
  43. #define TY_NORMAL 0
  44. #define TY_SPEC_LD 1
  45. #define TY_SPEC_RD 2
  46.  
  47. struct box_t
  48. {
  49.     vec2d min;
  50.     vec2d max;
  51.     int type;
  52. };
  53.  
  54. struct ball_t
  55. {
  56.     vec2d   pos,
  57.             vel,
  58.             acc;
  59.     float   radius;
  60.     float   friction,
  61.             restitution,
  62.             avel,
  63.             angle;
  64. };
  65.  
  66. int __real_box_size;
  67. ball_t* g_ball;
  68. box_t* g_boxes;
  69. int g_box_count;
  70.  
  71. vec2d g_col_normal;
  72.  
  73.  
  74. inline bool aabb_collide( const box_t& b1, const box_t& b2 )
  75. {
  76.     return ( ( b1.min.x < b2.max.x || b2.min.x < b1.max.x ) &&
  77.         ( b1.min.y < b2.max.y || b2.min.y < b1.max.y ) );
  78. }
  79.  
  80. inline bool aabb_point_collide( const box_t& box, vec2d& pos )
  81. {
  82.     return ( pos.x >= box.min.x && pos.x <= box.max.x &&
  83.             pos.y >= box.min.y && pos.y <= box.max.y );
  84. }
  85.  
  86. inline bool aa_1d_collide( const float f1a, const float f1b, const float f2a, const float f2b )
  87. {
  88.     return ( f1a < f2b || f2a < f1b );
  89. }
  90.  
  91. /*
  92. void fill_proxy( const vec2d& next_pos )
  93. {
  94.     vec2d m_normal( -g_ball->vel.y, g_ball->vel.x );
  95.     m_normal.normalize();
  96.     float p_min = m_normal * g_ball->pos - g_ball->radius;
  97.     float p_max = m_normal * g_ball->pos + g_ball->radius;
  98.  
  99.     vec2d bb_min( min( next_pos.x, g_ball->pos.x ) - g_ball->radius, min( next_pos.y, g_ball->pos.y ) - g_ball->radius );
  100.     vec2d bb_max( max( next_pos.x, g_ball->pos.x ) + g_ball->radius, max( next_pos.y, g_ball->pos.y ) + g_ball->radius );
  101.     box_t aabb = { bb_min, bb_max, 0 };
  102.  
  103.     g_proxy_size = 0;
  104.     for( int i = 0; i < g_box_count; ++i )
  105.     {
  106.         if( aabb_collide( aabb, *g_boxes[ i ] ) )
  107.         {
  108.             float p1 = m_normal * g_boxes[ i ]->min;
  109.             float p2 = m_normal * g_boxes[ i ]->max;
  110.             float p3 = m_normal * vec2d( g_boxes[ i ]->max.x, g_boxes[ i ]->min.y );
  111.             float p4 = m_normal * vec2d( g_boxes[ i ]->min.x, g_boxes[ i ]->max.y );
  112.             float pbmin = min( p1, p2 ); pbmin = min( pbmin, p3 ); pbmin = min( pbmin, p4 );
  113.             float pbmax = max( p1, p2 ); pbmax = max( pbmax, p3 ); pbmax = max( pbmax, p4 );
  114.  
  115.             if( aa_1d_collide( pbmin, pbmax, p_min, p_max ) )
  116.             {
  117.                 g_proxy[ g_proxy_size ] = g_boxes[ i ];
  118.                 g_proxy_size++;
  119.             }
  120.         }
  121.     }
  122. }
  123. */
  124.  
  125. const float MIN_TIMEPT = 0.001f;
  126. const float PUSHOUT_K = 1.01f;
  127. const float GETIN_K = 0.99f;
  128.  
  129. /// Collision function
  130. /// Ball - Box
  131. /// Ball can collide with edges and vertices of the box
  132. float ball_box_collision_t0( const box_t* box, const vec2d& next_pos, float max_time )
  133. {
  134.     vec2d m_normal( -g_ball->vel.y, g_ball->vel.x );
  135.     m_normal.normalize();
  136.     float p_mid = m_normal * g_ball->pos;
  137.     float p_min = p_mid - g_ball->radius;
  138.     float p_max = p_mid + g_ball->radius;
  139.  
  140.     vec2d m_vdir = next_pos - g_ball->pos;
  141.     vec2d m_vel = m_vdir;
  142.     float v_length = m_vdir.length();
  143.     m_vdir /= v_length;
  144.    
  145.     vec2d b_p1 = box->min;
  146.     vec2d b_p2 = vec2d( box->max.x, box->min.y );
  147.     vec2d b_p3 = box->max;
  148.     vec2d b_p4 = vec2d( box->min.x, box->max.y );
  149.  
  150.     /// collision data
  151.     vec2d col_normal( 0, 0 );
  152.     float col_time = max_time;
  153.  
  154.     vec2d D;
  155.     float len, d, c, c2;
  156.     bool col = false;
  157.     /// Edge 1
  158.     c = box->min.y - g_ball->radius;
  159.     d = ( c - g_ball->pos.y ) / ( next_pos.y - g_ball->pos.y );
  160.     c2 = g_ball->pos.x + m_vdir.x * d;
  161.     if( d > 0 && c2 >= box->min.x && c2 <= box->max.x && d <= col_time )
  162.     {
  163.         col_time = d;
  164.         col_normal.set( 0, -1 );
  165.         col = true;
  166.     }
  167.     /// Edge 2
  168.     c = box->max.x + g_ball->radius;
  169.     d = ( c - g_ball->pos.x ) / ( next_pos.x - g_ball->pos.x );
  170.     c2 = g_ball->pos.y + m_vdir.y * d;
  171.     if( d > 0 && c2 >= box->min.y && c2 <= box->max.y && d <= col_time )
  172.     {
  173.         col_time = d;
  174.         col_normal.set( 1, 0 );
  175.         col = true;
  176.     }
  177.     /// Edge 3
  178.     c = box->max.y + g_ball->radius;
  179.     d = ( c - g_ball->pos.y ) / ( next_pos.y - g_ball->pos.y );
  180.     c2 = g_ball->pos.x + m_vdir.x * d;
  181.     if( d > 0 && c2 >= box->min.x && c2 <= box->max.x && d <= col_time )
  182.     {
  183.         col_time = d;
  184.         col_normal.set( 0, 1 );
  185.         col = true;
  186.     }
  187.     /// Edge 4
  188.     c = box->min.x - g_ball->radius;
  189.     d = ( c - g_ball->pos.x ) / ( next_pos.x - g_ball->pos.x );
  190.     c2 = g_ball->pos.y + m_vdir.y * d;
  191.     if( d > 0 && c2 >= box->min.y && c2 <= box->max.y && d <= col_time )
  192.     {
  193.         col_time = d;
  194.         col_normal.set( -1, 0 );
  195.         col = true;
  196.     }
  197.  
  198.     vec2d col_pt;
  199.     vec2d col_unmax;
  200.     float len_unmax;
  201.     /// Vertex 1
  202.     D = b_p1 - g_ball->pos;
  203.     d = D * m_vdir;
  204.     d = d >= 0 ? d : 0;
  205.     c = d;
  206.     d = d < v_length ? d : v_length;
  207.  
  208.     col_pt = g_ball->pos + m_vdir * d;
  209.     col_unmax = g_ball->pos + m_vdir * c;
  210.     len_unmax = ( col_unmax - b_p1 ).length();
  211.  
  212.     d = ( c - sqrt( g_ball->radius * g_ball->radius - len_unmax * len_unmax ) ) / v_length;
  213.    
  214.     len = ( b_p1 - col_pt ).length();
  215.     col_pt = g_ball->pos + m_vel * d;
  216.     len -= c - d;
  217.  
  218.     if( len <= g_ball->radius )
  219.     {
  220.         if( d >= 0 && d < col_time )
  221.         {
  222.             col_time = d;
  223.             col_normal = col_pt - b_p1;
  224.             col_normal.normalize();
  225.             col = true;
  226.         }
  227.     }
  228.     /// Vertex 2
  229.     D = b_p2 - g_ball->pos;
  230.     d = D * m_vdir;
  231.     d = d >= 0 ? d : 0;
  232.     c = d;
  233.     d = d < v_length ? d : v_length;
  234.  
  235.     col_pt = g_ball->pos + m_vdir * d;
  236.     col_unmax = g_ball->pos + m_vdir * c;
  237.     len_unmax = ( col_unmax - b_p2 ).length();
  238.  
  239.     d = ( c - sqrt( g_ball->radius * g_ball->radius - len_unmax * len_unmax ) ) / v_length;
  240.    
  241.     len = ( b_p2 - col_pt ).length();
  242.     col_pt = g_ball->pos + m_vel * d;
  243.     len -= c - d;
  244.  
  245.     if( len <= g_ball->radius )
  246.     {
  247.         if( d >= 0 && d < col_time )
  248.         {
  249.             col_time = d;
  250.             col_normal = col_pt - b_p2;
  251.             col_normal.normalize();
  252.             col = true;
  253.         }
  254.     }
  255.     /// Vertex 3
  256.     D = b_p3 - g_ball->pos;
  257.     d = D * m_vdir;
  258.     d = d >= 0 ? d : 0;
  259.     c = d;
  260.     d = d < v_length ? d : v_length;
  261.  
  262.     col_pt = g_ball->pos + m_vdir * d;
  263.     col_unmax = g_ball->pos + m_vdir * c;
  264.     len_unmax = ( col_unmax - b_p3 ).length();
  265.  
  266.     d = ( c - sqrt( g_ball->radius * g_ball->radius - len_unmax * len_unmax ) ) / v_length;
  267.    
  268.     len = ( b_p3 - col_pt ).length();
  269.     col_pt = g_ball->pos + m_vel * d;
  270.     len -= c - d;
  271.  
  272.     if( len <= g_ball->radius )
  273.     {
  274.         if( d >= 0 && d < col_time )
  275.         {
  276.             col_time = d;
  277.             col_normal = col_pt - b_p3;
  278.             col_normal.normalize();
  279.             col = true;
  280.         }
  281.     }
  282.     /// Vertex 4
  283.     D = b_p4 - g_ball->pos;
  284.     d = D * m_vdir;
  285.     d = d >= 0 ? d : 0;
  286.     c = d;
  287.     d = d < v_length ? d : v_length;
  288.  
  289.     col_pt = g_ball->pos + m_vdir * d;
  290.     col_unmax = g_ball->pos + m_vdir * c;
  291.     len_unmax = ( col_unmax - b_p4 ).length();
  292.  
  293.     d = ( c - sqrt( g_ball->radius * g_ball->radius - len_unmax * len_unmax ) ) / v_length;
  294.    
  295.     len = ( b_p4 - col_pt ).length();
  296.     col_pt = g_ball->pos + m_vel * d;
  297.     len -= c - d;
  298.  
  299.     if( len <= g_ball->radius )
  300.     {
  301.         if( d >= 0 && d < col_time )
  302.         {
  303.             col_time = d;
  304.             col_normal = col_pt - b_p4;
  305.             col_normal.normalize();
  306.             col = true;
  307.         }
  308.     }
  309.  
  310.     /// Before returning, check the ball
  311.     vec2d center = ( box->min + box->max ) * 0.5f;
  312.     vec2d extents = box->max - center;
  313.     vec2d ptb = g_ball->pos - center;
  314.     if( ptb.x < -extents.x ) ptb.x = -extents.x;
  315.     if( ptb.x > extents.x ) ptb.x = extents.x;
  316.     if( ptb.y < -extents.y ) ptb.y = -extents.y;
  317.     if( ptb.y > extents.y ) ptb.y = extents.y;
  318.     vec2d ptn = ptb;
  319.     ptn.normalize();
  320.     if( ( g_ball->pos - ptb - center ).length() < g_ball->radius )
  321.     {
  322.         if( aabb_point_collide( *box, g_ball->pos ) )
  323.         {
  324.             vec2d normal = ptb;
  325.             if( abs( normal.x ) > abs( normal.y ) )
  326.             {
  327.                 g_ball->pos.x = center.x + sign( normal.x ) * ( extents.x + g_ball->radius ) * PUSHOUT_K;
  328.                 g_col_normal.set( sign( normal.x ), 0 );
  329.                 return MIN_TIMEPT;
  330.             }
  331.             else
  332.             {
  333.                 g_ball->pos.y = center.y + sign( normal.y ) * ( extents.y + g_ball->radius ) * PUSHOUT_K;
  334.                 g_col_normal.set( 0, sign( normal.y ) );
  335.                 return MIN_TIMEPT;
  336.             }
  337.         }
  338.         else
  339.         {
  340.             vec2d normal = g_ball->pos - ptb - center;
  341.             normal.normalize();
  342.             g_col_normal = normal;
  343.  
  344.             g_ball->pos = center + ptb * PUSHOUT_K + normal * g_ball->radius;
  345.             return MIN_TIMEPT;
  346.         }
  347.     }
  348.  
  349.     if( col == false ) return -1;
  350.     g_col_normal = col_normal;
  351.     return col_time;
  352. }
  353.  
  354. /// Collision function
  355. /// Ball - Box + circle inside cut ; edges - left/down
  356. /// Ball can collide with edges and vertices and the slope of the "box"
  357. float ball_box_collision_tldi( const box_t* box, const vec2d& next_pos, float max_time )
  358. {
  359.     vec2d m_normal( -g_ball->vel.y, g_ball->vel.x );
  360.     m_normal.normalize();
  361.     float p_mid = m_normal * g_ball->pos;
  362.     float p_min = p_mid - g_ball->radius;
  363.     float p_max = p_mid + g_ball->radius;
  364.  
  365.     vec2d m_vdir = next_pos - g_ball->pos;
  366.     vec2d m_vel = m_vdir;
  367.     float v_length = m_vdir.length();
  368.     m_vdir /= v_length;
  369.    
  370.     vec2d b_p1 = box->min;
  371.     vec2d b_p2 = vec2d( box->max.x, box->min.y );
  372.     vec2d b_p3 = box->max;
  373.     vec2d b_p4 = vec2d( box->min.x, box->max.y );
  374.  
  375.     /// collision data
  376.     vec2d col_normal( 0, 0 );
  377.     float col_time = max_time;
  378.  
  379.     vec2d D;
  380.     float len, d, c, c2;
  381.     bool col = false;
  382.     /// Edge 1 EMPTY
  383.     /// Edge 2 EMPTY
  384.     /// Edge 3
  385.     c = box->max.y + g_ball->radius;
  386.     d = ( c - g_ball->pos.y ) / ( next_pos.y - g_ball->pos.y );
  387.     c2 = g_ball->pos.x + m_vdir.x * d;
  388.     if( d > 0 && c2 >= box->min.x && c2 <= box->max.x && d <= col_time )
  389.     {
  390.         col_time = d;
  391.         col_normal.set( 0, 1 );
  392.         col = true;
  393.     }
  394.     /// Edge 4
  395.     c = box->min.x - g_ball->radius;
  396.     d = ( c - g_ball->pos.x ) / ( next_pos.x - g_ball->pos.x );
  397.     c2 = g_ball->pos.y + m_vdir.y * d;
  398.     if( d > 0 && c2 >= box->min.y && c2 <= box->max.y && d <= col_time )
  399.     {
  400.         col_time = d;
  401.         col_normal.set( -1, 0 );
  402.         col = true;
  403.     }
  404.  
  405.     vec2d col_pt;
  406.     vec2d col_unmax;
  407.     float len_unmax;
  408.     /// Vertex 1
  409.     D = b_p1 - g_ball->pos;
  410.     d = D * m_vdir;
  411.     d = d >= 0 ? d : 0;
  412.     c = d;
  413.     d = d < v_length ? d : v_length;
  414.  
  415.     col_pt = g_ball->pos + m_vdir * d;
  416.     col_unmax = g_ball->pos + m_vdir * c;
  417.     len_unmax = ( col_unmax - b_p1 ).length();
  418.  
  419.     d = ( c - sqrt( g_ball->radius * g_ball->radius - len_unmax * len_unmax ) ) / v_length;
  420.    
  421.     len = ( b_p1 - col_pt ).length();
  422.     col_pt = g_ball->pos + m_vel * d;
  423.     len -= c - d;
  424.  
  425.     if( len <= g_ball->radius )
  426.     {
  427.         if( d >= 0 && d < col_time )
  428.         {
  429.             col_time = d;
  430.             col_normal = col_pt - b_p1;
  431.             col_normal.normalize();
  432.             col = true;
  433.         }
  434.     }
  435.     /// Vertex 2 NOT
  436.     /// Vertex 3
  437.     D = b_p3 - g_ball->pos;
  438.     d = D * m_vdir;
  439.     d = d >= 0 ? d : 0;
  440.     c = d;
  441.     d = d < v_length ? d : v_length;
  442.  
  443.     col_pt = g_ball->pos + m_vdir * d;
  444.     col_unmax = g_ball->pos + m_vdir * c;
  445.     len_unmax = ( col_unmax - b_p3 ).length();
  446.  
  447.     d = ( c - sqrt( g_ball->radius * g_ball->radius - len_unmax * len_unmax ) ) / v_length;
  448.    
  449.     len = ( b_p3 - col_pt ).length();
  450.     col_pt = g_ball->pos + m_vel * d;
  451.     len -= c - d;
  452.  
  453.     if( len <= g_ball->radius )
  454.     {
  455.         if( d >= 0 && d < col_time )
  456.         {
  457.             col_time = d;
  458.             col_normal = col_pt - b_p3;
  459.             col_normal.normalize();
  460.             col = true;
  461.         }
  462.     }
  463.     /// Vertex 4
  464.     D = b_p4 - g_ball->pos;
  465.     d = D * m_vdir;
  466.     d = d >= 0 ? d : 0;
  467.     c = d;
  468.     d = d < v_length ? d : v_length;
  469.  
  470.     col_pt = g_ball->pos + m_vdir * d;
  471.     col_unmax = g_ball->pos + m_vdir * c;
  472.     len_unmax = ( col_unmax - b_p4 ).length();
  473.  
  474.     d = ( c - sqrt( g_ball->radius * g_ball->radius - len_unmax * len_unmax ) ) / v_length;
  475.    
  476.     len = ( b_p4 - col_pt ).length();
  477.     col_pt = g_ball->pos + m_vel * d;
  478.     len -= c - d;
  479.  
  480.     if( len <= g_ball->radius )
  481.     {
  482.         if( d >= 0 && d < col_time )
  483.         {
  484.             col_time = d;
  485.             col_normal = col_pt - b_p4;
  486.             col_normal.normalize();
  487.             col = true;
  488.         }
  489.     }
  490.     /// Long&round side
  491.     /// only square shapes like this supported which are bigger than the radius is..
  492.     /// get l1 - distance from center of circle to the possible collision
  493.     float l1 = box->max.x - box->min.x - g_ball->radius;
  494.     vec2d pos2cnt = b_p2 - g_ball->pos;
  495.     float p2c_length = pos2cnt.length();
  496.     pos2cnt /= p2c_length;
  497.     float angZ = acos( pos2cnt * m_vdir );
  498.     float stp1 = l1 / sin( angZ );
  499.     float angT = asin( p2c_length / stp1 );
  500.     float angX = deg2rad( 180 ) - angZ - angT;
  501.     float l3 = stp1 * sin( angX );
  502.     float time = l3 / v_length;
  503.     col_pt = g_ball->pos + m_vel * time;
  504.     vec2d col_norm = b_p2 - col_pt;
  505.     col_norm.normalize();
  506.     vec2d col_dv( 1, -1 );
  507.     col_dv.normalize();
  508.     if( col_norm * col_dv > cos( deg2rad( 45 ) ) &&
  509.         time >= 0 && time < col_time )
  510.     {
  511.         col_time = time;
  512.         col_normal = col_norm;
  513.         col = true;
  514.     }
  515.  
  516.     /// Before returning, check the ball
  517.     float axis1 = g_ball->pos.x + g_ball->radius - box->min.x;
  518.     float axis2 = box->max.y + g_ball->radius - g_ball->pos.y;
  519.     float axis3 = p2c_length - l1;
  520.     if( axis1 > 0 && axis1 < l1 + g_ball->radius &&
  521.         axis2 > 0 && axis2 < l1 + g_ball->radius &&
  522.         axis3 > 0.5 && axis3 < l1 )
  523.     {
  524.         int axisnb = 0;
  525.         float axiscmp = axis1;
  526.         if( axis2 < axis1 )
  527.         {
  528.             axisnb = 1;
  529.             axiscmp = axis2;
  530.         }
  531.         if( axis3 < axiscmp ) axisnb = 2;
  532.  
  533.         if( axisnb == 0 )
  534.         {
  535.             g_ball->pos.x = box->min.x - g_ball->radius;
  536.             g_col_normal.set( -1, 0 );
  537.             return MIN_TIMEPT;
  538.         }
  539.         if( axisnb == 1 )
  540.         {
  541.             g_ball->pos.y = box->max.y + g_ball->radius;
  542.             g_col_normal.set( 0, 1 );
  543.             return MIN_TIMEPT;
  544.         }
  545.         if( axisnb == 2 && col_norm * col_dv > cos( deg2rad( 45 ) ) )
  546.         {
  547.             g_ball->pos = b_p2 - pos2cnt * l1 * GETIN_K;
  548.             g_col_normal = pos2cnt;
  549.             return MIN_TIMEPT;
  550.         }
  551.     }
  552.  
  553.     if( col == false ) return -1;
  554.     g_col_normal = col_normal;
  555.     return col_time;
  556. }
  557.  
  558. /// Collision function
  559. /// Ball - Box + circle inside cut ; edges - right/down
  560. /// Ball can collide with edges and vertices and the slope of the "box"
  561. float ball_box_collision_trdi( const box_t* box, const vec2d& next_pos, float max_time )
  562. {
  563.     vec2d m_normal( -g_ball->vel.y, g_ball->vel.x );
  564.     m_normal.normalize();
  565.     float p_mid = m_normal * g_ball->pos;
  566.     float p_min = p_mid - g_ball->radius;
  567.     float p_max = p_mid + g_ball->radius;
  568.  
  569.     vec2d m_vdir = next_pos - g_ball->pos;
  570.     vec2d m_vel = m_vdir;
  571.     float v_length = m_vdir.length();
  572.     m_vdir /= v_length;
  573.    
  574.     vec2d b_p1 = box->min;
  575.     vec2d b_p2 = vec2d( box->max.x, box->min.y );
  576.     vec2d b_p3 = box->max;
  577.     vec2d b_p4 = vec2d( box->min.x, box->max.y );
  578.  
  579.     /// collision data
  580.     vec2d col_normal( 0, 0 );
  581.     float col_time = max_time;
  582.  
  583.     vec2d D;
  584.     float len, d, c, c2;
  585.     bool col = false;
  586.     /// Edge 1 EMPTY
  587.     /// Edge 2
  588.     c = box->max.x + g_ball->radius;
  589.     d = ( c - g_ball->pos.x ) / ( next_pos.x - g_ball->pos.x );
  590.     c2 = g_ball->pos.y + m_vdir.y * d;
  591.     if( d > 0 && c2 >= box->min.y && c2 <= box->max.y && d <= col_time )
  592.     {
  593.         col_time = d;
  594.         col_normal.set( 1, 0 );
  595.         col = true;
  596.     }
  597.     /// Edge 3
  598.     c = box->max.y + g_ball->radius;
  599.     d = ( c - g_ball->pos.y ) / ( next_pos.y - g_ball->pos.y );
  600.     c2 = g_ball->pos.x + m_vdir.x * d;
  601.     if( d > 0 && c2 >= box->min.x && c2 <= box->max.x && d <= col_time )
  602.     {
  603.         col_time = d;
  604.         col_normal.set( 0, 1 );
  605.         col = true;
  606.     }
  607.     /// Edge 4 EMPTY
  608.  
  609.     vec2d col_pt;
  610.     vec2d col_unmax;
  611.     float len_unmax;
  612.     /// Vertex 1 NOT
  613.     /// Vertex 2
  614.     D = b_p2 - g_ball->pos;
  615.     d = D * m_vdir;
  616.     d = d >= 0 ? d : 0;
  617.     c = d;
  618.     d = d < v_length ? d : v_length;
  619.  
  620.     col_pt = g_ball->pos + m_vdir * d;
  621.     col_unmax = g_ball->pos + m_vdir * c;
  622.     len_unmax = ( col_unmax - b_p2 ).length();
  623.  
  624.     d = ( c - sqrt( g_ball->radius * g_ball->radius - len_unmax * len_unmax ) ) / v_length;
  625.    
  626.     len = ( b_p2 - col_pt ).length();
  627.     col_pt = g_ball->pos + m_vel * d;
  628.     len -= c - d;
  629.  
  630.     if( len <= g_ball->radius )
  631.     {
  632.         if( d >= 0 && d < col_time )
  633.         {
  634.             col_time = d;
  635.             col_normal = col_pt - b_p2;
  636.             col_normal.normalize();
  637.             col = true;
  638.         }
  639.     }
  640.     /// Vertex 3
  641.     D = b_p3 - g_ball->pos;
  642.     d = D * m_vdir;
  643.     d = d >= 0 ? d : 0;
  644.     c = d;
  645.     d = d < v_length ? d : v_length;
  646.  
  647.     col_pt = g_ball->pos + m_vdir * d;
  648.     col_unmax = g_ball->pos + m_vdir * c;
  649.     len_unmax = ( col_unmax - b_p3 ).length();
  650.  
  651.     d = ( c - sqrt( g_ball->radius * g_ball->radius - len_unmax * len_unmax ) ) / v_length;
  652.    
  653.     len = ( b_p3 - col_pt ).length();
  654.     col_pt = g_ball->pos + m_vel * d;
  655.     len -= c - d;
  656.  
  657.     if( len <= g_ball->radius )
  658.     {
  659.         if( d >= 0 && d < col_time )
  660.         {
  661.             col_time = d;
  662.             col_normal = col_pt - b_p3;
  663.             col_normal.normalize();
  664.             col = true;
  665.         }
  666.     }
  667.     /// Vertex 4
  668.     D = b_p4 - g_ball->pos;
  669.     d = D * m_vdir;
  670.     d = d >= 0 ? d : 0;
  671.     c = d;
  672.     d = d < v_length ? d : v_length;
  673.  
  674.     col_pt = g_ball->pos + m_vdir * d;
  675.     col_unmax = g_ball->pos + m_vdir * c;
  676.     len_unmax = ( col_unmax - b_p4 ).length();
  677.  
  678.     d = ( c - sqrt( g_ball->radius * g_ball->radius - len_unmax * len_unmax ) ) / v_length;
  679.    
  680.     len = ( b_p4 - col_pt ).length();
  681.     col_pt = g_ball->pos + m_vel * d;
  682.     len -= c - d;
  683.  
  684.     if( len <= g_ball->radius )
  685.     {
  686.         if( d >= 0 && d < col_time )
  687.         {
  688.             col_time = d;
  689.             col_normal = col_pt - b_p4;
  690.             col_normal.normalize();
  691.             col = true;
  692.         }
  693.     }
  694.     /// Long&round side
  695.     /// only square shapes like this supported which are bigger than the radius is..
  696.     /// get l1 - distance from center of circle to the possible collision
  697.     float l1 = box->max.x - box->min.x - g_ball->radius;
  698.     vec2d pos2cnt = b_p1 - g_ball->pos;
  699.     float p2c_length = pos2cnt.length();
  700.     pos2cnt /= p2c_length;
  701.     float angZ = acos( pos2cnt * m_vdir );
  702.     float stp1 = l1 / sin( angZ );
  703.     float angT = asin( p2c_length / stp1 );
  704.     float angX = deg2rad( 180 ) - angZ - angT;
  705.     float l3 = stp1 * sin( angX );
  706.     float time = l3 / v_length;
  707.     col_pt = g_ball->pos + m_vel * time;
  708.     vec2d col_norm = b_p1 - col_pt;
  709.     col_norm.normalize();
  710.     vec2d col_dv( -1, -1 );
  711.     col_dv.normalize();
  712.     if( col_norm * col_dv > cos( deg2rad( 45 ) ) &&
  713.         time >= 0 && time < col_time )
  714.     {
  715.         col_time = time;
  716.         col_normal = col_norm;
  717.         col = true;
  718.     }
  719.  
  720.     /// Before returning, check the ball
  721.     float axis1 = box->max.x - g_ball->pos.x - g_ball->radius;
  722.     float axis2 = box->max.y + g_ball->radius - g_ball->pos.y;
  723.     float axis3 = p2c_length - l1;
  724.     if( axis1 > 0 && axis1 < l1 + g_ball->radius &&
  725.         axis2 > 0 && axis2 < l1 + g_ball->radius &&
  726.         axis3 > 0 && axis3 < l1 )
  727.     {
  728.         int axisnb = 0;
  729.         float axiscmp = axis1;
  730.         if( axis2 < axis1 )
  731.         {
  732.             axisnb = 1;
  733.             axiscmp = axis2;
  734.         }
  735.         if( axis3 < axiscmp ) axisnb = 2;
  736.  
  737.         if( axisnb == 0 )
  738.         {
  739.             g_ball->pos.x = box->max.x + g_ball->radius;
  740.             g_col_normal.set( 1, 0 );
  741.             return MIN_TIMEPT;
  742.         }
  743.         if( axisnb == 1 )
  744.         {
  745.             g_ball->pos.y = box->max.y + g_ball->radius;
  746.             g_col_normal.set( 0, 1 );
  747.             return MIN_TIMEPT;
  748.         }
  749.         if( axisnb == 2 && col_norm * col_dv > cos( deg2rad( 45 ) ) )
  750.         {
  751.             g_ball->pos = b_p1 - pos2cnt * l1 * GETIN_K;
  752.             g_col_normal = pos2cnt;
  753.             return MIN_TIMEPT;
  754.         }
  755.     }
  756.  
  757.     if( col == false ) return -1;
  758.     g_col_normal = col_normal;
  759.     return col_time;
  760. }
  761.  
  762.  
  763. void integrate( const float time )
  764. {
  765.     if( time <= 0 )
  766.         return;
  767.  
  768.     g_ball->vel += g_ball->acc * time;
  769.     g_ball->angle += g_ball->avel * time;
  770.     vec2d next_pos = g_ball->pos + g_ball->vel * time;
  771.  
  772.     float best_col_time = 2;
  773.     vec2d best_col_normal;
  774.  
  775.     float time_left = 1;
  776.  
  777.     while( time_left > 0 )
  778.     {
  779.         for( int i = 0; i < g_box_count; ++i )
  780.         {
  781.             float time = best_col_time;
  782.             if( g_boxes[ i ].type == TY_SPEC_LD )
  783.             {
  784.                 time = ball_box_collision_tldi( &(g_boxes[ i ]), next_pos, time_left );
  785.             }
  786.             else if( g_boxes[ i ].type == TY_SPEC_RD )
  787.             {
  788.                 time = ball_box_collision_trdi( &(g_boxes[ i ]), next_pos, time_left );
  789.             }
  790.             else
  791.             {
  792.                 time = ball_box_collision_t0( &(g_boxes[ i ]), next_pos, time_left );
  793.             }
  794.             if( time < best_col_time && time > 0 )
  795.             {
  796.                 best_col_time = time;
  797.                 best_col_normal = g_col_normal;
  798.             }
  799.         }
  800.  
  801.         time_left -= best_col_time;
  802.         g_ball->pos += g_ball->vel * min( best_col_time, 1.0f ) * time;
  803.  
  804.         if( best_col_time < 2 )
  805.         {
  806.             vec2d vel_new = g_ball->vel.reflect( best_col_normal );
  807.             vec2d bc_tangent( -best_col_normal.y, best_col_normal.x );
  808.             float vel_n = best_col_normal * vel_new * g_ball->restitution;
  809.             float vel_t = bc_tangent * vel_new * ( 1 - g_ball->friction );//lerp( 1, ( 1 - g_ball->friction ), time * best_col_time );
  810.             //length = 2 * pi * radius * k
  811.             //vel_t = 2 * pi * radius * k
  812.             //k = vel_t / 2 * pi * radius
  813.             g_ball->avel = -vel_t;// / ( 2 * PI * g_ball->radius );
  814.             g_ball->vel = best_col_normal * vel_n + bc_tangent * vel_t;
  815.             next_pos = g_ball->pos + g_ball->vel * time;
  816.  
  817.             best_col_time = 2;
  818.         }
  819.     }
  820. }
  821.  
  822. void storage_resize( int size )
  823. {
  824.     box_t* boxes = new box_t[ size ];
  825.     memcpy_s( boxes, size, g_boxes, __real_box_size );
  826.     if( size < g_box_count )
  827.     {
  828.         g_box_count = size;
  829.     }
  830.     __real_box_size = size;
  831.     delete [] g_boxes;
  832.     g_boxes = boxes;
  833. }
  834.  
  835.  
  836. ///////
  837. ///// THE
  838. ///// PHYSICS
  839. ///// ENGINE
  840. ///////
  841.  
  842.  
  843. #define DLL_EXP extern "C" __declspec(dllexport)
  844.  
  845. #define BALL_SET( what, varname, argname )                  \
  846.     DLL_EXP double phy_ball_##what##_set( double argname )  \
  847.     {                                                       \
  848.         g_ball->##varname = (float) argname;                \
  849.         return 0;                                           \
  850.     }
  851.  
  852. #define BALL_SETVEC( what, varname1, varname2, argname1, argname2 )             \
  853.     DLL_EXP double phy_ball_##what##_set( double argname1, double argname2 )    \
  854.     {                                                                           \
  855.         g_ball->##varname1 = (float) argname1;                                  \
  856.         g_ball->##varname2 = (float) argname2;                                  \
  857.         return 0;                                                               \
  858.     }
  859.  
  860. #define BALL_GET( what, varname )           \
  861.     DLL_EXP double phy_ball_##what##_get()  \
  862.     {                                       \
  863.         return (float) g_ball->##varname;   \
  864.     }
  865.  
  866.  
  867. bool g_initialized = false;
  868.  
  869. DLL_EXP double phy_start()
  870. {
  871.     g_boxes = new box_t[ 1000 ];
  872.     __real_box_size = 1000;
  873.     g_ball = new ball_t;
  874.  
  875.     memset( g_ball, 0, sizeof(ball_t) );
  876.    
  877.     g_initialized = true;
  878.  
  879.     return 0;
  880. }
  881. DLL_EXP double phy_end()
  882. {
  883.     delete [] g_boxes;
  884.     g_initialized = false;
  885.  
  886.     return 0;
  887. }
  888.  
  889. DLL_EXP double phy_step( double time )
  890. {
  891.     integrate( (float) time );
  892.     return 0;
  893. }
  894.  
  895. DLL_EXP double phy_box_add( double x1, double x2, double y1, double y2, double type )
  896. {
  897.     if( g_box_count == __real_box_size )
  898.     {
  899.         storage_resize( __real_box_size * 2 );
  900.     }
  901.     g_boxes[ g_box_count ].min.set( (float) x1, (float) y1 );
  902.     g_boxes[ g_box_count ].max.set( (float) x2, (float) y2 );
  903.     g_boxes[ g_box_count ].type = (int) type;
  904.     g_box_count++;
  905.     return 0;
  906. }
  907. DLL_EXP double phy_box_clear()
  908. {
  909.     g_box_count = 0;
  910.     return 0;
  911. }
  912.  
  913.  
  914. BALL_SET(friction,friction,friction)
  915. BALL_SET(restitution,restitution,restitution)
  916. BALL_SET(radius,radius,radius)
  917. BALL_SET(avel,avel,avel)
  918. BALL_SET(angle,angle,angle)
  919. BALL_SET(x,pos.x,x)
  920. BALL_SET(y,pos.y,y)
  921. BALL_SET(vel_x,vel.x,x)
  922. BALL_SET(vel_y,vel.y,y)
  923. BALL_SET(acc_x,acc.x,x)
  924. BALL_SET(acc_y,acc.y,y)
  925.  
  926. BALL_SETVEC(pos,pos.x,pos.y,x,y);
  927. BALL_SETVEC(vel,vel.x,vel.y,x,y);
  928. BALL_SETVEC(acc,acc.x,acc.y,x,y);
  929.  
  930. BALL_GET(friction,friction)
  931. BALL_GET(restitution,restitution)
  932. BALL_GET(radius,radius)
  933. BALL_GET(avel,avel)
  934. BALL_GET(angle,angle)
  935. BALL_GET(x,pos.x)
  936. BALL_GET(y,pos.y)
  937. BALL_GET(vel_x,vel.x)
  938. BALL_GET(vel_y,vel.y)
  939. BALL_GET(acc_x,acc.x)
  940. BALL_GET(acc_y,acc.y)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement