Add trees to vanilla gen, optimise noise generation.

This commit is contained in:
UnknownShadow200 2015-12-06 13:03:17 +11:00
parent b5e12c1700
commit 6adb2eec42
5 changed files with 152 additions and 52 deletions

View File

@ -17,53 +17,52 @@ namespace ClassicalSharp.Generator {
// make a random initial permutation based on seed,
// instead of using fixed permutation table in original code.
for( int i = 0; i < 256; i++ )
p[i + 256] = p[i] = rnd.Next( 256 );
p[i + 256] = p[i] = (byte)rnd.Next( 256 );
}
// TODO: need to half this maybe?
public override double Compute( double x, double y ) {
int xFloor = Utils.Floor( x ), yFloor = Utils.Floor( y );
// Find unit rectangle that contains point
int xFloor = x >= 0 ? (int)x : (int)x - 1;
int yFloor = y >= 0 ? (int)y : (int)y - 1;
int X = xFloor & 0xFF, Y = yFloor & 0xFF;
// Find relative x, y of each point in rectangle.
x -= Math.Floor( x ); y -= Math.Floor( y );
x -= xFloor; y -= yFloor;
// Compute fade curves for each of x, y.
double u = Fade( x ), v = Fade( y );
// Hash coordinates of the 4 rectangle corners.
int A = p[X] + Y, AA = p[A], AB = p[A + 1],
B = p[X + 1] + Y, BA = p[B], BB = p[B + 1];
// and add blended results from 4 corners of rectangle.
return Lerp(
v,
Lerp( u, Grad( p[AA], x, y ),
Grad( p[BA], x - 1, y ) ),
Lerp( u, Grad( p[AB], x, y - 1 ),
Grad( p[BB], x - 1, y - 1 ) )
);
}
static double Fade( double t ) {
return t * t * t * (t * (t * 6 - 15) + 10);
}
static double Lerp( double t, double a, double b ) {
return a + t * (b - a);
double u = x * x * x * (x * (x * 6 - 15) + 10); // Fade(x)
double v = y * y * y * (y * (y * 6 - 15) + 10); // Fade(y)
int A = p[X] + Y, B = p[X + 1] + Y;
double g22 = Grad( p[p[A]], x, y ), g12 = Grad( p[p[B]], x - 1, y );
double c1 = g22 + u * (g12 - g22);
double g21 = Grad( p[p[A + 1]], x, y - 1 ), g11 = Grad( p[p[B + 1]], x - 1, y - 1 );
double c2 = g21 + u * (g11 - g21);
return c1 + v * (c2 - c1);
}
static double Grad( int hash, double x, double y ) {
// convert low 4 bits of hash code into 12 gradient directions.
int h = hash & 15;
double u = h < 8 ? x : y;
double v = h < 4 ? y : h == 12 || h == 14 ? x : 0;
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
switch( hash & 15 ) {
case 0: return x + y;
case 1: return -x + y;
case 2: return x - y;
case 3: return -x - y;
case 4: return x;
case 5: return -x;
case 6: return x;
case 7: return -x;
case 8: return y;
case 9: return -y;
case 10: return y;
case 11: return -y;
case 12: return x + y;
case 13: return -y;
case 14: return -x + y;
case 15: return -y;
default: return 0;
}
}
int[] p = new int[512];
byte[] p = new byte[512];
}
public sealed class OctaveNoise : Noise {
readonly int octaves;

View File

@ -23,7 +23,7 @@ namespace ClassicalSharp.Generator {
oneY = width * length;
waterLevel = height / 2;
blocks = new byte[width * height * length];
rnd = new Random( 0x5553200 ); // 0x5553201 is flatter.
rnd = new Random( 0x5553201 ); // 0x5553201 is flatter.
CreateHeightmap();
CreateStrata();
@ -263,7 +263,104 @@ namespace ClassicalSharp.Generator {
}
void PlantTrees() {
int numPatches = width * length / 4000;
for( int i = 0; i < numPatches; i++ ) {
int patchX = rnd.Next( width ), patchZ = rnd.Next( length );
for( int j = 0; j < 20; j++ ) {
int treeX = patchX, treeZ = patchZ;
for( int k = 0; k < 20; k++ ) {
treeX += rnd.Next( 6 ) - rnd.Next( 6 );
treeZ += rnd.Next( 6 ) - rnd.Next( 6 );
if( treeX < 0 || treeZ < 0 || treeX >= width ||
treeZ >= length || rnd.NextDouble() >= 0.25 )
continue;
int treeY = heightmap[treeZ * width + treeX] + 1;
int treeHeight = 5 + rnd.Next( 3 );
if( CanGrowTree( treeX, treeY, treeZ, treeHeight ) ) {
GrowTree( treeX, treeY, treeZ, treeHeight );
}
}
}
}
}
bool CanGrowTree( int treeX, int treeY, int treeZ, int height ) {
return true;
// check tree base
int baseHeight = height - 4;
for( int y = treeY; y < treeY + baseHeight; y++ )
for( int z = treeZ - 1; z <= treeZ + 1; z++ )
for( int x = treeX - 1; x <= treeX + 1; x++ )
{
if( x < 0 || y < 0 || z < 0 || x >= width || y >= height || z >= length )
return false;
int index = (y * length + z) * width + x;
//if( blocks[index] != 0 ) return false;
}
// and also check canopy
for( int y = treeY + baseHeight; y < treeY + height; y++ )
for( int z = treeZ - 2; z <= treeZ + 2; z++ )
for( int x = treeX - 2; x <= treeX + 2; x++ )
{
if( x < 0 || y < 0 || z < 0 || x >= width || y >= height || z >= length )
return false;
int index = (y * length + z) * width + x;
//if( blocks[index] != 0 ) return false;
}
return true;
}
void GrowTree( int treeX, int treeY, int treeZ, int height ) {
int baseHeight = height - 4;
int index = 0;
// leaves bottom layer
for( int y = treeY + baseHeight; y < treeY + baseHeight + 2; y++ )
for( int zz = -2; zz <= 2; zz++ )
for( int xx = -2; xx <= 2; xx++ )
{
int x = xx + treeX, z = zz + treeZ;
index = (y * length + z) * width + x;
if( !Check( x, y, z ) ) continue; // TODO: get rid of these once CanGrowTree is fixed.
if( Math.Abs( xx ) == 2 && Math.Abs( zz ) == 2 ) {
if( rnd.NextDouble() >= 0.5 )
blocks[index] = (byte)Block.Leaves;
} else {
blocks[index] = (byte)Block.Leaves;
}
}
// leaves top layer
int bottomY = treeY + baseHeight + 2;
for( int y = treeY + baseHeight + 2; y < treeY + height; y++ )
for( int zz = -1; zz <= 1; zz++ )
for( int xx = -1; xx <= 1; xx++ )
{
int x = xx + treeX, z = zz + treeZ;
index = (y * length + z) * width + x;
if( !Check( x, y, z ) ) continue;
if( xx == 0 || zz == 0 ) {
blocks[index] = (byte)Block.Leaves;
} else if( y != bottomY && rnd.NextDouble() >= 0.5 ) {
blocks[index] = (byte)Block.Leaves;
}
}
// then place trunk
index = (treeY * length + treeZ ) * width + treeX;
for( int y = 0; y < height - 1; y++ ) {
if( !Check( treeX, treeY + y, treeZ ) ) continue;
blocks[index] = (byte)Block.Wood;
index += oneY;
}
}
bool Check( int x, int y, int z ) {
return x >= 0 && y >= 0 && z >= 0
&& x < width && y < height && z < length;
}
}
}

View File

@ -388,10 +388,6 @@ namespace ClassicalSharp.Singleplayer {
return;
}
// Base trunk
for( int yy = 0; yy < trunkH; yy++ )
game.UpdateBlock( x, y + yy, z, (byte)Block.Wood );
// Leaves bottom layer
y += trunkH;
for( int zz = -2; zz <= 2; zz++ ) {
@ -418,6 +414,11 @@ namespace ClassicalSharp.Singleplayer {
}
}
}
// Base trunk
y -= 2 + trunkH;
for( int yy = 0; yy < trunkH + 3; yy++ )
game.UpdateBlock( x, y + yy, z, (byte)Block.Wood );
}
bool CheckBounds( int x1, int x2, int y1, int y2, int z1, int z2 ) {

View File

@ -1,4 +1,5 @@
using System;
//#define TEST_VANILLA
using System;
using System.Net;
using OpenTK;
using OpenTK.Input;
@ -27,8 +28,11 @@ namespace ClassicalSharp.Singleplayer {
game.Events.RaiseBlockPermissionsChanged();
NewMap();
//MakeMap( 128, 128, 128 );
MakeMap( 128, 64, 128 );
#if TEST_VANILLA
MakeMap( 384, 64, 384 );
#else
MakeMap( 128, 128, 128 );
#endif
game.CommandManager.RegisterCommand( new GenerateCommand() );
}
@ -69,14 +73,17 @@ namespace ClassicalSharp.Singleplayer {
}
internal unsafe void MakeMap( int width, int height, int length ) {
//byte[] map = new byte[width * height * length];
//var sw = System.Diagnostics.Stopwatch.StartNew();
//fixed( byte* ptr = map ) {
// MapSet( width, length, ptr, 0, height / 2 - 2, (byte)Block.Dirt );
// MapSet( width, length, ptr, height / 2 - 1, height / 2 - 1, (byte)Block.Grass );
//}
#if TEST_VANILLA
byte[] map = new ClassicalSharp.Generator.NotchyGenerator()
.GenerateMap( width, height, length );
#else
byte[] map = new byte[width * height * length];
fixed( byte* ptr = map ) {
MapSet( width, length, ptr, 0, height / 2 - 2, (byte)Block.Dirt );
MapSet( width, length, ptr, height / 2 - 1, height / 2 - 1, (byte)Block.Grass );
}
#endif
game.Map.SetData( map, width, height, length );
game.Events.RaiseOnNewMapLoaded();
game.SetNewScreen( null );

View File

@ -242,10 +242,6 @@ namespace ClassicalSharp {
return value >= 0 ? (int)value : (int)value - 1;
}
public static int Floor( double value ) {
return value >= 0 ? (int)value : (int)value - 1;
}
public static int AdjViewDist( int value ) {
return (int)(1.4142135 * value);
}