Procedural Terrain Setup now can load terrain setups from XML files. This new feature supports some broad, new use cases.
This works just by applying the J2SE XMLDecoder to Procedural Terrain System, due to PTS’s instance-based OOD. The actual coding to accommodate consisted only of the loader code (as shown and explained below), adding a getter or two, and adjusting method visibilities. The config files are hand written (easy to do if you start from a sample). I have not yet implemented writing of the configs from apps, because I don’t yet know if there are any realistic needs for that.
You can see a sample of the very simple yet powerful syntax below. The rules are nicely summarized in the J2SE spec here.
- Create and tune your terrain by adjusting settings in your editor. No recompilation necessary.
- Saved Terrain configurations are very durable compared to Java serialization in that they are not tightly bound to the Java or application implementation. The higher load time (compared to load of binary .ser files) for these small files is insignificant compared to the times needed to establish connectivity and to initialize a terrain. The lack of durability of serialized files becomes an issue if you want to store configs for a long while (perhaps in a database), for cross-platform usage, and for app or Java upgrades.
- Sharing of terrain configurations on a network is extremely fast and extremely easy.
The PTS home page now has 2 new demos which load their terrain configs from the Internet. They are the red links (for now).
Here is a simple config file (used by the first red-linked demo). See the 2nd red demo link for a more complete config file showing setup of multiple textures, elevation procedures, area limiters.
<?xml version="1.0" encoding="UTF-8"?>
<!--
$Id: faults-terrainmap.xml 2772 2009-11-17 20:23:58Z blaine $
Sample TerrainMap config for an untextured terrain built from a jME
FaultFractalHeightMap.
-->
<java version="1.6.0_0" class="java.beans.XMLDecoder">
<object class="com.admc.agf.terrain.TerrainMap">
<float>30</float> <!-- blockLen -->
<float id="tm.lenPerVert">.3</float> <!-- lenPerVert -->
<void method="addProcedure">
<object class="com.admc.agf.terrain.JmeHeightMapProcedure">
<object class="com.jmex.terrain.util.FaultFractalHeightMap">
<int>4097</int>
<int>16</int>
<int>1</int>
<int>2</int>
<float>.3</float>
<long>7171</long> <!-- Randomization key -->
<void property="heightScale"><float>.1</float></void>
</object>
<void property="lenPerDatum"> <float idref="tm.lenPerVert"/> </void>
<void property="absoluteElevations"> <boolean>true</boolean> </void>
<void method="init"/>
</object>
</void>
</object>
</java>
Here is complete, working code needed to load a ProceduralTerrain with the configuration above (or indeed, any config file defining a TerrainMap). Client-specific settings such as how many terrain blocks to cache and how far away to instantiate and attach blocks, is not in my stored config, but it could be. TerrainRunner.java in the code base provides a more general config loader that will also load a TerrainTexturizer config if present in the file.
XMLDecoder decoder = null;
try {
String urlString = "file:/tmp/faults-terrainmap.xml";
InputStream iStream = new URL(urlString).openStream();
if (iStream == null)
throw new IllegalStateException(
"Resource is unavailable: " + urlString);
decoder = new XMLDecoder(new BufferedInputStream(iStream));
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
TerrainMap terrainMap = (TerrainMap) decoder.readObject();
terrainMap.init();
ProceduralTerrain newPTS = new ProceduralTerrain(
"proceduralTerrain", center, terrainMap,
Thread.currentThread().getPriority() - 1);
newPTS.setLoadRange(95f);
newPTS.setLoadedSpares(5);
newPTS.setAttachRange(65f);