NobleLand
From PodcastWiki
NobleLand was a submission of Noble Ape source code in Java to DarwinAtHome to allow Noble Ape's landscape generation algorithm to be used with DarwinAtHome.
The original code submission from November 25, 2006, is shown below.
/****************************************************************
NobleLand.java
=============================================================
Copyright 1996-2006 Tom Barbalet. All rights reserved.
This is an open source license. Please contact Tom Barbalet
<tom at nobleape dot com> for commercial licensing options.
Redistribution and use in source and binary forms, with or
without modification, are permitted provided that the
following conditions are met:
1. Redistributions of source code must retain the above
copyright notice, this list of conditions and the following
disclaimer.
2. Redistributions in binary form must reproduce the
above copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
3. Redistributions in any form must be accompanied by
information on how to obtain complete source code for this
software and any accompanying software that uses this
software. The source code must either be included in the
distribution or be available for no more than the cost of
distribution plus a nominal fee, and must be freely
redistributable under reasonable conditions. For an executable
file, complete source code means the source code for all modules
it contains. It does not include source code for modules or
files that typically accompany the major components of the
operating system on which the executable file runs.
THIS SOFTWARE IS PROVIDED BY TOM BARBALET "AS IS" AND ANY
EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOM
BARBALET, NOBLE APE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=============================================================
This software and Noble Ape are a continuing work of Tom
Barbalet, begun on 13 June 1996. No apes or cats were harmed
in the writing of this software.
****************************************************************/
public class NobleLand {
public int generator[];
public int resolution_bits;
public int multiplier;
private byte map[];
/*
dim = 256 x 2^resolution_bits;
+--- dim ---+
| |
dim dim
| |
+--- dim ---+
Initialized code below for 1024 x 1024 array of height points
Landscape is normally defined at a byte worth of height values
Multiplier allows for (256 * multiplier) possible values spread smoothly
*/
public void NobleLand()
{
generator = new int[2];
map = new byte[(256 * 256)];
generator[0] = 0;
generator[1] = 0;
resolution_bits = 2;
multiplier = 1;
}
private int Bilinear(int z00, int z01, int z10, int z11, int px, int py, int resolution_bits)
{
int and_value = (1 << resolution_bits) - 1;
int mic_x = px & and_value;
int mic_y = py & and_value;
z10 = z10 - z00;
z11 = z11 - z01 - z10;
z01 = (z01 - z00) << resolution_bits;
z10 = z10 << resolution_bits;
return z00 + (((z01 * mic_x) + (z10 * mic_y) + (z11 * mic_x * mic_y) ) >> (resolution_bits<<1));
}
private int Random(int local[])
{
int tmp0 = local[0];
int tmp = local[1];
if ((tmp == 0) && (tmp0 == 0)) {
tmp0 = 0x95f2;
tmp = 0x4dab;
}
local[0] = tmp & 0xffff;
if ((tmp0 & 1) == 1)
local[1] = (tmp ^ (tmp0 >> 1) ^ 0xd028) & 0xffff;
else
local[1] = (tmp ^ (tmp0 >> 1)) & 0xffff;
return (tmp);
}
/*
Init needs to be run at least once following the generator numbers being set - ideally externally
The generator numbers are 16-bit values
The generator is based in constantly refining binary spaces with each binary space having a +/- value
+-+-+---+--- ---+
+-+-+ | |
+-+-+---+
| | | |
+---+---+
| |
| |
| |
+---------------+
*/
public void Init()
{
byte scratch[] = new byte[(256 * 256)];
int random[] = new int[2];
int refine = 0;
random[0] = (generator[0] & 0xffff);
random[1] = (generator[1] & 0xffff);
while (refine < (256 * 256))
{
map[ refine ] = (byte) 128;
refine++;
}
refine = 0;
while (refine < 7) {
int major = (64 >> refine); /* major starts coarse */
int minor = (1 << refine); /* minor starts fine */
int py = 0;
while (py < minor) {
int px = 0;
while (px < minor) {
int val1 = ((px << 2) + (py << 10));
int ty = 0;
int tseed = Random(random);
while (ty < 4) {
int tx = 0;
while (tx < 4) {
int val2 = (tseed >> (tx | (ty << 2)));
int val3 = ((((val2 & 1) << 1)-1) * 20);
int my = 0;
val2 = (tx | (ty << 8));
while (my < major) {
int mx = 0;
while (mx < major) {
int point = ((mx | (my << 8)) + (major * (val1 + val2)));
if ((refine&2) == 2) { /* on 2, 3, 6, 7 */
int pointx = (point & 255);
int pointy = (point >> 8);
/* rotate 45 degrees */
point = (((pointx + pointy) & 255) | (((256 + pointx - pointy) & 255) << 8));
}
map[point] = (byte)(map[point] + val3);
mx++;
}
my++;
}
tx++;
}
ty++;
}
px++;
}
py++;
}
/* This is a four times rounder which blurbs the harsh edges and adds wrap around gradiation */
minor = 0;
while (minor < 4) {
byte front[];
byte back[];
int sy = 0;
if ((minor&1) == 0) {
front = map;
back = scratch;
} else {
front = scratch;
back = map;
}
while (sy < 256) {
int sx = 0;
while (sx < 256) {
int sum = 0;
int ty = 0;
while (ty < 3) {
int tx = 0;
while (tx < 3) {
sum = sum + front[((sx + 255 + tx) & 255) | (((sy + 255 + ty) & 255) << 8)];
tx++;
}
ty++;
}
back[sx | (sy << 8)] = (byte)(sum / 9);
sx ++;
}
sy ++;
}
minor ++;
}
refine ++;
}
}
public int Height(int px, int py)
{
int macro_x0 = ((px >> resolution_bits) & 255);
int macro_x1 = ((macro_x0 + 1) & 255);
int macro_y = ((py >> resolution_bits) & 255);
int macro_y0 = ( macro_y ) << 8;
int macro_y1 = ((macro_y + 1) & 255) << 8;
int z00 = multiplier * map[ macro_x0 | macro_y0 ];
int z01 = multiplier * map[ macro_x1 | macro_y0 ];
int z10 = multiplier * map[ macro_x0 | macro_y1 ];
int z11 = multiplier * map[ macro_x1 | macro_y1 ];
return Bilinear(z00, z01, z10, z11, px, py, resolution_bits);
}
}
/*
Some example source
{
int px, py;
int created_land[] = new int[ 2048 * 2048 ];
NobleLand noble_land = new NobleLand();
noble_land->generator[0] = 0xf3de;
noble_land->generator[1] = 0x3a56;
noble_land->resolution_bits = 3;
noble_land->multiplier = 128; // ranges from 0 to 32,640 (theoretically) (32,640 = 255 * 128)
noble_land->Init();
py = 0;
while( py < 2048 )
{
px = 0;
while( px < 2048 )
{
created_land[ px | ( py << 11 ) ] = noble_land->Height(px, py);
px++;
}
py++;
}
}
*/
