protected override void LoadInternal(int fileVersion, Stream stream, ref bool isOldFormat) { Debug.Assert(fileVersion == CURRENT_FILE_VERSION); ChunkHeader header = new ChunkHeader(); Dictionary <byte, MyVoxelMaterialDefinition> materialTable = null; HashSet <UInt64> materialLeaves = new HashSet <UInt64>(); HashSet <UInt64> contentLeaves = new HashSet <UInt64>(); while (header.ChunkType != ChunkTypeEnum.EndOfFile) { MyMicroOctreeLeaf contentLeaf; MyMicroOctreeLeaf materialLeaf; UInt64 key; header.ReadFrom(stream); Debug.Assert(Enum.IsDefined(typeof(ChunkTypeEnum), header.ChunkType)); switch (header.ChunkType) { case ChunkTypeEnum.StorageMetaData: ReadStorageMetaData(stream, header, ref isOldFormat); break; case ChunkTypeEnum.MaterialIndexTable: materialTable = ReadMaterialTable(stream, header, ref isOldFormat); break; case ChunkTypeEnum.MacroContentNodes: ReadOctreeNodes(stream, header, ref isOldFormat, m_contentNodes); break; case ChunkTypeEnum.MacroMaterialNodes: ReadOctreeNodes(stream, header, ref isOldFormat, m_materialNodes); break; case ChunkTypeEnum.ContentLeafProvider: ReadProviderLeaf(stream, header, ref isOldFormat, contentLeaves); break; case ChunkTypeEnum.ContentLeafOctree: ReadOctreeLeaf(stream, header, ref isOldFormat, MyStorageDataTypeEnum.Content, out key, out contentLeaf); m_contentLeaves.Add(key, contentLeaf); break; case ChunkTypeEnum.MaterialLeafProvider: ReadProviderLeaf(stream, header, ref isOldFormat, materialLeaves); break; case ChunkTypeEnum.MaterialLeafOctree: ReadOctreeLeaf(stream, header, ref isOldFormat, MyStorageDataTypeEnum.Material, out key, out materialLeaf); m_materialLeaves.Add(key, materialLeaf); break; case ChunkTypeEnum.DataProvider: ReadDataProvider(stream, header, ref isOldFormat, out m_dataProvider); break; case ChunkTypeEnum.EndOfFile: break; default: throw new InvalidBranchException(); } } { // At this point data provider should be loaded too, so have him create leaves MyCellCoord cell = new MyCellCoord(); foreach (var key in contentLeaves) { cell.SetUnpack(key); cell.Lod += LeafLodCount; m_contentLeaves.Add(key, new MyProviderLeaf(m_dataProvider, MyStorageDataTypeEnum.Content, ref cell)); } foreach (var key in materialLeaves) { cell.SetUnpack(key); cell.Lod += LeafLodCount; m_materialLeaves.Add(key, new MyProviderLeaf(m_dataProvider, MyStorageDataTypeEnum.Material, ref cell)); } } { // material reindexing when definitions change Debug.Assert(materialTable != null); bool needsReindexing = false; foreach (var entry in materialTable) { if (entry.Key != entry.Value.Index) { needsReindexing = true; } m_oldToNewIndexMap.Add(entry.Key, entry.Value.Index); } if (needsReindexing) { if (m_dataProvider != null) { m_dataProvider.ReindexMaterials(m_oldToNewIndexMap); } foreach (var entry in m_materialLeaves) { entry.Value.ReplaceValues(m_oldToNewIndexMap); } MySparseOctree.ReplaceValues(m_materialNodes, m_oldToNewIndexMap); } m_oldToNewIndexMap.Clear(); } }
IMyClipmapCell IMyClipmapCellHandler.CreateCell(MyClipmapScaleEnum scaleGroup, MyCellCoord cellCoord, ref MatrixD worldMatrix) { switch (scaleGroup) { case MyClipmapScaleEnum.Normal: return(new MyRenderVoxelCell(scaleGroup, cellCoord, ref worldMatrix)); case MyClipmapScaleEnum.Massive: return(new MyRenderVoxelCellBackground(cellCoord, ref worldMatrix, m_position, m_atmosphereRadius, m_planetRadius, m_hasAtmosphere, m_atmosphereWaveLengths.Value)); default: throw new InvalidBranchException(); } }
internal CellData GetCell(ref MyCellCoord cell) { MyPrecalcComponent.AssertUpdateThread(); bool isEmpty; CellData data; if (TryGetCell(cell, out isEmpty, out data)) { return(data); } MyIsoMesh mesh; if (!TryGetMesh(cell, out isEmpty, out mesh)) { ProfilerShort.Begin("Cell precalc"); if (true) { var min = cell.CoordInLod << MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS; var max = min + MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS; // overlap to neighbor; introduces extra data but it makes logic for raycasts simpler (no need to check neighbor cells) min -= 1; max += 2; mesh = MyPrecalcComponent.IsoMesher.Precalc(m_storage, 0, min, max, false); } else { mesh = MyPrecalcComponent.IsoMesher.Precalc(new MyIsoMesherArgs() { Storage = m_storage, GeometryCell = cell, }); } ProfilerShort.End(); } if (mesh != null) { data = new CellData(); data.Init( mesh.PositionOffset, mesh.PositionScale, mesh.Positions.GetInternalArray(), mesh.VerticesCount, mesh.Triangles.GetInternalArray(), mesh.TrianglesCount); } if (cell.Lod == 0) { using (m_lock.AcquireExclusiveUsing()) { if (data != null) { var key = cell.PackId64(); m_cellsByCoordinate[key] = data; } else { SetEmpty(ref cell, true); } } } return(data); }
public void ProcessChangedCellComponents() { ProfilerShort.Begin("ProcessChangedCellComponents"); m_currentHelper = this; Vector3I min, max, pos; List <int> triangles = null; foreach (var cell in m_changedCells) { MyCellCoord cellCoord = new MyCellCoord(0, cell); ulong packedCell = cellCoord.PackId64(); m_components.OpenCell(packedCell); min = CellToLowestCube(cell); max = min + m_cellSize - Vector3I.One; // Save a hashset of all the triangles in the current cell pos = min; for (var it = new Vector3I.RangeIterator(ref min, ref max); it.IsValid(); it.GetNext(out pos)) { if (!m_triangleRegistry.TryGetValue(pos, out triangles)) { continue; } foreach (var triIndex in triangles) { m_tmpCellTriangles.Add(triIndex); } } long timeBegin = m_mesh.GetCurrentTimestamp() + 1; long timeEnd = timeBegin; m_currentComponentRel = 0; foreach (var triIndex in m_tmpCellTriangles) { // Skip already visited triangles var triangle = m_mesh.GetTriangle(triIndex); if (m_currentComponentRel != 0 && m_mesh.VisitedBetween(triangle, timeBegin, timeEnd)) { continue; } m_components.OpenComponent(); // Make sure we have place in m_currentCellConnections if (m_currentComponentRel >= m_currentCellConnections.Count) { m_currentCellConnections.Add(new List <int>()); } // Find connected component from an unvisited triangle and mark its connections m_components.AddComponentTriangle(triangle, triangle.Center); triangle.ComponentIndex = m_components.OpenComponentIndex; m_mesh.PrepareTraversal(triangle, null, m_processTrianglePredicate); var primitiveEnum = m_mesh.GetEnumerator(); while (primitiveEnum.MoveNext()) { ; } primitiveEnum.Dispose(); m_components.CloseComponent(); timeEnd = m_mesh.GetCurrentTimestamp(); if (m_currentComponentRel == 0) { timeBegin = timeEnd; } m_currentComponentRel++; } m_tmpCellTriangles.Clear(); MyNavmeshComponents.ClosedCellInfo cellInfo = new MyNavmeshComponents.ClosedCellInfo(); m_components.CloseAndCacheCell(ref cellInfo); // Add new component primitives if (cellInfo.NewCell) { for (int i = 0; i < cellInfo.ComponentNum; ++i) { m_mesh.HighLevelGroup.AddPrimitive(cellInfo.StartingIndex + i, m_components.GetComponentCenter(i)); } } // Connect new components with the others in the neighboring cells for (int i = 0; i < cellInfo.ComponentNum; ++i) { foreach (var otherComponent in m_currentCellConnections[i]) { m_mesh.HighLevelGroup.ConnectPrimitives(cellInfo.StartingIndex + i, otherComponent); } m_currentCellConnections[i].Clear(); } // Set all the components as expanded for (int i = 0; i < cellInfo.ComponentNum; ++i) { int componentIndex = cellInfo.StartingIndex + i; var component = m_mesh.HighLevelGroup.GetPrimitive(componentIndex); if (component != null) { component.IsExpanded = true; } } } m_changedCells.Clear(); m_currentHelper = null; ProfilerShort.End(); }
private void AddVoxelMesh(MyVoxelBase voxelBase, IMyStorage storage, Dictionary <Vector3I, MyIsoMesh> cache, float border, Vector3D originPosition, MyOrientedBoundingBoxD obb, List <BoundingBoxD> bbList) { bool useCache = cache != null; if (useCache) { CheckCacheValidity(); } obb.HalfExtent += new Vector3D(border, 0, border); BoundingBoxD bb = obb.GetAABB(); int aabbSideSide = (int)Math.Round(bb.HalfExtents.Max() * 2); bb = new BoundingBoxD(bb.Min, bb.Min + aabbSideSide); bb.Translate(obb.Center - bb.Center); // For debug bbList.Add(new BoundingBoxD(bb.Min, bb.Max)); bb = (BoundingBoxD)bb.TransformFast(voxelBase.PositionComp.WorldMatrixInvScaled); bb.Translate(voxelBase.SizeInMetresHalf); Vector3I min = Vector3I.Round(bb.Min); Vector3I max = min + aabbSideSide; Vector3I geomMin, geomMax; MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref min, out geomMin); MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref max, out geomMax); var cullBox = obb; cullBox.Transform(voxelBase.PositionComp.WorldMatrixInvScaled); cullBox.Center += voxelBase.SizeInMetresHalf; ProfilerShort.Begin("WOOOORK"); Vector3I_RangeIterator it = new Vector3I_RangeIterator(ref geomMin, ref geomMax); MyCellCoord coord = new MyCellCoord(); BoundingBox localAabb; coord.Lod = NAVMESH_LOD; int hits = 0; MyIsoMesh gMesh; Vector3 offset = originPosition - voxelBase.PositionLeftBottomCorner; // Calculate rotation Vector3 gravityVector = -Vector3.Normalize(GameSystems.MyGravityProviderSystem.CalculateTotalGravityInPoint(originPosition)); Vector3 forwardVector = Vector3.CalculatePerpendicularVector(gravityVector); Quaternion quaternion = Quaternion.CreateFromForwardUp(forwardVector, gravityVector); Matrix rotation = Matrix.CreateFromQuaternion(Quaternion.Inverse(quaternion)); Matrix ownRotation = voxelBase.PositionComp.WorldMatrix.GetOrientation(); while (it.IsValid()) { ProfilerShort.Begin("ITERATOR"); if (useCache && cache.TryGetValue(it.Current, out gMesh)) { if (gMesh != null) { AddMeshTriangles(gMesh, offset, rotation, ownRotation); } it.MoveNext(); ProfilerShort.End(); continue; } coord.CoordInLod = it.Current; MyVoxelCoordSystems.GeometryCellCoordToLocalAABB(ref coord.CoordInLod, out localAabb); if (!cullBox.Intersects(ref localAabb)) { hits++; it.MoveNext(); ProfilerShort.End(); continue; } ProfilerShort.End(); var debugBB = new BoundingBoxD(localAabb.Min, localAabb.Max).Translate(-voxelBase.SizeInMetresHalf); bbList.Add(debugBB); ProfilerShort.Begin("Mesh Calc"); var voxelStart = coord.CoordInLod * MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS - 1; var voxelEnd = voxelStart + MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS //- 1 + 1 // overlap to neighbor so geometry is stitched together within same LOD + 1; // for eg. 9 vertices in row we need 9 + 1 samples (voxels) var generatedMesh = MyPrecalcComponent.IsoMesher.Precalc(storage, NAVMESH_LOD, voxelStart, voxelEnd, false, false, true); ProfilerShort.End(); if (useCache) { cache[it.Current] = generatedMesh; } if (generatedMesh != null) { ProfilerShort.Begin("Mesh NOT NULL"); AddMeshTriangles(generatedMesh, offset, rotation, ownRotation); ProfilerShort.End(); } it.MoveNext(); } ProfilerShort.End(); }
public void ProcessChangedCellComponents() { ProfilerShort.Begin("ProcessChangedCellComponents"); m_currentHelper = this; Vector3I min, max, pos; List <int> triangles = null; foreach (var cell in m_changedCells) { min = CellToLowestCube(cell); max = min + m_cellSize - Vector3I.One; // Save a hashset of all the triangles in the current cell pos = min; for (var it = new Vector3I.RangeIterator(ref min, ref max); it.IsValid(); it.GetNext(out pos)) { if (!m_triangleRegistry.TryGetValue(pos, out triangles)) { continue; } foreach (var triIndex in triangles) { m_tmpCellTriangles.Add(triIndex); } } if (m_tmpCellTriangles.Count == 0) { continue; } MyCellCoord cellCoord = new MyCellCoord(0, cell); ulong packedCell = cellCoord.PackId64(); m_components.OpenCell(packedCell); long timeBegin = m_mesh.GetCurrentTimestamp() + 1; long timeEnd = timeBegin; m_currentComponentRel = 0; m_tmpComponentTriangles.Clear(); foreach (var triIndex in m_tmpCellTriangles) { // Skip already visited triangles var triangle = m_mesh.GetTriangle(triIndex); if (m_currentComponentRel != 0 && m_mesh.VisitedBetween(triangle, timeBegin, timeEnd)) { continue; } m_components.OpenComponent(); // Make sure we have place in m_currentCellConnections if (m_currentComponentRel >= m_currentCellConnections.Count) { m_currentCellConnections.Add(new List <int>()); } // Find connected component from an unvisited triangle and mark its connections m_components.AddComponentTriangle(triangle, triangle.Center); triangle.ComponentIndex = m_currentComponentRel; m_tmpComponentTriangles.Add(triangle); m_mesh.PrepareTraversal(triangle, null, m_processTrianglePredicate); m_mesh.PerformTraversal(); m_tmpComponentTriangles.Add(null); m_components.CloseComponent(); timeEnd = m_mesh.GetCurrentTimestamp(); if (m_currentComponentRel == 0) { timeBegin = timeEnd; } m_currentComponentRel++; } m_tmpCellTriangles.Clear(); MyNavmeshComponents.ClosedCellInfo cellInfo = new MyNavmeshComponents.ClosedCellInfo(); m_components.CloseAndCacheCell(ref cellInfo); // Renumber triangles from the old indices to the newly assigned index from m_components int componentIndex = cellInfo.StartingIndex; foreach (var triangle in m_tmpComponentTriangles) { if (triangle == null) { componentIndex++; continue; } triangle.ComponentIndex = componentIndex; } m_tmpComponentTriangles.Clear(); // Remove old component primitives if (!cellInfo.NewCell && cellInfo.ComponentNum != cellInfo.OldComponentNum) { for (int i = 0; i < cellInfo.OldComponentNum; ++i) { m_mesh.HighLevelGroup.RemovePrimitive(cellInfo.OldStartingIndex + i); } } // Add new component primitives if (cellInfo.NewCell || cellInfo.ComponentNum != cellInfo.OldComponentNum) { for (int i = 0; i < cellInfo.ComponentNum; ++i) { m_mesh.HighLevelGroup.AddPrimitive(cellInfo.StartingIndex + i, m_components.GetComponentCenter(i)); } } // Update existing component primitives if (!cellInfo.NewCell && cellInfo.ComponentNum == cellInfo.OldComponentNum) { for (int i = 0; i < cellInfo.ComponentNum; ++i) { var primitive = m_mesh.HighLevelGroup.GetPrimitive(cellInfo.StartingIndex + i); primitive.UpdatePosition(m_components.GetComponentCenter(i)); } } // Connect new components with the others in the neighboring cells for (int i = 0; i < cellInfo.ComponentNum; ++i) { int compIndex = cellInfo.StartingIndex + i; var primitive = m_mesh.HighLevelGroup.GetPrimitive(compIndex); primitive.GetNeighbours(m_tmpNeighbors); // Connect to disconnected components foreach (var connection in m_currentCellConnections[i]) { if (!m_tmpNeighbors.Remove(connection)) { m_mesh.HighLevelGroup.ConnectPrimitives(compIndex, connection); } } // Disconnect neighbors that should be no longer connected foreach (var neighbor in m_tmpNeighbors) { // Only disconnect from the other cell if it is expanded and there was no connection found var neighborPrimitive = m_mesh.HighLevelGroup.TryGetPrimitive(neighbor); if (neighborPrimitive != null && neighborPrimitive.IsExpanded) { m_mesh.HighLevelGroup.DisconnectPrimitives(compIndex, neighbor); } } m_tmpNeighbors.Clear(); m_currentCellConnections[i].Clear(); } // Set all the components as expanded for (int i = 0; i < cellInfo.ComponentNum; ++i) { componentIndex = cellInfo.StartingIndex + i; var component = m_mesh.HighLevelGroup.GetPrimitive(componentIndex); if (component != null) { component.IsExpanded = true; } } } m_changedCells.Clear(); m_currentHelper = null; ProfilerShort.End(); }
public MyProviderLeaf(IMyStorageDataProvider provider, MyStorageDataTypeEnum dataType, ref MyCellCoord cell) { m_provider = provider; m_dataType = dataType; m_cell = cell; }
public void ProcessChangedCellComponents() { m_currentHelper = this; List <int> list = null; foreach (Vector3I vectori4 in this.m_changedCells) { Vector3I start = this.CellToLowestCube(vectori4); Vector3I end = ((Vector3I)(start + this.m_cellSize)) - Vector3I.One; Vector3I key = start; Vector3I_RangeIterator iterator = new Vector3I_RangeIterator(ref start, ref end); while (true) { if (!iterator.IsValid()) { if (m_tmpCellTriangles.Count != 0) { ulong cellCoord = new MyCellCoord(0, vectori4).PackId64(); this.m_components.OpenCell(cellCoord); long num2 = this.m_mesh.GetCurrentTimestamp() + 1L; long currentTimestamp = num2; this.m_currentComponentRel = 0; this.m_tmpComponentTriangles.Clear(); foreach (int num6 in m_tmpCellTriangles) { MyNavigationTriangle vertex = this.m_mesh.GetTriangle(num6); if ((this.m_currentComponentRel == 0) || !this.m_mesh.VisitedBetween(vertex, num2, currentTimestamp)) { this.m_components.OpenComponent(); if (this.m_currentComponentRel >= this.m_currentCellConnections.Count) { this.m_currentCellConnections.Add(new List <int>()); } this.m_components.AddComponentTriangle(vertex, vertex.Center); vertex.ComponentIndex = this.m_currentComponentRel; this.m_tmpComponentTriangles.Add(vertex); this.m_mesh.PrepareTraversal(vertex, null, this.m_processTrianglePredicate, null); this.m_mesh.PerformTraversal(); this.m_tmpComponentTriangles.Add(null); this.m_components.CloseComponent(); currentTimestamp = this.m_mesh.GetCurrentTimestamp(); if (this.m_currentComponentRel == 0) { num2 = currentTimestamp; } this.m_currentComponentRel++; } } m_tmpCellTriangles.Clear(); MyNavmeshComponents.ClosedCellInfo output = new MyNavmeshComponents.ClosedCellInfo(); this.m_components.CloseAndCacheCell(ref output); int startingIndex = output.StartingIndex; foreach (MyNavigationTriangle triangle2 in this.m_tmpComponentTriangles) { if (triangle2 == null) { startingIndex++; continue; } triangle2.ComponentIndex = startingIndex; } this.m_tmpComponentTriangles.Clear(); if (!output.NewCell && (output.ComponentNum != output.OldComponentNum)) { for (int i = 0; i < output.OldComponentNum; i++) { this.m_mesh.HighLevelGroup.RemovePrimitive(output.OldStartingIndex + i); } } if (output.NewCell || (output.ComponentNum != output.OldComponentNum)) { for (int i = 0; i < output.ComponentNum; i++) { this.m_mesh.HighLevelGroup.AddPrimitive(output.StartingIndex + i, this.m_components.GetComponentCenter(i)); } } if (!output.NewCell && (output.ComponentNum == output.OldComponentNum)) { for (int i = 0; i < output.ComponentNum; i++) { this.m_mesh.HighLevelGroup.GetPrimitive(output.StartingIndex + i).UpdatePosition(this.m_components.GetComponentCenter(i)); } } int num10 = 0; while (true) { if (num10 >= output.ComponentNum) { for (int i = 0; i < output.ComponentNum; i++) { startingIndex = output.StartingIndex + i; MyHighLevelPrimitive primitive = this.m_mesh.HighLevelGroup.GetPrimitive(startingIndex); if (primitive != null) { primitive.IsExpanded = true; } } break; } int index = output.StartingIndex + num10; this.m_mesh.HighLevelGroup.GetPrimitive(index).GetNeighbours(this.m_tmpNeighbors); foreach (int num12 in this.m_currentCellConnections[num10]) { if (!this.m_tmpNeighbors.Remove(num12)) { this.m_mesh.HighLevelGroup.ConnectPrimitives(index, num12); } } foreach (int num13 in this.m_tmpNeighbors) { MyHighLevelPrimitive primitive = this.m_mesh.HighLevelGroup.TryGetPrimitive(num13); if ((primitive != null) && primitive.IsExpanded) { this.m_mesh.HighLevelGroup.DisconnectPrimitives(index, num13); } } this.m_tmpNeighbors.Clear(); this.m_currentCellConnections[num10].Clear(); num10++; } } break; } if (this.m_triangleRegistry.TryGetValue(key, out list)) { foreach (int num5 in list) { m_tmpCellTriangles.Add(num5); } } iterator.GetNext(out key); } } this.m_changedCells.Clear(); m_currentHelper = null; }
private void UnclipCell(RequestCollector collector, MyCellCoord cell, bool isVisible) { var cellId = cell.PackId64(); var clipmapCellId = MyCellCoord.GetClipmapCellHash(m_clipmap.Id, cellId); MyClipmap_CellData data; if (isVisible) { bool highPriority = true; if (m_clippedCells.TryGetValue(cellId, out data)) { m_clippedCells.Remove(cellId); } else { highPriority = false; CellBlendData blendData; if (!m_blendedCells.TryGetValue(cellId, out blendData)) { data = CellsCache.Read(clipmapCellId); if (data == null) //cache miss { data = new MyClipmap_CellData(); ClippingCacheMisses++; } else { //cache hit ClippingCacheHits++; //System.Diagnostics.Debug.Assert((!data.InScene && data.Cell != null) || data.Cell == null, "Not allowed cell state"); data.InScene = false; if (data.Cell != null) { m_nonEmptyCells[cellId] = data; } } } else { data = blendData.CellData; if (blendData.State == BlendState.Removing) { blendData.UndoAfterFinish = true; } if (data.Cell != null) { m_nonEmptyCells[cellId] = data; } } } if (data.State == CellState.Invalid) { if (MyClipmap.UseQueries) { BoundingBoxD bbd; MyVoxelCoordSystems.RenderCellCoordToLocalAABB(ref cell, out bbd); BoundingBox bb = new BoundingBox(bbd); if (m_clipmap.m_prunningFunc == null || m_clipmap.m_prunningFunc(ref bb, false) == ContainmentType.Intersects) { collector.AddRequest(cellId, data, highPriority); } else { data.State = CellState.Loaded; data.WasLoaded = true; } } else { collector.AddRequest(cellId, data, highPriority); } } m_storedCellData.Add(cellId, data); data.ReadyInClipmap = true; data.ClippedOut = false; } else { if (!m_storedCellData.ContainsKey(cellId) && (!PendingCacheCellData.ContainsKey(clipmapCellId) || PendingCacheCellData[clipmapCellId].State == CellState.Invalid) && CellsCache.Read(clipmapCellId) == null) { if (!PendingCacheCellData.TryGetValue(clipmapCellId, out data)) { data = new MyClipmap_CellData(); PendingCacheCellData.Add(clipmapCellId, data); } if (MyClipmap.UseQueries) { BoundingBoxD bbd; MyVoxelCoordSystems.RenderCellCoordToLocalAABB(ref cell, out bbd); BoundingBox bb = new BoundingBox(bbd); if (m_clipmap.m_prunningFunc == null || m_clipmap.m_prunningFunc(ref bb, false) == ContainmentType.Intersects) { data.State = CellState.Invalid; collector.AddRequest(cellId, data, false); } else { data.State = CellState.Loaded; data.WasLoaded = true; } } else { data.State = CellState.Invalid; collector.AddRequest(cellId, data, false); } } } }
private static void WriteRange( ref WriteRangeArgs args, byte defaultData, int lodIdx, Vector3I lodCoord, ref Vector3I min, ref Vector3I max) { MyOctreeNode node = new MyOctreeNode(); { MyCellCoord leaf = new MyCellCoord(lodIdx - LeafLodCount, ref lodCoord); var leafKey = leaf.PackId64(); if (args.Leaves.ContainsKey(leafKey)) { args.Leaves.Remove(leafKey); var childBase = lodCoord << 1; Vector3I childOffset; MyCellCoord child = new MyCellCoord(); child.Lod = leaf.Lod - 1; var leafSize = LeafSizeInVoxels << child.Lod; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { ComputeChildCoord(i, out childOffset); child.CoordInLod = childBase + childOffset; var childCopy = child; childCopy.Lod += LeafLodCount; IMyOctreeLeafNode octreeLeaf = new MyProviderLeaf(args.Provider, args.DataType, ref childCopy); args.Leaves.Add(child.PackId64(), octreeLeaf); node.SetChild(i, true); node.SetData(i, octreeLeaf.GetFilteredValue()); } } else { leaf.Lod -= 1; // changes to node coord instead of leaf coord var nodeKey = leaf.PackId64(); if (!args.Nodes.TryGetValue(nodeKey, out node)) { for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { node.SetData(i, defaultData); } } } } if (lodIdx == (LeafLodCount + 1)) { MyCellCoord child = new MyCellCoord(); Vector3I childBase = lodCoord << 1; Vector3I minInLod = min >> LeafLodCount; Vector3I maxInLod = max >> LeafLodCount; Vector3I leafSizeMinusOne = new Vector3I(LeafSizeInVoxels - 1); Vector3I childOffset; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { ComputeChildCoord(i, out childOffset); child.CoordInLod = childBase + childOffset; if (!child.CoordInLod.IsInsideInclusive(ref minInLod, ref maxInLod)) { continue; } var childMin = child.CoordInLod << LeafLodCount; var childMax = childMin + LeafSizeInVoxels - 1; Vector3I.Max(ref childMin, ref min, out childMin); Vector3I.Min(ref childMax, ref max, out childMax); var readOffset = childMin - min; IMyOctreeLeafNode leaf; var leafKey = child.PackId64(); var startInChild = childMin - (child.CoordInLod << LeafLodCount); var endInChild = childMax - (child.CoordInLod << LeafLodCount); args.Leaves.TryGetValue(leafKey, out leaf); byte uniformValue; bool uniformLeaf; { // ensure leaf exists and is writable // the only writable leaf type is MicroOctree at this point byte childDefaultData = node.GetData(i); if (leaf == null) { var octree = new MyMicroOctreeLeaf(args.DataType, LeafLodCount, child.CoordInLod << (child.Lod + LeafLodCount)); octree.BuildFrom(childDefaultData); leaf = octree; } if (leaf.ReadOnly) { var rangeEnd = new Vector3I(LeafSizeInVoxels - 1); m_temporaryCache.Resize(Vector3I.Zero, rangeEnd); leaf.ReadRange(m_temporaryCache, ref Vector3I.Zero, 0, ref Vector3I.Zero, ref rangeEnd); var inCell = startInChild; for (var it2 = new Vector3I.RangeIterator(ref startInChild, ref endInChild); it2.IsValid(); it2.GetNext(out inCell)) { var read = readOffset + (inCell - startInChild); m_temporaryCache.Set(args.DataType, ref inCell, args.Source.Get(args.DataType, ref read)); } var octree = new MyMicroOctreeLeaf(args.DataType, LeafLodCount, child.CoordInLod << (child.Lod + LeafLodCount)); octree.BuildFrom(m_temporaryCache); leaf = octree; } else { leaf.WriteRange(args.Source, ref readOffset, ref startInChild, ref endInChild); } uniformLeaf = ((MyMicroOctreeLeaf)leaf).TryGetUniformValue(out uniformValue); } if (!uniformLeaf) { args.Leaves[leafKey] = leaf; node.SetChild(i, true); } else { args.Leaves.Remove(leafKey); node.SetChild(i, false); } node.SetData(i, leaf.GetFilteredValue()); } args.Nodes[new MyCellCoord(lodIdx - 1 - LeafLodCount, ref lodCoord).PackId64()] = node; } else { MyCellCoord child = new MyCellCoord(); child.Lod = lodIdx - 2 - LeafLodCount; var childBase = lodCoord << 1; Vector3I childOffset; var minInChild = (min >> (lodIdx - 1)) - childBase; var maxInChild = (max >> (lodIdx - 1)) - childBase; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { ComputeChildCoord(i, out childOffset); if (!childOffset.IsInsideInclusive(ref minInChild, ref maxInChild)) { continue; } child.CoordInLod = childBase + childOffset; WriteRange(ref args, node.GetData(i), lodIdx - 1, child.CoordInLod, ref min, ref max); var childKey = child.PackId64(); var childNode = args.Nodes[childKey]; if (!childNode.HasChildren && childNode.AllDataSame()) { node.SetChild(i, false); node.SetData(i, childNode.GetData(0)); args.Nodes.Remove(childKey); } else { node.SetChild(i, true); node.SetData(i, childNode.ComputeFilteredValue(args.DataFilter)); } } args.Nodes[new MyCellCoord(lodIdx - 1 - LeafLodCount, ref lodCoord).PackId64()] = node; } }
public void ProcessCellComponents() { ProfilerShort.Begin("ProcessCellComponents"); m_triangleLists.Add(m_packedCoord, m_triangleList.GetCopy()); long timeBegin = m_mesh.GetCurrentTimestamp() + 1; long timeEnd = timeBegin; m_currentComponentRel = 0; m_currentComponent = m_navmeshComponents.OpenCell(m_packedCoord); foreach (var triIndex in m_triangleList) { // Skip already visited triangles var triangle = m_mesh.GetTriangle(triIndex); if (m_mesh.VisitedBetween(triangle, timeBegin, timeEnd)) { continue; } m_navmeshComponents.OpenComponent(); // Make sure we have place in m_currentCellConnections if (m_currentComponentRel >= m_currentCellConnections.Count) { m_currentCellConnections.Add(new List <ConnectionInfo>()); } // Find connected component from an unvisited triangle ProfilerShort.Begin("Graph traversal"); m_currentHelper = this; m_navmeshComponents.AddComponentTriangle(triangle, triangle.Center); triangle.ComponentIndex = m_navmeshComponents.OpenComponentIndex; m_mesh.PrepareTraversal(triangle, null, m_processTrianglePredicate); var primitiveEnum = m_mesh.GetEnumerator(); while (primitiveEnum.MoveNext()) { ; } primitiveEnum.Dispose(); ProfilerShort.End(); m_navmeshComponents.CloseComponent(); timeEnd = m_mesh.GetCurrentTimestamp(); m_currentComponentRel++; } MyNavmeshComponents.ClosedCellInfo cellInfo = new MyNavmeshComponents.ClosedCellInfo(); m_navmeshComponents.CloseAndCacheCell(ref cellInfo); // Add new component primitives if (cellInfo.NewCell) { for (int i = 0; i < cellInfo.ComponentNum; ++i) { m_mesh.HighLevelGroup.AddPrimitive(cellInfo.StartingIndex + i, m_navmeshComponents.GetComponentCenter(i)); } } // Connect new components with the others in the neighboring cells for (int i = 0; i < cellInfo.ComponentNum; ++i) { foreach (var connectionInfo in m_currentCellConnections[i]) { if (!cellInfo.ExploredDirections.HasFlag(Base6Directions.GetDirectionFlag(connectionInfo.Direction))) { m_mesh.HighLevelGroup.ConnectPrimitives(cellInfo.StartingIndex + i, connectionInfo.ComponentIndex); } } m_currentCellConnections[i].Clear(); } // Mark explored directions in the navmesh component helper foreach (var direction in Base6Directions.EnumDirections) { var dirFlag = Base6Directions.GetDirectionFlag(direction); if (cellInfo.ExploredDirections.HasFlag(dirFlag)) { continue; } Vector3I dirVec = Base6Directions.GetIntVector(direction); MyCellCoord otherCoord = new MyCellCoord(); otherCoord.Lod = MyVoxelNavigationMesh.NAVMESH_LOD; otherCoord.CoordInLod = m_currentCell + dirVec; if (otherCoord.CoordInLod.X == -1 || otherCoord.CoordInLod.Y == -1 || otherCoord.CoordInLod.Z == -1) { continue; } ulong otherPackedCoord = otherCoord.PackId64(); if (m_triangleLists.ContainsKey(otherPackedCoord)) { m_navmeshComponents.MarkExplored(otherPackedCoord, Base6Directions.GetFlippedDirection(direction)); cellInfo.ExploredDirections |= Base6Directions.GetDirectionFlag(direction); } } m_navmeshComponents.SetExplored(m_packedCoord, cellInfo.ExploredDirections); // Set all the components as expanded for (int i = 0; i < cellInfo.ComponentNum; ++i) { int componentIndex = cellInfo.StartingIndex + i; var component = m_mesh.HighLevelGroup.GetPrimitive(componentIndex); if (component != null) { component.IsExpanded = true; } } ProfilerShort.End(); }
private static unsafe void ReadRange( MyStorageDataCache target, ref Vector3I targetWriteOffset, MyStorageDataTypeEnum type, int treeHeight, Dictionary <UInt64, MyOctreeNode> nodes, Dictionary <UInt64, IMyOctreeLeafNode> leaves, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod) { int stackIdx = 0; int stackSize = MySparseOctree.EstimateStackSize(treeHeight); MyCellCoord *stack = stackalloc MyCellCoord[stackSize]; MyCellCoord data = new MyCellCoord(treeHeight + LeafLodCount, ref Vector3I.Zero); stack[stackIdx++] = data; MyCellCoord cell = new MyCellCoord(); while (stackIdx > 0) { Debug.Assert(stackIdx <= stackSize); data = stack[--stackIdx]; cell.Lod = data.Lod - LeafLodCount; cell.CoordInLod = data.CoordInLod; int lodDiff; IMyOctreeLeafNode leaf; if (leaves.TryGetValue(cell.PackId64(), out leaf)) { lodDiff = data.Lod - lodIndex; var rangeMinInDataLod = minInLod >> lodDiff; var rangeMaxInDataLod = maxInLod >> lodDiff; if (data.CoordInLod.IsInsideInclusive(ref rangeMinInDataLod, ref rangeMaxInDataLod)) { var nodePosInLod = data.CoordInLod << lodDiff; var writeOffset = nodePosInLod - minInLod; Vector3I.Max(ref writeOffset, ref Vector3I.Zero, out writeOffset); writeOffset += targetWriteOffset; var lodSizeMinusOne = new Vector3I((1 << lodDiff) - 1); var minInLeaf = Vector3I.Clamp(minInLod - nodePosInLod, Vector3I.Zero, lodSizeMinusOne); var maxInLeaf = Vector3I.Clamp(maxInLod - nodePosInLod, Vector3I.Zero, lodSizeMinusOne); leaf.ReadRange(target, ref writeOffset, lodIndex, ref minInLeaf, ref maxInLeaf); } continue; } cell.Lod -= 1; lodDiff = data.Lod - 1 - lodIndex; var node = nodes[cell.PackId64()]; var min = minInLod >> lodDiff; var max = maxInLod >> lodDiff; var nodePositionInChild = data.CoordInLod << 1; min -= nodePositionInChild; max -= nodePositionInChild; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { Vector3I childPosRelative; ComputeChildCoord(i, out childPosRelative); if (!childPosRelative.IsInsideInclusive(ref min, ref max)) { continue; } if (lodIndex < data.Lod && node.HasChild(i)) { Debug.Assert(stackIdx < stackSize); stack[stackIdx++] = new MyCellCoord(data.Lod - 1, nodePositionInChild + childPosRelative); } else { var childMin = nodePositionInChild + childPosRelative; childMin <<= lodDiff; var writeOffset = childMin - minInLod; Vector3I.Max(ref writeOffset, ref Vector3I.Zero, out writeOffset); writeOffset += targetWriteOffset; var nodeData = node.GetData(i); if (lodDiff == 0) { target.Set(type, ref writeOffset, nodeData); } else { var childMax = childMin + ((1 << lodDiff) - 1); Vector3I.Max(ref childMin, ref minInLod, out childMin); Vector3I.Min(ref childMax, ref maxInLod, out childMax); for (int z = childMin.Z; z <= childMax.Z; ++z) { for (int y = childMin.Y; y <= childMax.Y; ++y) { for (int x = childMin.X; x <= childMax.X; ++x) { Vector3I write = writeOffset; write.X += x - childMin.X; write.Y += y - childMin.Y; write.Z += z - childMin.Z; target.Set(type, ref write, nodeData); } } } } } } } }
private static bool ResetOutsideBorders( IMyStorageDataProvider provider, MyStorageDataTypeEnum dataType, int lodIdx, Dictionary <UInt64, MyOctreeNode> nodes, Dictionary <UInt64, IMyOctreeLeafNode> leaves, Vector3I lodCoord, Vector3I minVoxel, Vector3I maxVoxel, out bool canCollapse, Dictionary <UInt64, IMyOctreeLeafNode> outResetLeaves = null) { canCollapse = false; bool changed = false; var currentCell = new MyCellCoord(lodIdx, lodCoord); var key = currentCell.PackId64(); var leafCell = currentCell; var leafKey = leafCell.PackId64(); IMyOctreeLeafNode leaf; if (leaves.TryGetValue(leafKey, out leaf)) { canCollapse = leaf.ReadOnly; if (leafCell.Lod != 0) { Debug.Assert(leaf.ReadOnly); return(false); } else if (!leaf.ReadOnly) { var minCell = minVoxel >> (LeafLodCount + leafCell.Lod); var maxCell = maxVoxel >> (LeafLodCount + leafCell.Lod); if (!leafCell.CoordInLod.IsInsideInclusive(ref minCell, ref maxCell)) { canCollapse = true; leaves.Remove(leafKey); var leafCellCopy = leafCell; leafCellCopy.Lod += LeafLodCount; var leafNew = new MyProviderLeaf(provider, dataType, ref leafCellCopy); leaves.Add(leafKey, leafNew); changed = true; if (outResetLeaves != null) { outResetLeaves.Add(leafKey, leafNew); } } } } else { currentCell.Lod -= 1; key = currentCell.PackId64(); var nodeCell = currentCell; var nodeKey = currentCell.PackId64(); var node = nodes[nodeKey]; var childBase = lodCoord << 1; Vector3I childOffset; var minInChild = (minVoxel >> (LeafLodCount + currentCell.Lod)) - childBase; var maxInChild = (maxVoxel >> (LeafLodCount + currentCell.Lod)) - childBase; var leafSize = LeafSizeInVoxels << currentCell.Lod; unsafe { canCollapse = true; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; i++) { ComputeChildCoord(i, out childOffset); if (childOffset.IsInsideExclusive(ref minInChild, ref maxInChild)) { canCollapse = false; continue; } currentCell.CoordInLod = childBase + childOffset; if (node.HasChild(i)) { bool localCanCollapse; bool resetChanged = ResetOutsideBorders(provider, dataType, currentCell.Lod, nodes, leaves, currentCell.CoordInLod, minVoxel, maxVoxel, out localCanCollapse, outResetLeaves: outResetLeaves); changed = changed || resetChanged; canCollapse = localCanCollapse && canCollapse; } else { var currentCellCopy = currentCell; currentCellCopy.Lod += LeafLodCount; IMyOctreeLeafNode octreeLeaf = new MyProviderLeaf(provider, dataType, ref currentCellCopy); leaves.Add(currentCell.PackId64(), octreeLeaf); node.SetChild(i, true); node.SetData(i, octreeLeaf.GetFilteredValue()); changed = true; } } nodes[nodeKey] = node; if (canCollapse) { // Remove leaves for (int i = 0; i < MyOctreeNode.CHILD_COUNT; i++) { if (node.HasChild(i)) { ComputeChildCoord(i, out childOffset); currentCell.CoordInLod = childBase + childOffset; var childKey = currentCell.PackId64(); leaves.Remove(childKey); node.SetChild(i, false); } } // Remove node nodes.Remove(nodeKey); // Add leaf var leafCellCopy = leafCell; leafCellCopy.Lod += LeafLodCount; var leafNew = new MyProviderLeaf(provider, dataType, ref leafCellCopy); leaves.Add(leafKey, leafNew); } } } return(changed); }
private static ulong CountChangedVoxelsAmount( MyOctreeStorage baseStorage, int lodIdx, Dictionary <UInt64, MyOctreeNode> nodes, Dictionary <UInt64, IMyOctreeLeafNode> leaves, Vector3I lodCoord) { var currentCell = new MyCellCoord(lodIdx, lodCoord); var leafKey = currentCell.PackId64(); IMyOctreeLeafNode leaf; if (leaves.TryGetValue(leafKey, out leaf)) { if (!leaf.ReadOnly && currentCell.Lod == 0) { // Read data from leaf var rangeEnd = new Vector3I(LeafSizeInVoxels - 1); m_temporaryCache.Resize(Vector3I.Zero, rangeEnd); leaf.ReadRange(m_temporaryCache, ref Vector3I.Zero, 0, ref Vector3I.Zero, ref rangeEnd); // Read data from base storage var minLeafVoxel = currentCell.CoordInLod * LeafSizeInVoxels; var maxLeafVoxel = minLeafVoxel + (LeafSizeInVoxels - 1); m_temporaryCache2.Resize(minLeafVoxel, maxLeafVoxel); baseStorage.ReadRange(m_temporaryCache2, MyStorageDataTypeFlags.Content, currentCell.Lod, ref minLeafVoxel, ref maxLeafVoxel); byte[] origData = m_temporaryCache2.Data; byte[] currData = m_temporaryCache.Data; Debug.Assert(currData.Length == origData.Length); if (currData.Length != origData.Length) { return(0); } ulong countChangedVoxels = 0; for (int i = (int)MyStorageDataTypeEnum.Content; i < m_temporaryCache.SizeLinear; i += m_temporaryCache.StepLinear) { countChangedVoxels += (ulong)Math.Abs(currData[i] - origData[i]); } return(countChangedVoxels); } } else { currentCell.Lod -= 1; var nodeKey = currentCell.PackId64(); var node = nodes[nodeKey]; var childBase = lodCoord << 1; Vector3I childOffset; if (node.HasChildren) { ulong count = 0; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; i++) { if (node.HasChild(i)) { ComputeChildCoord(i, out childOffset); currentCell.CoordInLod = childBase + childOffset; count += CountChangedVoxelsAmount(baseStorage, currentCell.Lod, nodes, leaves, currentCell.CoordInLod); } } return(count); } else { return((ulong)((MyOctreeNode.CHILD_COUNT << (currentCell.Lod * 3)) * LeafSizeInVoxels * LeafSizeInVoxels * LeafSizeInVoxels * MyVoxelConstants.VOXEL_CONTENT_FULL)); } } return(0); }
private unsafe void WriteRange( MyCellCoord cell, TLeafData defaultData, MyStorageData source, MyStorageDataTypeEnum type, ref Vector3I readOffset, ref Vector3I min, ref Vector3I max) { var nodeKey = cell.PackId32(); MyOctreeNode node; if (!m_nodes.TryGetValue(nodeKey, out node)) { for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { node.Data[i] = defaultData; } } if (cell.Lod == 0) { var childBase = cell.CoordInLod << 1; Vector3I childOffset; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { ComputeChildCoord(i, out childOffset); var child = childBase + childOffset; if (!child.IsInsideInclusive(ref min, ref max)) { continue; } child -= min; child += readOffset; node.Data[i] = source.Get(type, ref child); } m_nodes[nodeKey] = node; } else { var childBase = cell.CoordInLod << 1; Vector3I childOffset; var minInChild = (min >> cell.Lod) - childBase; var maxInChild = (max >> cell.Lod) - childBase; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { ComputeChildCoord(i, out childOffset); if (!childOffset.IsInsideInclusive(ref minInChild, ref maxInChild)) { continue; } var childCell = new MyCellCoord(cell.Lod - 1, childBase + childOffset); WriteRange(childCell, node.Data[i], source, type, ref readOffset, ref min, ref max); var childKey = childCell.PackId32(); var childNode = m_nodes[childKey]; if (!childNode.HasChildren && MyOctreeNode.AllDataSame(childNode.Data)) { node.SetChild(i, false); node.Data[i] = childNode.Data[0]; m_nodes.Remove(childKey); } else { node.SetChild(i, true); node.Data[i] = m_nodeFilter(childNode.Data, cell.Lod); } } m_nodes[nodeKey] = node; } }
internal void SetCellMesh(MyRenderMessageUpdateClipmapCell msg) { var cellId = msg.Metadata.Cell.PackId64(); MyClipmap_CellData data; var clipmapCellId = MyCellCoord.GetClipmapCellHash(m_clipmap.Id, cellId); // MyCellCoord cellc = new MyCellCoord(); // cellc.SetUnpack(cellId); //MyLog.Default.WriteLine("SetCellMesh Lod: " + cellc.Lod + " Coord: " + cellc.CoordInLod); if (m_storedCellData.TryGetValue(cellId, out data)) { PendingCacheCellData.Remove(clipmapCellId); if (data.State == CellState.Invalid) { // MyLog.Default.WriteLine("Invalid"); //Cell was invalidated while calculating from old data return; } if (data.Cell == null && msg.Batches.Count != 0) { //MyLog.Default.WriteLine("added to nonempty"); data.Cell = m_clipmap.m_cellHandler.CreateCell(m_clipmap.m_scaleGroup, msg.Metadata.Cell, ref m_clipmap.m_worldMatrix); System.Diagnostics.Debug.Assert(data.Cell != null, "Cell not created"); if (data.Cell != null) { if (data.Cell.IsValid()) { data.CellHandler = m_clipmap.m_cellHandler; m_nonEmptyCells[cellId] = data; } } } else if (data.Cell != null && msg.Batches.Count == 0) { //MyLog.Default.WriteLine("removed"); RemoveFromScene(cellId, data); m_nonEmptyCells.Remove(cellId); m_clipmap.m_cellHandler.DeleteCell(data.Cell); m_blendedCells.Remove(cellId); data.Cell = null; data.CellHandler = null; if (UseCache) { CellsCache.Remove(cellId); } } if (data.Cell != null) { //MyLog.Default.WriteLine("mesh updated"); if (data.Cell.IsValid()) { m_clipmap.m_cellHandler.UpdateMesh(data.Cell, msg); } } data.State = CellState.Loaded; data.WasLoaded = true; } else if (PendingCacheCellData.TryGetValue(clipmapCellId, out data)) { if (msg.Batches.Count != 0) { data.Cell = m_clipmap.m_cellHandler.CreateCell(m_clipmap.m_scaleGroup, msg.Metadata.Cell, ref m_clipmap.m_worldMatrix); m_clipmap.m_cellHandler.UpdateMesh(data.Cell, msg); data.CellHandler = m_clipmap.m_cellHandler; } CellsCache.Write(clipmapCellId, data); PendingCacheCellData.Remove(clipmapCellId); data.State = CellState.Loaded; data.WasLoaded = true; } }
internal unsafe ContainmentType Intersect(ref BoundingBoxI box, bool lazy) { int stackIdx = 0; int stackSize = MySparseOctree.EstimateStackSize(m_treeHeight); MyCellCoord *stack = stackalloc MyCellCoord[stackSize]; MyCellCoord data = new MyCellCoord(m_treeHeight - 1, ref Vector3I.Zero); stack[stackIdx++] = data; Vector3I minInLod = box.Min; Vector3I maxInLod = box.Max; MyOctreeNode node; Vector3I childPosRelative, min, max, nodePositionInChild; int lodDiff; // TODO(DI): Add support for checking for containment somehow, this needs neighbourhood information which kinda sucks. ContainmentType cont = ContainmentType.Disjoint; while (stackIdx > 0) { Debug.Assert(stackIdx <= stackSize); data = stack[--stackIdx]; node = m_nodes[data.PackId32()]; lodDiff = data.Lod; min = minInLod >> lodDiff; max = maxInLod >> lodDiff; nodePositionInChild = data.CoordInLod << 1; min -= nodePositionInChild; max -= nodePositionInChild; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { ComputeChildCoord(i, out childPosRelative); if (!childPosRelative.IsInsideInclusive(ref min, ref max)) { continue; } if (data.Lod > 0 && node.HasChild(i)) { Debug.Assert(stackIdx < stackSize); stack[stackIdx++] = new MyCellCoord(data.Lod - 1, nodePositionInChild + childPosRelative); } else { var nodeData = node.Data[i]; if (lodDiff == 0) { if (nodeData != 0) { return(ContainmentType.Intersects); } } else { BoundingBoxI nodeBox; nodeBox.Min = nodePositionInChild + childPosRelative; nodeBox.Min <<= lodDiff; nodeBox.Max = nodeBox.Min + (1 << lodDiff) - 1; Vector3I.Max(ref nodeBox.Min, ref minInLod, out nodeBox.Min); Vector3I.Min(ref nodeBox.Max, ref maxInLod, out nodeBox.Max); bool res; nodeBox.Intersects(ref nodeBox, out res); if (res) { return(ContainmentType.Intersects); } } } } } return(cont); }
public void DebugDraw() { //if (m_lodIndex > 5) // return; // if (m_lodIndex == 1) // { // float sizeInMetres = MyVoxelCoordSystems.RenderCellSizeInMeters(m_lodIndex); // //var start = localFarCameraBox.Min; // //var end = localFarCameraBox.Max; // var start = m_localNearCameraBox.Min; // var end = m_localNearCameraBox.Max; // Vector3I coord = start; // Color nearColor = Color.Yellow; // Color farColor = Color.White; // var startF = m_localFarCameraBox.Min; // var endF = m_localFarCameraBox.Max; // Vector3I coordF = startF; //// for (var it = new Vector3I_RangeIterator(ref startF, ref endF); ////it.IsValid(); it.GetNext(out coordF)) //// { //// Vector3D min = Vector3D.Transform((Vector3D)(sizeInMetres * coordF), m_parent.m_worldMatrix); //// Vector3D max = Vector3D.Transform((Vector3D)(sizeInMetres * coordF + new Vector3(sizeInMetres)), m_parent.m_worldMatrix); //// BoundingBoxD aabb = new BoundingBoxD(min, max); //// MyRenderProxy.DebugDrawAABB(aabb, farColor, 1, 1, false); //// if (Vector3D.Distance(CameraFrustumGetter().Matrix.Translation, aabb.Center) < 200) //// MyRenderProxy.DebugDrawText3D(aabb.Center, coordF.ToString(), farColor, 0.5f, false); //// } // for (var it = new Vector3I_RangeIterator(ref start, ref end); //it.IsValid(); it.GetNext(out coord)) // { // Vector3D min = Vector3D.Transform((Vector3D)(sizeInMetres * coord), m_clipmap.m_worldMatrix); // Vector3D max = Vector3D.Transform((Vector3D)(sizeInMetres * coord + new Vector3(sizeInMetres)), m_clipmap.m_worldMatrix); // BoundingBoxD aabb = new BoundingBoxD(min, max); // MyRenderProxy.DebugDrawAABB(aabb, nearColor, 1, 1, false); // } // Vector3D center = Vector3D.Transform(m_localPosition, m_clipmap.m_worldMatrix); // MyRenderProxy.DebugDrawSphere(center, m_nearDistance, nearColor, 1, false); // MyRenderProxy.DebugDrawSphere(center, m_farDistance, farColor, 1, false); // } var camera = m_clipmap.LastCameraPosition; //if (m_lodIndex < 6) { float sizeInMetres = MyVoxelCoordSystems.RenderCellSizeInMeters(m_lodIndex); Color color = LOD_COLORS[m_lodIndex] + new Vector4(0.2f); foreach (var cell in m_storedCellData) { if (!cell.Value.InScene) { continue; } MyCellCoord cellStr = new MyCellCoord(); cellStr.SetUnpack(cell.Key); var coordF = cellStr.CoordInLod; Vector3D min = Vector3D.Transform((Vector3D)(sizeInMetres * coordF), m_clipmap.m_worldMatrix); Vector3D max = Vector3D.Transform((Vector3D)(sizeInMetres * coordF + new Vector3(sizeInMetres)), m_clipmap.m_worldMatrix); BoundingBoxD aabb = new BoundingBoxD(min, max); double distance = Vector3D.Distance(camera, aabb.Center); //if (distance < sizeInMetres * 4) MyRenderProxy.DebugDrawAABB(aabb, color, 1, 1, true); if (distance < sizeInMetres * 2) { MyRenderProxy.DebugDrawText3D(aabb.Center, String.Format("{0}:{1}", m_lodIndex, coordF.ToString()), color, 0.7f, false); } } if (m_storedCellData.Count > 0) { Vector3D center = Vector3D.Transform(m_localPosition, m_clipmap.m_worldMatrix); //MyRenderProxy.DebugDrawSphere(center, m_farDistance, color, 1, false); } } }
private unsafe void AddVoxelMesh(MyVoxelBase voxelBase, IMyStorage storage, Dictionary <Vector3I, MyIsoMesh> cache, float border, Vector3D originPosition, MyOrientedBoundingBoxD obb, List <BoundingBoxD> bbList) { Vector3I vectori3; Vector3I vectori4; bool flag = cache != null; if (flag) { this.CheckCacheValidity(); } Vector3D *vectordPtr1 = (Vector3D *)ref obb.HalfExtent; vectordPtr1[0] += new Vector3D((double)border, 0.0, (double)border); BoundingBoxD aABB = obb.GetAABB(); int num = (int)Math.Round((double)(aABB.HalfExtents.Max() * 2.0)); BoundingBoxD *xdPtr1 = (BoundingBoxD *)ref aABB; xdPtr1 = (BoundingBoxD *)new BoundingBoxD(aABB.Min, aABB.Min + num); ((BoundingBoxD *)ref aABB).Translate(obb.Center - aABB.Center); bbList.Add(new BoundingBoxD(aABB.Min, aABB.Max)); aABB = aABB.TransformFast(voxelBase.PositionComp.WorldMatrixInvScaled); aABB.Translate(voxelBase.SizeInMetresHalf); Vector3I voxelCoord = Vector3I.Round(aABB.Min); Vector3I vectori2 = (Vector3I)(voxelCoord + num); MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref voxelCoord, out vectori3); MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref vectori2, out vectori4); MyOrientedBoundingBoxD xd2 = obb; xd2.Transform(voxelBase.PositionComp.WorldMatrixInvScaled); Vector3D *vectordPtr2 = (Vector3D *)ref xd2.Center; vectordPtr2[0] += voxelBase.SizeInMetresHalf; Vector3I_RangeIterator iterator = new Vector3I_RangeIterator(ref vectori3, ref vectori4); MyCellCoord coord = new MyCellCoord { Lod = 0 }; int num2 = 0; Vector3 offset = (Vector3)(originPosition - voxelBase.PositionLeftBottomCorner); Vector3 up = -Vector3.Normalize(MyGravityProviderSystem.CalculateTotalGravityInPoint(originPosition)); Matrix rotation = Matrix.CreateFromQuaternion(Quaternion.Inverse(Quaternion.CreateFromForwardUp(Vector3.CalculatePerpendicularVector(up), up))); Matrix orientation = (Matrix)voxelBase.PositionComp.WorldMatrix.GetOrientation(); while (iterator.IsValid()) { BoundingBox box; MyIsoMesh mesh; if (flag && cache.TryGetValue(iterator.Current, out mesh)) { if (mesh != null) { this.AddMeshTriangles(mesh, offset, rotation, orientation); } iterator.MoveNext(); continue; } coord.CoordInLod = iterator.Current; MyVoxelCoordSystems.GeometryCellCoordToLocalAABB(ref coord.CoordInLod, out box); if (!xd2.Intersects(ref box)) { num2++; iterator.MoveNext(); } else { BoundingBoxD item = new BoundingBoxD(box.Min, box.Max).Translate(-voxelBase.SizeInMetresHalf); bbList.Add(item); Vector3I lodVoxelMin = (coord.CoordInLod * 8) - 1; MyIsoMesh mesh2 = MyPrecalcComponent.IsoMesher.Precalc(storage, 0, lodVoxelMin, (Vector3I)(((lodVoxelMin + 8) + 1) + 1), MyStorageDataTypeFlags.Content, 0); if (flag) { cache[iterator.Current] = mesh2; } if (mesh2 != null) { this.AddMeshTriangles(mesh2, offset, rotation, orientation); } iterator.MoveNext(); } } }
internal void DoClipping(float camDistanceFromCenter, Vector3D localPosition, float farPlaneDistance, RequestCollector collector, bool frustumCulling, float rangeScale) { int lodIndex = m_lodIndex; if (!ShouldBeThisLodVisible(camDistanceFromCenter)) { MyUtils.Swap(ref m_storedCellData, ref m_clippedCells); m_storedCellData.Clear(); return; } m_localPosition = localPosition; MyClipmap.ComputeLodViewBounds(m_clipmap.m_scaleGroup, lodIndex, out m_nearDistance, out m_farDistance); farPlaneDistance *= rangeScale; m_farDistance *= rangeScale; m_nearDistance *= rangeScale; m_fitsInFrustum = (farPlaneDistance * 1.25f) > m_nearDistance; if (!m_fitsInFrustum && m_lodIndex == lodIndex) { return; } //var localFrustum = new BoundingFrustumD(CameraFrustumGetter().Matrix * m_parent.m_invWorldMatrix); var frustum = CameraFrustumGetter(); Vector3I min, max; // Vector3I ignoreMin, ignoreMax; var minD = m_localPosition - (double)m_farDistance; var maxD = m_localPosition + (double)m_farDistance; MyVoxelCoordSystems.LocalPositionToRenderCellCoord(lodIndex, ref minD, out min); MyVoxelCoordSystems.LocalPositionToRenderCellCoord(lodIndex, ref maxD, out max); BoundingBoxI lodBox = new BoundingBoxI(Vector3I.Zero, Vector3I.Max(m_lodSizeMinusOne, Vector3I.Zero)); bool intersects = false; //bool intersectsNear = false; m_localFarCameraBox = new BoundingBoxI(min, max); m_localNearCameraBox = new BoundingBoxI(min, max); if (lodBox.Intersects(m_localFarCameraBox)) { intersects = true; var intersection = lodBox; intersection.IntersectWith(ref m_localFarCameraBox); min = intersection.Min; max = intersection.Max; //Optimize only LOD2 and higher by two lods, because neighbour cells shares border cells //if (m_lodIndex > 1) //{ // float lowerFar, lowerNear; // MyClipmap.ComputeLodViewBounds(m_clipmap.m_scaleGroup, m_lodIndex - 2, out lowerFar, out lowerNear); // var minNear = m_localPosition - (lowerNear - MyVoxelCoordSystems.RenderCellSizeInMeters(m_lodIndex) / 2); // var maxNear = m_localPosition + (lowerNear - MyVoxelCoordSystems.RenderCellSizeInMeters(m_lodIndex) / 2); // MyVoxelCoordSystems.LocalPositionToRenderCellCoord(m_lodIndex, ref minNear, out ignoreMin); // MyVoxelCoordSystems.LocalPositionToRenderCellCoord(m_lodIndex, ref maxNear, out ignoreMax); // m_localNearCameraBox = new BoundingBoxI(ignoreMin, ignoreMax); // if (lodBox.Intersects(m_localNearCameraBox)) // intersectsNear = false; //} } //if (m_lastMin == min && m_lastMax == max && !m_clipmap.m_updateClipping) // return; //m_lastMin = min; //m_lastMax = max; //LodLevel parentLod, childLod; //GetNearbyLodLevels(out parentLod, out childLod); // Moves cells which are still needed from one collection to another. // All that is left behind is unloaded as no longer needed. // Move everything in range to collection of next stored cells. if (frustumCulling) { MyUtils.Swap(ref m_storedCellData, ref m_clippedCells); m_storedCellData.Clear(); } if (intersects) { float sizeInMetres = MyVoxelCoordSystems.RenderCellSizeInMeters(lodIndex); MyCellCoord cell = new MyCellCoord(lodIndex, ref min); for (var it = new Vector3I_RangeIterator(ref min, ref max); it.IsValid(); it.GetNext(out cell.CoordInLod)) { //if (intersectsNear && // m_localNearCameraBox.Contains(cell.CoordInLod) == ContainmentType.Contains) // continue; //if (frustumCulling) //{ // Vector3D minAABB = Vector3D.Transform((Vector3D)(sizeInMetres * (cell.CoordInLod - 2)), m_clipmap.m_worldMatrix); // Vector3D maxAABB = Vector3D.Transform((Vector3D)(sizeInMetres * (cell.CoordInLod + 2) + new Vector3(sizeInMetres)), m_clipmap.m_worldMatrix); // if (frustum.Contains(new BoundingBoxD(minAABB, maxAABB)) == ContainmentType.Disjoint) // { // m_outsideCells.Add(cell.CoordInLod); // continue; // } //} UnclipCell(collector, cell, true); } //cache cells around frustum if (collector.SentRequestsEmpty) { foreach (var outsideCell in m_outsideCells) { cell.CoordInLod = outsideCell; UnclipCell(collector, cell, frustumCulling); } } m_outsideCells.Clear(); } }
internal static void QueueJobCancel(MyWorkTracker <MyCellCoord, MyPrecalcJobPhysicsPrefetch> tracker, MyCellCoord id) { var threadCommandBuffer = ThreadCommandBuffer; lock (threadCommandBuffer) { ThreadCommandBuffer.Add(new JobCancelCommand { Tracker = tracker, Id = id, }); } }
internal unsafe void DebugDraw(IMyDebugDrawBatchAabb batch, Vector3 worldPos, MyVoxelDebugDrawMode mode) { Color?nullable; if (mode == MyVoxelDebugDrawMode.Content_MicroNodes) { foreach (KeyValuePair <uint, MyOctreeNode> pair in this.m_nodes) { MyCellCoord coord = new MyCellCoord(); coord.SetUnpack(pair.Key); MyOctreeNode node = pair.Value; for (int i = 0; i < 8; i++) { if (!node.HasChild(i) || (coord.Lod == 0)) { Vector3I vectori; BoundingBoxD xd; this.ComputeChildCoord(i, out vectori); Vector3I vectori2 = (Vector3I)((coord.CoordInLod << (coord.Lod + 1)) + (vectori << coord.Lod)); xd.Min = worldPos + (vectori2 * 1f); BoundingBoxD *xdPtr1 = (BoundingBoxD *)ref xd; xdPtr1->Max = xd.Min + (1f * (1 << (coord.Lod & 0x1f))); if (node.GetData(i) != 0) { nullable = null; batch.Add(ref xd, nullable); } } } } return; } else if (mode != MyVoxelDebugDrawMode.Content_MicroNodesScaled) { return; } foreach (KeyValuePair <uint, MyOctreeNode> pair2 in this.m_nodes) { MyCellCoord coord2 = new MyCellCoord(); coord2.SetUnpack(pair2.Key); MyOctreeNode node2 = pair2.Value; for (int i = 0; i < 8; i++) { if (!node2.HasChild(i)) { Vector3I vectori3; this.ComputeChildCoord(i, out vectori3); float num3 = ((float)node2.GetData(i)) / 255f; if (num3 != 0f) { BoundingBoxD xd2; num3 = (float)Math.Pow(num3 * 1.0, 0.3333); Vector3I vectori4 = (Vector3I)((coord2.CoordInLod << (coord2.Lod + 1)) + (vectori3 << coord2.Lod)); float num4 = 1f * (1 << (coord2.Lod & 0x1f)); Vector3 vector = (worldPos + (vectori4 * 1f)) + (0.5f * num4); xd2.Min = vector - ((0.5f * num3) * num4); xd2.Max = vector + ((0.5f * num3) * num4); nullable = null; batch.Add(ref xd2, nullable); } } } } }
public override void DoWork() { ProfilerShort.Begin("MyPrecalcJobRender.DoWork"); try { if (m_isCancelled) return; m_metadata.Cell = m_args.Cell; m_metadata.LocalAabb = BoundingBox.CreateInvalid(); var cellSize = MyVoxelCoordSystems.RenderCellSizeInLodVoxels(m_args.Cell.Lod); var min = m_args.Cell.CoordInLod * cellSize - 1; var max = min + cellSize - 1 + 1 // overlap to neighbor so geometry is stitched together within same LOD + 1 // extra overlap so there are more vertices for mapping to parent LOD + 1; // for eg. 9 vertices in row we need 9 + 1 samples (voxels) // + 1 // why not // + 1 // martin kroslak approved var clipmapCellId = MyCellCoord.GetClipmapCellHash(m_args.ClipmapId, m_args.Cell.PackId64()); MyIsoMesh highResMesh = IsoMeshCache.Read(clipmapCellId); if (highResMesh == null) { highResMesh = MyPrecalcComponent.IsoMesher.Precalc(m_args.Storage, m_args.Cell.Lod, min, max, true, MyFakes.ENABLE_VOXEL_COMPUTED_OCCLUSION); if (UseIsoCache && highResMesh != null) IsoMeshCache.Write(clipmapCellId, highResMesh); } if (m_isCancelled || highResMesh == null) return; MyIsoMesh lowResMesh = null; if (m_args.Cell.Lod < 15 && MyFakes.ENABLE_VOXEL_LOD_MORPHING) { var nextLodCell = m_args.Cell; nextLodCell.Lod++; clipmapCellId = MyCellCoord.GetClipmapCellHash(m_args.ClipmapId, nextLodCell.PackId64()); lowResMesh = IsoMeshCache.Read(clipmapCellId); if (lowResMesh == null) { // Less detailed mesh for vertex morph targets min >>= 1; max >>= 1; min -= 1; max += 2; lowResMesh = MyPrecalcComponent.IsoMesher.Precalc(m_args.Storage, m_args.Cell.Lod + 1, min, max, true, MyFakes.ENABLE_VOXEL_COMPUTED_OCCLUSION); if (UseIsoCache && lowResMesh != null) IsoMeshCache.Write(clipmapCellId, lowResMesh); } } if (m_isCancelled) return; RenderCellBuilder.BuildCell(m_args, highResMesh, lowResMesh, m_batches, out m_metadata); } finally { ProfilerShort.End(); } }
internal unsafe ContainmentType Intersect(ref BoundingBoxI box, int lod, bool exhaustiveContainmentCheck = true) { MyCellCoord *coordPtr = (MyCellCoord *)stackalloc byte[(((IntPtr)EstimateStackSize(this.m_treeHeight)) * sizeof(MyCellCoord))]; MyCellCoord coord = new MyCellCoord(this.m_treeHeight - 1, ref Vector3I.Zero); int index = 0 + 1; coordPtr[index] = coord; Vector3I min = box.Min; Vector3I max = box.Max; ContainmentType disjoint = ContainmentType.Disjoint; while (index > 0) { coord = coordPtr[--index]; MyOctreeNode node = this.m_nodes[coord.PackId32()]; int num3 = coord.Lod; Vector3I vectori6 = coord.CoordInLod << 1; Vector3I vectori4 = (min >> num3) - vectori6; Vector3I vectori5 = (max >> num3) - vectori6; for (int i = 0; i < 8; i++) { Vector3I vectori3; this.ComputeChildCoord(i, out vectori3); if (vectori3.IsInsideInclusiveEnd(ref vectori4, ref vectori5)) { if ((coord.Lod > 0) && node.HasChild(i)) { index++; coordPtr[index] = new MyCellCoord(coord.Lod - 1, (Vector3I)(vectori6 + vectori3)); } else { byte num5 = &node.Data.FixedElementField[i]; if (num3 == 0) { if (num5 != 0) { return(ContainmentType.Intersects); } } else { BoundingBoxI xi; bool flag; xi.Min = (Vector3I)(vectori6 + vectori3); Vector3I *vectoriPtr1 = (Vector3I *)ref xi.Min; vectoriPtr1[0] = vectoriPtr1[0] << num3; BoundingBoxI *xiPtr1 = (BoundingBoxI *)ref xi; xiPtr1->Max = (Vector3I)((xi.Min + (1 << (num3 & 0x1f))) - 1); Vector3I.Max(ref xi.Min, ref min, out xi.Min); Vector3I.Min(ref xi.Max, ref max, out xi.Max); ((BoundingBoxI *)ref xi).Intersects(ref xi, out flag); if (flag) { return(ContainmentType.Intersects); } } } } } } return(disjoint); }
private bool AddCell(Vector3I cellPos) { MyCellCoord coord = new MyCellCoord(NAVMESH_LOD, cellPos); var geometry = m_voxelMap.Storage.Geometry; MyVoxelGeometry.CellData data = geometry.GetCell(ref coord); if (data == null) { m_processedCells.Add(ref cellPos); m_higherLevelHelper.AddExplored(ref cellPos); return(false); } ulong packedCoord = coord.PackId64(); List <DebugDrawEdge> debugEdgesList = new List <DebugDrawEdge>(); m_debugCellEdges[packedCoord] = debugEdgesList; MyVoxelPathfinding.CellId cellId = new MyVoxelPathfinding.CellId() { VoxelMap = m_voxelMap, Pos = cellPos }; MyTrace.Send(TraceWindow.Ai, "Adding cell " + cellPos); m_connectionHelper.ClearCell(); m_vertexMapping.Init(data.VoxelVerticesCount); // Prepare list of possibly intersecting cube grids for voxel-grid navmesh intersection testing Vector3D bbMin = m_voxelMap.PositionLeftBottomCorner + (m_cellSize * (new Vector3D(-0.125) + cellPos)); Vector3D bbMax = m_voxelMap.PositionLeftBottomCorner + (m_cellSize * (Vector3D.One + cellPos)); BoundingBoxD cellBB = new BoundingBoxD(bbMin, bbMax); m_tmpGridList.Clear(); m_navmeshCoordinator.PrepareVoxelTriangleTests(cellBB, m_tmpGridList); Vector3D voxelMapCenter = m_voxelMap.PositionComp.GetPosition(); Vector3 centerDisplacement = voxelMapCenter - m_voxelMap.PositionLeftBottomCorner; // This is needed for correct edge classification - to tell, whether the edges are inner or outer edges of the cell ProfilerShort.Begin("Triangle preprocessing"); for (int i = 0; i < data.VoxelTrianglesCount; i++) { short a = data.VoxelTriangles[i].VertexIndex0; short b = data.VoxelTriangles[i].VertexIndex1; short c = data.VoxelTriangles[i].VertexIndex2; Vector3 aPos, bPos, cPos; Vector3 vert; data.GetUnpackedPosition(a, out vert); aPos = vert - centerDisplacement; data.GetUnpackedPosition(b, out vert); bPos = vert - centerDisplacement; data.GetUnpackedPosition(c, out vert); cPos = vert - centerDisplacement; bool invalidTriangle = false; if ((bPos - aPos).LengthSquared() <= MyVoxelConnectionHelper.OUTER_EDGE_EPSILON_SQ) { m_vertexMapping.Union(a, b); invalidTriangle = true; } if ((cPos - aPos).LengthSquared() <= MyVoxelConnectionHelper.OUTER_EDGE_EPSILON_SQ) { m_vertexMapping.Union(a, c); invalidTriangle = true; } if ((cPos - bPos).LengthSquared() <= MyVoxelConnectionHelper.OUTER_EDGE_EPSILON_SQ) { m_vertexMapping.Union(b, c); invalidTriangle = true; } if (invalidTriangle) { continue; } m_connectionHelper.PreprocessInnerEdge(a, b); m_connectionHelper.PreprocessInnerEdge(b, c); m_connectionHelper.PreprocessInnerEdge(c, a); } ProfilerShort.End(); ProfilerShort.Begin("Free face sorting"); // Ensure that the faces have increasing index numbers Mesh.SortFreeFaces(); ProfilerShort.End(); m_higherLevelHelper.OpenNewCell(coord); ProfilerShort.Begin("Adding triangles"); for (int i = 0; i < data.VoxelTrianglesCount; i++) { short a = data.VoxelTriangles[i].VertexIndex0; short b = data.VoxelTriangles[i].VertexIndex1; short c = data.VoxelTriangles[i].VertexIndex2; short setA = (short)m_vertexMapping.Find(a); short setB = (short)m_vertexMapping.Find(b); short setC = (short)m_vertexMapping.Find(c); if (setA == setB || setB == setC || setA == setC) { continue; } Vector3 aPos, bPos, cPos; Vector3 vert; data.GetUnpackedPosition(setA, out vert); aPos = vert - centerDisplacement; data.GetUnpackedPosition(setB, out vert); bPos = vert - centerDisplacement; data.GetUnpackedPosition(setC, out vert); cPos = vert - centerDisplacement; if (MyFakes.NAVMESH_PRESUMES_DOWNWARD_GRAVITY) { Vector3 normal = (cPos - aPos).Cross(bPos - aPos); normal.Normalize(); if (normal.Dot(ref Vector3.Up) <= Math.Cos(MathHelper.ToRadians(54.0f))) { continue; } } Vector3D aTformed = aPos + voxelMapCenter; Vector3D bTformed = bPos + voxelMapCenter; Vector3D cTformed = cPos + voxelMapCenter; bool intersecting = false; m_tmpLinkCandidates.Clear(); m_navmeshCoordinator.TestVoxelNavmeshTriangle(ref aTformed, ref bTformed, ref cTformed, m_tmpGridList, m_tmpLinkCandidates, out intersecting); if (intersecting) { m_tmpLinkCandidates.Clear(); continue; } if (!m_connectionHelper.IsInnerEdge(a, b)) { debugEdgesList.Add(new DebugDrawEdge(aTformed, bTformed)); } if (!m_connectionHelper.IsInnerEdge(b, c)) { debugEdgesList.Add(new DebugDrawEdge(bTformed, cTformed)); } if (!m_connectionHelper.IsInnerEdge(c, a)) { debugEdgesList.Add(new DebugDrawEdge(cTformed, aTformed)); } int edgeAB = m_connectionHelper.TryGetAndRemoveEdgeIndex(b, a, ref bPos, ref aPos); int edgeBC = m_connectionHelper.TryGetAndRemoveEdgeIndex(c, b, ref cPos, ref bPos); int edgeCA = m_connectionHelper.TryGetAndRemoveEdgeIndex(a, c, ref aPos, ref cPos); int formerAB = edgeAB; int formerBC = edgeBC; int formerCA = edgeCA; ProfilerShort.Begin("AddTriangle"); var tri = AddTriangle(ref aPos, ref bPos, ref cPos, ref edgeAB, ref edgeBC, ref edgeCA); ProfilerShort.End(); CheckMeshConsistency(); m_higherLevelHelper.AddTriangle(tri.Index); if (formerAB == -1) { m_connectionHelper.AddEdgeIndex(a, b, ref aPos, ref bPos, edgeAB); } if (formerBC == -1) { m_connectionHelper.AddEdgeIndex(b, c, ref bPos, ref cPos, edgeBC); } if (formerCA == -1) { m_connectionHelper.AddEdgeIndex(c, a, ref cPos, ref aPos, edgeCA); } // TODO: Instead of this, just add the tri into a list of tris that want to connect with the link candidates //m_navmeshCoordinator.TryAddVoxelNavmeshLinks(tri, cellId, m_tmpLinkCandidates); foreach (var candidate in m_tmpLinkCandidates) { List <MyNavigationPrimitive> primitives = null; if (!m_tmpCubeLinkCandidates.TryGetValue(candidate, out primitives)) { primitives = m_primitiveListPool.Allocate(); m_tmpCubeLinkCandidates.Add(candidate, primitives); } primitives.Add(tri); } m_tmpLinkCandidates.Clear(); } ProfilerShort.End(); m_tmpGridList.Clear(); m_connectionHelper.ClearCell(); m_vertexMapping.Clear(); Debug.Assert(!m_processedCells.Contains(ref cellPos)); m_processedCells.Add(ref cellPos); m_higherLevelHelper.AddExplored(ref cellPos); // Find connected components in the current cell's subgraph of the navigation mesh m_higherLevelHelper.ProcessCellComponents(); m_higherLevelHelper.CloseCell(); // Create navmesh links using the navmesh coordinator, taking into consideration the high level components m_navmeshCoordinator.TryAddVoxelNavmeshLinks2(cellId, m_tmpCubeLinkCandidates); m_navmeshCoordinator.UpdateVoxelNavmeshCellHighLevelLinks(cellId); foreach (var candidate in m_tmpCubeLinkCandidates) { candidate.Value.Clear(); m_primitiveListPool.Deallocate(candidate.Value); } m_tmpCubeLinkCandidates.Clear(); return(true); }
internal unsafe void ReadRange <TOperator>(ref TOperator target, MyStorageDataTypeEnum type, ref Vector3I writeOffset, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod) where TOperator : struct, IVoxelOperator { try { MyCellCoord *coordPtr = (MyCellCoord *)stackalloc byte[(((IntPtr)EstimateStackSize(this.m_treeHeight)) * sizeof(MyCellCoord))]; MyCellCoord coord = new MyCellCoord(this.m_treeHeight - 1, ref Vector3I.Zero); int index = 0 + 1; coordPtr[index] = coord; while (index > 0) { coord = coordPtr[--index]; MyOctreeNode node = this.m_nodes[coord.PackId32()]; int num3 = coord.Lod - lodIndex; Vector3I vectori4 = coord.CoordInLod << 1; Vector3I min = (minInLod >> num3) - vectori4; Vector3I max = (maxInLod >> num3) - vectori4; for (int i = 0; i < 8; i++) { Vector3I vectori; this.ComputeChildCoord(i, out vectori); if (vectori.IsInsideInclusiveEnd(ref min, ref max)) { if ((lodIndex < coord.Lod) && node.HasChild(i)) { index++; coordPtr[index] = new MyCellCoord(coord.Lod - 1, (Vector3I)(vectori4 + vectori)); } else { byte inOutContent = &node.Data.FixedElementField[i]; Vector3I result = (Vector3I)(vectori4 + vectori); if (num3 == 0) { Vector3I position = (Vector3I)((writeOffset + result) - minInLod); target.Op(ref position, type, ref inOutContent); } else { result = result << num3; Vector3I vectori7 = (Vector3I)((result + (1 << (num3 & 0x1f))) - 1); Vector3I *vectoriPtr1 = (Vector3I *)ref result; Vector3I.Max(ref (Vector3I) ref vectoriPtr1, ref minInLod, out result); Vector3I *vectoriPtr2 = (Vector3I *)ref vectori7; Vector3I.Min(ref (Vector3I) ref vectoriPtr2, ref maxInLod, out vectori7); int z = result.Z; while (z <= vectori7.Z) { int y = result.Y; while (true) { if (y > vectori7.Y) { z++; break; } int x = result.X; while (true) { if (x > vectori7.X) { y++; break; } Vector3I position = writeOffset; int * numPtr1 = (int *)ref position.X; numPtr1[0] += x - minInLod.X; int *numPtr2 = (int *)ref position.Y; numPtr2[0] += y - minInLod.Y; int *numPtr3 = (int *)ref position.Z; numPtr3[0] += z - minInLod.Z; target.Op(ref position, type, ref inOutContent); x++; } } } } } } } } } finally { } }
internal void OnCellRequestCancelled(MyCellCoord cell) { var workId = cell.PackId64(); m_renderWorkTracker.Cancel(workId); }
internal unsafe void ReadRange(MyStorageData target, MyStorageDataTypeEnum type, ref Vector3I writeOffset, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod) { ProfilerShort.Begin("MySparseOctree2.ReadRangeToContent"); try { int stackIdx = 0; int stackSize = MySparseOctree.EstimateStackSize(m_treeHeight); MyCellCoord *stack = stackalloc MyCellCoord[stackSize]; MyCellCoord data = new MyCellCoord(m_treeHeight - 1, ref Vector3I.Zero); stack[stackIdx++] = data; MyOctreeNode node; Vector3I childPosRelative, min, max, nodePositionInChild; int lodDiff; while (stackIdx > 0) { Debug.Assert(stackIdx <= stackSize); data = stack[--stackIdx]; node = m_nodes[data.PackId32()]; lodDiff = data.Lod - lodIndex; min = minInLod >> lodDiff; max = maxInLod >> lodDiff; nodePositionInChild = data.CoordInLod << 1; min -= nodePositionInChild; max -= nodePositionInChild; for (int i = 0; i < MyOctreeNode.CHILD_COUNT; ++i) { ComputeChildCoord(i, out childPosRelative); if (!childPosRelative.IsInsideInclusive(ref min, ref max)) { continue; } if (lodIndex < data.Lod && node.HasChild(i)) { Debug.Assert(stackIdx < stackSize); stack[stackIdx++] = new MyCellCoord(data.Lod - 1, nodePositionInChild + childPosRelative); } else { var nodeData = node.Data[i]; var childMin = nodePositionInChild + childPosRelative; if (lodDiff == 0) { var write = writeOffset + childMin - minInLod; target.Set(type, ref write, nodeData); } else { childMin <<= lodDiff; var childMax = childMin + (1 << lodDiff) - 1; Vector3I.Max(ref childMin, ref minInLod, out childMin); Vector3I.Min(ref childMax, ref maxInLod, out childMax); for (int z = childMin.Z; z <= childMax.Z; ++z) { for (int y = childMin.Y; y <= childMax.Y; ++y) { for (int x = childMin.X; x <= childMax.X; ++x) { var write = writeOffset; write.X += x - minInLod.X; write.Y += y - minInLod.Y; write.Z += z - minInLod.Z; target.Set(type, ref write, nodeData); } } } } } } } } finally { ProfilerShort.End(); } }
public bool Intersects(ref BoundingSphereD localSphere) { MyPrecalcComponent.AssertUpdateThread(); // Get min and max cell coordinate where boundingBox can fit BoundingBoxD sphereBoundingBox = BoundingBoxD.CreateInvalid(); sphereBoundingBox.Include(ref localSphere); Vector3I cellCoordMin, cellCoordMax; { Vector3D minD = sphereBoundingBox.Min; Vector3D maxD = sphereBoundingBox.Max; MyVoxelCoordSystems.LocalPositionToGeometryCellCoord(ref minD, out cellCoordMin); MyVoxelCoordSystems.LocalPositionToGeometryCellCoord(ref maxD, out cellCoordMax); } // Fix min and max cell coordinates so they don't overlap the voxelmap ClampCellCoord(ref cellCoordMin); ClampCellCoord(ref cellCoordMax); MyCellCoord cell = new MyCellCoord(); for (cell.CoordInLod.X = cellCoordMin.X; cell.CoordInLod.X <= cellCoordMax.X; cell.CoordInLod.X++) { for (cell.CoordInLod.Y = cellCoordMin.Y; cell.CoordInLod.Y <= cellCoordMax.Y; cell.CoordInLod.Y++) { for (cell.CoordInLod.Z = cellCoordMin.Z; cell.CoordInLod.Z <= cellCoordMax.Z; cell.CoordInLod.Z++) { // If no overlap between bounding box of data cell and the sphere BoundingBox cellBoundingBox; MyVoxelCoordSystems.GeometryCellCoordToLocalAABB(ref cell.CoordInLod, out cellBoundingBox); if (cellBoundingBox.Intersects(ref localSphere) == false) { continue; } // Get cell from cache. If not there, precalc it and store in the cache. // If null is returned, we know that cell doesn't contain any triangleVertexes so we don't need to do intersections. CellData cachedData = GetCell(ref cell); if (cachedData == null) { continue; } for (int i = 0; i < cachedData.VoxelTrianglesCount; i++) { MyVoxelTriangle voxelTriangle = cachedData.VoxelTriangles[i]; MyTriangle_Vertexes triangle; cachedData.GetUnpackedPosition(voxelTriangle.VertexIndex0, out triangle.Vertex0); cachedData.GetUnpackedPosition(voxelTriangle.VertexIndex1, out triangle.Vertex1); cachedData.GetUnpackedPosition(voxelTriangle.VertexIndex2, out triangle.Vertex2); BoundingBox localTriangleAABB = BoundingBox.CreateInvalid(); localTriangleAABB.Include(ref triangle.Vertex0); localTriangleAABB.Include(ref triangle.Vertex1); localTriangleAABB.Include(ref triangle.Vertex2); // First test intersection of triangle's bounding box with line's bounding box. And only if they overlap or intersect, do further intersection tests. if (localTriangleAABB.Intersects(ref localSphere)) { PlaneD trianglePlane = new PlaneD(triangle.Vertex0, triangle.Vertex1, triangle.Vertex2); if (MyUtils.GetSphereTriangleIntersection(ref localSphere, ref trianglePlane, ref triangle) != null) { // If intersection found - we are finished. We don't need to look for more. return(true); } } } } } } return(false); }
IMyClipmapCell IMyClipmapCellHandler.CreateCell(MyClipmapScaleEnum scaleGroup, MyCellCoord cellCoord, ref MatrixD worldMatrix) { switch (scaleGroup) { case MyClipmapScaleEnum.Normal: return(new MyRenderVoxelCell(scaleGroup, cellCoord, ref worldMatrix)); default: throw new InvalidBranchException(); } }