// complexplanet.cpp
//
// This program demonstrates how to use the libnoise library to generate
// terrain elevations for a complex planetary surface that has the size of the
// earth.
//
// This program outputs a grid of elevation points in geographic (lat/lon)
// projection.  This program creates six files from this grid:
// - A Terragen terrain (*.ter) file that has its elevation points measured in
//   meters.  This file is generated only if the grid of elevation points has
//   a spatial resolution <= 240 meters.
// - A raw terrain (*.raw) file that has its elevation points measured in
//   meters.  This terrain file contains 16-bit signed big-endian values, in
//   row-major order, ordered south to north.
// - A Windows bitmap file (*.bmp) that is colored according to elevation and
//   lit by an artificial light source.
// - A Windows bitmap file (*.bmp) that is colored according to elevation
//   only.
// - A Windows bitmap file (*.bmp) containing the normals of the terrain.  The
//   red channel represents the x normal coordinate, the green channel
//   represents the y normal coordinate, and the blue channel represents the z
//   normal coordinate.  Initially, the normal coordinates are between -0.5
//   and +0.5, but when stored in the bitmap, this range is mapped from 0 to
//   255.
// - A Windows bitmap file (*.bmp) containing the specularity map of the
//   terrain.  Black indicates no specularity, while white indicates full
//   specularity.
//
// The grid of elevation points can have a maximum horizontal resolution of
// 0.25 arcseconds (~7.5 meters.)  A higher-resolution grid will cause the
// terrain to appear blurry.
//
// The terrain elevations are generated by a collection of over a hundred
// noise modules in a hierarchy of groups and subgroups.  Each group and
// subgroup outputs a single output value that originates from a caching
// module (noise::module::Cache).  Each group and subgroup can be thought of
// as a single complex noise module that can be used as a source module for
// other noise modules.  The caching module was chosen as the source of the
// output value to prevent costly recalculations by each group and subgroup
// requesting an output value from it.
//
// The following is a list of module groups and subgroups that build the
// planet's terrain:
//
// Group (continent definition)
//   Subgroup (base continent definition)
//   Subgroup (continent definition)
// Group (terrain type definition)
//   Subgroup (terrain type definition)
// Group (mountainous terrain)
//   Subgroup (mountain base definition)
//   Subgroup (high mountainous terrain)
//   Subgroup (low mountainous terrain)
//   Subgroup (mountainous terrain)
// Group (hilly terrain)
//   Subgroup (hilly terrain)
// Group (plains terrain)
//   Subgroup (plains terrain)
// Group (badlands terrain)
//   Subgroup (badlands sand)
//   Subgroup (badlands cliffs)
//   Subgroup (badlands terrain)
// Group (river positions)
//   Subgroup (river positions)
// Group (scaled mountainous terrain)
//   Subgroup (scaled mountainous terrain)
// Group (scaled hilly terrain)
//   Subgroup (scaled hilly terrain)
// Group (scaled plains terrain)
//   Subgroup (scaled plains terrain)
// Group (scaled badlands terrain)
//   Subgroup (scaled badlands terrain)
// Group (final planet)
//   Subgroup (continental shelf)
//   Subgroup (base continent elevation)
//   Subgroup (continents with plains)
//   Subgroup (continents with hills)
//   Subgroup (continents with mountains)
//   Subgroup (continents with badlands)
//   Subgroup (continents with rivers)
//   Subgroup (unscaled final planet)
//   Subgroup (final planet)
//
// A description of each group and subgroup can be found above the source code
// for that group and subgroup.
//
// Copyright (C) 2004, 2005 by Jason Bevins
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// (COPYING.txt) for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc., 59
// Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// The developer's email is jlbezigvins@gmzigail.com (for great email, take
// off every 'zig'.)
//

#include <fstream>

#include <noise/noise.h>

#include "noiseutils.h"

using namespace noise;

int main ()
{

  ////////////////////////////////////////////////////////////////////////////
  // Constants
  //
  // Modify these constants to change the terrain of the planet and to change
  // the boundaries and size of the elevation grid.
  //
  // Note: "Planetary elevation units" range from -1.0 (for the lowest
  // underwater trenches) to +1.0 (for the highest mountain peaks.)
  //

  // Southernmost coordinate of elevation grid.
  const double SOUTH_COORD = -90;

  // Northernmost coordinate of elevation grid.
  const double NORTH_COORD = 90;

  // Westernmost coordinate of elevation grid.
  const double WEST_COORD = -180;

  // Easternmost coordinate of elevation grid.
  const double EAST_COORD = 180;

  // Width of elevation grid, in points.
  const int GRID_WIDTH = 4096;

  // Height of elevation grid, in points.
  const int GRID_HEIGHT = 2048;

  // Planet seed.  Change this to generate a different planet.
  const int CUR_SEED = 0;

  // Circumference of the planet, in meters.
  const double PLANET_CIRCUMFERENCE = 44236800.0;

  // Minimum elevation on the planet, in meters.  This value is approximate.
  const double MIN_ELEV = -8192.0;

  // Maximum elevation on the planet, in meters.  This value is approximate.
  const double MAX_ELEV = 8192.0;

  // Frequency of the planet's continents.  Higher frequency produces smaller,
  // more numerous continents.  This value is measured in radians.
  const double CONTINENT_FREQUENCY = 1.0;

  // Lacunarity of the planet's continents.  Changing this value produces
  // slightly different continents.  For the best results, this value should
  // be random, but close to 2.0.
  const double CONTINENT_LACUNARITY = 2.208984375;

  // Lacunarity of the planet's mountains.  Changing this value produces
  // slightly different mountains.  For the best results, this value should
  // be random, but close to 2.0.
  const double MOUNTAIN_LACUNARITY = 2.142578125;

  // Lacunarity of the planet's hills.  Changing this value produces slightly
  // different hills.  For the best results, this value should be random, but
  // close to 2.0.
  const double HILLS_LACUNARITY = 2.162109375;

  // Lacunarity of the planet's plains.  Changing this value produces slightly
  // different plains.  For the best results, this value should be random, but
  // close to 2.0.
  const double PLAINS_LACUNARITY = 2.314453125;

  // Lacunarity of the planet's badlands.  Changing this value produces
  // slightly different badlands.  For the best results, this value should be
  // random, but close to 2.0.
  const double BADLANDS_LACUNARITY = 2.212890625;

  // Specifies the "twistiness" of the mountains.
  const double MOUNTAINS_TWIST = 1.0;

  // Specifies the "twistiness" of the hills.
  const double HILLS_TWIST = 1.0;

  // Specifies the "twistiness" of the badlands.
  const double BADLANDS_TWIST = 1.0;

  // Specifies the planet's sea level.  This value must be between -1.0
  // (minimum planet elevation) and +1.0 (maximum planet elevation.)
  const double SEA_LEVEL = 0.0;

  // Specifies the level on the planet in which continental shelves appear.
  // This value must be between -1.0 (minimum planet elevation) and +1.0
  // (maximum planet elevation), and must be less than SEA_LEVEL.
  const double SHELF_LEVEL = -0.375;

  // Determines the amount of mountainous terrain that appears on the
  // planet.  Values range from 0.0 (no mountains) to 1.0 (all terrain is
  // covered in mountains).  Mountainous terrain will overlap hilly terrain.
  // Because the badlands terrain may overlap parts of the mountainous
  // terrain, setting MOUNTAINS_AMOUNT to 1.0 may not completely cover the
  // terrain in mountains.
  const double MOUNTAINS_AMOUNT = 0.5;

  // Determines the amount of hilly terrain that appears on the planet.
  // Values range from 0.0 (no hills) to 1.0 (all terrain is covered in
  // hills).  This value must be less than MOUNTAINS_AMOUNT.  Because the
  // mountainous terrain will overlap parts of the hilly terrain, and
  // the badlands terrain may overlap parts of the hilly terrain, setting
  // HILLS_AMOUNT to 1.0 may not completely cover the terrain in hills.
  const double HILLS_AMOUNT = (1.0 + MOUNTAINS_AMOUNT) / 2.0;

  // Determines the amount of badlands terrain that covers the planet.
  // Values range from 0.0 (no badlands) to 1.0 (all terrain is covered in
  // badlands.)  Badlands terrain will overlap any other type of terrain.
  const double BADLANDS_AMOUNT = 0.03125;

  // Offset to apply to the terrain type definition.  Low values (< 1.0) cause
  // the rough areas to appear only at high elevations.  High values (> 2.0)
  // cause the rough areas to appear at any elevation.  The percentage of
  // rough areas on the planet are independent of this value.
  const double TERRAIN_OFFSET = 1.0;

  // Specifies the amount of "glaciation" on the mountains.  This value
  // should be close to 1.0 and greater than 1.0.
  const double MOUNTAIN_GLACIATION = 1.375;

  // Scaling to apply to the base continent elevations, in planetary elevation
  // units.
  const double CONTINENT_HEIGHT_SCALE = (1.0 - SEA_LEVEL) / 4.0;

  // Maximum depth of the rivers, in planetary elevation units.
  const double RIVER_DEPTH = 0.0234375;


  ////////////////////////////////////////////////////////////////////////////
  // Module group: continent definition
  ////////////////////////////////////////////////////////////////////////////

  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: base continent definition (7 noise modules)
  //
  // This subgroup roughly defines the positions and base elevations of the
  // planet's continents.
  //
  // The "base elevation" is the elevation of the terrain before any terrain
  // features (mountains, hills, etc.) are placed on that terrain.
  //
  // -1.0 represents the lowest elevations and +1.0 represents the highest
  // elevations.
  //

  // 1: [Continent module]: This Perlin-noise module generates the continents.
  //    This noise module has a high number of octaves so that detail is
  //    visible at high zoom levels.
  module::Perlin baseContinentDef_pe0;
  baseContinentDef_pe0.SetSeed (CUR_SEED + 0);
  baseContinentDef_pe0.SetFrequency (CONTINENT_FREQUENCY);
  baseContinentDef_pe0.SetPersistence (0.5);
  baseContinentDef_pe0.SetLacunarity (CONTINENT_LACUNARITY);
  baseContinentDef_pe0.SetOctaveCount (14);
  baseContinentDef_pe0.SetNoiseQuality (QUALITY_STD);

  // 2: [Continent-with-ranges module]: Next, a curve module modifies the
  //    output value from the continent module so that very high values appear
  //    near sea level.  This defines the positions of the mountain ranges.
  module::Curve baseContinentDef_cu;
  baseContinentDef_cu.SetSourceModule (0, baseContinentDef_pe0);
  baseContinentDef_cu.AddControlPoint (-2.0000 + SEA_LEVEL,-1.625 + SEA_LEVEL);
  baseContinentDef_cu.AddControlPoint (-1.0000 + SEA_LEVEL,-1.375 + SEA_LEVEL);
  baseContinentDef_cu.AddControlPoint ( 0.0000 + SEA_LEVEL,-0.375 + SEA_LEVEL);
  baseContinentDef_cu.AddControlPoint ( 0.0625 + SEA_LEVEL, 0.125 + SEA_LEVEL);
  baseContinentDef_cu.AddControlPoint ( 0.1250 + SEA_LEVEL, 0.250 + SEA_LEVEL);
  baseContinentDef_cu.AddControlPoint ( 0.2500 + SEA_LEVEL, 1.000 + SEA_LEVEL);
  baseContinentDef_cu.AddControlPoint ( 0.5000 + SEA_LEVEL, 0.250 + SEA_LEVEL);
  baseContinentDef_cu.AddControlPoint ( 0.7500 + SEA_LEVEL, 0.250 + SEA_LEVEL);
  baseContinentDef_cu.AddControlPoint ( 1.0000 + SEA_LEVEL, 0.500 + SEA_LEVEL);
  baseContinentDef_cu.AddControlPoint ( 2.0000 + SEA_LEVEL, 0.500 + SEA_LEVEL);

  // 3: [Carver module]: This higher-frequency Perlin-noise module will be
  //    used by subsequent noise modules to carve out chunks from the mountain
  //    ranges within the continent-with-ranges module so that the mountain
  //    ranges will not be complely impassible.
  module::Perlin baseContinentDef_pe1;
  baseContinentDef_pe1.SetSeed (CUR_SEED + 1);
  baseContinentDef_pe1.SetFrequency (CONTINENT_FREQUENCY * 4.34375);
  baseContinentDef_pe1.SetPersistence (0.5);
  baseContinentDef_pe1.SetLacunarity (CONTINENT_LACUNARITY);
  baseContinentDef_pe1.SetOctaveCount (11);
  baseContinentDef_pe1.SetNoiseQuality (QUALITY_STD);

  // 4: [Scaled-carver module]: This scale/bias module scales the output
  //    value from the carver module such that it is usually near 1.0.  This
  //    is required for step 5.
  module::ScaleBias baseContinentDef_sb;
  baseContinentDef_sb.SetSourceModule (0, baseContinentDef_pe1);
  baseContinentDef_sb.SetScale (0.375);
  baseContinentDef_sb.SetBias (0.625);

  // 5: [Carved-continent module]: This minimum-value module carves out chunks
  //    from the continent-with-ranges module.  It does this by ensuring that
  //    only the minimum of the output values from the scaled-carver module
  //    and the continent-with-ranges module contributes to the output value
  //    of this subgroup.  Most of the time, the minimum-value module will
  //    select the output value from the continents-with-ranges module since
  //    the output value from the scaled-carver module is usually near 1.0.
  //    Occasionally, the output value from the scaled-carver module will be
  //    less than the output value from the continent-with-ranges module, so
  //    in this case, the output value from the scaled-carver module is
  //    selected.
  module::Min baseContinentDef_mi;
  baseContinentDef_mi.SetSourceModule (0, baseContinentDef_sb);
  baseContinentDef_mi.SetSourceModule (1, baseContinentDef_cu);

  // 6: [Clamped-continent module]: Finally, a clamp module modifies the
  //    carved-continent module to ensure that the output value of this
  //    subgroup is between -1.0 and 1.0.
  module::Clamp baseContinentDef_cl;
  baseContinentDef_cl.SetSourceModule (0, baseContinentDef_mi);
  baseContinentDef_cl.SetBounds (-1.0, 1.0);

  // 7: [Base-continent-definition subgroup]: Caches the output value from the
  //    clamped-continent module.
  module::Cache baseContinentDef;
  baseContinentDef.SetSourceModule (0, baseContinentDef_cl);


  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: continent definition (5 noise modules)
  //
  // This subgroup warps the output value from the the base-continent-
  // definition subgroup, producing more realistic terrain.
  //
  // Warping the base continent definition produces lumpier terrain with
  // cliffs and rifts.
  //
  // -1.0 represents the lowest elevations and +1.0 represents the highest
  // elevations.
  //

  // 1: [Coarse-turbulence module]: This turbulence module warps the output
  //    value from the base-continent-definition subgroup, adding some coarse
  //    detail to it.
  module::Turbulence continentDef_tu0;
  continentDef_tu0.SetSourceModule (0, baseContinentDef);
  continentDef_tu0.SetSeed (CUR_SEED + 10);
  continentDef_tu0.SetFrequency (CONTINENT_FREQUENCY * 15.25);
  continentDef_tu0.SetPower (CONTINENT_FREQUENCY / 113.75);
  continentDef_tu0.SetRoughness (13);

  // 2: [Intermediate-turbulence module]: This turbulence module warps the
  //    output value from the coarse-turbulence module.  This turbulence has
  //    a higher frequency, but lower power, than the coarse-turbulence
  //    module, adding some intermediate detail to it.
  module::Turbulence continentDef_tu1;
  continentDef_tu1.SetSourceModule (0, continentDef_tu0);
  continentDef_tu1.SetSeed (CUR_SEED + 11);
  continentDef_tu1.SetFrequency (CONTINENT_FREQUENCY * 47.25);
  continentDef_tu1.SetPower (CONTINENT_FREQUENCY / 433.75);
  continentDef_tu1.SetRoughness (12);

  // 3: [Warped-base-continent-definition module]: This turbulence module
  //    warps the output value from the intermediate-turbulence module.  This
  //    turbulence has a higher frequency, but lower power, than the
  //    intermediate-turbulence module, adding some fine detail to it.
  module::Turbulence continentDef_tu2;
  continentDef_tu2.SetSourceModule (0, continentDef_tu1);
  continentDef_tu2.SetSeed (CUR_SEED + 12);
  continentDef_tu2.SetFrequency (CONTINENT_FREQUENCY * 95.25);
  continentDef_tu2.SetPower (CONTINENT_FREQUENCY / 1019.75);
  continentDef_tu2.SetRoughness (11);

  // 4: [Select-turbulence module]: At this stage, the turbulence is applied
  //    to the entire base-continent-definition subgroup, producing some very
  //    rugged, unrealistic coastlines.  This selector module selects the
  //    output values from the (unwarped) base-continent-definition subgroup
  //    and the warped-base-continent-definition module, based on the output
  //    value from the (unwarped) base-continent-definition subgroup.  The
  //    selection boundary is near sea level and has a relatively smooth
  //    transition.  In effect, only the higher areas of the base-continent-
  //    definition subgroup become warped; the underwater and coastal areas
  //    remain unaffected.
  module::Select continentDef_se;
  continentDef_se.SetSourceModule (0, baseContinentDef);
  continentDef_se.SetSourceModule (1, continentDef_tu2);
  continentDef_se.SetControlModule (baseContinentDef);
  continentDef_se.SetBounds (SEA_LEVEL - 0.0375, SEA_LEVEL + 1000.0375);
  continentDef_se.SetEdgeFalloff (0.0625);

  // 7: [Continent-definition group]: Caches the output value from the
  //    clamped-continent module.  This is the output value for the entire
  //    continent-definition group.
  module::Cache continentDef;
  continentDef.SetSourceModule (0, continentDef_se);


  ////////////////////////////////////////////////////////////////////////////
  // Module group: terrain type definition
  ////////////////////////////////////////////////////////////////////////////

  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: terrain type definition (3 noise modules)
  //
  // This subgroup defines the positions of the terrain types on the planet.
  //
  // Terrain types include, in order of increasing roughness, plains, hills,
  // and mountains.
  //
  // This subgroup's output value is based on the output value from the
  // continent-definition group.  Rougher terrain mainly appears at higher
  // elevations.
  //
  // -1.0 represents the smoothest terrain types (plains and underwater) and
  // +1.0 represents the roughest terrain types (mountains).
  //

  // 1: [Warped-continent module]: This turbulence module slightly warps the
  //    output value from the continent-definition group.  This prevents the
  //    rougher terrain from appearing exclusively at higher elevations.
  //    Rough areas may now appear in the the ocean, creating rocky islands
  //    and fjords.
  module::Turbulence terrainTypeDef_tu;
  terrainTypeDef_tu.SetSourceModule (0, continentDef);
  terrainTypeDef_tu.SetSeed (CUR_SEED + 20);
  terrainTypeDef_tu.SetFrequency (CONTINENT_FREQUENCY * 18.125);
  terrainTypeDef_tu.SetPower (CONTINENT_FREQUENCY / 20.59375
    * TERRAIN_OFFSET);
  terrainTypeDef_tu.SetRoughness (3);

  // 2: [Roughness-probability-shift module]: This terracing module sharpens
  //    the edges of the warped-continent module near sea level and lowers
  //    the slope towards the higher-elevation areas.  This shrinks the areas
  //    in which the rough terrain appears, increasing the "rarity" of rough
  //    terrain.
  module::Terrace terrainTypeDef_te;
  terrainTypeDef_te.SetSourceModule (0, terrainTypeDef_tu);
  terrainTypeDef_te.AddControlPoint (-1.00);
  terrainTypeDef_te.AddControlPoint (SHELF_LEVEL + SEA_LEVEL / 2.0);
  terrainTypeDef_te.AddControlPoint (1.00);

  // 3: [Terrain-type-definition group]: Caches the output value from the
  //    roughness-probability-shift module.  This is the output value for
  //    the entire terrain-type-definition group.
  module::Cache terrainTypeDef;
  terrainTypeDef.SetSourceModule (0, terrainTypeDef_te);


  ////////////////////////////////////////////////////////////////////////////
  // Module group: mountainous terrain
  ////////////////////////////////////////////////////////////////////////////

  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: mountain base definition (9 noise modules)
  //
  // This subgroup generates the base-mountain elevations.  Other subgroups
  // will add the ridges and low areas to the base elevations.
  //
  // -1.0 represents low mountainous terrain and +1.0 represents high
  // mountainous terrain.
  //

  // 1: [Mountain-ridge module]: This ridged-multifractal-noise module
  //    generates the mountain ridges.
  module::RidgedMulti mountainBaseDef_rm0;
  mountainBaseDef_rm0.SetSeed (CUR_SEED + 30);
  mountainBaseDef_rm0.SetFrequency (1723.0);
  mountainBaseDef_rm0.SetLacunarity (MOUNTAIN_LACUNARITY);
  mountainBaseDef_rm0.SetOctaveCount (4);
  mountainBaseDef_rm0.SetNoiseQuality (QUALITY_STD);

  // 2: [Scaled-mountain-ridge module]: Next, a scale/bias module scales the
  //    output value from the mountain-ridge module so that its ridges are not
  //    too high.  The reason for this is that another subgroup adds actual
  //    mountainous terrain to these ridges.
  module::ScaleBias mountainBaseDef_sb0;
  mountainBaseDef_sb0.SetSourceModule (0, mountainBaseDef_rm0);
  mountainBaseDef_sb0.SetScale (0.5);
  mountainBaseDef_sb0.SetBias (0.375);

  // 3: [River-valley module]: This ridged-multifractal-noise module generates
  //    the river valleys.  It has a much lower frequency than the mountain-
  //    ridge module so that more mountain ridges will appear outside of the
  //    valleys.  Note that this noise module generates ridged-multifractal
  //    noise using only one octave; this information will be important in the
  //    next step.
  module::RidgedMulti mountainBaseDef_rm1;
  mountainBaseDef_rm1.SetSeed (CUR_SEED + 31);
  mountainBaseDef_rm1.SetFrequency (367.0);
  mountainBaseDef_rm1.SetLacunarity (MOUNTAIN_LACUNARITY);
  mountainBaseDef_rm1.SetOctaveCount (1);
  mountainBaseDef_rm1.SetNoiseQuality (QUALITY_BEST);

  // 4: [Scaled-river-valley module]: Next, a scale/bias module applies a
  //    scaling factor of -2.0 to the output value from the river-valley
  //    module.  This stretches the possible elevation values because one-
  //    octave ridged-multifractal noise has a lower range of output values
  //    than multiple-octave ridged-multifractal noise.  The negative scaling
  //    factor inverts the range of the output value, turning the ridges from
  //    the river-valley module into valleys.
  module::ScaleBias mountainBaseDef_sb1;
  mountainBaseDef_sb1.SetSourceModule (0, mountainBaseDef_rm1);
  mountainBaseDef_sb1.SetScale (-2.0);
  mountainBaseDef_sb1.SetBias (-0.5);

  // 5: [Low-flat module]: This low constant value is used by step 6.
  module::Const mountainBaseDef_co;
  mountainBaseDef_co.SetConstValue (-1.0);

  // 6: [Mountains-and-valleys module]: This blender module merges the
  //    scaled-mountain-ridge module and the scaled-river-valley module
  //    together.  It causes the low-lying areas of the terrain to become
  //    smooth, and causes the high-lying areas of the terrain to contain
  //    ridges.  To do this, it uses the scaled-river-valley module as the
  //    control module, causing the low-flat module to appear in the lower
  //    areas and causing the scaled-mountain-ridge module to appear in the
  //    higher areas.
  module::Blend mountainBaseDef_bl;
  mountainBaseDef_bl.SetSourceModule (0, mountainBaseDef_co);
  mountainBaseDef_bl.SetSourceModule (1, mountainBaseDef_sb0);
  mountainBaseDef_bl.SetControlModule (mountainBaseDef_sb1);

  // 7: [Coarse-turbulence module]: This turbulence module warps the output
  //    value from the mountain-and-valleys module, adding some coarse detail
  //    to it.
  module::Turbulence mountainBaseDef_tu0;
  mountainBaseDef_tu0.SetSourceModule (0, mountainBaseDef_bl);
  mountainBaseDef_tu0.SetSeed (CUR_SEED + 32);
  mountainBaseDef_tu0.SetFrequency (1337.0);
  mountainBaseDef_tu0.SetPower (1.0 / 6730.0 * MOUNTAINS_TWIST);
  mountainBaseDef_tu0.SetRoughness (4);

  // 8: [Warped-mountains-and-valleys module]: This turbulence module warps
  //    the output value from the coarse-turbulence module.  This turbulence
  //    has a higher frequency, but lower power, than the coarse-turbulence
  //    module, adding some fine detail to it.
  module::Turbulence mountainBaseDef_tu1;
  mountainBaseDef_tu1.SetSourceModule (0, mountainBaseDef_tu0);
  mountainBaseDef_tu1.SetSeed (CUR_SEED + 33);
  mountainBaseDef_tu1.SetFrequency (21221.0);
  mountainBaseDef_tu1.SetPower (1.0 / 120157.0 * MOUNTAINS_TWIST);
  mountainBaseDef_tu1.SetRoughness (6);

  // 9: [Mountain-base-definition subgroup]: Caches the output value from the
  //    warped-mountains-and-valleys module.
  module::Cache mountainBaseDef;
  mountainBaseDef.SetSourceModule (0, mountainBaseDef_tu1);


  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: high mountainous terrain (5 noise modules)
  //
  // This subgroup generates the mountainous terrain that appears at high
  // elevations within the mountain ridges.
  //
  // -1.0 represents the lowest elevations and +1.0 represents the highest
  // elevations.
  //

  // 1: [Mountain-basis-0 module]: This ridged-multifractal-noise module,
  //    along with the mountain-basis-1 module, generates the individual
  //    mountains.
  module::RidgedMulti mountainousHigh_rm0;
  mountainousHigh_rm0.SetSeed (CUR_SEED + 40);
  mountainousHigh_rm0.SetFrequency (2371.0);
  mountainousHigh_rm0.SetLacunarity (MOUNTAIN_LACUNARITY);
  mountainousHigh_rm0.SetOctaveCount (3);
  mountainousHigh_rm0.SetNoiseQuality (QUALITY_BEST);

  // 2: [Mountain-basis-1 module]: This ridged-multifractal-noise module,
  //    along with the mountain-basis-0 module, generates the individual
  //    mountains.
  module::RidgedMulti mountainousHigh_rm1;
  mountainousHigh_rm1.SetSeed (CUR_SEED + 41);
  mountainousHigh_rm1.SetFrequency (2341.0);
  mountainousHigh_rm1.SetLacunarity (MOUNTAIN_LACUNARITY);
  mountainousHigh_rm1.SetOctaveCount (3);
  mountainousHigh_rm1.SetNoiseQuality (QUALITY_BEST);

  // 3: [High-mountains module]: Next, a maximum-value module causes more
  //    mountains to appear at the expense of valleys.  It does this by
  //    ensuring that only the maximum of the output values from the two
  //    ridged-multifractal-noise modules contribute to the output value of
  //    this subgroup.
  module::Max mountainousHigh_ma;
  mountainousHigh_ma.SetSourceModule (0, mountainousHigh_rm0);
  mountainousHigh_ma.SetSourceModule (1, mountainousHigh_rm1);

  // 4: [Warped-high-mountains module]: This turbulence module warps the
  //    output value from the high-mountains module, adding some detail to it.
  module::Turbulence mountainousHigh_tu;
  mountainousHigh_tu.SetSourceModule (0, mountainousHigh_ma);
  mountainousHigh_tu.SetSeed (CUR_SEED + 42);
  mountainousHigh_tu.SetFrequency (31511.0);
  mountainousHigh_tu.SetPower (1.0 / 180371.0 * MOUNTAINS_TWIST);
  mountainousHigh_tu.SetRoughness (4);

  // 5: [High-mountainous-terrain subgroup]: Caches the output value from the
  //    warped-high-mountains module.
  module::Cache mountainousHigh;
  mountainousHigh.SetSourceModule (0, mountainousHigh_tu);


  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: low mountainous terrain (4 noise modules)
  //
  // This subgroup generates the mountainous terrain that appears at low
  // elevations within the river valleys.
  //
  // -1.0 represents the lowest elevations and +1.0 represents the highest
  // elevations.
  //

  // 1: [Lowland-basis-0 module]: This ridged-multifractal-noise module,
  //    along with the lowland-basis-1 module, produces the low mountainous
  //    terrain.
  module::RidgedMulti mountainousLow_rm0;
  mountainousLow_rm0.SetSeed (CUR_SEED + 50);
  mountainousLow_rm0.SetFrequency (1381.0);
  mountainousLow_rm0.SetLacunarity (MOUNTAIN_LACUNARITY);
  mountainousLow_rm0.SetOctaveCount (8);
  mountainousLow_rm0.SetNoiseQuality (QUALITY_BEST);

  // 1: [Lowland-basis-1 module]: This ridged-multifractal-noise module,
  //    along with the lowland-basis-0 module, produces the low mountainous
  //    terrain.
  module::RidgedMulti mountainousLow_rm1;
  mountainousLow_rm1.SetSeed (CUR_SEED + 51);
  mountainousLow_rm1.SetFrequency (1427.0);
  mountainousLow_rm1.SetLacunarity (MOUNTAIN_LACUNARITY);
  mountainousLow_rm1.SetOctaveCount (8);
  mountainousLow_rm1.SetNoiseQuality (QUALITY_BEST);

  // 3: [Low-mountainous-terrain module]: This multiplication module combines
  //    the output values from the two ridged-multifractal-noise modules.
  //    This causes the following to appear in the resulting terrain:
  //    - Cracks appear when two negative output values are multiplied
  //      together.
  //    - Flat areas appear when a positive and a negative output value are
  //      multiplied together.
  //    - Ridges appear when two positive output values are multiplied
  //      together.
  module::Multiply mountainousLow_mu;
  mountainousLow_mu.SetSourceModule (0, mountainousLow_rm0);
  mountainousLow_mu.SetSourceModule (1, mountainousLow_rm1);

  // 4: [Low-mountainous-terrain subgroup]: Caches the output value from the
  //    low-moutainous-terrain module.
  module::Cache mountainousLow;
  mountainousLow.SetSourceModule (0, mountainousLow_mu);


  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: mountainous terrain (7 noise modules)
  //
  // This subgroup generates the final mountainous terrain by combining the
  // high-mountainous-terrain subgroup with the low-mountainous-terrain
  // subgroup.
  //
  // -1.0 represents the lowest elevations and +1.0 represents the highest
  // elevations.
  //

  // 1: [Scaled-low-mountainous-terrain module]: First, this scale/bias module
  //    scales the output value from the low-mountainous-terrain subgroup to a
  //    very low value and biases it towards -1.0.  This results in the low
  //    mountainous areas becoming more-or-less flat with little variation.
  //    This will also result in the low mountainous areas appearing at the
  //    lowest elevations in this subgroup.
  module::ScaleBias mountainousTerrain_sb0;
  mountainousTerrain_sb0.SetSourceModule (0, mountainousLow);
  mountainousTerrain_sb0.SetScale (0.03125);
  mountainousTerrain_sb0.SetBias (-0.96875);

  // 2: [Scaled-high-mountainous-terrain module]: Next, this scale/bias module
  //    scales the output value from the high-mountainous-terrain subgroup to
  //    1/4 of its initial value and biases it so that its output value is
  //    usually positive.
  module::ScaleBias mountainousTerrain_sb1;
  mountainousTerrain_sb1.SetSourceModule (0, mountainousHigh);
  mountainousTerrain_sb1.SetScale (0.25);
  mountainousTerrain_sb1.SetBias (0.25);

  // 3: [Added-high-mountainous-terrain module]: This addition module adds the
  //    output value from the scaled-high-mountainous-terrain module to the
  //    output value from the mountain-base-definition subgroup.  Mountains
  //    now appear all over the terrain.
  module::Add mountainousTerrain_ad;
  mountainousTerrain_ad.SetSourceModule (0, mountainousTerrain_sb1);
  mountainousTerrain_ad.SetSourceModule (1, mountainBaseDef);

  // 4: [Combined-mountainous-terrain module]: Note that at this point, the
  //    entire terrain is covered in high mountainous terrain, even at the low
  //    elevations.  To make sure the mountains only appear at the higher
  //    elevations, this selector module causes low mountainous terrain to
  //    appear at the low elevations (within the valleys) and the high
  //    mountainous terrain to appear at the high elevations (within the
  //    ridges.)  To do this, this noise module selects the output value from
  //    the added-high-mountainous-terrain module if the output value from the
  //    mountain-base-definition subgroup is higher than a set amount.
  //    Otherwise, this noise module selects the output value from the scaled-
  //    low-mountainous-terrain module.
  module::Select mountainousTerrain_se;
  mountainousTerrain_se.SetSourceModule (0, mountainousTerrain_sb0);
  mountainousTerrain_se.SetSourceModule (1, mountainousTerrain_ad);
  mountainousTerrain_se.SetControlModule (mountainBaseDef);
  mountainousTerrain_se.SetBounds (-0.5, 999.5);
  mountainousTerrain_se.SetEdgeFalloff (0.5);

  // 5: [Scaled-mountainous-terrain-module]: This scale/bias module slightly
  //    reduces the range of the output value from the combined-mountainous-
  //    terrain module, decreasing the heights of the mountain peaks.
  module::ScaleBias mountainousTerrain_sb2;
  mountainousTerrain_sb2.SetSourceModule (0, mountainousTerrain_se);
  mountainousTerrain_sb2.SetScale (0.8);
  mountainousTerrain_sb2.SetBias (0.0);

  // 6: [Glaciated-mountainous-terrain-module]: This exponential-curve module
  //    applies an exponential curve to the output value from the scaled-
  //    mountainous-terrain module.  This causes the slope of the mountains to
  //    smoothly increase towards higher elevations, as if a glacier grinded
  //    out those mountains.  This exponential-curve module expects the output
  //    value to range from -1.0 to +1.0.
  module::Exponent mountainousTerrain_ex;
  mountainousTerrain_ex.SetSourceModule (0, mountainousTerrain_sb2);
  mountainousTerrain_ex.SetExponent (MOUNTAIN_GLACIATION);

  // 7: [Mountainous-terrain group]: Caches the output value from the
  //    glaciated-mountainous-terrain module.  This is the output value for
  //    the entire mountainous-terrain group.
  module::Cache mountainousTerrain;
  mountainousTerrain.SetSourceModule (0, mountainousTerrain_ex);


  ////////////////////////////////////////////////////////////////////////////
  // Module group: hilly terrain
  ////////////////////////////////////////////////////////////////////////////

  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: hilly terrain (11 noise modules)
  //
  // This subgroup generates the hilly terrain.
  //
  // -1.0 represents the lowest elevations and +1.0 represents the highest
  // elevations.
  //

  // 1: [Hills module]: This billow-noise module generates the hills.
  module::Billow hillyTerrain_bi;
  hillyTerrain_bi.SetSeed (CUR_SEED + 60);
  hillyTerrain_bi.SetFrequency (1663.0);
  hillyTerrain_bi.SetPersistence (0.5);
  hillyTerrain_bi.SetLacunarity (HILLS_LACUNARITY);
  hillyTerrain_bi.SetOctaveCount (6);
  hillyTerrain_bi.SetNoiseQuality (QUALITY_BEST);

  // 2: [Scaled-hills module]: Next, a scale/bias module scales the output
  //    value from the hills module so that its hilltops are not too high.
  //    The reason for this is that these hills are eventually added to the
  //    river valleys (see below.)
  module::ScaleBias hillyTerrain_sb0;
  hillyTerrain_sb0.SetSourceModule (0, hillyTerrain_bi);
  hillyTerrain_sb0.SetScale (0.5);
  hillyTerrain_sb0.SetBias (0.5);

  // 3: [River-valley module]: This ridged-multifractal-noise module generates
  //    the river valleys.  It has a much lower frequency so that more hills
  //    will appear in between the valleys.  Note that this noise module
  //    generates ridged-multifractal noise using only one octave; this
  //    information will be important in the next step.
  module::RidgedMulti hillyTerrain_rm;
  hillyTerrain_rm.SetSeed (CUR_SEED + 61);
  hillyTerrain_rm.SetFrequency (367.5);
  hillyTerrain_rm.SetLacunarity (HILLS_LACUNARITY);
  hillyTerrain_rm.SetNoiseQuality (QUALITY_BEST);
  hillyTerrain_rm.SetOctaveCount (1);

  // 4: [Scaled-river-valley module]: Next, a scale/bias module applies a
  //    scaling factor of -2.0 to the output value from the river-valley
  //    module.  This stretches the possible elevation values because one-
  //    octave ridged-multifractal noise has a lower range of output values
  //    than multiple-octave ridged-multifractal noise.  The negative scaling
  //    factor inverts the range of the output value, turning the ridges from
  //    the river-valley module into valleys.
  module::ScaleBias hillyTerrain_sb1;
  hillyTerrain_sb1.SetSourceModule (0, hillyTerrain_rm);
  hillyTerrain_sb1.SetScale (-2.0);
  hillyTerrain_sb1.SetBias (-0.5);

  // 5: [Low-flat module]: This low constant value is used by step 6.
  module::Const hillyTerrain_co;
  hillyTerrain_co.SetConstValue (-1.0);

  // 6: [Mountains-and-valleys module]: This blender module merges the
  //    scaled-hills module and the scaled-river-valley module together.  It
  //    causes the low-lying areas of the terrain to become smooth, and causes
  //    the high-lying areas of the terrain to contain hills.  To do this, it
  //    uses the scaled-hills module as the control module, causing the low-
  //    flat module to appear in the lower areas and causing the scaled-river-
  //    valley module to appear in the higher areas.
  module::Blend hillyTerrain_bl;
  hillyTerrain_bl.SetSourceModule (0, hillyTerrain_co);
  hillyTerrain_bl.SetSourceModule (1, hillyTerrain_sb1);
  hillyTerrain_bl.SetControlModule (hillyTerrain_sb0);

  // 7: [Scaled-hills-and-valleys module]: This scale/bias module slightly
  //    reduces the range of the output value from the hills-and-valleys
  //    module, decreasing the heights of the hilltops.
  module::ScaleBias hillyTerrain_sb2;
  hillyTerrain_sb2.SetSourceModule (0, hillyTerrain_bl);
  hillyTerrain_sb2.SetScale (0.75);
  hillyTerrain_sb2.SetBias (-0.25);

  // 8: [Increased-slope-hilly-terrain module]: To increase the hill slopes at
  //    higher elevations, this exponential-curve module applies an
  //    exponential curve to the output value the scaled-hills-and-valleys
  //    module.  This exponential-curve module expects the input value to
  //    range from -1.0 to 1.0.
  module::Exponent hillyTerrain_ex;
  hillyTerrain_ex.SetSourceModule (0, hillyTerrain_sb2);
  hillyTerrain_ex.SetExponent (1.375);

  // 9: [Coarse-turbulence module]: This turbulence module warps the output
  //    value from the increased-slope-hilly-terrain module, adding some
  //    coarse detail to it.
  module::Turbulence hillyTerrain_tu0;
  hillyTerrain_tu0.SetSourceModule (0, hillyTerrain_ex);
  hillyTerrain_tu0.SetSeed (CUR_SEED + 62);
  hillyTerrain_tu0.SetFrequency (1531.0);
  hillyTerrain_tu0.SetPower (1.0 / 16921.0 * HILLS_TWIST);
  hillyTerrain_tu0.SetRoughness (4);

  // 10: [Warped-hilly-terrain module]: This turbulence module warps the
  //     output value from the coarse-turbulence module.  This turbulence has
  //     a higher frequency, but lower power, than the coarse-turbulence
  //     module, adding some fine detail to it.
  module::Turbulence hillyTerrain_tu1;
  hillyTerrain_tu1.SetSourceModule (0, hillyTerrain_tu0);
  hillyTerrain_tu1.SetSeed (CUR_SEED + 63);
  hillyTerrain_tu1.SetFrequency (21617.0);
  hillyTerrain_tu1.SetPower (1.0 / 117529.0 * HILLS_TWIST);
  hillyTerrain_tu1.SetRoughness (6);

  // 11: [Hilly-terrain group]: Caches the output value from the warped-hilly-
  //     terrain module.  This is the output value for the entire hilly-
  //     terrain group.
  module::Cache hillyTerrain;
  hillyTerrain.SetSourceModule (0, hillyTerrain_tu1);


  ////////////////////////////////////////////////////////////////////////////
  // Module group: plains terrain
  ////////////////////////////////////////////////////////////////////////////

  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: plains terrain (7 noise modules)
  //
  // This subgroup generates the plains terrain.
  //
  // Because this subgroup will eventually be flattened considerably, the
  // types and combinations of noise modules that generate the plains are not
  // really that important; they only need to "look" interesting.
  //
  // -1.0 represents the lowest elevations and +1.0 represents the highest
  // elevations.
  //

  // 1: [Plains-basis-0 module]: This billow-noise module, along with the
  //    plains-basis-1 module, produces the plains.
  module::Billow plainsTerrain_bi0;
  plainsTerrain_bi0.SetSeed (CUR_SEED + 70);
  plainsTerrain_bi0.SetFrequency (1097.5);
  plainsTerrain_bi0.SetPersistence (0.5);
  plainsTerrain_bi0.SetLacunarity (PLAINS_LACUNARITY);
  plainsTerrain_bi0.SetOctaveCount (8);
  plainsTerrain_bi0.SetNoiseQuality (QUALITY_BEST);

  // 2: [Positive-plains-basis-0 module]: This scale/bias module makes the
  //    output value from the plains-basis-0 module positive since this output
  //    value will be multiplied together with the positive-plains-basis-1
  //    module.
  module::ScaleBias plainsTerrain_sb0;
  plainsTerrain_sb0.SetSourceModule (0, plainsTerrain_bi0);
  plainsTerrain_sb0.SetScale (0.5);
  plainsTerrain_sb0.SetBias (0.5);

  // 3: [Plains-basis-1 module]: This billow-noise module, along with the
  //    plains-basis-2 module, produces the plains.
  module::Billow plainsTerrain_bi1;
  plainsTerrain_bi1.SetSeed (CUR_SEED + 71);
  plainsTerrain_bi1.SetFrequency (1319.5);
  plainsTerrain_bi1.SetPersistence (0.5);
  plainsTerrain_bi1.SetLacunarity (PLAINS_LACUNARITY);
  plainsTerrain_bi1.SetOctaveCount (8);
  plainsTerrain_bi1.SetNoiseQuality (QUALITY_BEST);

  // 4: [Positive-plains-basis-1 module]: This scale/bias module makes the
  //    output value from the plains-basis-1 module positive since this output
  //    value will be multiplied together with the positive-plains-basis-0
  //    module.
  module::ScaleBias plainsTerrain_sb1;
  plainsTerrain_sb1.SetSourceModule (0, plainsTerrain_bi1);
  plainsTerrain_sb1.SetScale (0.5);
  plainsTerrain_sb1.SetBias (0.5);

  // 5: [Combined-plains-basis module]: This multiplication module combines
  //    the two plains basis modules together.
  module::Multiply plainsTerrain_mu;
  plainsTerrain_mu.SetSourceModule (0, plainsTerrain_sb0);
  plainsTerrain_mu.SetSourceModule (1, plainsTerrain_sb1);

  // 6: [Rescaled-plains-basis module]: This scale/bias module maps the output
  //    value that ranges from 0.0 to 1.0 back to a value that ranges from
  //    -1.0 to +1.0.
  module::ScaleBias plainsTerrain_sb2;
  plainsTerrain_sb2.SetSourceModule (0, plainsTerrain_mu);
  plainsTerrain_sb2.SetScale (2.0);
  plainsTerrain_sb2.SetBias (-1.0);

  // 7: [Plains-terrain group]: Caches the output value from the rescaled-
  //    plains-basis module.  This is the output value for the entire plains-
  //    terrain group.
  module::Cache plainsTerrain;
  plainsTerrain.SetSourceModule (0, plainsTerrain_sb2);


  ////////////////////////////////////////////////////////////////////////////
  // Module group: badlands terrain
  ////////////////////////////////////////////////////////////////////////////

  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: badlands sand (6 noise modules)
  //
  // This subgroup generates the sandy terrain for the badlands.
  //
  // -1.0 represents the lowest elevations and +1.0 represents the highest
  // elevations.
  //

  // 1: [Sand-dunes module]: This ridged-multifractal-noise module generates
  //    sand dunes.  This ridged-multifractal noise is generated with a single
  //    octave, which makes very smooth dunes.
  module::RidgedMulti badlandsSand_rm;
  badlandsSand_rm.SetSeed (CUR_SEED + 80);
  badlandsSand_rm.SetFrequency (6163.5);
  badlandsSand_rm.SetLacunarity (BADLANDS_LACUNARITY);
  badlandsSand_rm.SetNoiseQuality (QUALITY_BEST);
  badlandsSand_rm.SetOctaveCount (1);

  // 2: [Scaled-sand-dunes module]: This scale/bias module shrinks the dune
  //    heights by a small amount.  This is necessary so that the subsequent
  //    noise modules in this subgroup can add some detail to the dunes.
  module::ScaleBias badlandsSand_sb0;
  badlandsSand_sb0.SetSourceModule (0, badlandsSand_rm);
  badlandsSand_sb0.SetScale (0.875);
  badlandsSand_sb0.SetBias (0.0);

  // 3: [Dune-detail module]: This noise module uses Voronoi polygons to
  //    generate the detail to add to the dunes.  By enabling the distance
  //    algorithm, small polygonal pits are generated; the edges of the pits
  //    are joined to the edges of nearby pits.
  module::Voronoi badlandsSand_vo;
  badlandsSand_vo.SetSeed (CUR_SEED + 81);
  badlandsSand_vo.SetFrequency (16183.25);
  badlandsSand_vo.SetDisplacement (0.0);
  badlandsSand_vo.EnableDistance ();

  // 4: [Scaled-dune-detail module]: This scale/bias module shrinks the dune
  //    details by a large amount.  This is necessary so that the subsequent
  //    noise modules in this subgroup can add this detail to the sand-dunes
  //    module.
  module::ScaleBias badlandsSand_sb1;
  badlandsSand_sb1.SetSourceModule (0, badlandsSand_vo);
  badlandsSand_sb1.SetScale (0.25);
  badlandsSand_sb1.SetBias (0.25);

  // 5: [Dunes-with-detail module]: This addition module combines the scaled-
  //    sand-dunes module with the scaled-dune-detail module.
  module::Add badlandsSand_ad;
  badlandsSand_ad.SetSourceModule (0, badlandsSand_sb0);
  badlandsSand_ad.SetSourceModule (1, badlandsSand_sb1);

  // 6: [Badlands-sand subgroup]: Caches the output value from the dunes-with-
  //    detail module.
  module::Cache badlandsSand;
  badlandsSand.SetSourceModule (0, badlandsSand_ad);


  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: badlands cliffs (7 noise modules)
  //
  // This subgroup generates the cliffs for the badlands.
  //
  // -1.0 represents the lowest elevations and +1.0 represents the highest
  // elevations.
  //

  // 1: [Cliff-basis module]: This Perlin-noise module generates some coherent
  //    noise that will be used to generate the cliffs.
  module::Perlin badlandsCliffs_pe;
  badlandsCliffs_pe.SetSeed (CUR_SEED + 90);
  badlandsCliffs_pe.SetFrequency (CONTINENT_FREQUENCY * 839.0);
  badlandsCliffs_pe.SetPersistence (0.5);
  badlandsCliffs_pe.SetLacunarity (BADLANDS_LACUNARITY);
  badlandsCliffs_pe.SetOctaveCount (6);
  badlandsCliffs_pe.SetNoiseQuality (QUALITY_STD);

  // 2: [Cliff-shaping module]: Next, this curve module applies a curve to the
  //    output value from the cliff-basis module.  This curve is initially
  //    very shallow, but then its slope increases sharply.  At the highest
  //    elevations, the curve becomes very flat again.  This produces the
  //    stereotypical Utah-style desert cliffs.
  module::Curve badlandsCliffs_cu;
  badlandsCliffs_cu.SetSourceModule (0, badlandsCliffs_pe);
  badlandsCliffs_cu.AddControlPoint (-2.0000, -2.0000);
  badlandsCliffs_cu.AddControlPoint (-1.0000, -1.2500);
  badlandsCliffs_cu.AddControlPoint (-0.0000, -0.7500);
  badlandsCliffs_cu.AddControlPoint ( 0.5000, -0.2500);
  badlandsCliffs_cu.AddControlPoint ( 0.6250,  0.8750);
  badlandsCliffs_cu.AddControlPoint ( 0.7500,  1.0000);
  badlandsCliffs_cu.AddControlPoint ( 2.0000,  1.2500);

  // 3: [Clamped-cliffs module]: This clamping module makes the tops of the
  //    cliffs very flat by clamping the output value from the cliff-shaping
  //    module so that the tops of the cliffs are very flat.
  module::Clamp badlandsCliffs_cl;
  badlandsCliffs_cl.SetSourceModule (0, badlandsCliffs_cu);
  badlandsCliffs_cl.SetBounds (-999.125, 0.875);

  // 4: [Terraced-cliffs module]: Next, this terracing module applies some
  //    terraces to the clamped-cliffs module in the lower elevations before
  //    the sharp cliff transition.
  module::Terrace badlandsCliffs_te;
  badlandsCliffs_te.SetSourceModule (0, badlandsCliffs_cl);
  badlandsCliffs_te.AddControlPoint (-1.0000);
  badlandsCliffs_te.AddControlPoint (-0.8750);
  badlandsCliffs_te.AddControlPoint (-0.7500);
  badlandsCliffs_te.AddControlPoint (-0.5000);
  badlandsCliffs_te.AddControlPoint ( 0.0000);
  badlandsCliffs_te.AddControlPoint ( 1.0000);

  // 5: [Coarse-turbulence module]: This turbulence module warps the output
  //    value from the terraced-cliffs module, adding some coarse detail to
  //    it.
  module::Turbulence badlandsCliffs_tu0;
  badlandsCliffs_tu0.SetSeed (CUR_SEED + 91);
  badlandsCliffs_tu0.SetSourceModule (0, badlandsCliffs_te);
  badlandsCliffs_tu0.SetFrequency (16111.0);
  badlandsCliffs_tu0.SetPower (1.0 / 141539.0 * BADLANDS_TWIST);
  badlandsCliffs_tu0.SetRoughness (3);

  // 6: [Warped-cliffs module]: This turbulence module warps the output value
  //    from the coarse-turbulence module.  This turbulence has a higher
  //    frequency, but lower power, than the coarse-turbulence module, adding
  //    some fine detail to it.
  module::Turbulence badlandsCliffs_tu1;
  badlandsCliffs_tu1.SetSeed (CUR_SEED + 92);
  badlandsCliffs_tu1.SetSourceModule (0, badlandsCliffs_tu0);
  badlandsCliffs_tu1.SetFrequency (36107.0);
  badlandsCliffs_tu1.SetPower (1.0 / 211543.0 * BADLANDS_TWIST);
  badlandsCliffs_tu1.SetRoughness (3);

  // 7: [Badlands-cliffs subgroup]: Caches the output value from the warped-
  //    cliffs module.
  module::Cache badlandsCliffs;
  badlandsCliffs.SetSourceModule (0, badlandsCliffs_tu1);


  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: badlands terrain (3 noise modules)
  //
  // Generates the final badlands terrain.
  //
  // Using a scale/bias module, the badlands sand is flattened considerably,
  // then the sand elevations are lowered to around -1.0.  The maximum value
  // from the flattened sand module and the cliff module contributes to the
  // final elevation.  This causes sand to appear at the low elevations since
  // the sand is slightly higher than the cliff base.
  //
  // -1.0 represents the lowest elevations and +1.0 represents the highest
  // elevations.
  //

  // 1: [Scaled-sand-dunes module]: This scale/bias module considerably
  //    flattens the output value from the badlands-sands subgroup and lowers
  //    this value to near -1.0.
  module::ScaleBias badlandsTerrain_sb;
  badlandsTerrain_sb.SetSourceModule (0, badlandsSand);
  badlandsTerrain_sb.SetScale (0.25);
  badlandsTerrain_sb.SetBias (-0.75);

  // 2: [Dunes-and-cliffs module]: This maximum-value module causes the dunes
  //    to appear in the low areas and the cliffs to appear in the high areas.
  //    It does this by selecting the maximum of the output values from the
  //    scaled-sand-dunes module and the badlands-cliffs subgroup.
  module::Max badlandsTerrain_ma;
  badlandsTerrain_ma.SetSourceModule (0, badlandsCliffs);
  badlandsTerrain_ma.SetSourceModule (1, badlandsTerrain_sb);

  // 3: [Badlands-terrain group]: Caches the output value from the dunes-and-
  //    cliffs module.  This is the output value for the entire badlands-
  //    terrain group.
  module::Cache badlandsTerrain;
  badlandsTerrain.SetSourceModule (0, badlandsTerrain_ma);


  ////////////////////////////////////////////////////////////////////////////
  // Module group: river positions
  ////////////////////////////////////////////////////////////////////////////

  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: river positions (7 noise modules)
  //
  // This subgroup generates the river positions.
  //
  // -1.0 represents the lowest elevations and +1.0 represents the highest
  // elevations.
  //

  // 1: [Large-river-basis module]: This ridged-multifractal-noise module
  //    creates the large, deep rivers.
  module::RidgedMulti riverPositions_rm0;
  riverPositions_rm0.SetSeed (CUR_SEED + 100);
  riverPositions_rm0.SetFrequency (18.75);
  riverPositions_rm0.SetLacunarity (CONTINENT_LACUNARITY);
  riverPositions_rm0.SetOctaveCount (1);
  riverPositions_rm0.SetNoiseQuality (QUALITY_BEST);

  // 2: [Large-river-curve module]: This curve module applies a curve to the
  //    output value from the large-river-basis module so that the ridges
  //    become inverted.  This creates the rivers.  This curve also compresses
  //    the edge of the rivers, producing a sharp transition from the land to
  //    the river bottom.
  module::Curve riverPositions_cu0;
  riverPositions_cu0.SetSourceModule (0, riverPositions_rm0);
  riverPositions_cu0.AddControlPoint (-2.000,  2.000);
  riverPositions_cu0.AddControlPoint (-1.000,  1.000);
  riverPositions_cu0.AddControlPoint (-0.125,  0.875);
  riverPositions_cu0.AddControlPoint ( 0.000, -1.000);
  riverPositions_cu0.AddControlPoint ( 1.000, -1.500);
  riverPositions_cu0.AddControlPoint ( 2.000, -2.000);

  /// 3: [Small-river-basis module]: This ridged-multifractal-noise module
  //     creates the small, shallow rivers.
  module::RidgedMulti riverPositions_rm1;
  riverPositions_rm1.SetSeed (CUR_SEED + 101);
  riverPositions_rm1.SetFrequency (43.25);
  riverPositions_rm1.SetLacunarity (CONTINENT_LACUNARITY);
  riverPositions_rm1.SetOctaveCount (1);
  riverPositions_rm1.SetNoiseQuality (QUALITY_BEST);

  // 4: [Small-river-curve module]: This curve module applies a curve to the
  //    output value from the small-river-basis module so that the ridges
  //    become inverted.  This creates the rivers.  This curve also compresses
  //    the edge of the rivers, producing a sharp transition from the land to
  //    the river bottom.
  module::Curve riverPositions_cu1;
  riverPositions_cu1.SetSourceModule (0, riverPositions_rm1);
  riverPositions_cu1.AddControlPoint (-2.000,  2.0000);
  riverPositions_cu1.AddControlPoint (-1.000,  1.5000);
  riverPositions_cu1.AddControlPoint (-0.125,  1.4375);
  riverPositions_cu1.AddControlPoint ( 0.000,  0.5000);
  riverPositions_cu1.AddControlPoint ( 1.000,  0.2500);
  riverPositions_cu1.AddControlPoint ( 2.000,  0.0000);

  // 5: [Combined-rivers module]: This minimum-value module causes the small
  //    rivers to cut into the large rivers.  It does this by selecting the
  //    minimum output values from the large-river-curve module and the small-
  //    river-curve module.
  module::Min riverPositions_mi;
  riverPositions_mi.SetSourceModule (0, riverPositions_cu0);
  riverPositions_mi.SetSourceModule (1, riverPositions_cu1);

  // 6: [Warped-rivers module]: This turbulence module warps the output value
  //    from the combined-rivers module, which twists the rivers.  The high
  //    roughness produces less-smooth rivers.
  module::Turbulence riverPositions_tu;
  riverPositions_tu.SetSourceModule (0, riverPositions_mi);
  riverPositions_tu.SetSeed (CUR_SEED + 102);
  riverPositions_tu.SetFrequency (9.25);
  riverPositions_tu.SetPower (1.0 / 57.75);
  riverPositions_tu.SetRoughness (6);

  // 7: [River-positions group]: Caches the output value from the warped-
  //    rivers module.  This is the output value for the entire river-
  //    positions group.
  module::Cache riverPositions;
  riverPositions.SetSourceModule (0, riverPositions_tu);


  ////////////////////////////////////////////////////////////////////////////
  // Module group: scaled mountainous terrain
  ////////////////////////////////////////////////////////////////////////////

  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: scaled mountainous terrain (6 noise modules)
  //
  // This subgroup scales the output value from the mountainous-terrain group
  // so that it can be added to the elevation defined by the continent-
  // definition group.
  //
  // This subgroup scales the output value such that it is almost always
  // positive.  This is done so that a negative elevation does not get applied
  // to the continent-definition group, preventing parts of that group from
  // having negative terrain features "stamped" into it.
  //
  // The output value from this module subgroup is measured in planetary
  // elevation units (-1.0 for the lowest underwater trenches and +1.0 for the
  // highest mountain peaks.)
  //

  // 1: [Base-scaled-mountainous-terrain module]: This scale/bias module
  //    scales the output value from the mountainous-terrain group so that the
  //    output value is measured in planetary elevation units.
  module::ScaleBias scaledMountainousTerrain_sb0;
  scaledMountainousTerrain_sb0.SetSourceModule (0, mountainousTerrain);
  scaledMountainousTerrain_sb0.SetScale (0.125);
  scaledMountainousTerrain_sb0.SetBias (0.125);

  // 2: [Base-peak-modulation module]: At this stage, most mountain peaks have
  //    roughly the same elevation.  This Perlin-noise module generates some
  //    random values that will be used by subsequent noise modules to
  //    randomly change the elevations of the mountain peaks.
  module::Perlin scaledMountainousTerrain_pe;
  scaledMountainousTerrain_pe.SetSeed (CUR_SEED + 110);
  scaledMountainousTerrain_pe.SetFrequency (14.5);
  scaledMountainousTerrain_pe.SetPersistence (0.5);
  scaledMountainousTerrain_pe.SetLacunarity (MOUNTAIN_LACUNARITY);
  scaledMountainousTerrain_pe.SetOctaveCount (6);
  scaledMountainousTerrain_pe.SetNoiseQuality (QUALITY_STD);

  // 3: [Peak-modulation module]: This exponential-curve module applies an
  //    exponential curve to the output value from the base-peak-modulation
  //    module.  This produces a small number of high values and a much larger
  //    number of low values.  This means there will be a few peaks with much
  //    higher elevations than the majority of the peaks, making the terrain
  //    features more varied.
  module::Exponent scaledMountainousTerrain_ex;
  scaledMountainousTerrain_ex.SetSourceModule (0, scaledMountainousTerrain_pe);
  scaledMountainousTerrain_ex.SetExponent (1.25);

  // 4: [Scaled-peak-modulation module]: This scale/bias module modifies the
  //    range of the output value from the peak-modulation module so that it
  //    can be used as the modulator for the peak-height-multiplier module.
  //    It is important that this output value is not much lower than 1.0.
  module::ScaleBias scaledMountainousTerrain_sb1;
  scaledMountainousTerrain_sb1.SetSourceModule (0,
    scaledMountainousTerrain_ex);
  scaledMountainousTerrain_sb1.SetScale (0.25);
  scaledMountainousTerrain_sb1.SetBias (1.0);

  // 5: [Peak-height-multiplier module]: This multiplier module modulates the
  //    heights of the mountain peaks from the base-scaled-mountainous-terrain
  //    module using the output value from the scaled-peak-modulation module.
  module::Multiply scaledMountainousTerrain_mu;
  scaledMountainousTerrain_mu.SetSourceModule (0,
    scaledMountainousTerrain_sb0);
  scaledMountainousTerrain_mu.SetSourceModule (1,
    scaledMountainousTerrain_sb1);

  // 6: [Scaled-mountainous-terrain group]: Caches the output value from the
  //    peak-height-multiplier module.  This is the output value for the
  //    entire scaled-mountainous-terrain group.
  module::Cache scaledMountainousTerrain;
  scaledMountainousTerrain.SetSourceModule (0, scaledMountainousTerrain_mu);


  ////////////////////////////////////////////////////////////////////////////
  // Module group: scaled hilly terrain
  ////////////////////////////////////////////////////////////////////////////

  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: scaled hilly terrain (6 noise modules)
  //
  // This subgroup scales the output value from the hilly-terrain group so
  // that it can be added to the elevation defined by the continent-
  // definition group.  The scaling amount applied to the hills is one half of
  // the scaling amount applied to the scaled-mountainous-terrain group.
  //
  // This subgroup scales the output value such that it is almost always
  // positive.  This is done so that negative elevations are not applied to
  // the continent-definition group, preventing parts of the continent-
  // definition group from having negative terrain features "stamped" into it.
  //
  // The output value from this module subgroup is measured in planetary
  // elevation units (-1.0 for the lowest underwater trenches and +1.0 for the
  // highest mountain peaks.)
  //

  // 1: [Base-scaled-hilly-terrain module]: This scale/bias module scales the
  //    output value from the hilly-terrain group so that this output value is
  //    measured in planetary elevation units 
  module::ScaleBias scaledHillyTerrain_sb0;
  scaledHillyTerrain_sb0.SetSourceModule (0, hillyTerrain);
  scaledHillyTerrain_sb0.SetScale (0.0625);
  scaledHillyTerrain_sb0.SetBias (0.0625);

  // 2: [Base-hilltop-modulation module]: At this stage, most hilltops have
  //    roughly the same elevation.  This Perlin-noise module generates some
  //    random values that will be used by subsequent noise modules to
  //    randomly change the elevations of the hilltops.
  module::Perlin scaledHillyTerrain_pe;
  scaledHillyTerrain_pe.SetSeed (CUR_SEED + 120);
  scaledHillyTerrain_pe.SetFrequency (13.5);
  scaledHillyTerrain_pe.SetPersistence (0.5);
  scaledHillyTerrain_pe.SetLacunarity (HILLS_LACUNARITY);
  scaledHillyTerrain_pe.SetOctaveCount (6);
  scaledHillyTerrain_pe.SetNoiseQuality (QUALITY_STD);

  // 3: [Hilltop-modulation module]: This exponential-curve module applies an
  //    exponential curve to the output value from the base-hilltop-modulation
  //    module.  This produces a small number of high values and a much larger
  //    number of low values.  This means there will be a few hilltops with
  //    much higher elevations than the majority of the hilltops, making the
  //    terrain features more varied.
  module::Exponent scaledHillyTerrain_ex;
  scaledHillyTerrain_ex.SetSourceModule (0, scaledHillyTerrain_pe);
  scaledHillyTerrain_ex.SetExponent (1.25);

  // 4: [Scaled-hilltop-modulation module]: This scale/bias module modifies
  //    the range of the output value from the hilltop-modulation module so
  //    that it can be used as the modulator for the hilltop-height-multiplier
  //    module.  It is important that this output value is not much lower than
  //    1.0.
  module::ScaleBias scaledHillyTerrain_sb1;
  scaledHillyTerrain_sb1.SetSourceModule (0, scaledHillyTerrain_ex);
  scaledHillyTerrain_sb1.SetScale (0.5);
  scaledHillyTerrain_sb1.SetBias (1.5);

  // 5: [Hilltop-height-multiplier module]: This multiplier module modulates
  //    the heights of the hilltops from the base-scaled-hilly-terrain module
  //    using the output value from the scaled-hilltop-modulation module.
  module::Multiply scaledHillyTerrain_mu;
  scaledHillyTerrain_mu.SetSourceModule (0, scaledHillyTerrain_sb0);
  scaledHillyTerrain_mu.SetSourceModule (1, scaledHillyTerrain_sb1);

  // 6: [Scaled-hilly-terrain group]: Caches the output value from the
  //    hilltop-height-multiplier module.  This is the output value for the
  //    entire scaled-hilly-terrain group.
  module::Cache scaledHillyTerrain;
  scaledHillyTerrain.SetSourceModule (0, scaledHillyTerrain_mu);


  ////////////////////////////////////////////////////////////////////////////
  // Module group: scaled plains terrain
  ////////////////////////////////////////////////////////////////////////////

  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: scaled plains terrain (2 noise modules)
  //
  // This subgroup scales the output value from the plains-terrain group so
  // that it can be added to the elevations defined by the continent-
  // definition group.
  //
  // This subgroup scales the output value such that it is almost always
  // positive.  This is done so that negative elevations are not applied to
  // the continent-definition group, preventing parts of the continent-
  // definition group from having negative terrain features "stamped" into it.
  //
  // The output value from this module subgroup is measured in planetary
  // elevation units (-1.0 for the lowest underwater trenches and +1.0 for the
  // highest mountain peaks.)
  //

  // 1: [Scaled-plains-terrain module]: This scale/bias module greatly
  //    flattens the output value from the plains terrain.  This output value
  //    is measured in planetary elevation units 
  module::ScaleBias scaledPlainsTerrain_sb;
  scaledPlainsTerrain_sb.SetSourceModule (0, plainsTerrain);
  scaledPlainsTerrain_sb.SetScale (0.00390625);
  scaledPlainsTerrain_sb.SetBias (0.0078125);

  // 2: [Scaled-plains-terrain group]: Caches the output value from the
  //    scaled-plains-terrain module.  This is the output value for the entire
  //    scaled-plains-terrain group.
  module::Cache scaledPlainsTerrain;
  scaledPlainsTerrain.SetSourceModule (0, scaledPlainsTerrain_sb);


  ////////////////////////////////////////////////////////////////////////////
  // Module group: scaled badlands terrain
  ////////////////////////////////////////////////////////////////////////////

  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: scaled badlands terrain (2 noise modules)
  //
  // This subgroup scales the output value from the badlands-terrain group so
  // that it can be added to the elevations defined by the continent-
  // definition group.
  //
  // This subgroup scales the output value such that it is almost always
  // positive.  This is done so that negative elevations are not applied to
  // the continent-definition group, preventing parts of the continent-
  // definition group from having negative terrain features "stamped" into it.
  //
  // The output value from this module subgroup is measured in planetary
  // elevation units (-1.0 for the lowest underwater trenches and +1.0 for the
  // highest mountain peaks.)
  //

  // 1: [Scaled-badlands-terrain module]: This scale/bias module scales the
  //    output value from the badlands-terrain group so that it is measured
  //    in planetary elevation units 
  module::ScaleBias scaledBadlandsTerrain_sb;
  scaledBadlandsTerrain_sb.SetSourceModule (0, badlandsTerrain);
  scaledBadlandsTerrain_sb.SetScale (0.0625);
  scaledBadlandsTerrain_sb.SetBias (0.0625);

  // 2: [Scaled-badlands-terrain group]: Caches the output value from the
  //    scaled-badlands-terrain module.  This is the output value for the
  //    entire scaled-badlands-terrain group.
  module::Cache scaledBadlandsTerrain;
  scaledBadlandsTerrain.SetSourceModule (0, scaledBadlandsTerrain_sb);


  ////////////////////////////////////////////////////////////////////////////
  // Module group: final planet
  ////////////////////////////////////////////////////////////////////////////

  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: continental shelf (6 noise modules)
  //
  // This module subgroup creates the continental shelves.
  //
  // The output value from this module subgroup are measured in planetary
  // elevation units (-1.0 for the lowest underwater trenches and +1.0 for the
  // highest mountain peaks.)
  //

  // 1: [Shelf-creator module]: This terracing module applies a terracing
  //    curve to the continent-definition group at the specified shelf level.
  //    This terrace becomes the continental shelf.  Note that this terracing
  //    module also places another terrace below the continental shelf near
  //    -1.0.  The bottom of this terrace is defined as the bottom of the
  //    ocean; subsequent noise modules will later add oceanic trenches to the
  //    bottom of the ocean.
  module::Terrace continentalShelf_te;
  continentalShelf_te.SetSourceModule (0, continentDef);
  continentalShelf_te.AddControlPoint (-1.0);
  continentalShelf_te.AddControlPoint (-0.75);
  continentalShelf_te.AddControlPoint (SHELF_LEVEL);
  continentalShelf_te.AddControlPoint (1.0);

  // 2: [Oceanic-trench-basis module]: This ridged-multifractal-noise module
  //    generates some coherent noise that will be used to generate the
  //    oceanic trenches.  The ridges represent the bottom of the trenches.
  module::RidgedMulti continentalShelf_rm;
  continentalShelf_rm.SetSeed (CUR_SEED + 130);
  continentalShelf_rm.SetFrequency (CONTINENT_FREQUENCY * 4.375);
  continentalShelf_rm.SetLacunarity (CONTINENT_LACUNARITY);
  continentalShelf_rm.SetOctaveCount (16);
  continentalShelf_rm.SetNoiseQuality (QUALITY_BEST);

  // 3: [Oceanic-trench module]: This scale/bias module inverts the ridges
  //    from the oceanic-trench-basis-module so that the ridges become
  //    trenches.  This noise module also reduces the depth of the trenches so
  //    that their depths are measured in planetary elevation units.
  module::ScaleBias continentalShelf_sb;
  continentalShelf_sb.SetSourceModule (0, continentalShelf_rm);
  continentalShelf_sb.SetScale (-0.125);
  continentalShelf_sb.SetBias (-0.125);

  // 4: [Clamped-sea-bottom module]: This clamping module clamps the output
  //    value from the shelf-creator module so that its possible range is
  //    from the bottom of the ocean to sea level.  This is done because this
  //    subgroup is only concerned about the oceans.
  module::Clamp continentalShelf_cl;
  continentalShelf_cl.SetSourceModule (0, continentalShelf_te);
  continentalShelf_cl.SetBounds (-0.75, SEA_LEVEL);

  // 5: [Shelf-and-trenches module]: This addition module adds the oceanic
  //    trenches to the clamped-sea-bottom module.
  module::Add continentalShelf_ad;
  continentalShelf_ad.SetSourceModule (0, continentalShelf_sb);
  continentalShelf_ad.SetSourceModule (1, continentalShelf_cl);

  // 6: [Continental-shelf subgroup]: Caches the output value from the shelf-
  //    and-trenches module.
  module::Cache continentalShelf;
  continentalShelf.SetSourceModule (0, continentalShelf_ad);


  ////////////////////////////////////////////////////////////////////////////
  // Module group: base continent elevations (3 noise modules)
  //
  // This subgroup generates the base elevations for the continents, before
  // terrain features are added.
  //
  // The output value from this module subgroup is measured in planetary
  // elevation units (-1.0 for the lowest underwater trenches and +1.0 for the
  // highest mountain peaks.)
  //

  // 1: [Base-scaled-continent-elevations module]: This scale/bias module
  //    scales the output value from the continent-definition group so that it
  //    is measured in planetary elevation units 
  module::ScaleBias baseContinentElev_sb;
  baseContinentElev_sb.SetSourceModule (0, continentDef);
  baseContinentElev_sb.SetScale (CONTINENT_HEIGHT_SCALE);
  baseContinentElev_sb.SetBias (0.0);

  // 2: [Base-continent-with-oceans module]: This selector module applies the
  //    elevations of the continental shelves to the base elevations of the
  //    continent.  It does this by selecting the output value from the
  //    continental-shelf subgroup if the corresponding output value from the
  //    continent-definition group is below the shelf level.  Otherwise, it
  //    selects the output value from the base-scaled-continent-elevations
  //    module.
  module::Select baseContinentElev_se;
  baseContinentElev_se.SetSourceModule (0, baseContinentElev_sb);
  baseContinentElev_se.SetSourceModule (1, continentalShelf);
  baseContinentElev_se.SetControlModule (continentDef);
  baseContinentElev_se.SetBounds (SHELF_LEVEL - 1000.0, SHELF_LEVEL);
  baseContinentElev_se.SetEdgeFalloff (0.03125);

  // 3: [Base-continent-elevation subgroup]: Caches the output value from the
  //    base-continent-with-oceans module.
  module::Cache baseContinentElev;
  baseContinentElev.SetSourceModule (0, baseContinentElev_se);


  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: continents with plains (2 noise modules)
  //
  // This subgroup applies the scaled-plains-terrain group to the base-
  // continent-elevation subgroup.
  //
  // The output value from this module subgroup is measured in planetary
  // elevation units (-1.0 for the lowest underwater trenches and +1.0 for the
  // highest mountain peaks.)
  //

  // 1: [Continents-with-plains module]:  This addition module adds the
  //    scaled-plains-terrain group to the base-continent-elevation subgroup.
  module::Add continentsWithPlains_ad;
  continentsWithPlains_ad.SetSourceModule (0, baseContinentElev);
  continentsWithPlains_ad.SetSourceModule (1, scaledPlainsTerrain);

  // 2: [Continents-with-plains subgroup]: Caches the output value from the
  //    continents-with-plains module.
  module::Cache continentsWithPlains;
  continentsWithPlains.SetSourceModule (0, continentsWithPlains_ad);


  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: continents with hills (3 noise modules)
  //
  // This subgroup applies the scaled-hilly-terrain group to the continents-
  // with-plains subgroup.
  //
  // The output value from this module subgroup is measured in planetary
  // elevation units (-1.0 for the lowest underwater trenches and +1.0 for the
  // highest mountain peaks.)
  //

  // 1: [Continents-with-hills module]:  This addition module adds the scaled-
  //    hilly-terrain group to the base-continent-elevation subgroup.
  module::Add continentsWithHills_ad;
  continentsWithHills_ad.SetSourceModule (0, baseContinentElev);
  continentsWithHills_ad.SetSourceModule (1, scaledHillyTerrain);

  // 2: [Select-high-elevations module]: This selector module ensures that
  //    the hills only appear at higher elevations.  It does this by selecting
  //    the output value from the continent-with-hills module if the
  //    corresponding output value from the terrain-type-defintion group is
  //    above a certain value. Otherwise, it selects the output value from the
  //    continents-with-plains subgroup.
  module::Select continentsWithHills_se;
  continentsWithHills_se.SetSourceModule (0, continentsWithPlains);
  continentsWithHills_se.SetSourceModule (1, continentsWithHills_ad);
  continentsWithHills_se.SetControlModule (terrainTypeDef);
  continentsWithHills_se.SetBounds (1.0 - HILLS_AMOUNT, 1001.0 - HILLS_AMOUNT);
  continentsWithHills_se.SetEdgeFalloff (0.25);

  // 3: [Continents-with-hills subgroup]: Caches the output value from the
  //    select-high-elevations module.
  module::Cache continentsWithHills;
  continentsWithHills.SetSourceModule (0, continentsWithHills_se);


  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: continents with mountains (5 noise modules)
  //
  // This subgroup applies the scaled-mountainous-terrain group to the
  // continents-with-hills subgroup.
  //
  // The output value from this module subgroup is measured in planetary
  // elevation units (-1.0 for the lowest underwater trenches and +1.0 for the
  // highest mountain peaks.)
  //

  // 1: [Continents-and-mountains module]:  This addition module adds the
  //    scaled-mountainous-terrain group to the base-continent-elevation
  //    subgroup.
  module::Add continentsWithMountains_ad0;
  continentsWithMountains_ad0.SetSourceModule (0, baseContinentElev);
  continentsWithMountains_ad0.SetSourceModule (1, scaledMountainousTerrain);

  // 2: [Increase-mountain-heights module]:  This curve module applies a curve
  //    to the output value from the continent-definition group.  This
  //    modified output value is used by a subsequent noise module to add
  //    additional height to the mountains based on the current continent
  //    elevation.  The higher the continent elevation, the higher the
  //    mountains.
  module::Curve continentsWithMountains_cu;
  continentsWithMountains_cu.SetSourceModule (0, continentDef);
  continentsWithMountains_cu.AddControlPoint (                  -1.0, -0.0625);
  continentsWithMountains_cu.AddControlPoint (                   0.0,  0.0000);
  continentsWithMountains_cu.AddControlPoint (1.0 - MOUNTAINS_AMOUNT,  0.0625);
  continentsWithMountains_cu.AddControlPoint (                   1.0,  0.2500);

  // 3: [Add-increased-mountain-heights module]: This addition module adds
  //    the increased-mountain-heights module to the continents-and-
  //    mountains module.  The highest continent elevations now have the
  //    highest mountains.
  module::Add continentsWithMountains_ad1;
  continentsWithMountains_ad1.SetSourceModule (0, continentsWithMountains_ad0);
  continentsWithMountains_ad1.SetSourceModule (1, continentsWithMountains_cu);

  // 4: [Select-high-elevations module]: This selector module ensures that
  //    mountains only appear at higher elevations.  It does this by selecting
  //    the output value from the continent-with-mountains module if the
  //    corresponding output value from the terrain-type-defintion group is
  //    above a certain value.  Otherwise, it selects the output value from
  //    the continents-with-hills subgroup.  Note that the continents-with-
  //    hills subgroup also contains the plains terrain.
  module::Select continentsWithMountains_se;
  continentsWithMountains_se.SetSourceModule (0, continentsWithHills);
  continentsWithMountains_se.SetSourceModule (1, continentsWithMountains_ad1);
  continentsWithMountains_se.SetControlModule (terrainTypeDef);
  continentsWithMountains_se.SetBounds (1.0 - MOUNTAINS_AMOUNT,
    1001.0 - MOUNTAINS_AMOUNT);
  continentsWithMountains_se.SetEdgeFalloff (0.25);

  // 5: [Continents-with-mountains subgroup]: Caches the output value from
  //    the select-high-elevations module.
  module::Cache continentsWithMountains;
  continentsWithMountains.SetSourceModule (0, continentsWithMountains_se);


  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: continents with badlands (5 noise modules)
  //
  // This subgroup applies the scaled-badlands-terrain group to the
  // continents-with-mountains subgroup.
  //
  // The output value from this module subgroup is measured in planetary
  // elevation units (-1.0 for the lowest underwater trenches and +1.0 for the
  // highest mountain peaks.)
  //

  // 1: [Badlands-positions module]: This Perlin-noise module generates some
  //    random noise, which is used by subsequent noise modules to specify the
  //    locations of the badlands.
  module::Perlin continentsWithBadlands_pe;
  continentsWithBadlands_pe.SetSeed (CUR_SEED + 140);
  continentsWithBadlands_pe.SetFrequency (16.5);
  continentsWithBadlands_pe.SetPersistence (0.5);
  continentsWithBadlands_pe.SetLacunarity (CONTINENT_LACUNARITY);
  continentsWithBadlands_pe.SetOctaveCount (2);
  continentsWithBadlands_pe.SetNoiseQuality (QUALITY_STD);

  // 2: [Continents-and-badlands module]:  This addition module adds the
  //    scaled-badlands-terrain group to the base-continent-elevation
  //    subgroup.
  module::Add continentsWithBadlands_ad;
  continentsWithBadlands_ad.SetSourceModule (0, baseContinentElev);
  continentsWithBadlands_ad.SetSourceModule (1, scaledBadlandsTerrain);

  // 3: [Select-badlands-positions module]: This selector module places
  //    badlands at random spots on the continents based on the Perlin noise
  //    generated by the badlands-positions module.  To do this, it selects
  //    the output value from the continents-and-badlands module if the
  //    corresponding output value from the badlands-position module is
  //    greater than a specified value.  Otherwise, this selector module
  //    selects the output value from the continents-with-mountains subgroup.
  //    There is also a wide transition between these two noise modules so
  //    that the badlands can blend into the rest of the terrain on the
  //    continents.
  module::Select continentsWithBadlands_se;
  continentsWithBadlands_se.SetSourceModule (0, continentsWithMountains);
  continentsWithBadlands_se.SetSourceModule (1, continentsWithBadlands_ad);
  continentsWithBadlands_se.SetControlModule (continentsWithBadlands_pe);
  continentsWithBadlands_se.SetBounds (1.0 - BADLANDS_AMOUNT,
    1001.0 - BADLANDS_AMOUNT);
  continentsWithBadlands_se.SetEdgeFalloff (0.25);

  // 4: [Apply-badlands module]: This maximum-value module causes the badlands
  //    to "poke out" from the rest of the terrain.  It does this by ensuring
  //    that only the maximum of the output values from the continents-with-
  //    mountains subgroup and the select-badlands-positions modules
  //    contribute to the output value of this subgroup.  One side effect of
  //    this process is that the badlands will not appear in mountainous
  //    terrain.
  module::Max continentsWithBadlands_ma;
  continentsWithBadlands_ma.SetSourceModule (0, continentsWithMountains);
  continentsWithBadlands_ma.SetSourceModule (1, continentsWithBadlands_se);

  // 5: [Continents-with-badlands subgroup]: Caches the output value from the
  //    apply-badlands module.
  module::Cache continentsWithBadlands;
  continentsWithBadlands.SetSourceModule (0, continentsWithBadlands_ma);


  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: continents with rivers (4 noise modules)
  //
  // This subgroup applies the river-positions group to the continents-with-
  // badlands subgroup.
  //
  // The output value from this module subgroup is measured in planetary
  // elevation units (-1.0 for the lowest underwater trenches and +1.0 for the
  // highest mountain peaks.)
  //

  // 1: [Scaled-rivers module]: This scale/bias module scales the output value
  //    from the river-positions group so that it is measured in planetary
  //    elevation units and is negative; this is required for step 2.
  module::ScaleBias continentsWithRivers_sb;
  continentsWithRivers_sb.SetSourceModule (0, riverPositions);
  continentsWithRivers_sb.SetScale (RIVER_DEPTH / 2.0);
  continentsWithRivers_sb.SetBias (-RIVER_DEPTH / 2.0);

  // 2: [Add-rivers-to-continents module]: This addition module adds the
  //    rivers to the continents-with-badlands subgroup.  Because the scaled-
  //    rivers module only outputs a negative value, the scaled-rivers module
  //    carves the rivers out of the terrain.
  module::Add continentsWithRivers_ad;
  continentsWithRivers_ad.SetSourceModule (0, continentsWithBadlands);
  continentsWithRivers_ad.SetSourceModule (1, continentsWithRivers_sb);

  // 3: [Blended-rivers-to-continents module]: This selector module outputs
  //    deep rivers near sea level and shallower rivers in higher terrain.  It
  //    does this by selecting the output value from the continents-with-
  //    badlands subgroup if the corresponding output value from the
  //    continents-with-badlands subgroup is far from sea level.  Otherwise,
  //    this selector module selects the output value from the add-rivers-to-
  //    continents module.
  module::Select continentsWithRivers_se;
  continentsWithRivers_se.SetSourceModule (0, continentsWithBadlands);
  continentsWithRivers_se.SetSourceModule (1, continentsWithRivers_ad);
  continentsWithRivers_se.SetControlModule (continentsWithBadlands);
  continentsWithRivers_se.SetBounds (SEA_LEVEL,
    CONTINENT_HEIGHT_SCALE + SEA_LEVEL);
  continentsWithRivers_se.SetEdgeFalloff (CONTINENT_HEIGHT_SCALE - SEA_LEVEL);

  // 4: [Continents-with-rivers subgroup]: Caches the output value from the
  //    blended-rivers-to-continents module.
  module::Cache continentsWithRivers;
  continentsWithRivers.SetSourceModule (0, continentsWithRivers_se);


  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: unscaled final planet (1 noise module)
  //
  // This subgroup simply caches the output value from the continent-with-
  // rivers subgroup to contribute to the final output value.
  //

  // 1: [Unscaled-final-planet subgroup]: Caches the output value from the
  //    continent-with-rivers subgroup.
  module::Cache unscaledFinalPlanet;
  unscaledFinalPlanet.SetSourceModule (0, continentsWithRivers);


  ////////////////////////////////////////////////////////////////////////////
  // Module subgroup: final planet (2 noise modules)
  //
  // This subgroup scales the output value from the unscaled-final-planet
  // subgroup so that it represents an elevation in meters.
  //

  // 1: [Final-planet-in-meters module]: This scale/bias module scales the
  //    output value from the unscaled-final-planet subgroup so that its
  //    output value is measured in meters.
  module::ScaleBias finalPlanet_sb;
  finalPlanet_sb.SetSourceModule (0, unscaledFinalPlanet);
  finalPlanet_sb.SetScale ((MAX_ELEV - MIN_ELEV) / 2.0);
  finalPlanet_sb.SetBias (MIN_ELEV + ((MAX_ELEV - MIN_ELEV) / 2.0));

  // 2: [Final-planet group]: Caches the output value from the final-planet-
  //    in-meters module.  Stick a fork in it, we're done!
  module::Cache finalPlanet;
  finalPlanet.SetSourceModule (0, finalPlanet_sb);


  ////////////////////////////////////////////////////////////////////////////
  // Check constants
  //
  // This checks the constants entered at the top of the file to make sure
  // they are valid.

  assert (SOUTH_COORD < NORTH_COORD);
  assert (WEST_COORD < EAST_COORD);
  assert (GRID_WIDTH > 0);
  assert (GRID_HEIGHT > 0);
  assert (PLANET_CIRCUMFERENCE >= 1.0);
  assert (MIN_ELEV < MAX_ELEV);
  assert (CONTINENT_FREQUENCY >= 1.0);
  assert (CONTINENT_LACUNARITY >= 1.0);
  assert (CONTINENT_LACUNARITY <= 4.0);
  assert (MOUNTAIN_LACUNARITY >= 1.0);
  assert (MOUNTAIN_LACUNARITY <= 4.0);
  assert (HILLS_LACUNARITY >= 1.0);
  assert (HILLS_LACUNARITY <= 4.0);
  assert (PLAINS_LACUNARITY >= 1.0);
  assert (PLAINS_LACUNARITY <= 4.0);
  assert (BADLANDS_LACUNARITY >= 1.0);
  assert (BADLANDS_LACUNARITY <= 4.0);
  assert (MOUNTAINS_TWIST >= 0.0);
  assert (HILLS_TWIST >= 0.0);
  assert (BADLANDS_TWIST >= 0.0);
  assert (SEA_LEVEL >= -1.0);
  assert (SEA_LEVEL <=  1.0);
  assert (SHELF_LEVEL >= -1.0);
  assert (SHELF_LEVEL <=  1.0);
  assert (SEA_LEVEL > SHELF_LEVEL);
  assert (MOUNTAINS_AMOUNT >=  0.0);
  assert (MOUNTAINS_AMOUNT <=  1.0);
  assert (HILLS_AMOUNT >= 0.0);
  assert (HILLS_AMOUNT <= 1.0);
  assert (BADLANDS_AMOUNT >= 0.0);
  assert (BADLANDS_AMOUNT <= 1.0);
  assert (MOUNTAINS_AMOUNT < HILLS_AMOUNT);
  assert (MOUNTAIN_GLACIATION >= 1.0);
  assert (RIVER_DEPTH >= 0.0);


  ////////////////////////////////////////////////////////////////////////////
  // Create the elevation grid and resulting images

  // First, create a spherical-noise-map builder.
  utils::NoiseMapBuilderSphere planet;
  utils::NoiseMap elevGrid;

  // Pass in the boundaries of the elevation grid to extract.
  planet.SetBounds (SOUTH_COORD, NORTH_COORD, WEST_COORD, EAST_COORD);
  planet.SetDestSize (GRID_WIDTH, GRID_HEIGHT);

  // Build the elevation grid with the output values from the final-planet
  // group.
  planet.SetSourceModule (finalPlanet);
  planet.SetDestNoiseMap (elevGrid);
  planet.Build ();

  // Calculate the spatial resolution of the elevation grid, in meters.
  // Assume that the spatial resolution is the same in both the x and y
  // directions.  This is needed by the Terragen file writer.
  double degExtent = EAST_COORD - WEST_COORD;
  double gridExtent = (double)GRID_WIDTH;
  double metersPerDegree = (PLANET_CIRCUMFERENCE / 360.0);
  double resInMeters = (degExtent / gridExtent) * metersPerDegree;
  
  // Write the elevation grid as a Terragen terrain file (*.ter).
  if (resInMeters <= 240.0) {
    utils::WriterTER terrainWriter;
    terrainWriter.SetSourceNoiseMap (elevGrid);
    terrainWriter.SetDestFilename ("terrain.ter");
    terrainWriter.SetMetersPerPoint (resInMeters);
    terrainWriter.WriteDestFile ();
  }

  // Write the elevation grid as a raw file (*.raw)
  int x, y;
  uint8* pLineBuffer = new uint8[GRID_WIDTH * 2];
  std::ofstream os;
  os.open ("terrain.raw", std::ios::out | std::ios::binary);
  for (y = 0; y < GRID_HEIGHT; y++) {
    float* pSource = elevGrid.GetSlabPtr (y);
    uint8* pDest = pLineBuffer;
    for (x = 0; x < GRID_WIDTH; x++) {
      int16 elev = (int16)(floor (*pSource));
      *pDest++ = (uint8)(((uint16)elev & 0xff00) >> 8);
      *pDest++ = (uint8)(((uint16)elev & 0x00ff)     );
      ++pSource;
    }
    os.write ((char*)pLineBuffer, GRID_WIDTH * 2);
  }
  os.close ();
  delete[] pLineBuffer;

  // Calculate the sea level, in meters.
  double seaLevelInMeters = (((SEA_LEVEL + 1.0) / 2.0)
    * (MAX_ELEV - MIN_ELEV)) + MIN_ELEV;

  // Now generate an image that is colored by elevation and has an artificial
  // light-source.
  utils::Image destImage;
  utils::RendererImage imageRenderer;
  imageRenderer.SetSourceNoiseMap (elevGrid);
  imageRenderer.SetDestImage (destImage);
  imageRenderer.ClearGradient ();
  imageRenderer.AddGradientPoint (-16384.0 + seaLevelInMeters, utils::Color (  0,   0,   0, 255));
  imageRenderer.AddGradientPoint (    -256 + seaLevelInMeters, utils::Color (  6,  58, 127, 255));
  imageRenderer.AddGradientPoint (    -1.0 + seaLevelInMeters, utils::Color ( 14, 112, 192, 255));
  imageRenderer.AddGradientPoint (     0.0 + seaLevelInMeters, utils::Color ( 70, 120,  60, 255));
  imageRenderer.AddGradientPoint (  1024.0 + seaLevelInMeters, utils::Color (110, 140,  75, 255));
  imageRenderer.AddGradientPoint (  2048.0 + seaLevelInMeters, utils::Color (160, 140, 111, 255));
  imageRenderer.AddGradientPoint (  3072.0 + seaLevelInMeters, utils::Color (184, 163, 141, 255));
  imageRenderer.AddGradientPoint (  4096.0 + seaLevelInMeters, utils::Color (255, 255, 255, 255));
  imageRenderer.AddGradientPoint (  6144.0 + seaLevelInMeters, utils::Color (128, 255, 255, 255));
  imageRenderer.AddGradientPoint ( 16384.0 + seaLevelInMeters, utils::Color (  0,   0, 255, 255));
  imageRenderer.EnableLight (true);
  imageRenderer.SetLightContrast (1.0 / resInMeters);
  imageRenderer.SetLightIntensity (2.0);
  imageRenderer.SetLightElev (45.0);
  imageRenderer.SetLightAzimuth (135.0);
  imageRenderer.Render ();

  // Write the image as a Windows bitmap file (*.bmp).
  utils::WriterBMP bitmapWriter;
  bitmapWriter.SetSourceImage (destImage);
  bitmapWriter.SetDestFilename ("terrain.bmp");
  bitmapWriter.WriteDestFile ();

  // Flatten the seas that are deeper than 15 meters or so.  We do not flatten
  // all the seas so that we can color the shallow areas with a different
  // color than the deeper seas.
  const double DEEP_SEA_LEVEL = -256.0;
  for (y = 0; y < GRID_HEIGHT; y++) {
    float* pCur = elevGrid.GetSlabPtr (y);
    for (x = 0; x < GRID_WIDTH; x++) {
      if (*pCur < (SEA_LEVEL + DEEP_SEA_LEVEL)) {
        *pCur = (SEA_LEVEL + DEEP_SEA_LEVEL);
      }
      ++pCur;
    }
  }

  // Now generate the surface map.  This is an unshaded map that is colored by
  // elevation.  Using OpenGL or another 3D API, a surface map can be used in
  // conjunction with a normal map to light the map in any direction in real
  // time.
  utils::RendererImage surfaceRenderer;
  surfaceRenderer.SetSourceNoiseMap (elevGrid);
  surfaceRenderer.SetDestImage (destImage);
  surfaceRenderer.ClearGradient ();
  surfaceRenderer.AddGradientPoint (      -16384.0 + seaLevelInMeters, utils::Color (  3,  29,  63, 255));
  surfaceRenderer.AddGradientPoint (DEEP_SEA_LEVEL + seaLevelInMeters, utils::Color (  3,  29,  63, 255));
  surfaceRenderer.AddGradientPoint (          -1.0 + seaLevelInMeters, utils::Color (  7, 106, 127, 255));
  surfaceRenderer.AddGradientPoint (           0.0 + seaLevelInMeters, utils::Color ( 62,  86,  30, 255));
  surfaceRenderer.AddGradientPoint (        1024.0 + seaLevelInMeters, utils::Color ( 84,  96,  50, 255));
  surfaceRenderer.AddGradientPoint (        2048.0 + seaLevelInMeters, utils::Color (130, 127,  97, 255));
  surfaceRenderer.AddGradientPoint (        3072.0 + seaLevelInMeters, utils::Color (184, 163, 141, 255));
  surfaceRenderer.AddGradientPoint (        4096.0 + seaLevelInMeters, utils::Color (255, 255, 255, 255));
  surfaceRenderer.AddGradientPoint (        6144.0 + seaLevelInMeters, utils::Color (128, 255, 255, 255));
  surfaceRenderer.AddGradientPoint (       16384.0 + seaLevelInMeters, utils::Color (  0,   0, 255, 255));
  surfaceRenderer.EnableLight (false);
  surfaceRenderer.Render ();

  // Write the image as a Windows bitmap file (*.bmp).
  bitmapWriter.SetSourceImage (destImage);
  bitmapWriter.SetDestFilename ("terrainsurface.bmp");
  bitmapWriter.WriteDestFile ();

  // Now generate the specularity map.  This defines the "shininess" of the
  // elevation grid.  Water areas are the shiniest.
  utils::RendererImage specularityRenderer;
  specularityRenderer.SetSourceNoiseMap (elevGrid);
  specularityRenderer.SetDestImage (destImage);
  specularityRenderer.ClearGradient ();
  specularityRenderer.AddGradientPoint (MIN_ELEV              , utils::Color (255, 255, 255, 255));
  specularityRenderer.AddGradientPoint (seaLevelInMeters      , utils::Color (255, 255, 255, 255));
  specularityRenderer.AddGradientPoint (seaLevelInMeters + 1.0, utils::Color (  0,   0,   0, 255));
  specularityRenderer.AddGradientPoint (MAX_ELEV              , utils::Color (128, 128, 128, 255));
  specularityRenderer.EnableLight (false);
  specularityRenderer.Render ();

  // Write the specularity map as a Windows bitmap file (*.bmp).
  bitmapWriter.SetSourceImage (destImage);
  bitmapWriter.SetDestFilename ("terrainspec.bmp");
  bitmapWriter.WriteDestFile ();

  // Finally, render the normal map.  Using OpenGL or another 3D API, a
  // surface map can be used in conjunction with a normal map to light the map
  // in any direction in real time.
  utils::RendererNormalMap normalMapRenderer;
  normalMapRenderer.SetSourceNoiseMap (elevGrid);
  normalMapRenderer.SetDestImage (destImage);
  normalMapRenderer.SetBumpHeight (1.0 / resInMeters);
  normalMapRenderer.Render ();

  // Write the normal map as a Windows bitmap file (*.bmp).
  bitmapWriter.SetSourceImage (destImage);
  bitmapWriter.SetDestFilename ("terrainnormal.bmp");
  bitmapWriter.WriteDestFile ();

  return 0;
}
