home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-05-31 | 5.1 KB | 146 lines | [TEXT/ttxt] |
- // This may look like C code, but it is really -*- C++ -*-
- /*
- ************************************************************************
- *
- * Generating Fractal Maps
- *
- * The algorithm is based on (but *only* based on) the following
- * explanation described in the "documentation" to program MARS
- * (Tim Clarke, tjc1005@hermes.cam.ac.uk, posted in some "games"
- * group)
- *
- * "This is a recursive subdivision, or plasma, fractal. You start of
- * with a random height at (0,0) and therefore also at (256,0), (0,256),
- * (256,256). Call a routine that takes as input the size and position
- * of a square, in the first case the entire map.
- * This routine get the heights from the corners of the square it gets
- * given. Across each edge (if the map has not been written to at the
- * point halfway along that edge), it takes the average of the heights of
- * the 2 corners on that edge, applies some noise proportional to the
- * length of the edge, and writes the result into the map at a position
- * halfway along the edge. The center of the square is the average of the
- * four corners+noise.
- * The routine then calls itself recursively, splitting each square into
- * four quadrants, calling itself for each quadrant until the length of
- * the side is 2 pixels.
- * This is probably old-hat to many people, but the map is made more
- * realistic by blurring [applying some filter to it]
- * The colors are done so that the sun is on the horizon to the East:
- * Color=A*[ w(u+1,v)-w(u,v) ]+B
- * with A and B chosen so that the full range of the palette is used.
- * The sky is a similar fractal but without the colour transformation"
- * <EOQ>
- *
- * The first distinction is the present program is that the algorithm
- * is iterative rather than recursive. For another thing, our map is
- * *NOT* periodic. BTW, it lets us use seeds in every corner of a map
- * (which would create "biased" clouds).
- *
- * Note that a map's pixel value is computed average + noise, scaled up to
- * the current dim. So when 2*scale > max pixel value, we've got a problem.
- * To get around that, the scale factor of the noise is chosen not
- * to exceed max_pixel_value/2.
- *
- * Since map is not-periodical, if a pixel sticks out of the map,
- * we force it within: say, when we need to operate map(2^order,j),
- * we actually dealing with map((2^order)-1,j), etc.
- *
- * $Id: fractal_map.cc,v 2.0 1995/03/16 21:18:01 oleg Exp oleg $
- *
- ************************************************************************
- */
-
- #ifdef __GNUC__
- #pragma implementation "fractal_map.h"
- #endif
-
- #include "fractal_map.h"
- #include <minmax.h>
- #include "std.h"
-
- // Get some noise with a dispersion 'scale'
- // (which is assumed to be a power of 2)
- // and average 0
- // Say, if scale=2 return either 0 or 1
- // if scale=128, return a random number
- // within [-64,63]
- // Note, that usually a couple of low-order
- // bits of Random() are "less" random;
- // therefore, we shift them out.
- inline int FractalMap::get_noise(const card scale) const
- {
- #ifdef __SC__
- return ((Random() >> 2) & (scale-1)) - scale/2;
- #else
- return ( rand() & (scale-1) ) - scale/2;
- #endif
- }
-
- FractalMap::FractalMap
- (const card order, const Seeds& _seeds, const card bits_per_pixel)
- : LazyImage(1<<order,1<<order,bits_per_pixel),
- seeds(_seeds)
- {
- if( order < 2 || order > 14 )
- _error("Order %d of the desired fractal map is unusual, "
- "I prefer something within [2,14]",order);
- }
-
- //------------------------------------------------------------------------
- // Here where the map is really constructed
-
- void FractalMap::fill_in(IMAGE& im) const
- {
- const card largest_noise_scale = 1<<(im.q_depth()-1);
- const card pixel_mask = (1<<im.q_depth())-1;
- const card dim = im.q_nrows();
-
- im(0,0) = seeds.s00; // Seed the map
- im(dim-1,0) = seeds.s10;
- im(0,dim-1) = seeds.s01;
- im(dim-1,dim-1) = seeds.s11;
-
- for(register card scale=dim; scale>1; scale >>= 1)
- {
- const card scale_half = scale>>1;
- const card noise_scale = min(scale,largest_noise_scale);
- register int i,j;
- for(i=0; i<dim; i += scale)
- {
- int i_up = min(i+scale,dim-1);
- int i_hp = i+scale_half;
- int corner00 = im(i,0); // caching
- int corner10 = im(i_up,0);
- int mid30 = im(i_hp,0) =
- (((corner00+corner10)>>1) + get_noise(noise_scale)) & pixel_mask;
- for(j=0; j<dim; j += scale)
- {
- int j_up = min(j+scale,dim-1);
- int j_hp = j+scale_half;
- const int corner01 = im(i,j_up);
- const int corner11 = im(i_up,j_up);
- const int mid03 = i == 0 ?
- ( ((corner00+corner01)>>1) +
- get_noise(noise_scale) ) & pixel_mask : im(i,j_hp);
- const int mid31 = ( ((corner01+corner11)>>1) +
- get_noise(noise_scale) ) & pixel_mask;
- const int mid13 = ( ((corner10+corner11)>>1) +
- get_noise(noise_scale) ) & pixel_mask;
- const int mid33 = ( ((mid30+mid03+mid31+mid13)>>2) +
- get_noise(noise_scale) ) & pixel_mask;
- im(i_hp,j_up) = mid31;
- if( i == 0 )
- im(i,j_hp) = mid03;
- im(i_up,j_hp) = mid13;
- im(i_hp,j_hp) = mid33;
- // Note, corner01 for col j becomes
- corner00 = corner01; // corner00 for the next j
- corner10 = corner11;
- mid30 = mid31;
- }
- }
- }
- }
-
-
-