1 /**
2  * @file
3  * @brief Procedurally generated dungeon layouts.
4  **/
5 #include "AppHdr.h"
6 
7 #include "dgn-proclayouts.h"
8 
9 #include <cmath>
10 
11 #include "coord.h"
12 #include "coordit.h"
13 #include "files.h"
14 #include "perlin.h"
15 #include "tag-version.h"
16 #include "terrain.h"
17 
_pick_pseudorandom_wall(uint64_t val)18 static dungeon_feature_type _pick_pseudorandom_wall(uint64_t val)
19 {
20     static dungeon_feature_type features[] =
21     {
22         DNGN_STONE_WALL,
23         DNGN_STONE_WALL,
24         DNGN_STONE_WALL,
25         DNGN_STONE_WALL,
26         DNGN_ROCK_WALL,
27         DNGN_ROCK_WALL,
28         DNGN_ROCK_WALL,
29         DNGN_CRYSTAL_WALL,
30         DNGN_METAL_WALL
31     };
32     return features[val%9];
33 }
34 
35 ProceduralSample
operator ()(const coord_def & p,const uint32_t offset) const36 ColumnLayout::operator()(const coord_def &p, const uint32_t offset) const
37 {
38     int x = abs(p.x) % (_col_width + _col_space);
39     int y = abs(p.y) % (_row_width + _row_space);
40     if (x < _col_width && y < _row_width)
41     {
42         int w = _col_width + _col_space;
43         dungeon_feature_type feat = _pick_pseudorandom_wall(hash3(p.x/w, p.y/w, 2));
44         return ProceduralSample(p, feat, offset + 4096);
45     }
46     return ProceduralSample(p, DNGN_FLOOR, offset + 4096);
47 }
48 
49 ProceduralSample
operator ()(const coord_def & p,const uint32_t offset) const50 DiamondLayout::operator()(const coord_def &p, const uint32_t offset) const
51 {
52     uint8_t halfCell = w + s;
53     uint8_t cellSize = halfCell * 2;
54     uint8_t x = abs(abs(p.x) % cellSize - halfCell);
55     uint8_t y = abs(abs(p.y) % cellSize - halfCell);
56     if (x+y < w)
57     {
58         dungeon_feature_type feat = _pick_pseudorandom_wall(hash3(p.x/w, p.y/w, 2));
59         return ProceduralSample(p, feat, offset + 4096);
60     }
61     return ProceduralSample(p, DNGN_FLOOR, offset + 4096);
62 }
63 
_get_changepoint(const worley::noise_datum & n,const double scale)64 static uint32_t _get_changepoint(const worley::noise_datum &n, const double scale)
65 {
66     return max(1, (int) floor((n.distance[1] - n.distance[0]) * scale) - 5);
67 }
68 
69 ProceduralSample
operator ()(const coord_def & p,const uint32_t offset) const70 WorleyLayout::operator()(const coord_def &p, const uint32_t offset) const
71 {
72     const double offset_scale = 5000.0;
73     double x = p.x / scale;
74     double y = p.y / scale;
75     double z = offset / offset_scale;
76     worley::noise_datum n = worley::noise(x, y, z + seed);
77 
78     const uint32_t changepoint = offset + _get_changepoint(n, offset_scale);
79     const uint8_t size = layouts.size();
80     bool parity = n.id[0] % 4;
81     uint32_t id = n.id[0] / 4;
82     const uint8_t choice = parity
83         ? id % size
84         : min(id % size, (id / size) % size);
85     const coord_def pd = p + id;
86     ProceduralSample sample = (*layouts[(choice + seed) % size])(pd, offset);
87 
88     return ProceduralSample(p, sample.feat(),
89                 min(changepoint, sample.changepoint()));
90 }
91 
92 ProceduralSample
operator ()(const coord_def & p,const uint32_t offset) const93 ChaosLayout::operator()(const coord_def &p, const uint32_t offset) const
94 {
95     uint64_t base = hash3(p.x, p.y, seed);
96     uint32_t density = baseDensity + seed % 50 + (seed >> 16) % 60;
97     if ((base % 1000) < density)
98         return ProceduralSample(p, _pick_pseudorandom_wall(base/3), offset + 4096);
99     return ProceduralSample(p, DNGN_FLOOR, offset + 4096);
100 }
101 
102 ProceduralSample
operator ()(const coord_def & p,const uint32_t offset) const103 RoilingChaosLayout::operator()(const coord_def &p, const uint32_t offset) const
104 {
105     const double scale = (density - 350) + 4800;
106     double x = p.x;
107     double y = p.y;
108     double z = offset / scale;
109     worley::noise_datum n = worley::noise(x, y, z);
110     const uint32_t changepoint = offset + _get_changepoint(n, scale);
111     ProceduralSample sample = ChaosLayout(n.id[0] + seed, density)(p, offset);
112     return ProceduralSample(p, sample.feat(), min(sample.changepoint(), changepoint));
113 }
114 
115 ProceduralSample
operator ()(const coord_def & p,const uint32_t offset) const116 WastesLayout::operator()(const coord_def &p, const uint32_t offset) const
117 {
118     double x = p.x;
119     double y = p.y;
120     double z = offset / 3;
121     worley::noise_datum n = worley::noise(x, y, z);
122     const uint32_t changepoint = offset + _get_changepoint(n, 3);
123     ProceduralSample sample = ChaosLayout(n.id[0], 10)(p, offset);
124     dungeon_feature_type feat = feat_is_solid(sample.feat())
125         ? DNGN_ROCK_WALL : DNGN_FLOOR;
126     return ProceduralSample(p, feat, min(sample.changepoint(), changepoint));
127 }
128 
129 ProceduralSample
operator ()(const coord_def & p,const uint32_t offset) const130 RiverLayout::operator()(const coord_def &p, const uint32_t offset) const
131 {
132     const double scale = 10000;
133     const double scalar = 90.0;
134     double x = (p.x + perlin::fBM(p.x/4.0, p.y/4.0, seed, 5) * 3) / scalar;
135     double y = (p.y + perlin::fBM(p.x/4.0 + 3.7, p.y/4.0 + 1.9, seed + 4, 5) * 3) / scalar;
136     worley::noise_datum n = worley::noise(x, y, offset / scale + seed);
137     const uint32_t changepoint = offset + _get_changepoint(n, scale);
138     if ((n.id[0] ^ n.id[1] ^ seed) % 4)
139         return layout(p, offset);
140 
141     double delta = n.distance[1] - n.distance[0];
142     if (delta < 1.5/scalar)
143     {
144         dungeon_feature_type feat = DNGN_SHALLOW_WATER;
145         uint64_t hash = hash3(p.x, p.y, n.id[0] + seed);
146         if (!(hash % 5))
147             feat = DNGN_DEEP_WATER;
148         if (!(hash % 23))
149             feat = DNGN_TREE;
150         return ProceduralSample(p, feat, changepoint);
151     }
152     return layout(p, offset);
153 }
154 
155 ProceduralSample
operator ()(const coord_def & p,const uint32_t offset) const156 NewAbyssLayout::operator()(const coord_def &p, const uint32_t offset) const
157 {
158     const double scale = 1.0 / 3.2;
159     uint64_t base = hash3(p.x, p.y, seed);
160     worley::noise_datum noise = worley::noise(
161             p.x * scale,
162             p.y * scale,
163             offset / 1000.0);
164     dungeon_feature_type feat = DNGN_FLOOR;
165 
166     int dist = noise.distance[0] * 100;
167     bool isWall = (dist > 118 || dist < 30);
168     int delta = min(abs(dist - 118), abs(30 - dist));
169 
170     if ((noise.id[0] + noise.id[1]) % 6 == 0)
171         isWall = false;
172 
173     if (base % 3 == 0)
174         isWall = !isWall;
175 
176     if (isWall)
177     {
178         int fuzz = (base / 3) % 3 ? 0 : (base / 9) % 3 - 1;
179         feat = _pick_pseudorandom_wall(noise.id[0] + fuzz);
180     }
181 
182     return ProceduralSample(p, feat, offset + delta);
183 }
184 
sanitize_feature(dungeon_feature_type feature,bool strict)185 dungeon_feature_type sanitize_feature(dungeon_feature_type feature, bool strict)
186 {
187     if (feat_is_gate(feature)
188 #if TAG_MAJOR_VERSION == 34
189         || feature == DNGN_TELEPORTER
190 #endif
191         || feature == DNGN_TRANSPORTER
192         || feature == DNGN_TRANSPORTER_LANDING)
193     {
194         return DNGN_STONE_ARCH;
195     }
196     if (feat_is_stair(feature) || feat_is_sealed(feature))
197         return strict ? DNGN_FLOOR : DNGN_STONE_ARCH;
198     if (feat_is_altar(feature) || feat_is_trap(feature))
199         return DNGN_FLOOR;
200 
201     switch (feature)
202     {
203         case DNGN_SEALED_DOOR:
204             return DNGN_CLOSED_DOOR;
205         case DNGN_SEALED_CLEAR_DOOR:
206             return DNGN_CLOSED_CLEAR_DOOR;
207         case DNGN_PERMAROCK_WALL:
208             return DNGN_ROCK_WALL;
209         case DNGN_CLEAR_PERMAROCK_WALL:
210             return DNGN_CLEAR_ROCK_WALL;
211         case DNGN_SLIMY_WALL:
212             return DNGN_CRYSTAL_WALL; // !?
213         case DNGN_UNSEEN:
214         case DNGN_ENDLESS_SALT:
215             return DNGN_FLOOR;
216         case DNGN_OPEN_SEA:
217             return DNGN_DEEP_WATER;
218         case DNGN_LAVA_SEA:
219             return DNGN_LAVA;
220         case DNGN_ENTER_SHOP:
221             return DNGN_ABANDONED_SHOP;
222         default:
223             return feature;
224     }
225 }
226 
LevelLayout(level_id id,uint32_t _seed,const ProceduralLayout & _layout)227 LevelLayout::LevelLayout(level_id id, uint32_t _seed, const ProceduralLayout &_layout) : seed(_seed), layout(_layout)
228 {
229     if (!is_existing_level(id))
230     {
231         for (rectangle_iterator ri(0); ri; ++ri)
232             grid(*ri) = DNGN_UNSEEN;
233         return;
234     }
235     level_excursion le;
236     le.go_to(id);
237     grid = feature_grid(env.grid);
238     for (rectangle_iterator ri(0); ri; ++ri)
239     {
240         grid(*ri) = sanitize_feature(grid(*ri), true);
241         if (!in_bounds(*ri))
242         {
243             grid(*ri) = DNGN_UNSEEN;
244             continue;
245         }
246 
247         uint32_t solid_count = 0;
248         for (adjacent_iterator ai(*ri); ai; ++ai)
249             solid_count += cell_is_solid(*ai);
250         coord_def p = *ri;
251         uint64_t base = hash3(p.x, p.y, seed);
252         int div = base % 2 ? 12 : 11;
253         switch (solid_count)
254         {
255             case 8:
256                 grid(*ri) = DNGN_UNSEEN;
257                 break;
258             case 7:
259             case 6:
260             case 5:
261                 if (!((base / 2) % div))
262                     grid(*ri) = DNGN_UNSEEN;
263                 break;
264             case 0:
265             case 1:
266                 if (!(base % 14))
267                     grid(*ri) = DNGN_UNSEEN;
268                 break;
269         }
270     }
271 }
272 
273 ProceduralSample
operator ()(const coord_def & p,const uint32_t offset) const274 LevelLayout::operator()(const coord_def &p, const uint32_t offset) const
275 {
276     coord_def cp = clip(p);
277     dungeon_feature_type feat = grid(cp);
278     if (feat == DNGN_UNSEEN)
279         return layout(p, offset);
280     return ProceduralSample(p, feat, offset + 4096);
281 }
282 
283 ProceduralSample
operator ()(const coord_def & p,const uint32_t offset) const284 NoiseLayout::operator()(const coord_def &p, const uint32_t offset) const
285 {
286     return ProceduralSample(p, DNGN_FLOOR, offset + 4096);
287 }
288 
289 ProceduralSample
operator ()(const coord_def & p,const uint32_t offset) const290 ForestLayout::operator()(const coord_def &p, const uint32_t offset) const
291 {
292     dungeon_feature_type feat = DNGN_FLOOR;
293 
294     const static WorleyFunction base(0.32,0.4,0.5,0,0,0);
295     const static WorleyFunction offx(0.6,0.6,0.2,854.3,123.4,0.0);
296     const static WorleyFunction offy(0.6,0.6,0.2,123.2,3623.51,0.0);
297     const static WorleyDistortFunction tfunc(base,offx,2.0,offy,1.5);
298 
299     worley::noise_datum fn = tfunc.datum(p.x,p.y,offset);
300 
301     // Split the id into some 8-bit numbers to use for randomness
302     uint8_t rand[2] = { (uint8_t)(fn.id[0] >> 24), (uint8_t)(fn.id[0] >> 16) };
303         // , fn.id[0] >> 8 & 0x000000ff, fn.id[0] & 0x000000ff };
304 
305     double diff = fn.distance[1]-fn.distance[0];
306     float size_factor = (float)rand[1]/(255.0 * 2.0) + 0.15;
307     // 75% chance of trees
308     if (rand[0]<0xC0)
309     {
310         // Size of clump depends on factor
311         if (diff > size_factor)
312             feat = DNGN_TREE;
313     }
314     // Small chance of henge
315     else if (rand[0]<0xC8)
316     {
317         if (diff > (size_factor+0.3) && diff < (size_factor+0.4))
318             feat = DNGN_STONE_ARCH;
319     }
320     // Somewhat under 25% chance of pool
321     else if (rand[0]<0xE0)
322     {
323         if (diff > size_factor*2.0)
324             feat = DNGN_DEEP_WATER;
325         else if (diff > size_factor)
326             feat = DNGN_SHALLOW_WATER;
327     }
328     // 25% chance of empty cell
329     return ProceduralSample(p, feat, offset + 1); // Delta is always 1 because the layout will be clamped
330 }
331 
332 // An expansive underworld containing seas, rivers, lakes, forests, cities, mountains, and perhaps more...
333 ProceduralSample
operator ()(const coord_def & p,const uint32_t offset) const334 ClampLayout::operator()(const coord_def &p, const uint32_t offset) const
335 {
336     uint32_t cycle = offset / clamp;
337     uint32_t order = hash3(p.x, p.y, 0xDEADBEEF + cycle);
338     if (bursty)
339         order &= hash3(p.x + 31, p.y - 37, 0x0DEFACED + cycle);
340     order %= clamp;
341     uint32_t clamp_offset = (offset + order) / clamp * clamp;
342     ProceduralSample sample = layout(p, clamp_offset);
343     uint32_t cp = max(sample.changepoint(), offset + order);
344     return ProceduralSample(p, sample.feat(), cp);
345 }
346 
347 ProceduralSample
operator ()(const coord_def & p,const uint32_t offset) const348 UnderworldLayout::operator()(const coord_def &p, const uint32_t offset) const
349 {
350     // Define various environmental functions based on noise. These factors
351     // combine to determine what terrain gets drawn at a given coordinate.
352 
353     // Wetness gives us features like water, and optimal wetness will be required for plants
354     const static SimplexFunction func_wet(0.5,0.5,3.0,3463.128,-3737.987,0,2);
355     // Terrain height gives us mountains, rivers, ocean
356     const static SimplexFunction func_height(0.3,0.3,1.0,7.543,2.123,0,4);
357     // Temperament. Plants struggle to grow in extreme temperatures, and we only see lava in hot places.
358     const static SimplexFunction func_hot(0.1,0.1,2.0,111.612,11.243,0,1);
359     // Citification; areas with a high settle factor will tend  to feature "man"-made architecture
360     // TODO: Citi/gentrification could use a worley layer instead (or a mix) to have better geometry
361     // and stop things like wall types suddenly changing halfway through a city.
362     const static SimplexFunction func_city(0.2,0.2,1.0,2.732,22.43,0,1);
363     // Gentrification; some cities are richer than others, this affects wall types
364     // but we can also choose what features to build inside the cities, influencing
365     // features like statues, fountains, plants, regularness, and even monsters/loot
366     const static SimplexFunction func_rich(0.05,0.05,1,9.543,5.543,0,1);
367 
368     // To create lots of lines everywhere that can often be perpendicular to other
369     // features; for creating bridges, dividing walls
370     const static WorleyFunction func_lateral(0.2,0.2,1,2000.543,1414.823,0);
371 
372     // Jitter needs to be completely random everywhere, so this can be used
373     // instead of normal random methods:
374     // if (jitter < (chance_in_1)) { ... }
375     const static SimplexFunction func_jitter(10,10,0.5,1123.543,2451.143,0,5);
376 
377     // Compute all our environment factors at the current spot
378     double wet = func_wet(p, offset);
379     double height = func_height(p, offset);
380     double hot = func_hot(p, offset);
381     double city = func_city(p, offset);
382     double rich = func_rich(p, offset);
383     double lateral = func_lateral(p, offset);
384     double jitter = func_jitter(p, offset);
385 
386     // TODO: The abyss doesn't support all of these yet but would be nice if:
387     //  * Clusters of plants around water edge
388     //  * Hot and wet areas are "tropical" with plants/trees (and steam)
389     //  * Extremely hot or cold areas should generate fire or ice clouds respectively.
390     //    If an "ice" feature were ever created this would be a good place for it.
391     //  * Wet cities have
392     //  * City + water areas have lateral bridges
393     //  * Borrow some easing functions from somewhere to better
394     //    control how features vary across bounaries
395     //  * Look at surrounding squares to determine gradients - will help
396     //    with lateral features and also e.g. growing plants on sunlit mountainsides...
397     //  * Use some lateral wetness to try and join mountain streams up to rivers...
398     //  * Petrified trees and other fun stuff in extreme temperatures
399     //  * Cities - Make the decor more interesting, and choose fountain types based on wetness
400     //  * Cities - Pave floor within wall limit
401     //  * Cities - might sometimes want to modify the terrain based on what was here before the city.
402     //             e.g. if the city was built on water then there should be fountains,
403     //             flooding, pools, aqueducts, with lava we get furnaces, etc.
404     //  * Rather than basing all the factors purely on separate perlin layers,
405     //    could combine some factors; e.g. cities thrive best at optimal combinations
406     //    of wet, height and hot, so the city/rich factor could be based on how close to optimum those three are...
407 
408     // Factors controlling how the environment is mapped to terrain
409     double water_depth = 0.2 * wet;
410     double water_deep_depth = 0.07 * wet;
411     double mountain_height = 0.8;
412     double mountain_top_height = 0.95;
413 
414     // Default feature
415     dungeon_feature_type feat = DNGN_FLOOR;
416 
417     // Lakes and rivers
418     if (height < water_depth)
419         feat = DNGN_SHALLOW_WATER;
420     if (height < water_deep_depth)
421         feat = DNGN_DEEP_WATER;
422 
423     if (height > mountain_height)
424     {
425         double dist_to_top = (height - mountain_height) / (mountain_top_height - mountain_height);
426         if (height > mountain_top_height
427             || lateral < dist_to_top)
428         {
429             if (hot > 0.7 && (dist_to_top>=1.0 || lateral/dist_to_top < 0.2))
430                 feat = DNGN_LAVA;
431             else
432                 feat = DNGN_ROCK_WALL;
433         }
434     }
435 
436     // Forest
437     bool enable_forest = true;
438     // Forests fill an important gap in the middling height gap between water and mountainous regions
439     double forest_start_height = 0.43;
440     double forest_end_height = 0.57;
441 
442     if (enable_forest)
443     {
444         // A narrow river running through the middle of forresty heights at good wetness levels
445         bool is_river = (abs(height-0.5) < (wet/10.0));
446         if (is_river)
447             feat = DNGN_SHALLOW_WATER;
448 
449         // Forests are somewhat finnicky about their conditions now
450         double forest =
451             _optimum_range(height, forest_start_height, forest_end_height)
452             * _optimum_range(wet, 0.5, 0.8)
453             * _optimum_range(hot, 0.4, 0.6);
454 
455         // Forest should now be 1.0 in the center of the range, 0.0 at the end
456         if (jitter < (forest * 0.5))
457             feat = DNGN_DEMONIC_TREE;
458     }
459 
460     // City
461     double city_outer_limit = 0.4;
462     double city_wall_limit = 0.65;
463     double city_wall_width = 0.05;
464     double city_inner_wall_limit = 0.8;
465     bool enable_city = true;
466 
467     // Cities become less likely at extreme heights and depths
468     double extreme_proximity = max(0.0,abs(height-0.5)-0.3) * 5.0;
469     city = city * (1.0 - extreme_proximity);
470 
471     if (enable_city && city >= city_outer_limit)
472     {
473         dungeon_feature_type city_wall = DNGN_ROCK_WALL;
474         if (rich > 0.5) city_wall = DNGN_STONE_WALL;
475         else if (rich > 0.75) city_wall = DNGN_METAL_WALL;
476         else if (rich > 0.9) city_wall = DNGN_CRYSTAL_WALL;
477 
478         // Doors and windows
479         if (jitter>0.5 && jitter<0.6) city_wall = DNGN_CLOSED_DOOR;
480         if (jitter>0.7 && jitter<0.75) city_wall = DNGN_CLEAR_STONE_WALL;
481 
482         // Outer cloisters
483         if (city < city_wall_limit)
484         {
485             if ((lateral >= 0.3 && lateral < 0.4 || lateral >= 0.6 && lateral < 0.7)
486                  || (lateral >= 0.4 && lateral < 0.6 && city < (city_outer_limit+city_wall_width)))
487             {
488                 feat = city_wall;
489             }
490             else if (lateral >= 0.4 && lateral < 0.6)
491                 feat = DNGN_FLOOR;
492         }
493 
494         // Main outer wall
495         if (city >= city_wall_limit)
496         {
497             // Within outer wall reset all terrain to floor.
498             feat = DNGN_FLOOR;
499 
500             if (city < (city_wall_limit + city_wall_width))
501                 feat = city_wall;
502             // Wall of inner halls
503             else if (city >= city_inner_wall_limit)
504             {
505                 if (city < (city_inner_wall_limit + city_wall_width))
506                     feat = city_wall;
507                 // Decide on what decor we want within the inner walls
508                 else if (jitter > 0.9)
509                 {
510                     if (rich>0.8)
511                         feat = DNGN_FOUNTAIN_BLUE;
512                     else if (rich>0.5)
513                         feat = DNGN_GRANITE_STATUE;
514                     else if (rich>0.2)
515                         feat = DNGN_GRATE;
516                     else
517                         feat = DNGN_STONE_ARCH;
518                 }
519             }
520         }
521     }
522 
523     int delta = 1;
524 
525     return ProceduralSample(p, feat, offset + delta);
526 }
527 
_optimum_range(const double val,const double rstart,const double rend) const528 double NoiseLayout::_optimum_range(const double val, const double rstart, const double rend) const
529 {
530     double mid = (rstart + rend) / 2.0;
531     return _optimum_range_mid(val, rstart, mid, mid, rend);
532 }
_optimum_range_mid(const double val,const double rstart,const double rmax1,const double rmax2,const double rend) const533 double NoiseLayout::_optimum_range_mid(const double val, const double rstart, const double rmax1, const double rmax2, const double rend) const
534 {
535     if (rmax1 <= val && val <= rmax2) return 1.0;
536     if (val <= rstart || val >= rend) return 0.0;
537     if (val < rmax1)
538         return (val - rstart) / (rmax1-rstart);
539     return 1.0 - (val - rmax2)/(rend - rmax2);
540 }
541 
operator ()(const coord_def & p,const uint32_t offset) const542 double ProceduralFunction::operator()(const coord_def &p, const uint32_t offset) const
543 {
544     return ProceduralFunction::operator()(p.x,p.y,offset);
545 }
546 
operator ()(double,double,double) const547 double ProceduralFunction::operator()(double, double, double) const
548 {
549     return 0;
550 }
551 
operator ()(const coord_def & p,const uint32_t offset) const552 double SimplexFunction::operator()(const coord_def &p, const uint32_t offset) const
553 {
554     return SimplexFunction::operator()(p.x,p.y,offset);
555 }
556 
operator ()(double x,double y,double z) const557 double SimplexFunction::operator()(double x, double y, double z) const
558 {
559     double hx = (x / (double)10 + seed_x) * scale_x;
560     double hy = (y / (double)10 + seed_y) * scale_y;
561     double hz = (z / (double)10000 + seed_z) * scale_z;
562     // Use octaval simplex and scale into a 0..1 range
563     return perlin::fBM(hx, hy, hz, octaves) / 2.0 + 0.5;
564 }
565 
operator ()(const coord_def & p,const uint32_t offset) const566 double WorleyFunction::operator()(const coord_def &p, const uint32_t offset) const
567 {
568     return WorleyFunction::operator()(p.x,p.y,offset);
569 }
570 
operator ()(double x,double y,double z) const571 double WorleyFunction::operator()(double x, double y, double z) const
572 {
573     worley::noise_datum d = datum(x,y,z);
574     return d.distance[1]-d.distance[0];
575 }
576 
datum(double x,double y,double z) const577 worley::noise_datum WorleyFunction::datum(double x, double y, double z) const
578 {
579     double hx = (x * (double)0.8 + seed_x) * scale_x;
580     double hy = (y * (double)0.8 + seed_y) * scale_y;
581     double hz = (z * (double)0.0008 + seed_z) * scale_z;
582     return worley::noise(hx, hy, hz);
583 }
584 
operator ()(double x,double y,double z) const585 double DistortFunction::operator()(double x, double y, double z) const
586 {
587     double offx = off_x(x,y,z);
588     double offy = off_y(x,y,z);
589     return base(x+offx,y+offy,z);
590 }
591 
datum(double x,double y,double z) const592 worley::noise_datum WorleyDistortFunction::datum(double x, double y, double z) const
593 {
594     double offx = off_x(x,y,z);
595     double offy = off_y(x,y,z);
596     return wbase.datum(x+offx,y+offy,z);
597 }
598