public void TessellateBlock(List<VertexPositionColorLighting>[] vertexLists, List<short>[] indexLists, BlockPosition worldBlockPosition, RelativeBlockPosition relativeBlockPosition) { GetRequiredBlocks(worldBlockPosition); BuildLeftQuad(vertexLists[Face.Left], indexLists[Face.Left], relativeBlockPosition); BuildRightQuad(vertexLists[Face.Right], indexLists[Face.Right], relativeBlockPosition); BuildFrontQuad(vertexLists[Face.Front], indexLists[Face.Front], relativeBlockPosition); BuildBackQuad(vertexLists[Face.Back], indexLists[Face.Back], relativeBlockPosition); BuildTopQuad(vertexLists[Face.Top], indexLists[Face.Top], relativeBlockPosition); BuildBottomQuad(vertexLists[Face.Bottom], indexLists[Face.Bottom], relativeBlockPosition); NumberOfBlocksTessellated++; }
void BuildRightQuad(List<VertexPositionColorLighting> vertexList, List<short> indexList, RelativeBlockPosition relativeBlockPosition) { if (!rightBlock.CanBeSeenThrough) { return; } var topRightFrontIndex = (short)vertexList.Count; vertexList.Add(new VertexPositionColorLighting { Position = relativeBlockPosition.Up.Right.Front, Color = Color.LightGray, Lighting = AverageLightingOver(rightBlock, rightUpBlock, rightFrontBlock, rightUpFrontBlock, SideFaceLightingLimit) }); var topRightBackIndex = (short)vertexList.Count; vertexList.Add(new VertexPositionColorLighting { Position = relativeBlockPosition.Up.Right, Color = Color.LightGray, Lighting = AverageLightingOver(rightBlock, rightUpBlock, rightBackBlock, rightUpBackBlock, SideFaceLightingLimit) }); var bottomRightBackIndex = (short)vertexList.Count; vertexList.Add(new VertexPositionColorLighting { Position = relativeBlockPosition.Right, Color = Color.LightGray, Lighting = AverageLightingOver(rightBlock, rightDownBlock, rightBackBlock, rightDownBackBlock, SideFaceLightingLimit) }); var bottomRightFrontIndex = (short)vertexList.Count; vertexList.Add(new VertexPositionColorLighting { Position = relativeBlockPosition.Right.Front, Color = Color.LightGray, Lighting = AverageLightingOver(rightBlock, rightDownBlock, rightFrontBlock, rightDownFrontBlock, SideFaceLightingLimit) }); indexList.Add(topRightFrontIndex); indexList.Add(topRightBackIndex); indexList.Add(bottomRightBackIndex); indexList.Add(topRightFrontIndex); indexList.Add(bottomRightBackIndex); indexList.Add(bottomRightFrontIndex); }
void BuildTopQuad(List<VertexPositionColorLighting> vertexList, List<short> indexList, RelativeBlockPosition relativeBlockPosition) { if (!upBlock.CanBeSeenThrough) { return; } var topLeftBackIndex = (short)vertexList.Count; vertexList.Add(new VertexPositionColorLighting { Position = relativeBlockPosition.Up, Color = Color.LightGray, Lighting = AverageLightingOver(upBlock, upLeftBlock, upBackBlock, upLeftBackBlock, TopFaceLightingLimit) }); var topRightBackIndex = (short)vertexList.Count; vertexList.Add(new VertexPositionColorLighting { Position = relativeBlockPosition.Right.Up, Color = Color.LightGray, Lighting = AverageLightingOver(upBlock, upRightBlock, upBackBlock, upRightBackBlock, TopFaceLightingLimit) }); var topRightFrontIndex = (short)vertexList.Count; vertexList.Add(new VertexPositionColorLighting { Position = relativeBlockPosition.Right.Up.Front, Color = Color.LightGray, Lighting = AverageLightingOver(upBlock, upRightBlock, upFrontBlock, upRightFrontBlock, TopFaceLightingLimit) }); var topLeftFrontIndex = (short)vertexList.Count; vertexList.Add(new VertexPositionColorLighting { Position = relativeBlockPosition.Up.Front, Color = Color.LightGray, Lighting = AverageLightingOver(upBlock, upLeftBlock, upFrontBlock, upLeftFrontBlock, TopFaceLightingLimit) }); indexList.Add(topLeftBackIndex); indexList.Add(topRightBackIndex); indexList.Add(topRightFrontIndex); indexList.Add(topLeftBackIndex); indexList.Add(topRightFrontIndex); indexList.Add(topLeftFrontIndex); }
void BuildBackQuad(List<VertexPositionColorLighting> vertexList, List<short> indexList, RelativeBlockPosition relativeBlockPosition) { if (!backBlock.CanBeSeenThrough) { return; } var topRightBackIndex = (short)vertexList.Count; vertexList.Add(new VertexPositionColorLighting { Position = relativeBlockPosition.Right.Up, Color = Color.LightGray, Lighting = AverageLightingOver(backBlock, backUpBlock, backRightBlock, backUpRightBlock, SideFaceLightingLimit) }); var topLeftBackIndex = (short)vertexList.Count; vertexList.Add(new VertexPositionColorLighting { Position = relativeBlockPosition.Up, Color = Color.LightGray, Lighting = AverageLightingOver(backBlock, backUpBlock, backLeftBlock, backUpLeftBlock, SideFaceLightingLimit) }); var bottomLeftBackIndex = (short)vertexList.Count; vertexList.Add(new VertexPositionColorLighting { Position = relativeBlockPosition, Color = Color.LightGray, Lighting = AverageLightingOver(backBlock, backDownBlock, backLeftBlock, backDownLeftBlock, SideFaceLightingLimit) }); var bottomRightBackIndex = (short)vertexList.Count; vertexList.Add(new VertexPositionColorLighting { Position = relativeBlockPosition.Right, Color = Color.LightGray, Lighting = AverageLightingOver(backBlock, backDownBlock, backRightBlock, backDownRightBlock, SideFaceLightingLimit) }); indexList.Add(topRightBackIndex); indexList.Add(topLeftBackIndex); indexList.Add(bottomLeftBackIndex); indexList.Add(topRightBackIndex); indexList.Add(bottomLeftBackIndex); indexList.Add(bottomRightBackIndex); }
void BuildBottomQuad(List<VertexPositionColorLighting> vertexList, List<short> indexList, RelativeBlockPosition relativeBlockPosition) { if (!downBlock.CanBeSeenThrough) { return; } var bottomLeftFrontIndex = (short)vertexList.Count; vertexList.Add(new VertexPositionColorLighting { Position = relativeBlockPosition.Front, Color = Color.LightGray, Lighting = AverageLightingOver(downBlock, downLeftBlock, downFrontBlock, downLeftFrontBlock, BottomFaceLightingLimit) }); var bottomRightFrontIndex = (short)vertexList.Count; vertexList.Add(new VertexPositionColorLighting { Position = relativeBlockPosition.Right.Front, Color = Color.LightGray, Lighting = AverageLightingOver(downBlock, downRightBlock, downFrontBlock, downRightFrontBlock, BottomFaceLightingLimit) }); var bottomRightBackIndex = (short)vertexList.Count; vertexList.Add(new VertexPositionColorLighting { Position = relativeBlockPosition.Right, Color = Color.LightGray, Lighting = AverageLightingOver(downBlock, downRightBlock, downBackBlock, downRightBackBlock, BottomFaceLightingLimit) }); var bottomLeftBackIndex = (short)vertexList.Count; vertexList.Add(new VertexPositionColorLighting { Position = relativeBlockPosition, Color = Color.LightGray, Lighting = AverageLightingOver(downBlock, downLeftBlock, downBackBlock, downLeftBackBlock, BottomFaceLightingLimit) }); indexList.Add(bottomLeftFrontIndex); indexList.Add(bottomRightFrontIndex); indexList.Add(bottomRightBackIndex); indexList.Add(bottomLeftFrontIndex); indexList.Add(bottomRightBackIndex); indexList.Add(bottomLeftBackIndex); }
public void SetLightLevel(RelativeBlockPosition position, byte lightLevel) { lightArray[position.X, position.Y, position.Z] = lightLevel; }
public void Tessellate() { // TODO: I guess DX9 can be CPU-bound by the number of draw calls so we might // want to switch back to a single VB/IB per chunk. var vertexLists = new List<VertexPositionColorLighting>[6]; var indexLists = new List<short>[6]; for (int x = 0; x < 6; x++) { // You'd think that setting a largeish initial capacity would save us some time growing // the lists, but it turns out to be the exact opposite in practice. Not sure why. vertexLists[x] = new List<VertexPositionColorLighting>(); indexLists[x] = new List<short>(); } // We save iteration by only doing a slice of the chunk bounded at the top // by the highest solid block and at the bottom by the lowest non-solid block in the // neighborhood minus one. Anything above or below that isnt going to have geometry. // TODO: If we want to burn extra memory in order to optimize this even more aggressively, // we could keep track of lowest/highest for each colum in the chunk. var lowerTesselationLimit = Math.Max(lowestInvisibleBlock - 1, 0); var tessellator = new Tessellator(world); for (int x = 0; x < XDimension; x++) { for (int y = lowerTesselationLimit; y <= highestVisibleBlock; y++) { for (int z = 0; z < ZDimension; z++) { var position = new RelativeBlockPosition(x, y, z); var prototype = GetBlockPrototype(position); if (prototype.CanBeSeen) { var worldBlockPosition = new BlockPosition(Position, position); tessellator.TessellateBlock(vertexLists, indexLists, worldBlockPosition, position); } } } } // TODO: is the conversion causing extra work here? renderer.Initialize((Vector3)OriginInWorld, vertexLists, indexLists); }
public void SetBlockPrototype(RelativeBlockPosition position, BlockPrototype prototype) { blockArray[position.X, position.Y, position.Z] = prototype; if (prototype.CanBeSeen && position.Y > highestVisibleBlock) { highestVisibleBlock = position.Y; } if (!prototype.CanBeSeen && position.Y < lowestInvisibleBlock) { lowestInvisibleBlock = position.Y; } }
public byte GetLightLevel(RelativeBlockPosition position) { return lightArray[position.X, position.Y, position.Z]; }
public BlockPrototype GetBlockPrototype(RelativeBlockPosition position) { return blockArray[position.X, position.Y, position.Z]; }
// TODO: we should only calculate lighting once all neighbor chunks have geometry // and have sunlight casted public void CalculateLighting() { var calculationLimit = GetHighestVisibleBlockInNeighborhood(); var propagator = new LightPropagator(); for (int x = 0; x < XDimension; x++) { for (int y = lowestSunlitBlock; y <= calculationLimit; y++) { for (int z = 0; z < ZDimension; z++) { // TODO: For now we can propogate only if the light is full strength, // but that won't work for light sources that are less than full strength. Maybe have a source // and destination light map so we don't have to deal with half-calculated data? if (NeedsPropogation(x, y, z)) { propagator.NumberOfRecursions = 0; var relativeBlockPosition = new RelativeBlockPosition(x, y, z); if (GetLightLevel(relativeBlockPosition) == World.MaximumLightLevel) { // TODO: because the propagator will happily move into neighboring chunks to do its work, we need to // think about the implications for multi-threading and race conditions. propagator.PropagateSunlightFromBlock(world, new BlockPosition(Position, relativeBlockPosition)); NumberOfLightPropagations++; } } } } } }
public BlockPosition(ChunkPosition chunkPosition, RelativeBlockPosition relativeBlockPosition) { X = chunkPosition.X * Chunk.XDimension + relativeBlockPosition.X; Y = relativeBlockPosition.Y; Z = chunkPosition.Z * Chunk.XDimension + relativeBlockPosition.Z; }