mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-15 02:25:32 -04:00
Add trees to vanilla gen, optimise noise generation.
This commit is contained in:
parent
b5e12c1700
commit
6adb2eec42
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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 ) {
|
||||
|
@ -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 );
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user