/// \brief One dimensional midpoint displacement fractal. /// /// Size must be a power of 2. /// Falloff is the decay of displacement as the fractal is refined. /// Array is size + 1 long. array[0] and array[size] are filled /// with the control points for the fractal. void Segment::fill1d(BasePoint const & l, BasePoint const &h, float *array) const { array[0] = l.height(); array[m_res] = h.height(); LinInterp li(m_res, l.roughness(), h.roughness()); // seed the RNG. // The RNG is seeded only once for the line and the seed is based on the // two endpoints -because they are the common parameters for two adjoining // tiles //srand((l.seed() * 1000 + h.seed())); WFMath::MTRand::uint32 seed[2] = { l.seed(), h.seed() }; WFMath::MTRand rng(seed, 2); // stride is used to step across the array in a deterministic fashion // effectively we do the 1/2 point, then the 1/4 points, then the 1/8th // points etc. this has to be the same order every time because we call // on the RNG at every point decltype(getResolution()) stride = m_res / 2; // depth is used to indicate what level we are on. the displacement is // reduced each time we traverse the array. float depth = 1; while (stride) { for (decltype(getResolution()) i = stride; i < m_res; i += stride * 2) { auto hh = array[i - stride]; auto lh = array[i + stride]; auto hd = std::fabs(hh - lh); auto roughness = li.calc(i); //eliminate the problem where hd is nearly zero, leaving a flat section. if ((hd * 100.f) < roughness) { hd += 0.05f * roughness; } array[i] = ((hh + lh) / 2.f) + randHalf(rng) * roughness * hd / (1.f + std::pow(depth, BasePoint::FALLOFF)); } stride >>= 1; depth++; } }