00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051 #ifndef lint
00052 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/libbn/noise.c,v 14.12 2006/09/04 04:42:40 lbutler Exp $ (ARL)";
00053 #endif
00054
00055 #include "common.h"
00056
00057
00058
00059 #include <stdio.h>
00060 #include <stdlib.h>
00061 #include <math.h>
00062 #include "machine.h"
00063 #include "bu.h"
00064 #include "vmath.h"
00065 #include "bn.h"
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075 #define SMOOTHSTEP(x) ( (x) * (x) * (3 - 2*(x)) )
00076
00077
00078
00079
00080 #define FLOOR(x) ( (int)(x) - ( (x) < 0 && (x) != (int)(x) ) )
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095 static void
00096 filter_args(fastf_t *src, fastf_t *p, fastf_t *f, int *ip)
00097 {
00098 register int i;
00099 point_t dst;
00100 static unsigned long max2x = ~((unsigned long)0);
00101 static unsigned long max = (~((unsigned long)0)) >> 1;
00102
00103 for (i=0 ; i < 3 ; i++) {
00104
00105 if (src[i] < 0) dst[i] = -src[i];
00106 else dst[i] = src[i];
00107
00108
00109
00110 while (dst[i] > max || dst[i]<0) {
00111 if (dst[i] > max) {
00112 dst[i] = max2x - dst[i];
00113 } else {
00114 dst[i] = -dst[i];
00115 }
00116 }
00117
00118 }
00119
00120 p[X] = dst[0]; ip[X] = FLOOR(p[X]); f[X] = p[X] - ip[X];
00121 p[Y] = dst[1]; ip[Y] = FLOOR(p[Y]); f[Y] = p[Y] - ip[Y];
00122 p[Z] = dst[2]; ip[Z] = FLOOR(p[Z]); f[Z] = p[Z] - ip[Z];
00123 }
00124
00125
00126 #define MAXSIZE 267
00127
00128
00129
00130
00131 static double RTable[MAXSIZE];
00132
00133 #define INCRSUM(m,s,x,y,z) ((s)*(RTable[m]*0.5 \
00134 + RTable[m+1]*(x) \
00135 + RTable[m+2]*(y) \
00136 + RTable[m+3]*(z)))
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146 struct str_ht {
00147 long magic;
00148 char hashTableValid;
00149 long *hashTableMagic1;
00150 short *hashTable;
00151 long *hashTableMagic2;
00152 long magic_end;
00153 };
00154
00155 static struct str_ht ht;
00156
00157 #define MAGIC_STRHT1 1771561
00158 #define MAGIC_STRHT2 1651771
00159 #define MAGIC_TAB1 9823
00160 #define MAGIC_TAB2 784642
00161 #define CK_HT() { \
00162 BU_CKMAG(&ht.magic, MAGIC_STRHT1, "struct str_ht ht 1"); \
00163 BU_CKMAG(&ht.magic_end, MAGIC_STRHT2, "struct str_ht ht 2"); \
00164 BU_CKMAG(ht.hashTableMagic1, MAGIC_TAB1, "hashTable Magic 1"); \
00165 BU_CKMAG(ht.hashTableMagic2, MAGIC_TAB2, "hashTable Magic 2"); \
00166 if (ht.hashTable != (short *)&ht.hashTableMagic1[1] ) \
00167 bu_bomb("ht.hashTable changed rel ht.hashTableMagic1"); \
00168 if (ht.hashTableMagic2 != (long *)&ht.hashTable[4096] ) \
00169 bu_bomb("ht.hashTable changed rel ht.hashTableMagic2"); \
00170 }
00171
00172
00173
00174
00175
00176
00177
00178 #define Hash3d(a,b,c) \
00179 ht.hashTable[ \
00180 ht.hashTable[ \
00181 ht.hashTable[(a) & 0xfff] ^ ((b) & 0xfff) \
00182 ] ^ ((c) & 0xfff) \
00183 ]
00184
00185
00186 void
00187 bn_noise_init(void)
00188 {
00189 int i, j, k, temp;
00190 int rndtabi = BN_RAND_TABSIZE - 1;
00191
00192 bu_semaphore_acquire( BU_SEM_BN_NOISE );
00193
00194 if (ht.hashTableValid) {
00195 bu_semaphore_release( BU_SEM_BN_NOISE );
00196 return;
00197 }
00198
00199 BN_RANDSEED(rndtabi, (BN_RAND_TABSIZE-1) );
00200 ht.hashTableMagic1 = (long *) bu_malloc(
00201 2*sizeof(long) + 4096*sizeof(short int),
00202 "noise hashTable");
00203 ht.hashTable = (short *)&ht.hashTableMagic1[1];
00204 ht.hashTableMagic2 = (long *)&ht.hashTable[4096];
00205
00206 *ht.hashTableMagic1 = MAGIC_TAB1;
00207 *ht.hashTableMagic2 = MAGIC_TAB2;
00208
00209 ht.magic_end = MAGIC_STRHT2;
00210 ht.magic = MAGIC_STRHT1;
00211
00212 for (i = 0; i < 4096; i++)
00213 ht.hashTable[i] = i;
00214
00215
00216 for (i = 4095; i > 0; i--) {
00217 j = (int)(BN_RANDOM(rndtabi) * 4096.0);
00218
00219 temp = ht.hashTable[i];
00220 ht.hashTable[i] = ht.hashTable[j];
00221 ht.hashTable[j] = temp;
00222 }
00223
00224 BN_RANDSEED(k, 13);
00225
00226 for (i = 0; i < MAXSIZE; i++)
00227 RTable[i] = BN_RANDOM(k) * 2.0 - 1.0;
00228
00229
00230 ht.hashTableValid = 1;
00231
00232 bu_semaphore_release( BU_SEM_BN_NOISE );
00233
00234
00235 CK_HT();
00236 }
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252 double
00253 bn_noise_perlin(fastf_t *point)
00254 {
00255 register int jx, jy, jz;
00256 int ix, iy, iz;
00257 double x, y, z;
00258 double fx, fy, fz;
00259 double sx, sy, sz, tx, ty, tz;
00260 double sum;
00261 short m;
00262 point_t p, f;
00263 int ip[3];
00264
00265 if (!ht.hashTableValid) bn_noise_init();
00266 else {
00267
00268 }
00269
00270
00271
00272 filter_args( point, p, f, ip);
00273 ix = ip[X];
00274 iy = ip[Y];
00275 iz = ip[Z];
00276
00277 fx = f[X];
00278 fy = f[Y];
00279 fz = f[Z];
00280
00281 x = p[X];
00282 y = p[Y];
00283 z = p[Z];
00284
00285 jx = ix + 1;
00286 jy = iy + 1;
00287 jz = iz + 1;
00288
00289 sx = SMOOTHSTEP(fx);
00290 sy = SMOOTHSTEP(fy);
00291 sz = SMOOTHSTEP(fz);
00292
00293
00294 tx = 1.0 - sx;
00295 ty = 1.0 - sy;
00296 tz = 1.0 - sz;
00297
00298
00299
00300
00301
00302 m = Hash3d( ix, iy, iz ) & 0xFF;
00303 sum = INCRSUM(m,(tx*ty*tz),(x-ix),(y-iy),(z-iz));
00304
00305 m = Hash3d( jx, iy, iz ) & 0xFF;
00306 sum += INCRSUM(m,(sx*ty*tz),(x-jx),(y-iy),(z-iz));
00307
00308 m = Hash3d( ix, jy, iz ) & 0xFF;
00309 sum += INCRSUM(m,(tx*sy*tz),(x-ix),(y-jy),(z-iz));
00310
00311 m = Hash3d( jx, jy, iz ) & 0xFF;
00312 sum += INCRSUM(m,(sx*sy*tz),(x-jx),(y-jy),(z-iz));
00313
00314 m = Hash3d( ix, iy, jz ) & 0xFF;
00315 sum += INCRSUM(m,(tx*ty*sz),(x-ix),(y-iy),(z-jz));
00316
00317 m = Hash3d( jx, iy, jz ) & 0xFF;
00318 sum += INCRSUM(m,(sx*ty*sz),(x-jx),(y-iy),(z-jz));
00319
00320 m = Hash3d( ix, jy, jz ) & 0xFF;
00321 sum += INCRSUM(m,(tx*sy*sz),(x-ix),(y-jy),(z-jz));
00322
00323 m = Hash3d( jx, jy, jz ) & 0xFF;
00324 sum += INCRSUM(m,(sx*sy*sz),(x-jx),(y-jy),(z-jz));
00325
00326 return sum;
00327
00328 }
00329
00330
00331
00332
00333 void
00334 bn_noise_vec(fastf_t *point, fastf_t *result)
00335 {
00336 register int jx, jy, jz;
00337 int ix, iy, iz;
00338 double x, y, z;
00339 double px, py, pz, s;
00340 double sx, sy, sz, tx, ty, tz;
00341 short m;
00342 point_t p, f;
00343 int ip[3];
00344
00345
00346 if ( ! ht.hashTableValid ) bn_noise_init();
00347
00348
00349
00350
00351
00352
00353
00354 filter_args( point, p, f, ip);
00355 ix = ip[X];
00356 iy = ip[Y];
00357 iz = ip[Z];
00358
00359 x = p[X];
00360 y = p[Y];
00361 z = p[Z];
00362
00363 jx = ix+1; jy = iy + 1; jz = iz + 1;
00364
00365 sx = SMOOTHSTEP(x - ix);
00366 sy = SMOOTHSTEP(y - iy);
00367 sz = SMOOTHSTEP(z - iz);
00368
00369
00370 tx = 1.0 - sx;
00371 ty = 1.0 - sy;
00372 tz = 1.0 - sz;
00373
00374
00375
00376
00377 m = Hash3d( ix, iy, iz ) & 0xFF;
00378 px = x-ix;
00379 py = y-iy;
00380 pz = z-iz;
00381 s = tx*ty*tz;
00382 result[0] = INCRSUM(m,s,px,py,pz);
00383 result[1] = INCRSUM(m+4,s,px,py,pz);
00384 result[2] = INCRSUM(m+8,s,px,py,pz);
00385
00386 m = Hash3d( jx, iy, iz ) & 0xFF;
00387 px = x-jx;
00388 s = sx*ty*tz;
00389 result[0] += INCRSUM(m,s,px,py,pz);
00390 result[1] += INCRSUM(m+4,s,px,py,pz);
00391 result[2] += INCRSUM(m+8,s,px,py,pz);
00392
00393 m = Hash3d( jx, jy, iz ) & 0xFF;
00394 py = y-jy;
00395 s = sx*sy*tz;
00396 result[0] += INCRSUM(m,s,px,py,pz);
00397 result[1] += INCRSUM(m+4,s,px,py,pz);
00398 result[2] += INCRSUM(m+8,s,px,py,pz);
00399
00400 m = Hash3d( ix, jy, iz ) & 0xFF;
00401 px = x-ix;
00402 s = tx*sy*tz;
00403 result[0] += INCRSUM(m,s,px,py,pz);
00404 result[1] += INCRSUM(m+4,s,px,py,pz);
00405 result[2] += INCRSUM(m+8,s,px,py,pz);
00406
00407 m = Hash3d( ix, jy, jz ) & 0xFF;
00408 pz = z-jz;
00409 s = tx*sy*sz;
00410 result[0] += INCRSUM(m,s,px,py,pz);
00411 result[1] += INCRSUM(m+4,s,px,py,pz);
00412 result[2] += INCRSUM(m+8,s,px,py,pz);
00413
00414 m = Hash3d( jx, jy, jz ) & 0xFF;
00415 px = x-jx;
00416 s = sx*sy*sz;
00417 result[0] += INCRSUM(m,s,px,py,pz);
00418 result[1] += INCRSUM(m+4,s,px,py,pz);
00419 result[2] += INCRSUM(m+8,s,px,py,pz);
00420
00421 m = Hash3d( jx, iy, jz ) & 0xFF;
00422 py = y-iy;
00423 s = sx*ty*sz;
00424 result[0] += INCRSUM(m,s,px,py,pz);
00425 result[1] += INCRSUM(m+4,s,px,py,pz);
00426 result[2] += INCRSUM(m+8,s,px,py,pz);
00427
00428 m = Hash3d( ix, iy, jz ) & 0xFF;
00429 px = x-ix;
00430 s = tx*ty*sz;
00431 result[0] += INCRSUM(m,s,px,py,pz);
00432 result[1] += INCRSUM(m+4,s,px,py,pz);
00433 result[2] += INCRSUM(m+8,s,px,py,pz);
00434 }
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450 struct fbm_spec {
00451 long magic;
00452 double octaves;
00453 double lacunarity;
00454 double h_val;
00455 double remainder;
00456 double *spec_wgts;
00457 };
00458 #define MAGIC_fbm_spec_wgt 0x837592
00459
00460 static struct fbm_spec *etbl = (struct fbm_spec *)NULL;
00461 static int etbl_next = 0;
00462 static int etbl_size = 0;
00463
00464 #define PSCALE(_p, _s) _p[0] *= _s; _p[1] *= _s; _p[2] *= _s
00465 #define PCOPY(_d, _s) _d[0] = _s[0]; _d[1] = _s[1]; _d[2] = _s[2]
00466
00467
00468
00469 static struct fbm_spec *
00470 build_spec_tbl(double h_val, double lacunarity, double octaves)
00471 {
00472 struct fbm_spec *ep;
00473 double *spec_wgts;
00474 double frequency;
00475 int i;
00476
00477
00478
00479
00480
00481
00482
00483 if (etbl_next >= etbl_size) {
00484 if (etbl_size) {
00485 etbl_size *= 2;
00486 etbl = (struct fbm_spec *)bu_realloc((char *)etbl,
00487 etbl_size*sizeof(struct fbm_spec),
00488 "spectral weights table");
00489 } else
00490 etbl = (struct fbm_spec *)bu_calloc(etbl_size = 10,
00491 sizeof(struct fbm_spec),
00492 "spectral weights table");
00493
00494 if (!etbl) abort();
00495 }
00496
00497
00498 ep = &etbl[etbl_next];
00499 ep->magic = MAGIC_fbm_spec_wgt; ep->octaves = octaves;
00500 ep->h_val = h_val; ep->lacunarity = lacunarity;
00501 spec_wgts = ep->spec_wgts =
00502 (double *)bu_malloc( ((int)(octaves+1)) * sizeof(double),
00503 "spectral weights" );
00504
00505
00506 for (frequency = 1.0, i=0 ; i < octaves ; i++) {
00507
00508 spec_wgts[i] = pow(frequency, -h_val);
00509 frequency *= lacunarity;
00510 }
00511
00512 etbl_next++;
00513 return ep;
00514 }
00515
00516
00517
00518
00519
00520
00521
00522
00523 struct fbm_spec *
00524 find_spec_wgt(double h, double l, double o)
00525 {
00526 struct fbm_spec *ep;
00527 int i;
00528
00529
00530 for (ep = etbl, i=0 ; i < etbl_next ; i++, ep++) {
00531 if (ep->magic != MAGIC_fbm_spec_wgt) bu_bomb("find_spec_wgt");
00532 if (ep->lacunarity == l && ep->h_val == h &&
00533 ep->octaves >= o )
00534 return ep;
00535 }
00536
00537
00538
00539
00540
00541 bu_semaphore_acquire( BU_SEM_BN_NOISE );
00542
00543
00544
00545
00546 for (ep = etbl, i=0 ; i < etbl_next ; i++, ep++) {
00547 if (ep->magic != MAGIC_fbm_spec_wgt) bu_bomb("find_spec_wgt");
00548 if (ep->lacunarity == l && ep->h_val == h &&
00549 ep->octaves >= o )
00550 break;
00551 }
00552
00553 if (i >= etbl_next) ep = build_spec_tbl(h, l, o);
00554
00555 bu_semaphore_release( BU_SEM_BN_NOISE );
00556
00557 return (ep);
00558 }
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584 double
00585 bn_noise_fbm(fastf_t *point, double h_val, double lacunarity, double octaves)
00586 {
00587 struct fbm_spec *ep;
00588 double value, remainder, *spec_wgts;
00589 point_t pt;
00590 int i, oct;
00591
00592
00593
00594
00595
00596
00597
00598 ep = find_spec_wgt(h_val, lacunarity, octaves);
00599
00600
00601
00602 value = 0.0;
00603
00604 PCOPY(pt, point);
00605
00606 spec_wgts = ep->spec_wgts;
00607
00608
00609 oct=(int)octaves;
00610 for (i=0 ; i < oct ; i++) {
00611 value += bn_noise_perlin( pt ) * spec_wgts[i];
00612 PSCALE(pt, lacunarity);
00613 }
00614
00615 remainder = octaves - (int)octaves;
00616 if ( remainder ) {
00617
00618
00619
00620 value += remainder * bn_noise_perlin( pt ) * spec_wgts[i];
00621 }
00622
00623 return( value );
00624
00625 }
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654 double
00655 bn_noise_turb(fastf_t *point, double h_val, double lacunarity, double octaves)
00656 {
00657 struct fbm_spec *ep;
00658 double value, remainder, *spec_wgts;
00659 point_t pt;
00660 int i, oct;
00661
00662
00663
00664
00665
00666
00667
00668
00669 #define CACHE_SPECTRAL_WGTS 1
00670 #ifdef CACHE_SPECTRAL_WGTS
00671
00672 ep = find_spec_wgt(h_val, lacunarity, octaves);
00673
00674
00675
00676 value = 0.0;
00677
00678
00679
00680
00681 PCOPY(pt, point);
00682 spec_wgts = ep->spec_wgts;
00683
00684
00685 oct=(int)octaves;
00686 for (i=0 ; i < oct ; i++) {
00687 value += fabs(bn_noise_perlin( pt )) * spec_wgts[i];
00688 PSCALE(pt, lacunarity);
00689 }
00690
00691 remainder = octaves - (int)octaves;
00692 if ( remainder ) {
00693
00694
00695
00696 value += remainder * bn_noise_perlin( pt ) * spec_wgts[i];
00697 }
00698 #else
00699 PCOPY(pt, point);
00700
00701 value = 0.0;
00702 frequency = 1.0;
00703
00704 oct=(int)octaves;
00705 for (i=0 ; i < oct ; i++) {
00706 value += fabs(bn_noise_perlin( pt )) * pow(frequency, -h_val);
00707 frequency *= lacunarity;
00708 PSCALE(pt, lacunarity);
00709 }
00710
00711 remainder = octaves - (int)octaves;
00712 if ( remainder ) {
00713
00714
00715
00716 value += remainder * bn_noise_perlin( pt ) * pow(frequency, -h_val);
00717 }
00718 #endif
00719 return( value );
00720
00721 }
00722
00723
00724
00725
00726
00727
00728
00729 double
00730 bn_noise_ridged(fastf_t *point, double h_val, double lacunarity, double octaves, double offset)
00731 {
00732 struct fbm_spec *ep;
00733 double result, weight, signal, *spec_wgts;
00734 point_t pt;
00735 int i;
00736
00737
00738
00739
00740
00741
00742
00743 ep = find_spec_wgt(h_val, lacunarity, octaves);
00744
00745
00746
00747
00748 PCOPY(pt, point);
00749 spec_wgts = ep->spec_wgts;
00750
00751
00752
00753 signal = bn_noise_perlin(pt);
00754
00755
00756 if (signal < 0.0) signal = -signal;
00757
00758
00759 signal = offset - signal;
00760
00761
00762 signal *= signal;
00763
00764
00765 result = signal;
00766 weight = 1.0;
00767
00768 for (i=1 ; i < octaves ; i++ ) {
00769 PSCALE(pt, lacunarity);
00770
00771 signal = bn_noise_perlin(pt);
00772
00773 if (signal < 0.0) signal = - signal;
00774 signal = offset - signal;
00775
00776
00777 signal *= weight;
00778 result += signal * spec_wgts[i];
00779 }
00780 return result;
00781 }
00782
00783
00784
00785
00786
00787
00788 double
00789 bn_noise_mf(fastf_t *point, double h_val, double lacunarity, double octaves, double offset)
00790 {
00791 double frequency = 1.0;
00792 struct fbm_spec *ep;
00793 double result, weight, signal, *spec_wgts;
00794 point_t pt;
00795 int i;
00796
00797
00798
00799
00800
00801
00802
00803 ep = find_spec_wgt( h_val, lacunarity, octaves );
00804
00805
00806
00807
00808 PCOPY( pt, point );
00809 spec_wgts = ep->spec_wgts;
00810 offset = 1.0;
00811
00812 result = (bn_noise_perlin(pt) + offset) * spec_wgts[0];
00813 weight = result;
00814
00815 for (i=1 ; i < octaves ; i++) {
00816 PSCALE(pt, lacunarity);
00817
00818 if (weight > 1.0) weight = 1.0;
00819
00820 signal = ( bn_noise_perlin(pt) + offset ) * spec_wgts[i];
00821
00822 signal += fabs(bn_noise_perlin( pt )) * pow(frequency, -h_val);
00823 frequency *= lacunarity;
00824 PSCALE(pt, lacunarity);
00825 }
00826 return result;
00827 }
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838