public static void PlaceStructure(Structure structure, Vector3I position, bool eraseSolid = false) { Vector3I shift = structure.Root; Vector3I origin = position - shift; Vector3I extents = structure.Size; ConcurrentDictionary <Vector2I, Chunk> chunkCache = new ConcurrentDictionary <Vector2I, Chunk>(); ushort[] blocks = structure.Blocks; ushort airID = ItemCache.GetIndex("winecrash:air"); Parallel.For(0, blocks.Length, i => { WMath.FlatTo3D(i, extents.X, extents.Y, out int localX, out int localY, out int localZ); Vector3I globalBpos = new Vector3I(localX, localY, localZ) + origin; GlobalToLocal(globalBpos, out Vector2I cpos, out Vector3I bpos); Chunk c; if (!chunkCache.TryGetValue(cpos, out c)) { c = GetChunk(cpos, "winecrash:overworld"); chunkCache.TryAdd(cpos, c); } if (c && (eraseSolid || c.GetBlockIndex(bpos.X, bpos.Y, bpos.Z) == airID)) { c.SetBlock(bpos.X, bpos.Y, bpos.Z, blocks[i]); } });
private static ushort[] Populate(Vector2I chunkCoords, ushort[] indices, Vector3I[] surfaces) { double treeDensity = 0.005D; int chunkHash = chunkCoords.GetHashCode() * Seed.Value; Random treeRandom = new Random(chunkHash); Structure tree = Structure.Get("Tree"); ushort dirtID = ItemCache.GetIndex("winecrash:dirt"); ushort grassID = ItemCache.GetIndex("winecrash:grass"); ushort debugID = ItemCache.GetIndex("winecrash:direction"); // do trees for (int i = 0; i < surfaces.Length; i++) { int flatten = WMath.Flatten3D(surfaces[i].X, surfaces[i].Y, surfaces[i].Z, Chunk.Width, Chunk.Height); bool doTree = treeRandom.NextDouble() < treeDensity; if ((indices[flatten] == dirtID || indices[flatten] == grassID) && doTree) { indices[flatten] = dirtID; PlaceStructure(tree, LocalToGlobal(chunkCoords, new Vector3D(surfaces[i].X, surfaces[i].Y + 1, surfaces[i].Z)), false); } } return(indices); }
public Structure(string name, Vector3I size, Vector3I root, string[] palette, int[] data) : base(name) { this.Size = size; this.Root = root; ushort[] paletteIDs = new ushort[palette.Length]; _Blocks = new ushort[data.Length]; //create palette ids for (int i = 0; i < palette.Length; i++) { paletteIDs[i] = ItemCache.GetIndex(palette[i]); } //create blocks for (int i = 0; i < data.Length; i++) { _Blocks[i] = paletteIDs[data[i]]; } _Cache.Add(this); }
internal override Mesh BuildModel() { if (this.Texture) { return(base.BuildModel()); } else { float nbItems = ItemCache.TotalItems; float iindex = ItemCache.GetIndex(this.Identifier); float yPercent = iindex; Vector2F shift = new Vector2F(0, yPercent); Vector2F scale = new Vector2D(1F / 6F, 1F / nbItems); Vector2F[] uvs = new Vector2F[36] { // up new Vector2F(scale.X * 2, scale.Y * yPercent), new Vector2F(scale.X * 2, scale.Y * (yPercent + 1)), new Vector2F(scale.X * 3, scale.Y * yPercent), new Vector2F(scale.X * 3, scale.Y * yPercent), new Vector2F(scale.X * 2, scale.Y * (yPercent + 1)), new Vector2F(scale.X * 3, scale.Y * (yPercent + 1)), // down new Vector2F(scale.X * 4, scale.Y * (yPercent + 1)), new Vector2F(scale.X * 4, scale.Y * yPercent), new Vector2F(scale.X * 3, scale.Y * (yPercent + 1)), new Vector2F(scale.X * 3, scale.Y * (yPercent + 1)), new Vector2F(scale.X * 4, scale.Y * yPercent), new Vector2F(scale.X * 3, scale.Y * yPercent), // west new Vector2F(scale.X * 2, scale.Y * yPercent), new Vector2F(scale.X * 1, scale.Y * yPercent), new Vector2F(scale.X * 2, scale.Y * (yPercent + 1)), new Vector2F(scale.X * 2, scale.Y * (yPercent + 1)), new Vector2F(scale.X * 1, scale.Y * yPercent), new Vector2F(scale.X * 1, scale.Y * (yPercent + 1)), // east new Vector2F(scale.X * 1, scale.Y * (yPercent + 1)), new Vector2F(scale.X * 1, scale.Y * yPercent), new Vector2F(scale.X * 0, scale.Y * (yPercent + 1)), new Vector2F(scale.X * 0, scale.Y * (yPercent + 1)), new Vector2F(scale.X * 1, scale.Y * yPercent), new Vector2F(scale.X * 0, scale.Y * yPercent), // north new Vector2F(scale.X * 5, scale.Y * yPercent), new Vector2F(scale.X * 4, scale.Y * yPercent), new Vector2F(scale.X * 5, scale.Y * (yPercent + 1)), new Vector2F(scale.X * 5, scale.Y * (yPercent + 1)), new Vector2F(scale.X * 4, scale.Y * yPercent), new Vector2F(scale.X * 4, scale.Y * (yPercent + 1)), // south new Vector2F(scale.X * 6, scale.Y * (yPercent + 1)), new Vector2F(scale.X * 6, scale.Y * yPercent), new Vector2F(scale.X * 5, scale.Y * (yPercent + 1)), new Vector2F(scale.X * 5, scale.Y * (yPercent + 1)), new Vector2F(scale.X * 6, scale.Y * yPercent), new Vector2F(scale.X * 5, scale.Y * yPercent), }; Mesh m = new Mesh(this.Identifier + " 3D Render [Cube]") { Vertices = _CubeVertices, UVs = uvs, Normals = _CubeNormals, Triangles = _CubeIndices, Tangents = new Vector4F[36] }; m.Apply(true); return(m); } }
private static ushort[] PaintLandmass(Vector2I chunkCoords, ushort[] indices, out Vector3I[] surfaces) { ushort airID = ItemCache.GetIndex("winecrash:air"); ushort stoneID = ItemCache.GetIndex("winecrash:stone"); ushort grassID = ItemCache.GetIndex("winecrash:grass"); ushort dirtID = ItemCache.GetIndex("winecrash:dirt"); ushort sandID = ItemCache.GetIndex("winecrash:sand"); ushort waterID = ItemCache.GetIndex("winecrash:water"); ushort bedrockID = ItemCache.GetIndex("winecrash:bedrock"); //ushort[] indices = new ushort[Chunk.Width * Chunk.Height * Chunk.Depth]; Vector3F shift = Vector3F.Zero; Vector3F basePos = new Vector3F((chunkCoords.X * Chunk.Width) + shift.X, shift.Y, (chunkCoords.Y * Chunk.Depth) + shift.Z); ConcurrentBag <Vector3I> allSurfaces = new ConcurrentBag <Vector3I>(); // for each x and z, for y from top to bottom: for (int i = 0; i < Chunk.Width * Chunk.Depth; i++) { //Parallel.For(0, Chunk.Width /** Chunk.Height*/ * Chunk.Depth, i => //{ // get the x / z position WMath.FlatTo2D(i, Chunk.Width, out int x, out int z); int surfaceHeight = Chunk.Height - 1; bool heightFound = false; for (int y = Chunk.Height - 1; y > -1; y--) { int idx = WMath.Flatten3D(x, y, z, Chunk.Width, Chunk.Height); // if height already have been found, check back if // there is a surface or not (3D terrain, like grass under arches or so) if (heightFound) { if (indices[idx] == airID) // if air found, reset height { surfaceHeight = y; heightFound = false; } } else { surfaceHeight = y; if (indices[idx] != airID) { heightFound = true; allSurfaces.Add(new Vector3I(x, y, z)); } } // second pass: check the difference between surface and // the current block height. if (heightFound) { int deltaHeight = surfaceHeight - y; bool ocean = surfaceHeight < 64; // surface => grass if (deltaHeight == 0) { indices[idx] = ocean ? sandID : grassID; } // dirt, under the grass else if (deltaHeight < 3) { indices[idx] = ocean ? sandID : dirtID; } } if (y < 64 && indices[idx] == airID) { indices[idx] = waterID; } if (y < 3) { double chance = Winecrash.Random.NextDouble(); if (y == 2 && chance < 0.33) { indices[idx] = bedrockID; } else if (y == 1 && chance < 0.66) { indices[idx] = bedrockID; } else if (y == 0) { indices[idx] = bedrockID; } } } //Vector3F finalPos = new Vector3F((basePos.X + x) * baseLandmassScale, basePos.Y + y, // (basePos.Z + z) * baseLandmassScale) * globalScale; //}); } surfaces = allSurfaces.ToArray(); return(indices); }
private static ushort[] GenerateLandmass(Vector2I chunkCoords) { float globalScale = 1.0F; float baseLandmassScale = 0.005F; // lower => wider. yeah ik. float detailBias = 0.0F; float oceanLevel = 63; float landDeformity = 40; float oceanDeformity = 20; float landMaxHeight = oceanLevel + landDeformity; float oceanMaxDepth = oceanLevel - oceanDeformity; float mountainsDeformity = 10; float moutainsScale = 0.01F; float maxLevel = 63 + 40; // this is meant to be used as a 2D base for continents apparently unused \/ IModule3D baseLandmass = new ImprovedPerlin(World.Seed.Value, NoiseQuality.Best); var billow = new Billow { Primitive3D = baseLandmass, OctaveCount = 5.0F, Frequency = 0.9F, }; IModule3D detailsLandmass = new ImprovedPerlin(World.Seed.Value * 123456, NoiseQuality.Best); detailsLandmass = new ScaleBias(detailsLandmass, .2F, detailBias); baseLandmass = new Add(billow, detailsLandmass); //LibNoise.Modifier.Exponent baseLandExp = new Exponent(baseLandmass, 1.0F); //var combiner = new LibNoise.Combiner.Add(baseLandmass1, baseLandmass1); float oceanCoverage = 0.5F; ushort airID = ItemCache.GetIndex("winecrash:air"); ushort stoneID = ItemCache.GetIndex("winecrash:stone"); ushort[] indices = new ushort[Chunk.Width * Chunk.Height * Chunk.Depth]; Vector3F shift = Vector3F.Zero; Vector3F basePos = new Vector3F((chunkCoords.X * Chunk.Width) + shift.X, shift.Y, (chunkCoords.Y * Chunk.Depth) + shift.Z); for (int i = 0; i < Chunk.Width * Chunk.Height * Chunk.Depth; i++) { //Parallel.For(0, Chunk.Width * Chunk.Height * Chunk.Depth, i => //{ indices[i] = airID; // get, from index, the x,y,z coordinates of the block. Then move it from the basePos x scale. WMath.FlatTo3D(i, Chunk.Width, Chunk.Height, out int x, out int y, out int z); if (y > maxLevel) { continue; } Vector3F finalPos = new Vector3F((basePos.X + x) * baseLandmassScale, basePos.Y + y, (basePos.Z + z) * baseLandmassScale) * globalScale; float landMassPct = baseLandmass.GetValue(finalPos.X, 0, finalPos.Z); // retreive the 2D base land value (as seen from top). If under land cap, it's ocean. bool isLand = landMassPct > oceanCoverage; float landPct = (float)Math.Pow(WMath.Remap(landMassPct, oceanCoverage, 1.0F, 0.0F, 1.0F), 2F); float waterPct = WMath.Remap(landMassPct, 0.0F, oceanCoverage, 0.0F, 1.0F); float landMassHeight = oceanLevel + (landPct * landDeformity); int finalLandMassHeight = (int)landMassHeight; float waterHeight = oceanMaxDepth + (waterPct * oceanDeformity); int finalWaterHeight = (int)waterHeight; if (isLand) { if (y < finalLandMassHeight) { indices[i] = stoneID; } } else if (y == oceanLevel - 1) { //indices[i] = waterID; } else if (y < oceanLevel - 1) { if (y > finalWaterHeight) { //indices[i] = waterID; } else { indices[i] = stoneID; } } // debug: display this as grass / sand. //indices[i] = y == 63 ? (isLand ? grassID : sandID) : (y > 63 ? airID : debugID);//debug.GetValue(finalPos.X, finalPos.Y, finalPos.Z) < cap ? stoneID : airID; //}); } return(indices); }
public ushort[] LoadBlocks() { ushort[] blocks = new ushort[Chunk.Width * Chunk.Height * Chunk.Depth]; int chunkindex = 0; for (int z = 0; z < Chunk.Depth; z++) { for (int y = 0; y < Chunk.Height; y++) { for (int x = 0; x < Chunk.Width; x++) { blocks[x + Chunk.Width * y + Chunk.Width * Chunk.Height * z] = ItemCache.GetIndex(Palette[Indices[chunkindex++]]); } } } return(blocks); }
internal virtual Mesh BuildModel() { if (this.Identifier == "winecrash:air") { return(PlayerEntity.PlayerRightArmMesh); } Texture texture = this.Texture ?? Texture.Blank; List <Vector3F> vertices = new List <Vector3F>(); List <Vector2F> uvs = new List <Vector2F>(); List <Vector3F> normals = new List <Vector3F>(); List <uint> triangles = new List <uint>(); Stack <BlockFaces> faces = new Stack <BlockFaces>(6); uint triangle = 0; Block block = null; ushort index = 0; Vector3F deltas = new Vector3F(1.0F / texture.Size.X, 1.0F / texture.Size.Y); deltas.Z = Math.Min(deltas.X, deltas.Y); float nbItems = ItemCache.TotalItems; float iindex = ItemCache.GetIndex(this.Identifier); float yPercent = iindex; Vector2F shift = new Vector2F(0, yPercent); Vector2F scale = new Vector2D(1F / 6F, 1F / nbItems); Vector3F up = Vector3F.Up; Vector3F down = Vector3F.Down; Vector3F left = Vector3F.Left; Vector3F right = Vector3F.Right; Vector3F forward = Vector3F.Forward; Vector3F south = Vector3F.Backward; void CreateUVs(float minXPos, float minYPos, BlockFaces face) { float maxXPos = minXPos + deltas.X; float maxYPos = minYPos + deltas.Y; switch (face) { case BlockFaces.Up: { uvs.AddRange(new[] { new Vector2F(minXPos, minYPos + yPercent) * scale, //0 new Vector2F(minXPos, maxYPos + yPercent) * scale, //incr new Vector2F(maxXPos, minYPos + yPercent) * scale, //2 new Vector2F(maxXPos, minYPos + yPercent) * scale, //3 new Vector2F(minXPos, maxYPos + yPercent) * scale, //4 new Vector2F(maxXPos, maxYPos + yPercent) * scale, //5 }); } break; case BlockFaces.Down: { uvs.AddRange(new[] { new Vector2F(maxXPos, maxYPos + yPercent) * scale, //top left new Vector2F(maxXPos, minYPos + yPercent) * scale, //bottom left new Vector2F(minXPos, maxYPos + yPercent) * scale, //top right new Vector2F(minXPos, maxYPos + yPercent) * scale, //top right new Vector2F(maxXPos, minYPos + yPercent) * scale, //bottom left new Vector2F(maxXPos, minYPos + yPercent) * scale, //top left }); } break; case BlockFaces.North: { uvs.AddRange(new[] { new Vector2F(maxXPos, minYPos + yPercent) * scale, //5 new Vector2F(minXPos, minYPos + yPercent) * scale, //4 new Vector2F(maxXPos, maxYPos + yPercent) * scale, //3 new Vector2F(maxXPos, maxYPos + yPercent) * scale, //2 new Vector2F(minXPos, minYPos + yPercent) * scale, //incr new Vector2F(minXPos, maxYPos + yPercent) * scale, //0 }); } break; case BlockFaces.South: { uvs.AddRange(new[] { new Vector2F(maxXPos, maxYPos + yPercent) * scale, //0 topleft new Vector2F(maxXPos, minYPos + yPercent) * scale, //2 bottom left new Vector2F(minXPos, maxYPos + yPercent) * scale, //incr top right new Vector2F(minXPos, maxYPos + yPercent) * scale, // 4 top right new Vector2F(maxXPos, minYPos + yPercent) * scale, //3 bottom left new Vector2F(minXPos, minYPos + yPercent) * scale, //5 bottom right }); } break; case BlockFaces.West: { uvs.AddRange(new[] { new Vector2F(maxXPos, minYPos + yPercent) * scale, //5 new Vector2F(minXPos, minYPos + yPercent) * scale, //4 new Vector2F(maxXPos, maxYPos + yPercent) * scale, //3 new Vector2F(maxXPos, maxYPos + yPercent) * scale, //2 new Vector2F(minXPos, minYPos + yPercent) * scale, //incr new Vector2F(minXPos, maxYPos + yPercent) * scale, //0 }); } break; case BlockFaces.East: { uvs.AddRange(new[] { new Vector2F(maxXPos, maxYPos + yPercent) * scale, //5 new Vector2F(maxXPos, minYPos + yPercent) * scale, //3 new Vector2F(minXPos, maxYPos + yPercent) * scale, //4 new Vector2F(minXPos, maxYPos + yPercent) * scale, //incr new Vector2F(maxXPos, minYPos + yPercent) * scale, //2 new Vector2F(minXPos, minYPos + yPercent) * scale, //0 }); } break; } } void CreateVertices(float minXPos, float minYPos, BlockFaces face) { float maxXPos = minXPos + deltas.X; float maxYPos = minYPos + deltas.Y; float halfZdelta = deltas.Z / 2.0F; const float scaleFactor = 1.5F; switch (face) { case BlockFaces.Up: { vertices.AddRange(new[] { new Vector3F(minXPos - 0.5F, maxYPos - 0.5F, -halfZdelta) * scaleFactor, new Vector3F(minXPos - 0.5F, maxYPos - 0.5F, halfZdelta) * scaleFactor, new Vector3F(maxXPos - 0.5F, maxYPos - 0.5F, -halfZdelta) * scaleFactor, new Vector3F(maxXPos - 0.5F, maxYPos - 0.5F, -halfZdelta) * scaleFactor, new Vector3F(minXPos - 0.5F, maxYPos - 0.5F, halfZdelta) * scaleFactor, new Vector3F(maxXPos - 0.5F, maxYPos - 0.5F, halfZdelta) * scaleFactor }); } break; case BlockFaces.Down: { vertices.AddRange(new[] { new Vector3F(minXPos - 0.5F, minYPos - 0.5F, halfZdelta) * scaleFactor, new Vector3F(minXPos - 0.5F, minYPos - 0.5F, -halfZdelta) * scaleFactor, new Vector3F(maxXPos - 0.5F, minYPos - 0.5F, halfZdelta) * scaleFactor, new Vector3F(maxXPos - 0.5F, minYPos - 0.5F, halfZdelta) * scaleFactor, new Vector3F(minXPos - 0.5F, minYPos - 0.5F, -halfZdelta) * scaleFactor, new Vector3F(maxXPos - 0.5F, minYPos - 0.5F, -halfZdelta) * scaleFactor }); } break; case BlockFaces.West: { vertices.AddRange(new[] { new Vector3F(minXPos - 0.5F, minYPos - 0.5F, -halfZdelta) * scaleFactor, new Vector3F(minXPos - 0.5F, minYPos - 0.5F, halfZdelta) * scaleFactor, new Vector3F(minXPos - 0.5F, maxYPos - 0.5F, -halfZdelta) * scaleFactor, new Vector3F(minXPos - 0.5F, maxYPos - 0.5F, -halfZdelta) * scaleFactor, new Vector3F(minXPos - 0.5F, minYPos - 0.5F, halfZdelta) * scaleFactor, new Vector3F(minXPos - 0.5F, maxYPos - 0.5F, halfZdelta) * scaleFactor }); } break; case BlockFaces.East: { vertices.AddRange(new[] { new Vector3F(maxXPos - 0.5F, maxYPos - 0.5F, halfZdelta) * scaleFactor, new Vector3F(maxXPos - 0.5F, minYPos - 0.5F, halfZdelta) * scaleFactor, new Vector3F(maxXPos - 0.5F, maxYPos - 0.5F, -halfZdelta) * scaleFactor, new Vector3F(maxXPos - 0.5F, maxYPos - 0.5F, -halfZdelta) * scaleFactor, new Vector3F(maxXPos - 0.5F, minYPos - 0.5F, halfZdelta) * scaleFactor, new Vector3F(maxXPos - 0.5F, minYPos - 0.5F, -halfZdelta) * scaleFactor }); } break; case BlockFaces.North: { vertices.AddRange(new[] { new Vector3F(minXPos - 0.5F, minYPos - 0.5F, halfZdelta) * scaleFactor, new Vector3F(maxXPos - 0.5F, minYPos - 0.5F, halfZdelta) * scaleFactor, new Vector3F(minXPos - 0.5F, maxYPos - 0.5F, halfZdelta) * scaleFactor, new Vector3F(minXPos - 0.5F, maxYPos - 0.5F, halfZdelta) * scaleFactor, new Vector3F(maxXPos - 0.5F, minYPos - 0.5F, halfZdelta) * scaleFactor, new Vector3F(maxXPos - 0.5F, maxYPos - 0.5F, halfZdelta) * scaleFactor }); } break; case BlockFaces.South: { vertices.AddRange(new[] { new Vector3F(maxXPos - 0.5F, maxYPos - 0.5F, -halfZdelta) * scaleFactor, new Vector3F(maxXPos - 0.5F, minYPos - 0.5F, -halfZdelta) * scaleFactor, new Vector3F(minXPos - 0.5F, maxYPos - 0.5F, -halfZdelta) * scaleFactor, new Vector3F(minXPos - 0.5F, maxYPos - 0.5F, -halfZdelta) * scaleFactor, new Vector3F(maxXPos - 0.5F, minYPos - 0.5F, -halfZdelta) * scaleFactor, new Vector3F(minXPos - 0.5F, minYPos - 0.5F, -halfZdelta) * scaleFactor }); } break; } } void CreateNormals(BlockFaces face) { switch (face) { case BlockFaces.Up: { normals.AddRange(new[] { up, up, up, up, up, up }); } break; case BlockFaces.Down: { normals.AddRange(new[] { down, down, down, down, down, down }); } break; case BlockFaces.West: { normals.AddRange(new[] { left, left, left, left, left, left }); } break; case BlockFaces.East: { normals.AddRange(new[] { right, right, right, right, right, right }); } break; case BlockFaces.North: { normals.AddRange(new[] { forward, forward, forward, forward, forward, forward }); } break; case BlockFaces.South: { normals.AddRange(new[] { south, south, south, south, south, south }); } break; } } for (int y = 0; y < texture.Size.Y; y++) { for (int x = 0; x < texture.Size.X; x++) { if (!IsTransparent(texture, x, y)) { float xminpos = deltas.X * x; float yminpos = deltas.Y * y; float xmaxpos = xminpos + deltas.X; float xmaspos = yminpos + deltas.Y; if (IsTransparent(texture, x, y + 1)) { faces.Push(BlockFaces.Up); } if (IsTransparent(texture, x, y - 1)) { faces.Push(BlockFaces.Down); } if (IsTransparent(texture, x - 1, y)) { faces.Push(BlockFaces.West); } if (IsTransparent(texture, x + 1, y)) { faces.Push(BlockFaces.East); } faces.Push(BlockFaces.North); faces.Push(BlockFaces.South); foreach (BlockFaces face in faces) { CreateVertices(xminpos, yminpos, face); CreateUVs(xminpos, yminpos, face); CreateNormals(face); triangles.AddRange(new uint[6] { triangle, triangle + 1, triangle + 2, triangle + 3, triangle + 4, triangle + 5 }); triangle += 6; } faces.Clear(); } } } Mesh mesh = null; if (vertices.Count != 0) { mesh = new Mesh(this.Identifier + " 3D Render [Standard]") { Vertices = vertices.ToArray(), Triangles = triangles.ToArray(), UVs = uvs.ToArray(), Normals = normals.ToArray(), Tangents = new Vector4F[vertices.Count] }; mesh.Apply(true); } vertices = null; triangles = null; uvs = null; normals = null; return(mesh); }