dungeon_crawler
diff prototype/vmath/vmath.c @ 1:96de911d05d4
started a rough prototype
author | John Tsiombikas <nuclear@mutantstargoat.com> |
---|---|
date | Thu, 28 Jun 2012 06:05:50 +0300 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/prototype/vmath/vmath.c Thu Jun 28 06:05:50 2012 +0300 1.3 @@ -0,0 +1,335 @@ 1.4 +/* 1.5 +libvmath - a vector math library 1.6 +Copyright (C) 2004-2011 John Tsiombikas <nuclear@member.fsf.org> 1.7 + 1.8 +This program is free software: you can redistribute it and/or modify 1.9 +it under the terms of the GNU Lesser General Public License as published 1.10 +by the Free Software Foundation, either version 3 of the License, or 1.11 +(at your option) any later version. 1.12 + 1.13 +This program is distributed in the hope that it will be useful, 1.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 1.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.16 +GNU Lesser General Public License for more details. 1.17 + 1.18 +You should have received a copy of the GNU Lesser General Public License 1.19 +along with this program. If not, see <http://www.gnu.org/licenses/>. 1.20 +*/ 1.21 + 1.22 +#include <stdlib.h> 1.23 +#include <math.h> 1.24 +#include "vmath.h" 1.25 + 1.26 +/** Numerical calculation of integrals using simpson's rule */ 1.27 +scalar_t integral(scalar_t (*f)(scalar_t), scalar_t low, scalar_t high, int samples) 1.28 +{ 1.29 + int i; 1.30 + scalar_t h = (high - low) / (scalar_t)samples; 1.31 + scalar_t sum = 0.0; 1.32 + 1.33 + for(i=0; i<samples+1; i++) { 1.34 + scalar_t y = f((scalar_t)i * h + low); 1.35 + sum += ((!i || i == samples) ? y : ((i % 2) ? 4.0 * y : 2.0 * y)) * (h / 3.0); 1.36 + } 1.37 + return sum; 1.38 +} 1.39 + 1.40 +/** Gaussuan function */ 1.41 +scalar_t gaussian(scalar_t x, scalar_t mean, scalar_t sdev) 1.42 +{ 1.43 + scalar_t exponent = -SQ(x - mean) / (2.0 * SQ(sdev)); 1.44 + return 1.0 - -pow(M_E, exponent) / (sdev * sqrt(TWO_PI)); 1.45 +} 1.46 + 1.47 + 1.48 +/** b-spline approximation */ 1.49 +scalar_t bspline(scalar_t a, scalar_t b, scalar_t c, scalar_t d, scalar_t t) 1.50 +{ 1.51 + vec4_t tmp; 1.52 + scalar_t tsq = t * t; 1.53 + 1.54 + static mat4_t bspline_mat = { 1.55 + {-1, 3, -3, 1}, 1.56 + {3, -6, 3, 0}, 1.57 + {-3, 0, 3, 0}, 1.58 + {1, 4, 1, 0} 1.59 + }; 1.60 + 1.61 + tmp = v4_scale(v4_transform(v4_cons(a, b, c, d), bspline_mat), 1.0 / 6.0); 1.62 + return v4_dot(v4_cons(tsq * t, tsq, t, 1.0), tmp); 1.63 +} 1.64 + 1.65 +/** Catmull-rom spline interpolation */ 1.66 +scalar_t spline(scalar_t a, scalar_t b, scalar_t c, scalar_t d, scalar_t t) { 1.67 + vec4_t tmp; 1.68 + scalar_t tsq = t * t; 1.69 + 1.70 + static mat4_t crspline_mat = { 1.71 + {-1, 3, -3, 1}, 1.72 + {2, -5, 4, -1}, 1.73 + {-1, 0, 1, 0}, 1.74 + {0, 2, 0, 0} 1.75 + }; 1.76 + 1.77 + tmp = v4_scale(v4_transform(v4_cons(a, b, c, d), crspline_mat), 0.5); 1.78 + return v4_dot(v4_cons(tsq * t, tsq, t, 1.0), tmp); 1.79 +} 1.80 + 1.81 +/** Bezier interpolation */ 1.82 +scalar_t bezier(scalar_t a, scalar_t b, scalar_t c, scalar_t d, scalar_t t) 1.83 +{ 1.84 + scalar_t omt, omt3, t3, f; 1.85 + t3 = t * t * t; 1.86 + omt = 1.0f - t; 1.87 + omt3 = omt * omt * omt; 1.88 + f = 3 * t * omt; 1.89 + 1.90 + return (a * omt3) + (b * f * omt) + (c * f * t) + (d * t3); 1.91 +} 1.92 + 1.93 +/* ---- Ken Perlin's implementation of noise ---- */ 1.94 + 1.95 +#define B 0x100 1.96 +#define BM 0xff 1.97 +#define N 0x1000 1.98 +#define NP 12 /* 2^N */ 1.99 +#define NM 0xfff 1.100 + 1.101 +#define s_curve(t) (t * t * (3.0f - 2.0f * t)) 1.102 + 1.103 +#define setup(elem, b0, b1, r0, r1) \ 1.104 + do { \ 1.105 + scalar_t t = elem + N; \ 1.106 + b0 = ((int)t) & BM; \ 1.107 + b1 = (b0 + 1) & BM; \ 1.108 + r0 = t - (int)t; \ 1.109 + r1 = r0 - 1.0f; \ 1.110 + } while(0) 1.111 + 1.112 + 1.113 +static int perm[B + B + 2]; /* permuted index from g_n onto themselves */ 1.114 +static vec3_t grad3[B + B + 2]; /* 3D random gradients */ 1.115 +static vec2_t grad2[B + B + 2]; /* 2D random gradients */ 1.116 +static scalar_t grad1[B + B + 2]; /* 1D random ... slopes */ 1.117 +static int tables_valid; 1.118 + 1.119 +static void init_noise() 1.120 +{ 1.121 + int i; 1.122 + 1.123 + /* calculate random gradients */ 1.124 + for(i=0; i<B; i++) { 1.125 + perm[i] = i; /* .. and initialize permutation mapping to identity */ 1.126 + 1.127 + grad1[i] = (scalar_t)((rand() % (B + B)) - B) / B; 1.128 + 1.129 + grad2[i].x = (scalar_t)((rand() % (B + B)) - B) / B; 1.130 + grad2[i].y = (scalar_t)((rand() % (B + B)) - B) / B; 1.131 + grad2[i] = v2_normalize(grad2[i]); 1.132 + 1.133 + grad3[i].x = (scalar_t)((rand() % (B + B)) - B) / B; 1.134 + grad3[i].y = (scalar_t)((rand() % (B + B)) - B) / B; 1.135 + grad3[i].z = (scalar_t)((rand() % (B + B)) - B) / B; 1.136 + grad3[i] = v3_normalize(grad3[i]); 1.137 + } 1.138 + 1.139 + /* permute indices by swapping them randomly */ 1.140 + for(i=0; i<B; i++) { 1.141 + int rand_idx = rand() % B; 1.142 + 1.143 + int tmp = perm[i]; 1.144 + perm[i] = perm[rand_idx]; 1.145 + perm[rand_idx] = tmp; 1.146 + } 1.147 + 1.148 + /* fill up the rest of the arrays by duplicating the existing gradients */ 1.149 + /* and permutations */ 1.150 + for(i=0; i<B+2; i++) { 1.151 + perm[B + i] = perm[i]; 1.152 + grad1[B + i] = grad1[i]; 1.153 + grad2[B + i] = grad2[i]; 1.154 + grad3[B + i] = grad3[i]; 1.155 + } 1.156 +} 1.157 + 1.158 +scalar_t noise1(scalar_t x) 1.159 +{ 1.160 + int bx0, bx1; 1.161 + scalar_t rx0, rx1, sx, u, v; 1.162 + 1.163 + if(!tables_valid) { 1.164 + init_noise(); 1.165 + tables_valid = 1; 1.166 + } 1.167 + 1.168 + setup(x, bx0, bx1, rx0, rx1); 1.169 + sx = s_curve(rx0); 1.170 + u = rx0 * grad1[perm[bx0]]; 1.171 + v = rx1 * grad1[perm[bx1]]; 1.172 + 1.173 + return lerp(u, v, sx); 1.174 +} 1.175 + 1.176 +scalar_t noise2(scalar_t x, scalar_t y) 1.177 +{ 1.178 + int i, j, b00, b10, b01, b11; 1.179 + int bx0, bx1, by0, by1; 1.180 + scalar_t rx0, rx1, ry0, ry1; 1.181 + scalar_t sx, sy, u, v, a, b; 1.182 + 1.183 + if(!tables_valid) { 1.184 + init_noise(); 1.185 + tables_valid = 1; 1.186 + } 1.187 + 1.188 + setup(x, bx0, bx1, rx0, rx1); 1.189 + setup(y, by0, by1, ry0, ry1); 1.190 + 1.191 + i = perm[bx0]; 1.192 + j = perm[bx1]; 1.193 + 1.194 + b00 = perm[i + by0]; 1.195 + b10 = perm[j + by0]; 1.196 + b01 = perm[i + by1]; 1.197 + b11 = perm[j + by1]; 1.198 + 1.199 + /* calculate hermite inteprolating factors */ 1.200 + sx = s_curve(rx0); 1.201 + sy = s_curve(ry0); 1.202 + 1.203 + /* interpolate along the left edge */ 1.204 + u = v2_dot(grad2[b00], v2_cons(rx0, ry0)); 1.205 + v = v2_dot(grad2[b10], v2_cons(rx1, ry0)); 1.206 + a = lerp(u, v, sx); 1.207 + 1.208 + /* interpolate along the right edge */ 1.209 + u = v2_dot(grad2[b01], v2_cons(rx0, ry1)); 1.210 + v = v2_dot(grad2[b11], v2_cons(rx1, ry1)); 1.211 + b = lerp(u, v, sx); 1.212 + 1.213 + /* interpolate between them */ 1.214 + return lerp(a, b, sy); 1.215 +} 1.216 + 1.217 +scalar_t noise3(scalar_t x, scalar_t y, scalar_t z) 1.218 +{ 1.219 + int i, j; 1.220 + int bx0, bx1, by0, by1, bz0, bz1; 1.221 + int b00, b10, b01, b11; 1.222 + scalar_t rx0, rx1, ry0, ry1, rz0, rz1; 1.223 + scalar_t sx, sy, sz; 1.224 + scalar_t u, v, a, b, c, d; 1.225 + 1.226 + if(!tables_valid) { 1.227 + init_noise(); 1.228 + tables_valid = 1; 1.229 + } 1.230 + 1.231 + setup(x, bx0, bx1, rx0, rx1); 1.232 + setup(y, by0, by1, ry0, ry1); 1.233 + setup(z, bz0, bz1, rz0, rz1); 1.234 + 1.235 + i = perm[bx0]; 1.236 + j = perm[bx1]; 1.237 + 1.238 + b00 = perm[i + by0]; 1.239 + b10 = perm[j + by0]; 1.240 + b01 = perm[i + by1]; 1.241 + b11 = perm[j + by1]; 1.242 + 1.243 + /* calculate hermite interpolating factors */ 1.244 + sx = s_curve(rx0); 1.245 + sy = s_curve(ry0); 1.246 + sz = s_curve(rz0); 1.247 + 1.248 + /* interpolate along the top slice of the cell */ 1.249 + u = v3_dot(grad3[b00 + bz0], v3_cons(rx0, ry0, rz0)); 1.250 + v = v3_dot(grad3[b10 + bz0], v3_cons(rx1, ry0, rz0)); 1.251 + a = lerp(u, v, sx); 1.252 + 1.253 + u = v3_dot(grad3[b01 + bz0], v3_cons(rx0, ry1, rz0)); 1.254 + v = v3_dot(grad3[b11 + bz0], v3_cons(rx1, ry1, rz0)); 1.255 + b = lerp(u, v, sx); 1.256 + 1.257 + c = lerp(a, b, sy); 1.258 + 1.259 + /* interpolate along the bottom slice of the cell */ 1.260 + u = v3_dot(grad3[b00 + bz0], v3_cons(rx0, ry0, rz1)); 1.261 + v = v3_dot(grad3[b10 + bz0], v3_cons(rx1, ry0, rz1)); 1.262 + a = lerp(u, v, sx); 1.263 + 1.264 + u = v3_dot(grad3[b01 + bz0], v3_cons(rx0, ry1, rz1)); 1.265 + v = v3_dot(grad3[b11 + bz0], v3_cons(rx1, ry1, rz1)); 1.266 + b = lerp(u, v, sx); 1.267 + 1.268 + d = lerp(a, b, sy); 1.269 + 1.270 + /* interpolate between slices */ 1.271 + return lerp(c, d, sz); 1.272 +} 1.273 + 1.274 +scalar_t fbm1(scalar_t x, int octaves) 1.275 +{ 1.276 + int i; 1.277 + scalar_t res = 0.0f, freq = 1.0f; 1.278 + for(i=0; i<octaves; i++) { 1.279 + res += noise1(x * freq) / freq; 1.280 + freq *= 2.0f; 1.281 + } 1.282 + return res; 1.283 +} 1.284 + 1.285 +scalar_t fbm2(scalar_t x, scalar_t y, int octaves) 1.286 +{ 1.287 + int i; 1.288 + scalar_t res = 0.0f, freq = 1.0f; 1.289 + for(i=0; i<octaves; i++) { 1.290 + res += noise2(x * freq, y * freq) / freq; 1.291 + freq *= 2.0f; 1.292 + } 1.293 + return res; 1.294 +} 1.295 + 1.296 +scalar_t fbm3(scalar_t x, scalar_t y, scalar_t z, int octaves) 1.297 +{ 1.298 + int i; 1.299 + scalar_t res = 0.0f, freq = 1.0f; 1.300 + for(i=0; i<octaves; i++) { 1.301 + res += noise3(x * freq, y * freq, z * freq) / freq; 1.302 + freq *= 2.0f; 1.303 + } 1.304 + return res; 1.305 +} 1.306 + 1.307 +scalar_t turbulence1(scalar_t x, int octaves) 1.308 +{ 1.309 + int i; 1.310 + scalar_t res = 0.0f, freq = 1.0f; 1.311 + for(i=0; i<octaves; i++) { 1.312 + res += fabs(noise1(x * freq) / freq); 1.313 + freq *= 2.0f; 1.314 + } 1.315 + return res; 1.316 +} 1.317 + 1.318 +scalar_t turbulence2(scalar_t x, scalar_t y, int octaves) 1.319 +{ 1.320 + int i; 1.321 + scalar_t res = 0.0f, freq = 1.0f; 1.322 + for(i=0; i<octaves; i++) { 1.323 + res += fabs(noise2(x * freq, y * freq) / freq); 1.324 + freq *= 2.0f; 1.325 + } 1.326 + return res; 1.327 +} 1.328 + 1.329 +scalar_t turbulence3(scalar_t x, scalar_t y, scalar_t z, int octaves) 1.330 +{ 1.331 + int i; 1.332 + scalar_t res = 0.0f, freq = 1.0f; 1.333 + for(i=0; i<octaves; i++) { 1.334 + res += fabs(noise3(x * freq, y * freq, z * freq) / freq); 1.335 + freq *= 2.0f; 1.336 + } 1.337 + return res; 1.338 +}