protected override JobHandle OnUpdate(JobHandle inputDeps) { var barrier = m_Barrier.CreateCommandBuffer().ToConcurrent(); var level = GetSingleton <LevelComponent>(); var voxelBuffer = m_Barrier.GetBufferFromEntity <VoxelBuffer>(false); var updateVoxelHandle = Entities .WithBurst() //.WithoutBurst() .WithNativeDisableParallelForRestriction(voxelBuffer) .WithName("Update_Chunk") .ForEach((Entity entity, int entityInQueryIndex, ref ChunkComponent cc, in UpdateChunkTag updateData, in LocalToParent pp) => { barrier.RemoveComponent <UpdateChunkTag>(entityInQueryIndex, entity); var buffer = voxelBuffer[entity]; var stencil = updateData.input; var stencilCenter = new float4(stencil.centerX, stencil.centerY, 0, 1); var translatedStencil = math.mul(math.inverse(pp.Value), stencilCenter); var xNeighbor = cc.leftNeighbour; var yNeighbor = cc.upNeighbour; stencil.centerX = translatedStencil.x; stencil.centerY = translatedStencil.y; { int xStart = (int)(stencil.XStart / level.voxelSize); int xEnd = (int)((stencil.XEnd) / level.voxelSize); int yStart = (int)(stencil.YStart / level.voxelSize); int yEnd = (int)(stencil.YEnd / level.voxelSize); if (xStart < 0) { xStart = 0; } if (yStart < 0) { yStart = 0; } if (xEnd >= LevelComponent.VoxelResolution) { xEnd = LevelComponent.VoxelResolution - 1; } if (yEnd >= LevelComponent.VoxelResolution) { yEnd = LevelComponent.VoxelResolution - 1; } for (int y = yStart; y <= yEnd; y++) { for (int x = xStart; x <= xEnd; x++) { int i = y * LevelComponent.VoxelResolution + x; float2 pos = buffer[i].Value.position; if (stencil.InRange(pos)) { buffer[i] = buffer[i].Value.Copy(stencil.fillType); if (stencil.shape == VoxelShape.Rectangle) { handleSquareY(ref voxelBuffer, ref buffer, ref stencil, yNeighbor, x, y, i); handleSquareX(ref voxelBuffer, ref buffer, ref stencil, xNeighbor, x, y, i); } else { handleCircleX(ref voxelBuffer, ref buffer, ref stencil, xNeighbor, x, y, i); handleCircleY(ref voxelBuffer, ref buffer, ref stencil, yNeighbor, x, y, i); } } } } } barrier.AddComponent <TriangulateTag>(entityInQueryIndex, entity); }).Schedule(inputDeps);
protected override JobHandle OnUpdate(JobHandle inputDeps) { inputDeps.Complete(); var barrier = m_Barrier.CreateCommandBuffer().ToConcurrent(); var bfe = m_Barrier.GetBufferFromEntity <VoxelBuffer>(true); var level = GetSingleton <LevelComponent>(); var handle = Entities .WithBurst() .WithReadOnly(bfe) .WithName("Do_Triangulation") .WithAll <RenderMesh>() .ForEach((Entity entity, int entityInQueryIndex, ref ChunkComponent cc, in TriangulateTag updateData) => { int edgeCacheMin = 0, edgeCacheMax = 0; var xNeighbour = cc.leftNeighbour; var yNeighbour = cc.upNeighbour; var xyNeighbour = cc.diagNeighbour; var rowCacheMax = new NativeArray <int>(LevelComponent.VoxelResolution * 2 + 1, Allocator.Temp, NativeArrayOptions.UninitializedMemory); var rowCacheMin = new NativeArray <int>(LevelComponent.VoxelResolution * 2 + 1, Allocator.Temp, NativeArrayOptions.UninitializedMemory); barrier.RemoveComponent <TriangulateTag>(entityInQueryIndex, entity); var vertices = barrier.AddBuffer <VectorBuffer>(entityInQueryIndex, entity); var triangles = barrier.AddBuffer <IntBuffer>(entityInQueryIndex, entity); FillFirstRowCache(level.chunkSize); TriangulateCellRows(level.chunkSize); if (cc.upNeighbour != Entity.Null) { TriangulateGapRow(level.chunkSize); } rowCacheMax.Dispose(); rowCacheMin.Dispose(); barrier.AddComponent <MeshAssignTag>(entityInQueryIndex, entity); #region wtf tbh void FillFirstRowCache(float chunkSize) { // first corner var voxels = bfe[entity]; CacheFirstCorner(voxels[0]); int i; for (i = 0; i < LevelComponent.VoxelResolution - 1; i++) { CacheNextEdgeAndCorner(i * 2, voxels[i], voxels[i + 1]); } if (xNeighbour != Entity.Null) { var n = bfe[xNeighbour][0].Value.CopyDummyX(chunkSize); CacheNextEdgeAndCorner(i * 2, voxels[i], n); } } void CacheFirstCorner(Voxel voxel) { if (voxel.state) { rowCacheMax[0] = vertices.Length; vertices.Add(voxel.position); } } void CacheNextEdgeAndCorner(int index, Voxel xMin, Voxel xMax) { Debug.Assert(xMin.position.y == xMax.position.y); if (xMin.state != xMax.state) { rowCacheMax[index + 1] = vertices.Length; vertices.Add(xMin.XEdgePoint); } if (xMax.state) { rowCacheMax[index + 2] = vertices.Length; vertices.Add(xMax.position); } } void TriangulateCellRows(float chunkSize) { var voxels = bfe[entity]; int cells = LevelComponent.VoxelResolution - 1; for (int i = 0, y = 0; y < cells; y++, i++) { SwapRowCaches(); CacheFirstCorner(voxels[i + LevelComponent.VoxelResolution]); CacheNextMiddleEdge(voxels[i], voxels[i + LevelComponent.VoxelResolution]); for (int x = 0; x < cells; x++, i++) { var a = voxels[i]; var b = voxels[i + 1]; var c = voxels[i + LevelComponent.VoxelResolution]; var d = voxels[i + LevelComponent.VoxelResolution + 1]; int cacheIndex = x * 2; CacheNextEdgeAndCorner(cacheIndex, c, d); CacheNextMiddleEdge(b, d); TriangulateCell(cacheIndex, a, b, c, d); } if (xNeighbour != Entity.Null) { TriangulateGapCell(chunkSize, i); } } } void SwapRowCaches() { var temp = rowCacheMin; rowCacheMin = rowCacheMax; rowCacheMax = temp; } void CacheNextMiddleEdge(Voxel yMin, Voxel yMax) { Debug.Assert(yMin.position.x == yMax.position.x); Debug.Assert(yMin.position.y < yMax.position.y); edgeCacheMin = edgeCacheMax; if (yMin.state != yMax.state) { edgeCacheMax = vertices.Length; vertices.Add(yMin.YEdgePoint); } } void TriangulateGapCell(float chunkSize, int i) { Debug.Assert(i % LevelComponent.VoxelResolution == (LevelComponent.VoxelResolution - 1)); var voxels = bfe[entity]; int cacheIndex = (LevelComponent.VoxelResolution - 1) * 2; var a = voxels[i]; var b = bfe[xNeighbour][i + 1 - LevelComponent.VoxelResolution].Value.CopyDummyX(chunkSize); var c = voxels[i + LevelComponent.VoxelResolution]; var d = bfe[xNeighbour][i + 1].Value.CopyDummyX(chunkSize); CacheNextEdgeAndCorner(cacheIndex, voxels[i + LevelComponent.VoxelResolution], d); CacheNextMiddleEdge(b, d); TriangulateCell(cacheIndex, a, b, c, d); } void TriangulateGapRow(float chunkSize) { int cells = LevelComponent.VoxelResolution - 1; int offset = cells * LevelComponent.VoxelResolution; var voxels = bfe[entity]; var neighbourVoxels = bfe[yNeighbour]; var dummyY = neighbourVoxels[0].Value.CopyDummyY(chunkSize); SwapRowCaches(); CacheFirstCorner(dummyY); CacheNextMiddleEdge(voxels[cells * LevelComponent.VoxelResolution], dummyY); for (int x = 0; x < cells; x++) { var dummyT = dummyY.CopyDummyX(0); dummyY = neighbourVoxels[x + 1].Value.CopyDummyY(chunkSize); var cacheIndex = x * 2; CacheNextEdgeAndCorner(cacheIndex, dummyT, dummyY); CacheNextMiddleEdge(voxels[x + offset + 1], dummyY); TriangulateCell(cacheIndex, voxels[x + offset], voxels[x + offset + 1], dummyT, dummyY); } if (xyNeighbour != Entity.Null) { var leftVoxels = bfe[xNeighbour]; var a = voxels[voxels.Length - 1]; var b = leftVoxels[leftVoxels.Length - LevelComponent.VoxelResolution].Value.CopyDummyX(chunkSize); var c = neighbourVoxels[LevelComponent.VoxelResolution - 1].Value.CopyDummyY(chunkSize); var d = bfe[xyNeighbour][0].Value.CopyDummyXY(chunkSize); Debug.Assert(a.Value.position.x == c.position.x); Debug.Assert(a.Value.position.y == b.position.y); Debug.Assert(b.position.x == d.position.x); Debug.Assert(c.position.y == d.position.y); var cacheIndex = cells * 2; CacheNextEdgeAndCorner(cacheIndex, c, d); CacheNextMiddleEdge(b, d); TriangulateCell(cacheIndex, a, b, c, d); } } void TriangulateCell(int i, in Voxel a, in Voxel b, in Voxel c, in Voxel d) { var cas = 0; if (a.state) { cas |= 0b0001; } if (b.state) { cas |= 0b0010; } if (c.state) { cas |= 0b0100; } if (d.state) { cas |= 0b1000; } switch (cas) { case 0: break; case 1: AddTriangle(rowCacheMin[i], edgeCacheMin, rowCacheMin[i + 1], ref triangles); break; case 2: AddTriangle(rowCacheMin[i + 2], rowCacheMin[i + 1], edgeCacheMax, ref triangles); break; case 3: AddQuad(rowCacheMin[i], edgeCacheMin, edgeCacheMax, rowCacheMin[i + 2], ref triangles); break; case 4: AddTriangle(rowCacheMax[i], rowCacheMax[i + 1], edgeCacheMin, ref triangles); break; case 5: AddQuad(rowCacheMin[i], rowCacheMax[i], rowCacheMax[i + 1], rowCacheMin[i + 1], ref triangles); break; case 6: AddTriangle(rowCacheMin[i + 2], rowCacheMin[i + 1], edgeCacheMax, ref triangles); AddTriangle(rowCacheMax[i], rowCacheMax[i + 1], edgeCacheMin, ref triangles); break; case 7: AddPentagon( rowCacheMin[i], rowCacheMax[i], rowCacheMax[i + 1], edgeCacheMax, rowCacheMin[i + 2], ref triangles); break; case 8: AddTriangle(rowCacheMax[i + 2], edgeCacheMax, rowCacheMax[i + 1], ref triangles); break; case 9: AddTriangle(rowCacheMin[i], edgeCacheMin, rowCacheMin[i + 1], ref triangles); AddTriangle(rowCacheMax[i + 2], edgeCacheMax, rowCacheMax[i + 1], ref triangles); break; case 10: AddQuad(rowCacheMin[i + 1], rowCacheMax[i + 1], rowCacheMax[i + 2], rowCacheMin[i + 2], ref triangles); break; case 11: AddPentagon( rowCacheMin[i + 2], rowCacheMin[i], edgeCacheMin, rowCacheMax[i + 1], rowCacheMax[i + 2], ref triangles); break; case 12: AddQuad(edgeCacheMin, rowCacheMax[i], rowCacheMax[i + 2], edgeCacheMax, ref triangles); break; case 13: AddPentagon( rowCacheMax[i], rowCacheMax[i + 2], edgeCacheMax, rowCacheMin[i + 1], rowCacheMin[i], ref triangles); break; case 14: AddPentagon( rowCacheMax[i + 2], rowCacheMin[i + 2], rowCacheMin[i + 1], edgeCacheMin, rowCacheMax[i], ref triangles); break; case 15: AddQuad(rowCacheMin[i], rowCacheMax[i], rowCacheMax[i + 2], rowCacheMin[i + 2], ref triangles); break; } } #endregion }).Schedule(inputDeps); m_Barrier.AddJobHandleForProducer(handle); return(handle); }