internal void InvalidateRange(Vector3I lodMin, Vector3I lodMax) { // MyLog.Default.WriteLine("InvalidateRange Lod: " + m_lodIndex + " Min: " + lodMin + " Max: " + lodMax); var cell = new MyCellCoord(m_lodIndex, lodMin); for (var it = new Vector3I.RangeIterator(ref lodMin, ref lodMax); it.IsValid(); it.GetNext(out cell.CoordInLod)) { CellData data; var id = cell.PackId64(); // MyLog.Default.WriteLine("Setting to: m_lodIndex " + cell.Lod + " Coord: " + cell.CoordInLod); if (m_storedCellData.TryGetValue(id, out data)) { data.State = CellState.Invalid; //MyLog.Default.WriteLine("Really set to: m_lodIndex " + cell.Lod + " Coord: " + cell.CoordInLod); } if (MyClipmap.UseCache) { var clipmapCellId = MyCellCoord.GetClipmapCellHash(m_clipmap.Id, id); var cachedCell = MyClipmap.CellsCache.Read(clipmapCellId); if (cachedCell != null) { cachedCell.State = CellState.Invalid; } } } }
internal void DiscardClippedCells(RequestCollector collector) { foreach (var entry in m_clippedCells) { var data = entry.Value; data.ClippedOut = true; if (UseCache) { var clipmapCellId = MyCellCoord.GetClipmapCellHash(m_clipmap.Id, entry.Key); CellsCache.Write(clipmapCellId, data); Delete(entry.Key, data, false); } else { if (data.Cell != null) { Delete(entry.Key, data); } data.ReadyInClipmap = false; } } m_clippedCells.Clear(); }
internal void KeepOrDiscardClippedCells(RequestCollector collector) { LodLevel parentLod, childLod; GetNearbyLodLevels(out parentLod, out childLod); MyCellCoord thisLodCell = new MyCellCoord(); foreach (var entry in m_clippedCells) { var data = entry.Value; bool needed = false; // too far, but less detailed data might be missing so we still check parent thisLodCell.SetUnpack(entry.Key); needed = !WasAncestorCellLoaded(parentLod, ref thisLodCell); if (needed) { if (data.State == CellState.Invalid) { if (!TryAddCellRequest(collector, parentLod, thisLodCell, entry.Key, data)) { continue; } } m_storedCellData.Add(entry.Key, data); } else { if (UseCache && data.State == CellState.Loaded) { var clipmapCellId = MyCellCoord.GetClipmapCellHash(m_clipmap.Id, entry.Key); CellsCache.Write(clipmapCellId, data); Delete(entry.Key, data, false); } else { if (data.State == CellState.Pending) { collector.CancelRequest(entry.Key); } if (data.Cell != null) { Delete(entry.Key, data); } } if (!UseCache) { CellsCache.Reset(); } } } m_clippedCells.Clear(); }
internal void SetCellMesh(MyRenderMessageUpdateClipmapCell msg) { var cellId = msg.Metadata.Cell.PackId64(); 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; } }
private void UnclipCell(RequestCollector collector, MyCellCoord cell, bool isVisible) { var cellId = cell.PackId64(); var clipmapCellId = MyCellCoord.GetClipmapCellHash(m_clipmap.Id, cellId); 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 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 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); } } } }
internal void DoClipping_Old(Vector3D localPosition, float farPlaneDistance, RequestCollector collector) { m_localPosition = localPosition; MyClipmap.ComputeLodViewBounds(m_clipmap.m_scaleGroup, m_lodIndex, out m_nearDistance, out m_farDistance); m_fitsInFrustum = (farPlaneDistance * 1.25f) > m_nearDistance; if (!m_fitsInFrustum) { return; } //var localFrustum = new BoundingFrustumD(CameraFrustumGetter().Matrix * m_parent.m_invWorldMatrix); var frustum = CameraFrustumGetter(); Vector3I min, max; Vector3I ignoreMin, ignoreMax; var minD = m_localPosition - m_farDistance; var maxD = m_localPosition + m_farDistance; MyVoxelCoordSystems.LocalPositionToRenderCellCoord(m_lodIndex, ref minD, out min); MyVoxelCoordSystems.LocalPositionToRenderCellCoord(m_lodIndex, ref maxD, out max); BoundingBoxI lodBox = new BoundingBoxI(Vector3I.Zero, m_lodSizeMinusOne); 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.Intersect(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. MyUtils.Swap(ref m_storedCellData, ref m_clippedCells); m_storedCellData.Clear(); if (intersects) { float sizeInMetres = MyVoxelCoordSystems.RenderCellSizeInMeters(m_lodIndex); MyCellCoord cell = new MyCellCoord(m_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 (!WasAncestorCellLoaded(parentLod, ref cell)) // continue; 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) { continue; } var cellId = cell.PackId64(); CellData data; if (m_clippedCells.TryGetValue(cellId, out data)) { m_clippedCells.Remove(cellId); } else { var clipmapCellId = MyCellCoord.GetClipmapCellHash(m_clipmap.Id, cellId); data = CellsCache.Read(clipmapCellId); if (data == null) //cache miss { data = new 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; } } } if (data.State == CellState.Invalid) { if (!TryAddCellRequest(collector, parentLod, cell, cellId, data)) { continue; } } m_storedCellData.Add(cellId, data); } } }
/// <summary> /// Recursive clipping function requests cells in provided range and /// cells needed from parent to wrap the lod safely /// </summary> /// <param name="collector"></param> /// <param name="it0">requested range</param> /// <param name="ignore">inner range filled by children</param> private void DoClipping(RequestCollector collector, Vector3I min, Vector3I max, ref BoundingBox ignore) { LodLevel parentLod, clevel; GetNearbyLodLevels(out parentLod, out clevel); MyCellCoord cell = new MyCellCoord(m_lodIndex, Vector3I.Zero); //if (collector.SentRequestsEmpty) { MyUtils.Swap(ref m_storedCellData, ref m_clippedCells); m_storedCellData.Clear(); } var it0 = new Vector3I.RangeIterator(ref min, ref max); cell.CoordInLod = it0.Current; var shiftToParent = MyVoxelCoordSystems.RenderCellSizeShiftToLessDetailed(cell.Lod); var parentCell = parentLod != null ? new MyCellCoord(parentLod.m_lodIndex, cell.CoordInLod >> shiftToParent) : cell; var parentIgnore = new BoundingBox(parentCell.CoordInLod, parentCell.CoordInLod); BoundingBox bb = new BoundingBox(cell.CoordInLod, cell.CoordInLod); for (; it0.IsValid(); it0.GetNext(out cell.CoordInLod)) //cells to be loaded { if (ignore.Contains((Vector3)cell.CoordInLod) == ContainmentType.Contains) { continue; //lower lod requested } if (parentLod != null) //get also their lodcell mates { parentCell = new MyCellCoord(parentLod.m_lodIndex, cell.CoordInLod >> shiftToParent); var it = GetChildrenCoords(this, ref parentCell); bb.Include(it); parentIgnore.Max = parentCell.CoordInLod; } } if (parentLod != null) { Vector3I parentMinI = Vector3I.Round(parentIgnore.Min - Vector3.One); Vector3I parentMaxI = Vector3I.Round(parentIgnore.Max + Vector3.One); //Vector3I.Clamp(ref parentMinI, ref Vector3I.Zero, ref m_lodSizeMinusOne, out parentMinI); //Vector3I.Clamp(ref parentMaxI, ref Vector3I.Zero, ref m_lodSizeMinusOne, out parentMaxI); var parentIterator = new Vector3I.RangeIterator(ref parentMinI, ref parentMaxI); parentLod.DoClipping(collector, parentMinI, parentMaxI, ref parentIgnore); } Vector3I start, end; start = Vector3I.Round(bb.Min); end = Vector3I.Round(bb.Max); Vector3I.Clamp(ref start, ref Vector3I.Zero, ref m_lodSizeMinusOne, out start); Vector3I.Clamp(ref end, ref Vector3I.Zero, ref m_lodSizeMinusOne, out end); it0 = new Vector3I.RangeIterator(ref start, ref end); cell.CoordInLod = it0.Current; for (; it0.IsValid(); it0.GetNext(out cell.CoordInLod)) //cells to be loaded { if (ignore.Contains((Vector3)cell.CoordInLod) == ContainmentType.Contains) { continue; //lower lod requested } var cellId = cell.PackId64(); CellData data; if (m_clippedCells.TryGetValue(cellId, out data)) { m_clippedCells.Remove(cellId); } else { var clipmapCellId = MyCellCoord.GetClipmapCellHash(m_clipmap.Id, cellId); data = CellsCache.Read(clipmapCellId); if (data == null) //cache miss { data = new CellData(); ClippingCacheMisses++; } else { //cache hit ClippingCacheHits++; data.InScene = false; if (data.Cell != null) { m_nonEmptyCells[cellId] = data; } } } if (data.State == CellState.Invalid) { if (!TryAddCellRequest(collector, parentLod, cell, cellId, data)) { continue; } } if (!m_storedCellData.ContainsKey(cellId)) { m_storedCellData.Add(cellId, data); } } }