lash_game_standard.c (15910B)
1 #include <stdlib.h> 2 #include <math.h> 3 4 #include "lash_game_standard.h" 5 6 7 #define LASH_M_PI_DOUBLE (M_PI * 2) 8 9 // http://stackoverflow.com/questions/4003232/how-to-code-a-modulo-operator-in-c-c-obj-c-that-handles-negative-numbers 10 // modulus must be handled differently for negatives 11 12 unsigned char lash_getQuadrant(const float rads) { 13 int mod, quad; 14 mod = (int)floor(rads / M_PI_2); 15 quad = mod % 4; 16 17 if (mod < 0) 18 if (quad != 0) 19 quad += 4; 20 21 return quad + 1; 22 } 23 24 unsigned char lash_getQuadrantFromCartesian(const int dx, const int dy) { 25 if (dx > 0) { 26 if (dy > 0) { 27 return 1; 28 } else { 29 return 4; 30 } 31 } else { 32 if (dy > 0) { 33 return 2; 34 } else { 35 return 3; 36 } 37 } 38 return 0; 39 } 40 41 42 enum lash_anglespan_compare lash_compareAngleSpan(float old_rad_min, float old_rad_max, float new_rad_min, float new_rad_max) { 43 double full_circle = 2 * M_PI; 44 45 if (old_rad_max > full_circle) { 46 // if new angle is fully contained by the old, and the old angles are on each side of 2π 47 if (new_rad_min + full_circle < old_rad_max && new_rad_min + full_circle > old_rad_min) { 48 new_rad_min += full_circle; 49 new_rad_max += full_circle; 50 } 51 } else if (new_rad_max > full_circle && old_rad_max <= full_circle && old_rad_min < full_circle) { 52 // if the new angle are on each side of 2π, and the old min is inside the span 53 //if (new_rad_min < old_rad_max + full_circle && new_rad_min > old_rad_min + full_circle) { 54 old_rad_min += full_circle; 55 old_rad_max += full_circle; 56 //} 57 } 58 59 enum lash_anglespan_compare result = LASH_ANGLESPAN_NONE; 60 if (new_rad_max < old_rad_max && new_rad_min > old_rad_min) { 61 result = LASH_ANGLESPAN_SPLIT; 62 } else { 63 if (new_rad_max >= old_rad_max && new_rad_min <= old_rad_max) 64 result = LASH_ANGLESPAN_MAX; 65 if (new_rad_min <= old_rad_min && new_rad_max >= old_rad_min) 66 result = result == LASH_ANGLESPAN_MAX ? LASH_ANGLESPAN_BOTH : LASH_ANGLESPAN_MIN; 67 } 68 return result; 69 } 70 71 int lash_getContainedAngleOnly(const double x, const double y, const double m, const double w_container, const double h_container, const int buf_top, const int buf_right, const int buf_bottom, const int buf_left, double *angle_min, double *angle_max) { 72 double n = 0.f; 73 return lash_getContainedAngle(x, y, m, w_container, h_container, buf_top, buf_right, buf_bottom, buf_left, angle_min, angle_max, 0, &n, &n, &n, &n); 74 } 75 76 int lash_getContainedAngle(const double x, const double y, const double m, const double w_container, const double h_container, const int buf_top, const int buf_right, const int buf_bottom, const int buf_left, double *angle_min, double *angle_max, const int include_dcoords, double *x_min, double *y_min, double *x_max, double *y_max) { 77 // any left 78 if (x - m < buf_left) { 79 // topleft 80 if (y - m < buf_top) { 81 double min_mod = M_PI; 82 double max_mod = 2 * M_PI; 83 *angle_min = min_mod + acos((x - buf_left) / m); 84 *angle_max = max_mod + asin((y - buf_top) / m); 85 if (include_dcoords) { 86 /* *x_min = buf_left; 87 *y_min = y + floor(sin(*angle_min - min_mod) * m); 88 *x_max = x + floor(cos(*angle_max - max_mod) * m); 89 *y_max = buf_top; */ 90 *x_min = buf_left; 91 *y_min = y + (sin(*angle_min - min_mod) * m); 92 *x_max = x + (cos(*angle_max - max_mod) * m); 93 *y_max = buf_top; 94 } 95 return 0; 96 // bottomleft 97 } else if (y + m > h_container - buf_bottom) { 98 double min_mod = 3 * M_PI_2; 99 double max_mod = 5 * M_PI_2; 100 *angle_min = min_mod + acos((x - buf_left) / m); 101 *angle_max = max_mod + asin((h_container - buf_bottom - y) / m); 102 if (include_dcoords) { 103 /* *x_min = x + floor(sin(*angle_min - min_mod) * m); 104 *y_min = h_container - buf_bottom; 105 *x_max = buf_left; 106 *y_max = y - floor(cos(*angle_max - max_mod) * m); */ 107 *x_min = x + (sin(*angle_min - min_mod) * m); 108 *y_min = h_container - buf_bottom; 109 *x_max = buf_left; 110 *y_max = y - (cos(*angle_max - max_mod) * m); 111 } 112 return 0; 113 } else { 114 // left 115 double tmp_angle = acos((x - buf_left) / m); 116 *angle_min = M_PI + tmp_angle; 117 *angle_max = (3 * M_PI) - tmp_angle; 118 if (include_dcoords) { 119 //int tmp_side = floor(sin(tmp_angle) * m); 120 int tmp_side = (sin(tmp_angle) * m); 121 *x_min = buf_left; 122 *y_min = y + tmp_side; 123 *x_max = buf_left; 124 *y_max = y - tmp_side; 125 } 126 return 0; 127 } 128 // any right 129 } else if (x + m > w_container - buf_right) { 130 // top right 131 if (y - m < buf_top) { 132 double min_mod = M_PI_2; 133 double max_mod = 3 * M_PI_2; 134 *angle_min = min_mod + acos((y - buf_top) / m); 135 *angle_max = max_mod + asin((w_container - buf_right - x) / m); 136 if (include_dcoords) { 137 /* *x_min = x - floor(sin(*angle_min - min_mod) * m); 138 *y_min = buf_top; 139 *x_max = w_container - buf_left; 140 *y_max = y + floor(cos(*angle_max - max_mod) * m); */ 141 *x_min = x - (sin(*angle_min - min_mod) * m); 142 *y_min = buf_top; 143 *x_max = w_container - buf_left; 144 *y_max = y + (cos(*angle_max - max_mod) * m); 145 } 146 return 0; 147 // bottom right 148 } else if (y + m > h_container - buf_bottom) { 149 //double min_mod = 0; 150 double max_mod = M_PI; 151 *angle_min = acos((w_container - buf_right - x) / m); 152 *angle_max = max_mod + asin((h_container - buf_bottom - y) / m); 153 if (include_dcoords) { 154 /* *x_min = w_container - buf_left; 155 *y_min = y - floor(sin(*angle_min) * m); 156 *x_max = x - floor(cos(*angle_max - max_mod) * m); 157 *y_max = h_container - buf_bottom;*/ 158 *x_min = w_container - buf_left; 159 *y_min = y - (sin(*angle_min) * m); 160 *x_max = x - (cos(*angle_max - max_mod) * m); 161 *y_max = h_container - buf_bottom; 162 } 163 return 0; 164 // right 165 } else { 166 //angle min has no modifier 167 //double tmp_angle = acos((h_container - buf_right - x) / m); 168 *angle_min = acos((w_container - buf_right - x) / m); 169 *angle_max = (2 * M_PI) - *angle_min; 170 if (include_dcoords) { 171 //int tmp_side = floor(sin(*angle_min) * m); 172 int tmp_side = (sin(*angle_min) * m); 173 *x_min = w_container - buf_right; 174 *y_min = y - tmp_side; 175 *x_max = w_container - buf_right; 176 *y_max = y + tmp_side; 177 178 } 179 return 0; 180 } 181 // top (only) 182 } else if (y - m < buf_top) { 183 double tmp_angle = acos((y - buf_top) / m); 184 *angle_min = M_PI_2 + tmp_angle; 185 *angle_max = (5 * M_PI_2) - tmp_angle; 186 if (include_dcoords) { 187 //int tmp_side = floor(sin(tmp_angle) * m); 188 int tmp_side = (sin(tmp_angle) * m); 189 *x_min = x - tmp_side; 190 *y_min = buf_top; 191 *x_max = x + tmp_side; 192 *y_max = buf_top; 193 } 194 return 0; 195 // bottom (only) 196 } else if (y + m > h_container - buf_bottom) { 197 double tmp_angle = acos((h_container - buf_bottom - y) / m); 198 *angle_min = (3 * M_PI_2) + tmp_angle; 199 *angle_max = (7 * M_PI_2) - tmp_angle; 200 if (include_dcoords) { 201 //int tmp_side = floor(sin(tmp_angle) * m); 202 int tmp_side = (sin(tmp_angle) * m); 203 *x_min = x + tmp_side; 204 *y_min = h_container - buf_bottom; 205 *x_max = x - tmp_side; 206 *y_max = h_container - buf_bottom; 207 } 208 return 0; 209 } 210 211 // default; no limit 212 *angle_min = 0.f; 213 *angle_max = 2 * M_PI; 214 if (include_dcoords) { 215 *x_min = h_container - buf_right; 216 *y_min = y; 217 *x_max = h_container - buf_right; 218 *y_max = y; 219 } 220 return 0; 221 } 222 223 float lash_cartesianMagnitude(const int target_x, const int target_y, const int source_x, const int source_y) { 224 return sqrt(pow(target_x - source_x, 2) + pow(target_y - source_y, 2)); 225 } 226 227 // self.h = abs((targetindex % map.w) - (index % map.w)) + abs(math.floor(targetindex / map.w) - math.floor(index / map.w)) 228 int lash_getManhattanMagnitudeFromCartesian(const lash_game_coords_t targetcoords, const lash_game_coords_t sourcecoords) { 229 //return abs((target_idx % *w) - (source_idx % *w)) + abs(floor(target_idx / *w) - floor(source_idx / *w)); 230 return abs(targetcoords.y - sourcecoords.y) + abs(targetcoords.x - sourcecoords.x); 231 } 232 233 int lash_polarToCartesian(const float radians, const float radius, const int source_x, const int source_y, int *target_x, int *target_y) { 234 *target_x = source_x + floor(cos(radians) * radius); 235 *target_y = source_y + floor(sin(radians) * radius); 236 return 0; 237 } 238 239 int lash_cartesianToPolar(const int source_x, const int source_y, const int target_x, const int target_y, float *radians, float *radius, const int inv_x, const int inv_y) { 240 241 float tmp_radians; 242 243 int x = target_x - source_x; 244 if (inv_x != 0) 245 x *= -1; 246 247 int y = target_y - source_y; 248 if (inv_y != 0) 249 y *= -1; 250 251 *radius = sqrt(pow(x, 2) + pow(y, 2)); 252 tmp_radians = atan2((float)y, (float)x); 253 if (tmp_radians < 0) 254 tmp_radians += 2 * M_PI; 255 256 *radians = tmp_radians; 257 258 return 0; 259 } 260 261 int lash_cartesianToIndex(unsigned long int *index, const unsigned int *w, const unsigned int *h, unsigned int *unit_size, const lash_game_coords_cartesian_t *coords) { 262 263 if (coords->x > *w - 1 || coords->y > *h - 1) 264 return 1; 265 266 //*index = coords->x; 267 //*index += floor(coords->y * *w); 268 *index = coords->x / *unit_size; 269 *index += floor((coords->y * *w) / *unit_size); 270 271 return 0; 272 } 273 274 int lash_indexToCartesian(lash_game_coords_cartesian_t *coords, const unsigned int *w, const unsigned int *h, unsigned int *unit_size, const lash_game_map_index_t *index) { 275 276 if ((*index) >= *w * *h) 277 return 1; 278 279 if (*unit_size < 1) 280 *unit_size = 1; 281 282 coords->x = (unsigned int)((*index % *w) * *unit_size); 283 coords->y = (unsigned int)(floor(*index / *w) * *unit_size); 284 285 return 0; 286 } 287 288 int lash_cartesianToFloat(lash_game_coords_float_t *coords_float, const unsigned int *w, const unsigned int *h, const lash_game_coords_cartesian_t *coords_cartesian) { 289 coords_float->x = (float)coords_cartesian->x / *w; 290 coords_float->y = (float)coords_cartesian->y / *h; 291 return 0; 292 } 293 294 int lash_linearIntersect(const lash_game_line_t a, const lash_game_line_t b, lash_game_coords_float_t *coords) { 295 296 coords->x = (b.c - a.c) / (a.m - b.m); 297 coords->y = (a.m * coords->x) + a.c; 298 if (isinf(coords->x) || isinf(coords->y)) 299 return 1; 300 return 0; 301 302 } 303 304 int lash_cartesianToLinear(const lash_game_coords_float_t src, const lash_game_coords_float_t target, lash_game_line_t *result) { 305 if (target.x == src.x) { 306 result->m = INFINITY; 307 result->c = INFINITY; 308 return 1; 309 } else if (target.y == src.y) { 310 result->m = NAN; 311 result->c = NAN; 312 return 1; 313 } else { 314 result->m = (target.y - src.y) / (float)(target.x - src.x); 315 result->c = ((-result->m) * src.x) + src.y; 316 } 317 return 0; 318 } 319 320 float lash_distanceToRadians(const float distance, const float radius) { 321 return LASH_M_PI_DOUBLE * (distance / (LASH_M_PI_DOUBLE * radius)); 322 } 323 324 float lash_normalizeRadians(float radians) { 325 char rotations = floor(radians / (2 * M_PI)); 326 if (rotations != 0) 327 radians -= LASH_M_PI_DOUBLE * rotations; 328 else if (radians < 0) 329 radians += LASH_M_PI_DOUBLE; 330 return radians; 331 } 332 333 float lash_normalizeQuadrantRadians(float radians) { 334 float rotations = floor(radians / M_PI_2); 335 if (rotations != 0) 336 radians -= (float)M_PI_2 * rotations; 337 else if (radians < 0) 338 radians += M_PI_2 + (float)(M_PI_2 * rotations); 339 return radians; 340 } 341 342 // calculates at the point of impact. 343 /// \todo resultquad calculation should resolve to being able to use resultquad for the objrad calculation below 344 void lash_collisionSurfaceDeflectSimple(float *objvel, float *objrad, const float surfacerad, float bounce) { 345 346 347 if (bounce < 0.f) 348 bounce = 0.0; 349 else if (bounce > 1.f) 350 bounce = 1.f; 351 352 float resultquad; // the angle of impact 353 float direction; // the difference of objrad and surfacerad 354 float xvel, yvel; // the resulting velocities after bounce is calculated 355 float objradnormal, surfaceradnormal, objradquad, surfaceradquad, radmod; 356 char surfacequadrant, objquadrant; // quadrant the surface and object angles belong to 357 358 objradnormal = lash_normalizeRadians(*objrad); 359 surfaceradnormal = lash_normalizeRadians(surfacerad); 360 361 radmod = 0.f; // bounce angle 362 363 surfacequadrant = floor(surfaceradnormal / M_PI_2); 364 objquadrant = floor(objradnormal / M_PI_2); 365 366 objradquad = objradnormal - (objquadrant * (float)M_PI_2); // object rads normalized within quadrant 367 surfaceradquad = surfaceradnormal - (surfacequadrant * (float)M_PI_2); // surface rads normalized within quadrant 368 369 if (objquadrant % 2 != surfacequadrant % 2) 370 direction = surfaceradquad + (M_PI_2 - objradquad); 371 else 372 direction = surfaceradquad - objradquad; 373 374 375 if (direction < 0.f) 376 resultquad = M_PI + direction; 377 else //if (direction < M_PI_2) 378 resultquad = M_PI - direction; 379 //else 380 //resultquad = direction; 381 382 383 if (direction < 0.f) 384 xvel = cos(-direction) * *objvel; 385 else 386 xvel = cos(direction) * *objvel; 387 388 yvel = sin(direction) * *objvel * bounce; 389 390 if (resultquad != M_PI_2) 391 radmod = atan(yvel / xvel); 392 393 if (radmod < 0.f) 394 radmod = -radmod; 395 396 if (direction < 0.f) 397 *objrad = *objrad + direction - radmod; 398 else if (direction > M_PI_2) 399 *objrad = *objrad - resultquad - radmod; 400 else 401 *objrad = *objrad + direction + radmod; 402 403 *objvel = sqrt(pow(xvel, 2) + pow(yvel, 2)); 404 405 } 406 407 408 // if want intersect coords, pass both as pointers, if NULL the coords are not resolved 409 char lash_collisionCheckCircleLine(const lash_game_coords_float_t circle_centre, const float circle_radius, const lash_game_line_t slope, lash_game_coords_float_t *intersect_coords_1, lash_game_coords_float_t *intersect_coords_2) { 410 return lash_collisionCircleLine(circle_centre, circle_radius, slope, intersect_coords_1, intersect_coords_2); 411 } 412 413 char lash_collisionCircleLine(const lash_game_coords_float_t circle_centre, const float circle_radius, const lash_game_line_t slope, lash_game_coords_float_t *intersect_coords_1, lash_game_coords_float_t *intersect_coords_2) { 414 float a, b, c, discriminant; 415 char intersections = 0; 416 417 // quadratic equation to resolve intersections from circle and line equation (substitute the line into circle, expand and collect equal terms) 418 // binomial: (m²+1)x²+2(mc−mq−p)x+(q²−r²+p²−2cq+c²)=0. 419 // discriminant: -2(mc−mq−p) +/- sqrt(pow(2(mc-mq-p), 2) - (4 * ((m*m)+1) * ((p*p)-(r*r)+(q*q)-(2*c*q)+(c*c)))) 420 // taken from http://math.stackexchange.com/questions/228841/how-do-i-calculate-the-intersections-of-a-straight-line-and-a-circle 421 a = (slope.m * slope.m) + 1; 422 b = 2 * ((slope.m * slope.c) - (slope.m * circle_centre.y) - circle_centre.x); 423 c = (circle_centre.x * circle_centre.x) + (circle_centre.y * circle_centre.y) - (2 * slope.c * circle_centre.y) + (slope.c * slope.c) - (circle_radius * circle_radius); 424 425 discriminant = (b * b) - (4 * a * c); 426 if (discriminant > 0) 427 intersections = 2; 428 else if (discriminant == 0) 429 intersections = 1; 430 431 if (intersections == 0) { 432 intersect_coords_1 = NULL; 433 intersect_coords_2 = NULL; 434 } else if (intersect_coords_1 != NULL && intersect_coords_2 != NULL) { 435 intersect_coords_1->x = (-b - sqrt(discriminant)) / (2 * a); 436 intersect_coords_1->y = (slope.m * intersect_coords_1->x) + slope.c; 437 if (intersections == 2) { 438 intersect_coords_2->x = (-b + sqrt(discriminant)) / (2 * a); 439 intersect_coords_2->y = (slope.m * intersect_coords_2->x) + slope.c; 440 } 441 } 442 443 return intersections; 444 } 445 446 447 /* 448 /// \todo check if this is faster with circle/line intersect check 449 void lash_collisionCheckCircleLine(const lash_game_coords_float_t c_coords, const float c_r, const lash_game_coords_float_t l_coords_1, const lash_game_coords_float_t l_coords_2, float *intersect_perp) { 450 float l_reverse_vx, l_reverse_vy; 451 lash_game_line_t l_slope, l_reverse_slope; 452 lash_game_coords_float_t intersect_coords; 453 lash_cartesianToLinear(l_coords_1, l_coords_2, &l_slope); 454 reverse_vy = l_coords_1.x - l_coords_2.x; 455 reverse_vx = l_coords_1.y - l_coords_2.y; 456 l_reverse_slope.m = (reverse_vy / reverse_vx) * -1; 457 l_reverse_slope.c = c_coords.y - (l_reverse_slope.m * c_coords.x); 458 lash_linearIntersect(l_slope, l_reverse_slope, &intersect_coords); 459 } 460 */ 461 462 /* 463 int lash_isBigEndian() { 464 if (_lash_endian == -1) { 465 union { 466 uint32_t i; 467 char[4] c; 468 } bint = (0x01020304); 469 if (bint.c[0] == 1) 470 _lash_endian = 1; 471 else 472 _lash_endian = 0; 473 } 474 return _lash_endian; 475 } 476 */