Files
GameLib/src/Util.c
2023-09-24 21:15:57 +02:00

410 lines
7.8 KiB
C

// Copyright (C) 2011-2021 Valeriano Alfonso Rodriguez (Kableado)
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Util.h"
/////////////////////////////
// Misc
//
float CosineInterpolation(float f) { return (1.0f - cos(f * Pi)) * 0.5f; }
int MinimumInt(int i0, int i1) {
if (i1 < i0) {
return i1;
}
return i0;
}
int MaximumInt(int i0, int i1) {
if (i1 > i0) {
return i1;
}
return i0;
}
/////////////////////////////
// Rect
//
void Rect_UnionRect(Rect r0, Rect r1, Rect rd) {
rd->x0 = MinimumInt(r0->x0, r1->x0);
rd->y0 = MinimumInt(r0->y0, r1->y0);
rd->x1 = MaximumInt(r0->x1, r1->x1);
rd->y1 = MaximumInt(r0->y1, r1->y1);
}
int Rect_PointInside(Rect r, int x, int y) { return (x >= r->x0 && x < r->x1 && y >= r->y0 && y < r->y1); }
int Rect_PointInsideAny(TRect r[], int rCount, int x, int y) {
int insideAny = 0;
int i;
for (i = 0; i < rCount; i++) {
if (Rect_PointInside(&(r[i]), x, y)) {
insideAny = 1;
break;
}
}
return insideAny;
}
/////////////////////////////
// SolveQuadratic
//
// Solves a Quadratic equation using a, b and c coeficients.
int SolveQuadratic(float a, float b, float c, float *Rmin, float *Rmax) {
float root;
float divisor;
float b2;
b2 = b * b;
root = b2 - 4.0 * a * c;
if (root < 0) {
// Complex
return (0);
}
divisor = (2.0 * a);
if (fabs(divisor) == 0.0f) {
// +inf -inf
return (0);
}
root = sqrtf(root);
Rmin[0] = (float)((-b - root) / divisor);
Rmax[0] = (float)((-b + root) / divisor);
return (1);
}
////////////////////////////////////////////////
// vec2 //
//////////
// A 2D vector.
float vec2_norm(vec2 v) {
float len;
len = vec2_len(v);
vec2_scale(v, v, 1.0f / len);
return (len);
}
void vec2_orthogonalize4(vec2 v) {
if (fabs(v[0]) > fabs(v[1])) {
if (v[0] >= 0) {
v[0] = 1.0f;
v[1] = 0.0f;
} else {
v[0] = -1.0f;
v[1] = 0.0f;
}
} else {
if (v[1] >= 0) {
v[1] = 1.0f;
v[0] = 0.0f;
} else {
v[1] = -1.0f;
v[0] = 0.0f;
}
}
}
void vec2_orthogonalize8(vec2 v) {
float diff = fabs(fabs(v[0]) - fabs(v[1]));
if (diff > 0.2f) {
if (fabs(v[0]) > fabs(v[1])) {
if (v[0] >= 0) {
v[0] = 1.0f;
v[1] = 0.0f;
} else {
v[0] = -1.0f;
v[1] = 0.0f;
}
} else {
if (v[1] >= 0) {
v[1] = 1.0f;
v[0] = 0.0f;
} else {
v[1] = -1.0f;
v[0] = 0.0f;
}
}
} else {
if (v[0] > 0.0f) {
v[0] = 0.707f;
} else {
v[0] = -0.707f;
}
if (v[1] > 0.0f) {
v[1] = 0.707f;
} else {
v[1] = -0.707f;
}
}
}
/////////////////////////////
// Intersec_RayUnitCircle
//
// Intersection between a ray and a Unit Circle.
int Intersec_RayUnitCircle(vec2 orig, vec2 vel, vec2 center, float *t) {
float a, b, c;
float Rmin, Rmax;
vec2 distv;
float qlvel;
float qdistv;
// Check if the collision is even posible
qlvel = vec2_dot(vel, vel);
if (fabs(qlvel) <= 0.0f)
return (0);
vec2_minus(distv, orig, center);
qdistv = vec2_dot(distv, distv);
// Solve as a unit circle
a = qlvel;
b = 2.0f * vec2_dot(distv, vel);
c = qdistv - 1.0f;
if (SolveQuadratic(a, b, c, &Rmin, &Rmax)) {
if (Rmin >= -0.0f && Rmin < Rmax && Rmin <= 1.0f) {
*t = Rmin;
return (1);
}
if (Rmax >= -0.0f && Rmin > Rmax && Rmax <= 1.0f) {
*t = Rmax;
return (1);
}
}
return (0);
}
/////////////////////////////
// Colision_CircleCircle
//
// Colision point of a circle against another circle.
int Colision_CircleCircle(vec2 cir1, float rad1, vec2 vel, vec2 cir2, float rad2, float *t, vec2 n) {
vec2 vel_a, orig_a, cen_a, temp;
float rads, invrads;
float maxx, minx;
float maxy, miny;
// Check if the collision is even posible
rads = rad1 + rad2;
minx = cir1[0] - rads;
maxx = cir1[0] + rads;
if (vel[0] > 0) {
maxx += vel[0];
} else {
minx += vel[0];
}
if (cir2[0] < minx || cir2[0] > maxx)
return (0);
miny = cir1[1] - rads;
maxy = cir1[1] + rads;
if (vel[1] > 0) {
maxy += vel[1];
} else {
miny += vel[1];
}
if (cir2[1] < miny || cir2[1] > maxy)
return (0);
// Convert to a unit circle vs ray
invrads = 1.0f / rads;
vec2_scale(vel_a, vel, invrads);
vec2_scale(orig_a, cir1, invrads);
vec2_scale(cen_a, cir2, invrads);
if (Intersec_RayUnitCircle(orig_a, vel_a, cen_a, t)) {
// Calculate n
vec2_scaleadd(temp, cir1, vel, *t);
vec2_minus(n, temp, cir2);
vec2_scale(n, n, invrads);
return (1);
}
return (0);
}
/////////////////////////////
// Intersect_RayEdge
//
// Intersection between a ray and a edge.
int Intersect_RayEdge(vec2 pos, vec2 vel, vec2 norm, vec2 edgePos, float len, float *t) {
vec2 pos2, intersection, perp, edgePos2;
float delta, d1, d2, hLen;
vec2_plus(pos2, pos, vel);
hLen = len / 2;
// Check intersection against the line
delta = vec2_dot(norm, edgePos);
d1 = vec2_dot(pos, norm) - delta;
d2 = vec2_dot(pos2, norm) - delta;
if (d1 >= -0.0001f && d2 <= 0.0001f) {
// Intersection with line, Calculate intersection point
*t = d1 / (d1 - d2);
vec2_scaleadd(intersection, pos, vel, *t);
// Perpendicular
vec2_perp(perp, norm);
// Check sides
vec2_scaleadd(edgePos2, edgePos, perp, -hLen);
delta = -vec2_dot(perp, edgePos2);
d1 = (-vec2_dot(perp, intersection)) - delta;
vec2_scaleadd(edgePos2, edgePos, perp, hLen);
delta = vec2_dot(perp, edgePos2);
d2 = vec2_dot(perp, intersection) - delta;
if (d1 <= 0.0f && d2 <= 0.0f) {
// Intersection inside Edge.
return (1);
}
}
return (0);
}
/////////////////////////////
// absmod
//
int absmod(int v, int d) {
if (v < 0) {
v += d * (((v / d) * (-1)) + 1);
return (v);
} else {
return (v % d);
}
}
float fabsmod(float v, int d) {
if (v < 0) {
v += d * ((((int)(v / d)) * (-1)) + 1);
return (v);
} else {
v -= d * (((int)(v / d)) + 1);
return (v);
}
}
/////////////////////////////
// IsBigEndian
//
int IsBigEndian() {
union {
unsigned int i;
char c[4];
} bint = {0x01020304};
return bint.c[0] == 1;
}
/////////////////////////////
// EndsWith
//
int EndsWith(char *str, char *suffix) {
if (!str || !suffix)
return 0;
int lenStr = strlen(str);
int lenSuffix = strlen(suffix);
if (lenSuffix > lenStr)
return 0;
return strncmp(str + lenStr - lenSuffix, suffix, lenSuffix) == 0;
}
/////////////////////////////
// Rand
//
// (LGC++) + cambio de semilla
#define __seed_n 30
#define __seed_a 30
#define __seed_b 5
#define __seed_c 10
#define __seed_d 15
// #define __LGC_a 1664525ul
// #define __LGC_c 1013904223ul
// #define __LGC_m 4294967296ul
#define __LGC_a 16807ul
#define __LGC_c 2
#define __LGC_m 2147483647ul
unsigned __seeds[30];
int __seed_i = -1;
unsigned __rand_count;
unsigned __rand_orig_seed;
void Rand_Seed(unsigned seed) {
int i;
__seeds[0] = seed;
for (i = 1; i < 30; i++) {
__seeds[i] = (__seeds[i - 1] * __LGC_a + __LGC_c) % __LGC_m;
//__seeds[i]=(__seeds[i-1]*__LGC_a+__LGC_c);
}
__seed_i = 29;
// Cambio de semilla
__rand_count = 0;
__rand_orig_seed = seed;
}
unsigned Rand_Get() {
unsigned val;
int a, b, c, d;
if (__seed_i == -1) {
Rand_Seed(1);
}
a = __seed_i - __seed_a;
if (a < 0)
a += __seed_n;
b = __seed_i - __seed_b;
if (b < 0)
b += __seed_n;
c = __seed_i - __seed_c;
if (c < 0)
c += __seed_n;
d = __seed_i - __seed_d;
if (d < 0)
d += __seed_n;
val = __seeds[a] ^ __seeds[b] ^ __seeds[c] ^ __seeds[d];
a = __seed_i - 1;
if (a < 0)
a = __seed_n - 1;
__seeds[__seed_i] = (__seeds[a] * __LGC_a + __LGC_c) % __LGC_m;
//__seeds[__seed_i]=(__seeds[a]*__LGC_a+__LGC_c);
__seed_i++;
if (__seed_i == __seed_n)
__seed_i = 0;
// Cambio de semilla
__rand_count++;
if (__rand_count > (1 << 15)) {
Rand_Seed(__rand_orig_seed + 1);
}
return (val);
}
unsigned Rand_GetBetween(int min, int max) {
if (min == max) {
return max;
}
return (Rand_Get() % (max - min)) + min;
}
/////////////////////////////
// Print
//
// Prints the formated text
int Print(char *fmt, ...) {
va_list ap;
int n;
// Print
va_start(ap, fmt);
n = vprintf(fmt, ap);
va_end(ap);
// Flush
fflush(stdout);
return (n);
}