1 /* gph-cmath - C graphics math library
2 * Copyright (C) 2018-2023 John Tsiombikas <nuclear@member.fsf.org>
4 * This program is free software. Feel free to use, modify, and/or redistribute
5 * it under the terms of the MIT/X11 license. See LICENSE for details.
6 * If you intend to redistribute parts of the code without the LICENSE file
7 * replace this paragraph with the full contents of the LICENSE file.
11 static CGM_INLINE float cgm_deg_to_rad(float deg)
13 return M_PI * deg / 180.0f;
16 static CGM_INLINE float cgm_rad_to_deg(float rad)
18 return 180.0f * rad / M_PI;
21 static CGM_INLINE float cgm_smoothstep(float a, float b, float x)
23 if(x < a) return 0.0f;
24 if(x >= b) return 1.0f;
26 x = (x - a) / (b - a);
27 return x * x * (3.0f - 2.0f * x);
30 static CGM_INLINE float cgm_lerp(float a, float b, float t)
32 return a + (b - a) * t;
35 static CGM_INLINE float cgm_logerp(float a, float b, float t)
37 if(a == 0.0f) return 0.0f;
38 return a * pow(b / a, t);
41 static CGM_INLINE float cgm_bezier(float a, float b, float c, float d, float t)
43 float omt, omt3, t3, f;
46 omt3 = omt * omt * omt;
49 return (a * omt3) + (b * f * omt) + (c * f * t) + (d * t3);
52 static CGM_INLINE float cgm_bspline(float a, float b, float c, float d, float t)
54 static const float mat[] = {
63 cgm_wcons(&qfact, tsq * t, tsq, t, 1.0f);
64 cgm_wcons(&tmp, a, b, c, d);
65 cgm_wmul_m4v4(&tmp, mat);
66 cgm_wscale(&tmp, 1.0f / 6.0f);
67 return cgm_wdot(&tmp, &qfact);
70 static CGM_INLINE float cgm_spline(float a, float b, float c, float d, float t)
72 static const float mat[] = {
81 cgm_wcons(&qfact, tsq * t, tsq, t, 1.0f);
82 cgm_wcons(&tmp, a, b, c, d);
83 cgm_wmul_m4v4(&tmp, mat);
84 cgm_wscale(&tmp, 1.0f / 6.0f);
85 return cgm_wdot(&tmp, &qfact);
88 static CGM_INLINE void cgm_discrand(cgm_vec3 *pt, float rad)
90 float theta = 2.0f * M_PI * (float)rand() / RAND_MAX;
91 float r = sqrt((float)rand() / RAND_MAX) * rad;
92 pt->x = cos(theta) * r;
93 pt->y = sin(theta) * r;
97 static CGM_INLINE void cgm_sphrand(cgm_vec3 *pt, float rad)
99 float u, v, theta, phi;
101 u = (float)rand() / RAND_MAX;
102 v = (float)rand() / RAND_MAX;
104 theta = 2.0f * M_PI * u;
105 phi = acos(2.0f * v - 1.0f);
107 pt->x = cos(theta) * sin(phi) * rad;
108 pt->y = sin(theta) * sin(phi) * rad;
109 pt->z = cos(phi) * rad;
112 static CGM_INLINE void cgm_unproject(cgm_vec3 *res, const cgm_vec3 *norm_scrpos,
113 const float *inv_viewproj)
117 pos.x = 2.0f * norm_scrpos->x - 1.0f;
118 pos.y = 2.0f * norm_scrpos->y - 1.0f;
119 pos.z = 2.0f * norm_scrpos->z - 1.0f;
122 cgm_wmul_m4v4(&pos, inv_viewproj);
124 res->x = pos.x / pos.w;
125 res->y = pos.y / pos.w;
126 res->z = pos.z / pos.w;
129 static CGM_INLINE void cgm_glu_unproject(float winx, float winy, float winz,
130 const float *view, const float *proj, const int *vp,
131 float *objx, float *objy, float *objz)
136 cgm_mcopy(inv_pv, view);
137 cgm_mmul(inv_pv, proj);
138 cgm_minverse(inv_pv);
140 npos.x = (winx - vp[0]) / vp[2];
141 npos.y = (winy - vp[1]) / vp[4];
144 cgm_unproject(&res, &npos, inv_pv);
151 static CGM_INLINE void cgm_pick_ray(cgm_ray *ray, float nx, float ny,
152 const float *viewmat, const float *projmat)
154 cgm_vec3 npos, farpt;
157 cgm_mcopy(inv_pv, viewmat);
158 cgm_mmul(inv_pv, projmat);
159 cgm_minverse(inv_pv);
161 cgm_vcons(&npos, nx, ny, 0.0f);
162 cgm_unproject(&ray->origin, &npos, inv_pv);
164 cgm_unproject(&farpt, &npos, inv_pv);
166 ray->dir.x = farpt.x - ray->origin.x;
167 ray->dir.y = farpt.y - ray->origin.y;
168 ray->dir.z = farpt.z - ray->origin.z;
171 static CGM_INLINE void cgm_raypos(cgm_vec3 *p, const cgm_ray *ray, float t)
173 p->x = ray->origin.x + ray->dir.x * t;
174 p->y = ray->origin.y + ray->dir.y * t;
175 p->z = ray->origin.z + ray->dir.z * t;
178 static CGM_INLINE void cgm_bary(cgm_vec3 *bary, const cgm_vec3 *a,
179 const cgm_vec3 *b, const cgm_vec3 *c, const cgm_vec3 *pt)
181 float d00, d01, d11, d20, d21, denom;
182 cgm_vec3 v0 = *b, v1 = *c, v2 = *pt;
188 d00 = cgm_vdot(&v0, &v0);
189 d01 = cgm_vdot(&v0, &v1);
190 d11 = cgm_vdot(&v1, &v1);
191 d20 = cgm_vdot(&v2, &v0);
192 d21 = cgm_vdot(&v2, &v1);
193 denom = d00 * d11 - d01 * d01;
195 bary->y = (d11 * d20 - d01 * d21) / denom;
196 bary->z = (d00 * d21 - d01 * d20) / denom;
197 bary->x = 1.0f - bary->y - bary->z;
200 static CGM_INLINE void cgm_uvec_to_sph(float *theta, float *phi, const cgm_vec3 *v)
202 *theta = atan2(v->z, v->x);
206 static CGM_INLINE void cgm_sph_to_uvec(cgm_vec3 *v, float theta, float phi)
208 v->x = sin(theta) * cos(phi);
210 v->z = cos(theta) * cos(phi);