internal void InvalidateRange(Vector3I minVoxelChanged, Vector3I maxVoxelChanged, int lod) { MyPrecalcComponent.AssertUpdateThread(); // No physics there ever was so we don't care. if (!m_bodiesInitialized) { return; } if (m_queueInvalidation) { if (m_queuedRange.Max.X < 0) { m_queuedRange = new BoundingBoxI(minVoxelChanged, maxVoxelChanged); } else { var bb = new BoundingBoxI(minVoxelChanged, maxVoxelChanged); m_queuedRange.Include(ref bb); } return; } ProfilerShort.Begin("MyVoxelPhysicsBody.InvalidateRange"); minVoxelChanged -= 1; // MyPrecalcComponent.InvalidatedRangeInflate; maxVoxelChanged += 1; //MyPrecalcComponent.InvalidatedRangeInflate; m_voxelMap.Storage.ClampVoxelCoord(ref minVoxelChanged); m_voxelMap.Storage.ClampVoxelCoord(ref maxVoxelChanged); Vector3I minCellChanged, maxCellChanged; MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref minVoxelChanged, out minCellChanged); MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref maxVoxelChanged, out maxCellChanged); Vector3I minCellChangedVoxelMap, maxCellChangedVoxelMap; minCellChangedVoxelMap = (minCellChanged - m_cellsOffset) >> lod; maxCellChangedVoxelMap = (maxCellChanged - m_cellsOffset) >> lod; var maxCell = m_voxelMap.Size - 1; MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref maxCell, out maxCell); maxCell >>= lod; Vector3I.Min(ref maxCellChangedVoxelMap, ref maxCell, out maxCellChangedVoxelMap); Debug.Assert(RigidBody != null, "RigidBody in voxel physics is null! This must not happen."); var rb = GetRigidBody(lod); Debug.Assert(rb != null, "RigidBody in voxel physics is null! This must not happen."); if (rb != null) { HkUniformGridShape shape = (HkUniformGridShape)rb.GetShape(); Debug.Assert(shape.Base.IsValid); var numCells = (maxCellChangedVoxelMap - minCellChangedVoxelMap + 1).Size; if (numCells >= m_cellsToGenerateBuffer.Length) { m_cellsToGenerateBuffer = new Vector3I[MathHelper.GetNearestBiggerPowerOfTwo(numCells)]; } var tmpBuffer = m_cellsToGenerateBuffer; int invalidCount = shape.InvalidateRange(ref minCellChangedVoxelMap, ref maxCellChangedVoxelMap, tmpBuffer); Debug.Assert(invalidCount <= tmpBuffer.Length); //if (numCells <= 8) //shape.InvalidateRangeImmediate(ref minCellChangedVoxelMap, ref maxCellChangedVoxelMap); Debug.Assert(invalidCount <= tmpBuffer.Length); for (int i = 0; i < invalidCount; i++) { InvalidCells[lod].Add(tmpBuffer[i]); } if (RunningBatchTask[lod] == null && InvalidCells[lod].Count != 0) { MyPrecalcComponent.PhysicsWithInvalidCells.Add(this); } } if (minCellChangedVoxelMap == Vector3I.Zero && maxCellChangedVoxelMap == maxCell) { m_workTracker.CancelAll(); } else { var cell = minCellChanged; for (var it = new Vector3I_RangeIterator(ref minCellChanged, ref maxCellChanged); it.IsValid(); it.GetNext(out cell)) { m_workTracker.Cancel(new MyCellCoord(lod, cell)); } } m_needsShapeUpdate = true; ProfilerShort.End(); m_voxelMap.RaisePhysicsChanged(); }
public MyIsoMesh Precalc(IMyStorage storage, int lod, Vector3I voxelStart, Vector3I voxelEnd, bool generateMaterials, bool useAmbient, bool doNotCheck = false) { // change range so normal can be computed at edges (expand by 1 in all directions) voxelStart -= 1; voxelEnd += 1; if (storage == null) { return(null); } using (storage.Pin()) { if (storage.Closed) { return(null); } MyVoxelRequestFlags request = MyVoxelRequestFlags.ContentChecked; // | (doNotCheck ? MyVoxelRequestFlags.DoNotCheck : 0); bool readAmbient = false; if (generateMaterials && storage.DataProvider != null && storage.DataProvider.ProvidesAmbient) { readAmbient = true; } m_cache.Resize(voxelStart, voxelEnd); if (readAmbient) { m_cache.StoreOcclusion = true; } storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, lod, ref voxelStart, ref voxelEnd, ref request); if (request.HasFlag(MyVoxelRequestFlags.EmptyContent) || request.HasFlag(MyVoxelRequestFlags.FullContent) || (!request.HasFlag(MyVoxelRequestFlags.ContentChecked) && !m_cache.ContainsIsoSurface())) { return(null); } var center = (storage.Size / 2) * MyVoxelConstants.VOXEL_SIZE_IN_METRES; var voxelSize = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << lod); var vertexCellOffset = voxelStart - AffectedRangeOffset; double numCellsHalf = 0.5 * (m_cache.Size3D.X - 3); var posOffset = ((Vector3D)vertexCellOffset + numCellsHalf) * (double)voxelSize; if (generateMaterials) { // 255 is the new black m_cache.ClearMaterials(255); } if (readAmbient) { m_cache.Clear(MyStorageDataTypeEnum.Occlusion, 0); } IsoMesher mesher = new IsoMesher(); ProfilerShort.Begin("Dual Contouring"); unsafe { fixed(byte *content = m_cache[MyStorageDataTypeEnum.Content]) fixed(byte *material = m_cache[MyStorageDataTypeEnum.Material]) { var size3d = m_cache.Size3D; Debug.Assert(size3d.X == size3d.Y && size3d.Y == size3d.Z); mesher.Calculate(size3d.X, content, material, m_buffer, useAmbient, posOffset - center); } } ProfilerShort.End(); if (generateMaterials) { request = 0; request |= MyVoxelRequestFlags.SurfaceMaterial; request |= MyVoxelRequestFlags.OneMaterial; var req = readAmbient ? MyStorageDataTypeFlags.Material | MyStorageDataTypeFlags.Occlusion : MyStorageDataTypeFlags.Material; storage.ReadRange(m_cache, req, lod, ref voxelStart, ref voxelEnd, ref request); FixCacheMaterial(voxelStart, voxelEnd); unsafe { fixed(byte *content = m_cache[MyStorageDataTypeEnum.Content]) fixed(byte *material = m_cache[MyStorageDataTypeEnum.Material]) { int materialOverride = request.HasFlag(MyVoxelRequestFlags.OneMaterial) ? m_cache.Material(0) : -1; var size3d = m_cache.Size3D; Debug.Assert(size3d.X == size3d.Y && size3d.Y == size3d.Z); if (readAmbient) fixed(byte *ambient = m_cache[MyStorageDataTypeEnum.Occlusion]) mesher.CalculateMaterials(size3d.X, content, material, ambient, materialOverride); else { mesher.CalculateMaterials(size3d.X, content, material, null, materialOverride); } } } } else { m_cache.ClearMaterials(0); } mesher.Finish(m_buffer); if (m_buffer.VerticesCount == 0 || m_buffer.Triangles.Count == 0) { return(null); } ProfilerShort.Begin("Geometry post-processing"); { var positions = m_buffer.Positions.GetInternalArray(); var vertexCells = m_buffer.Cells.GetInternalArray(); for (int i = 0; i < m_buffer.VerticesCount; i++) { Debug.Assert(positions[i].IsInsideInclusive(ref Vector3.MinusOne, ref Vector3.One)); vertexCells[i] += vertexCellOffset; Debug.Assert(vertexCells[i].IsInsideInclusive(voxelStart + 1, voxelEnd - 1)); } m_buffer.PositionOffset = posOffset; m_buffer.PositionScale = new Vector3((float)(numCellsHalf * voxelSize)); m_buffer.CellStart = voxelStart + 1; m_buffer.CellEnd = voxelEnd - 1; } ProfilerShort.End(); // Replace filled mesh with new one. // This way prevents allocation of meshes which then end up empty. var buffer = m_buffer; m_buffer = new MyIsoMesh(); return(buffer); } }
public virtual void UnregisterFromSystems(MyCubeBlock block) { // Note: ResourceDistributor, WeaponSystem and TemrminalSystem can be null on closing (they are not in the ship but in the logical group). That's why they are null-checked if (ResourceDistributor != null) { ProfilerShort.Begin("Unregister Power producer"); var powerProducer = block.Components.Get <MyResourceSourceComponent>(); if (powerProducer != null) { ResourceDistributor.RemoveSource(powerProducer); } ProfilerShort.BeginNextBlock("Unregister Power consumer"); var powerConsumer = block.Components.Get <MyResourceSinkComponent>(); if (!(block is MyThrust) && powerConsumer != null) { ResourceDistributor.RemoveSink(powerConsumer); } ProfilerShort.End(); var socketOwner = block as IMyRechargeSocketOwner; if (socketOwner != null) { socketOwner.RechargeSocket.ResourceDistributor = null; } } ProfilerShort.Begin("Unregister gun object"); if (WeaponSystem != null) { var weapon = block as IMyGunObject <MyDeviceBase>; if (weapon != null) { WeaponSystem.Unregister(weapon); } } ProfilerShort.BeginNextBlock("Unregister functional block"); if (TerminalSystem != null) { var functionalBlock = block as MyTerminalBlock; if (functionalBlock != null) { TerminalSystem.Remove(functionalBlock); } } // CH: We probably don't need to unregister controller blocks here. It's done in ShipController's OnUnregisteredFromGridSystems /*ProfilerShort.BeginNextBlock("Unregister controller block"); * if (ControlSystem != null) * { * var controllableBlock = block as MyShipController; * if (controllableBlock != null && controllableBlock.ControllerInfo.Controller != null) * ControlSystem.RemoveControllerBlock(controllableBlock); * }*/ ProfilerShort.BeginNextBlock("Unregister inventory block"); var inventoryBlock = (block != null && block.HasInventory) ? block : null; if (inventoryBlock != null && inventoryBlock.HasInventory) { ConveyorSystem.Remove(inventoryBlock); } ProfilerShort.BeginNextBlock("Unregister conveyor block"); var conveyorBlock = block as IMyConveyorEndpointBlock; if (conveyorBlock != null) { ConveyorSystem.RemoveConveyorBlock(conveyorBlock); } ProfilerShort.BeginNextBlock("Unregister segment block"); var segmentBlock = block as IMyConveyorSegmentBlock; if (segmentBlock != null) { ConveyorSystem.RemoveSegmentBlock(segmentBlock); } ProfilerShort.BeginNextBlock("Unregister Reflector light"); var reflectorLight = block as MyReflectorLight; if (reflectorLight != null) { ReflectorLightSystem.Unregister(reflectorLight); } if (MyFakes.ENABLE_WHEEL_CONTROLS_IN_COCKPIT) { ProfilerShort.BeginNextBlock("Unregister wheel"); var wheel = block as MyMotorSuspension; if (wheel != null) { WheelSystem.Unregister(wheel); } } ProfilerShort.BeginNextBlock("Unregister landing gear"); var gear = block as IMyLandingGear; if (gear != null) { LandingSystem.Unregister(gear); } ProfilerShort.BeginNextBlock("Unregister gyro"); var gyro = block as MyGyro; if (gyro != null) { GyroSystem.Unregister(gyro); } ProfilerShort.BeginNextBlock("Unregister camera"); var camera = block as MyCameraBlock; if (camera != null) { CameraSystem.Unregister(camera); } ProfilerShort.BeginNextBlock("block.OnUnregisteredFromGridSystems()"); block.OnUnregisteredFromGridSystems(); ProfilerShort.End(); }
protected override void DoDetection(bool useHead) { ProfilerShort.Begin("DoDetection"); if (Character == MySession.Static.ControlledEntity) { MyHud.SelectedObjectHighlight.RemoveHighlight(); } var head = Character.GetHeadMatrix(false); var headPos = head.Translation - (Vector3D)head.Forward * 0.3; // Move to center of head, we don't want eyes (in front of head) Vector3D from; Vector3D dir; if (!useHead) { //Ondrej version var cameraMatrix = MySector.MainCamera.WorldMatrix; dir = cameraMatrix.Forward; from = MyUtils.LinePlaneIntersection(headPos, (Vector3)dir, cameraMatrix.Translation, (Vector3)dir); } else { //Petr version dir = head.Forward; from = headPos; } Vector3D to = from + dir * MyConstants.DEFAULT_INTERACTIVE_DISTANCE; StartPosition = from; LineD intersectionLine = new LineD(from, to); // Processing of hit entities var geometryHit = MyEntities.GetIntersectionWithLine(ref intersectionLine, null, null, ignoreFloatingObjects: false); bool hasUseObject = false; if (geometryHit.HasValue) { var hitEntity = geometryHit.Value.Entity; // Cube Grids are special case var cubeGrid = hitEntity as MyCubeGrid; if (cubeGrid != null) { // For hit cube grids get the fat hit fatblock instead. var slimBlock = cubeGrid.GetTargetedBlock(geometryHit.Value.IntersectionPointInWorldSpace); if (slimBlock != null && slimBlock.FatBlock != null) { hitEntity = slimBlock.FatBlock; } } m_hitUseComponents.Clear(); var hitUseObject = hitEntity as IMyUseObject; // Retrive all above use components from parent structure. (Because of subParts) GetUseComponentsFromParentStructure(hitEntity, m_hitUseComponents); // Check for UseObjects and entities with UseObjectComponentBase. // Assuming that entity cannot be IMyUseObject and have UseObjectComponentBase in hierarchy // at the same time. if (hitUseObject != null || m_hitUseComponents.Count > 0) { if (m_hitUseComponents.Count > 0) { // Process the valid hit entity var closestDetectorDistance = float.MaxValue; double physicalHitDistance = Vector3D.Distance(from, geometryHit.Value.IntersectionPointInWorldSpace); MyUseObjectsComponentBase hitUseComp = null; // Evaluate the set of found detectors and try to find the closest one foreach (var hitUseComponent in m_hitUseComponents) { float detectorDistance; var interactive = hitUseComponent.RaycastDetectors(from, to, out detectorDistance); detectorDistance *= MyConstants.DEFAULT_INTERACTIVE_DISTANCE; if (Math.Abs(detectorDistance) < Math.Abs(closestDetectorDistance) && (detectorDistance < physicalHitDistance)) // Remove to fix the problem with picking through physic bodies, { // but will introduce new problem with detectors inside physic bodies. closestDetectorDistance = detectorDistance; hitUseComp = hitUseComponent; hitEntity = hitUseComponent.Entity; hitUseObject = interactive; } } // Detector found if (hitUseComp != null) { // Process successful hit with results var detectorPhysics = hitUseComp.DetectorPhysics; HitMaterial = detectorPhysics.GetMaterialAt(HitPosition); HitBody = geometryHit.Value.Entity.Physics.RigidBody; HitPosition = geometryHit.Value.IntersectionPointInWorldSpace; DetectedEntity = hitEntity; } } else { // Case for hitting IMyUseObject already before even looking for UseComponent. // Floating object case. HitMaterial = hitEntity.Physics.GetMaterialAt(HitPosition); HitBody = hitEntity.Physics.RigidBody; } // General logic for processing both cases. if (hitUseObject != null) { HitPosition = geometryHit.Value.IntersectionPointInWorldSpace; DetectedEntity = hitEntity; if (UseObject != null && UseObject != hitEntity && UseObject != hitUseObject) { UseObject.OnSelectionLost(); } if (Character == MySession.Static.ControlledEntity && hitUseObject.SupportedActions != UseActionEnum.None) { HandleInteractiveObject(hitUseObject); UseObject = hitUseObject; hasUseObject = true; } } } } if (!hasUseObject) { if (UseObject != null) { UseObject.OnSelectionLost(); } UseObject = null; } ProfilerShort.End(); }
void IWork.DoWork(WorkData workData = null) { ProfilerShort.Begin("MyDepositQuery.DoWork"); try { var cache = Cache; cache.Resize(new Vector3I(MyOreDetectorComponent.CELL_SIZE_IN_LOD_VOXELS)); var min = m_args.Cell << MyOreDetectorComponent.CELL_SIZE_IN_VOXELS_BITS; var max = min + (MyOreDetectorComponent.CELL_SIZE_IN_LOD_VOXELS - 1); var storage = m_args.VoxelMap.Storage; if (storage == null || storage.Closed) { return; // voxel map was probably closed in the meantime. } using (storage.Pin()) { storage.ReadRange(cache, MyStorageDataTypeFlags.Content, MyOreDetectorComponent.QUERY_LOD, ref min, ref max); if (!cache.ContainsVoxelsAboveIsoLevel()) { return; } storage.ReadRange(cache, MyStorageDataTypeFlags.Material, MyOreDetectorComponent.QUERY_LOD, ref min, ref max); } var materialData = MaterialData; Vector3I c; for (c.Z = 0; c.Z < MyOreDetectorComponent.CELL_SIZE_IN_LOD_VOXELS; ++c.Z) { for (c.Y = 0; c.Y < MyOreDetectorComponent.CELL_SIZE_IN_LOD_VOXELS; ++c.Y) { for (c.X = 0; c.X < MyOreDetectorComponent.CELL_SIZE_IN_LOD_VOXELS; ++c.X) { int i = cache.ComputeLinear(ref c); if (cache.Content(i) > MyVoxelConstants.VOXEL_ISO_LEVEL) { const float VOXEL_SIZE = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << MyOreDetectorComponent.QUERY_LOD); const float VOXEL_SIZE_HALF = VOXEL_SIZE * 0.5f; var material = cache.Material(i); Vector3D localPos = (c + min) * VOXEL_SIZE + VOXEL_SIZE_HALF; materialData[material].Sum += localPos; materialData[material].Count += 1; } } } } for (int materialIdx = 0; materialIdx < materialData.Length; ++materialIdx) { if (materialData[materialIdx].Count == 0) { continue; } var material = MyDefinitionManager.Static.GetVoxelMaterialDefinition((byte)materialIdx); if (material.IsRare) { if (m_result == null) { m_result = new MyEntityOreDeposit(m_args.VoxelMap, m_args.Cell); } m_result.Materials.Add(new MyEntityOreDeposit.Data() { Material = material, AverageLocalPosition = Vector3D.Transform((materialData[materialIdx].Sum / materialData[materialIdx].Count - m_args.VoxelMap.SizeInMetresHalf), Quaternion.CreateFromRotationMatrix(m_args.VoxelMap.WorldMatrix)), }); } } Array.Clear(materialData, 0, materialData.Length); } finally { ProfilerShort.End(); } }
internal static void Run(ISrvBindable depthRead) { // The maximum number of supported GPU particles ISrvBindable textureArraySrv; int emitterCount = MyGPUEmitters.Gather(m_emitterData, out textureArraySrv); if (emitterCount == 0) { return; } // Unbind current targets while we run the compute stages of the system //RC.DeviceContext.OutputMerger.SetTargets(null); // global GPU particles setup RC.SetDepthStencilState(MyDepthStencilStateManager.DefaultDepthState); RC.SetRasterizerState(MyRasterizerStateManager.NocullRasterizerState); RC.SetInputLayout(null); RC.ComputeShader.SetConstantBuffer(MyCommon.FRAME_SLOT, MyCommon.FrameConstants); RC.ComputeShader.SetSamplers(0, MySamplerStateManager.StandardSamplers); RC.PixelShader.SetSamplers(0, MySamplerStateManager.StandardSamplers); RC.AllShaderStages.SetConstantBuffer(4, MyRender11.DynamicShadows.ShadowCascades.CascadeConstantBuffer); RC.VertexShader.SetSampler(MyCommon.SHADOW_SAMPLER_SLOT, MySamplerStateManager.Shadowmap); RC.VertexShader.SetSrv(MyCommon.CASCADES_SM_SLOT, MyRender11.DynamicShadows.ShadowCascades.CascadeShadowmapArray); RC.VertexShader.SetSamplers(0, MySamplerStateManager.StandardSamplers); // If we are resetting the particle system, then initialize the dead list if (m_resetSystem) { ResetInternal(); m_resetSystem = false; } MyGpuProfiler.IC_BeginBlock("Emit"); // Emit particles into the system Emit(emitterCount, m_emitterData); MyGpuProfiler.IC_EndBlock(); // Run the simulation for this frame MyGpuProfiler.IC_BeginBlock("Simulate"); Simulate(depthRead); MyGpuProfiler.IC_EndBlock(); // Copy the atomic counter in the alive list UAV into a constant buffer for access by subsequent passes RC.CopyStructureCount(m_activeListConstantBuffer, 0, m_aliveIndexBuffer.m_uav); // Only read number of alive and dead particle back to the CPU in debug as we don't want to stall the GPU in release code ProfilerShort.Begin("Debug - ReadCounter"); MyGpuProfiler.IC_BeginBlock("Debug - ReadCounter"); int numActiveParticlesAfterSimulation = ReadCounter(m_aliveIndexBuffer); MyGpuProfiler.IC_EndBlock(); ProfilerShort.End(); MyGpuProfiler.IC_BeginBlock("Render"); Render(textureArraySrv, depthRead); MyGpuProfiler.IC_EndBlock(); RC.ComputeShader.SetSamplers(0, MySamplerStateManager.StandardSamplers); MyStatsDisplay.Write("GPU particles", "Live #", numActiveParticlesAfterSimulation); }
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 static void MakeCrater(MyVoxelBase voxelMap, BoundingSphereD sphere, Vector3 direction, MyVoxelMaterialDefinition material) { ProfilerShort.Begin("MakeCrater"); Vector3 normal = Vector3.Normalize(sphere.Center - voxelMap.RootVoxel.WorldMatrix.Translation); Vector3I minCorner, maxCorner; { Vector3D sphereMin = sphere.Center - (sphere.Radius - MyVoxelConstants.VOXEL_SIZE_IN_METRES) * 1.3f; Vector3D sphereMax = sphere.Center + (sphere.Radius + MyVoxelConstants.VOXEL_SIZE_IN_METRES) * 1.3f; MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMap.PositionLeftBottomCorner, ref sphereMin, out minCorner); MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMap.PositionLeftBottomCorner, ref sphereMax, out maxCorner); } voxelMap.Storage.ClampVoxelCoord(ref minCorner); voxelMap.Storage.ClampVoxelCoord(ref maxCorner); Vector3I worldMinCorner = minCorner + voxelMap.StorageMin; Vector3I worldMaxCorner = maxCorner + voxelMap.StorageMin; // We are tracking which voxels were changed, so we can invalidate only needed cells in the cache bool changed = false; ProfilerShort.Begin("Reading cache"); m_cache.Resize(minCorner, maxCorner); voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, ref worldMinCorner, ref worldMaxCorner); ProfilerShort.End(); ProfilerShort.Begin("Changing cache"); int removedVoxelContent = 0; Vector3I tempVoxelCoord; Vector3I cachePos = (maxCorner - minCorner) / 2; byte oldMaterial = m_cache.Material(ref cachePos); float digRatio = 1 - Vector3.Dot(normal, direction); Vector3 newCenter = sphere.Center - normal * (float)sphere.Radius * 1.1f;//0.9f; float sphRadA = (float)(sphere.Radius * 1.5f); float sphRadSqA = (float)(sphRadA * sphRadA); float voxelSizeHalfTransformedPosA = MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * (2 * sphRadA + MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF); float voxelSizeHalfTransformedNegA = MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * (-2 * sphRadA + MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF); Vector3 newDelCenter = newCenter + normal * (float)sphere.Radius * (0.7f + digRatio) + direction * (float)sphere.Radius * 0.65f; float sphRadD = (float)(sphere.Radius); float sphRadSqD = (float)(sphRadD * sphRadD); float voxelSizeHalfTransformedPosD = MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * (2 * sphRadD + MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF); float voxelSizeHalfTransformedNegD = MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * (-2 * sphRadD + MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF); Vector3 newSetCenter = newCenter + normal * (float)sphere.Radius * (digRatio) + direction * (float)sphere.Radius * 0.3f; float sphRadS = (float)(sphere.Radius * 0.1f); float sphRadSqS = (float)(sphRadS * sphRadS); float voxelSizeHalfTransformedPosS = MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * (2 * sphRadS + MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF); for (tempVoxelCoord.Z = minCorner.Z, cachePos.Z = 0; tempVoxelCoord.Z <= maxCorner.Z; tempVoxelCoord.Z++, ++cachePos.Z) { for (tempVoxelCoord.Y = minCorner.Y, cachePos.Y = 0; tempVoxelCoord.Y <= maxCorner.Y; tempVoxelCoord.Y++, ++cachePos.Y) { for (tempVoxelCoord.X = minCorner.X, cachePos.X = 0; tempVoxelCoord.X <= maxCorner.X; tempVoxelCoord.X++, ++cachePos.X) { Vector3D voxelPosition; MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref tempVoxelCoord, out voxelPosition); byte originalContent = m_cache.Content(ref cachePos); //Add sphere if (originalContent != MyVoxelConstants.VOXEL_CONTENT_FULL) { float addDist = (float)(voxelPosition - newCenter).LengthSquared(); float addDiff = (float)(addDist - sphRadSqA); byte newContent; if (addDiff > voxelSizeHalfTransformedPosA) { newContent = MyVoxelConstants.VOXEL_CONTENT_EMPTY; } else if (addDiff < voxelSizeHalfTransformedNegA) { newContent = MyVoxelConstants.VOXEL_CONTENT_FULL; } else { float value = (float)Math.Sqrt(addDist + sphRadSqA - 2 * sphRadA * Math.Sqrt(addDist)); if (addDiff < 0) { value = -value; } // This formula will work even if diff is positive or negative newContent = (byte)(MyVoxelConstants.VOXEL_ISO_LEVEL - value / MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * MyVoxelConstants.VOXEL_ISO_LEVEL); } if (newContent > originalContent) { if (material != null) { m_cache.Material(ref cachePos, oldMaterial); } changed = true; m_cache.Content(ref cachePos, newContent); } } //Delete sphere float delDist = (float)(voxelPosition - newDelCenter).LengthSquared(); float delDiff = (float)(delDist - sphRadSqD); byte contentToRemove; if (delDiff > voxelSizeHalfTransformedPosD) { contentToRemove = MyVoxelConstants.VOXEL_CONTENT_EMPTY; } else if (delDiff < voxelSizeHalfTransformedNegD) { contentToRemove = MyVoxelConstants.VOXEL_CONTENT_FULL; } else { float value = (float)Math.Sqrt(delDist + sphRadSqD - 2 * sphRadD * Math.Sqrt(delDist)); if (delDiff < 0) { value = -value; } // This formula will work even if diff is positive or negative contentToRemove = (byte)(MyVoxelConstants.VOXEL_ISO_LEVEL - value / MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * MyVoxelConstants.VOXEL_ISO_LEVEL); } originalContent = m_cache.Content(ref cachePos); if (originalContent > MyVoxelConstants.VOXEL_CONTENT_EMPTY && contentToRemove > MyVoxelConstants.VOXEL_CONTENT_EMPTY) { changed = true; int newVal = originalContent - contentToRemove; if (newVal < MyVoxelConstants.VOXEL_CONTENT_EMPTY) { newVal = MyVoxelConstants.VOXEL_CONTENT_EMPTY; } m_cache.Content(ref cachePos, (byte)newVal); removedVoxelContent += originalContent - newVal; } //Set material float setDist = (float)(voxelPosition - newSetCenter).LengthSquared(); float setDiff = (float)(setDist - sphRadSqS); if (setDiff <= MyVoxelConstants.VOXEL_SIZE_IN_METRES * 1.5f) // could be VOXEL_SIZE_IN_METRES_HALF, but we want to set material in empty cells correctly { MyVoxelMaterialDefinition originalMaterial = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref cachePos)); // Change the material: // - always on boundaries between material and nothing // - smoothly on inner boundaries MyVoxelMaterialDefinition newMaterial = material; if (setDiff > 0) { byte content = m_cache.Content(ref cachePos); if (content == MyVoxelConstants.VOXEL_CONTENT_FULL) { newMaterial = originalMaterial; } if (setDiff >= voxelSizeHalfTransformedPosS && content != MyVoxelConstants.VOXEL_CONTENT_EMPTY) // set material behind boundary only for empty voxels { newMaterial = originalMaterial; } } if (originalMaterial == newMaterial) { continue; } m_cache.Material(ref cachePos, newMaterial.Index); changed = true; } float dist = (float)(voxelPosition - newCenter).LengthSquared(); float diff = (float)(dist - sphRadSqA); if (diff <= 0f) { originalContent = m_cache.Content(ref cachePos); if (originalContent > MyVoxelConstants.VOXEL_CONTENT_EMPTY) { bool wrinkled = m_cache.WrinkleVoxelContent(ref cachePos, MyVoxelConstants.DEFAULT_WRINKLE_WEIGHT_ADD, MyVoxelConstants.DEFAULT_WRINKLE_WEIGHT_REMOVE); if (wrinkled) { changed = true; } } } } } } ProfilerShort.End(); if (changed) { ProfilerShort.Begin("RemoveSmallVoxelsUsingChachedVoxels"); RemoveSmallVoxelsUsingChachedVoxels(); ProfilerShort.BeginNextBlock("Writing cache"); minCorner += voxelMap.StorageMin; maxCorner += voxelMap.StorageMin; voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, ref minCorner, ref maxCorner); MyShapeSphere sphereShape = new MyShapeSphere(); sphereShape.Center = sphere.Center; sphereShape.Radius = (float)(sphere.Radius * 1.5); OnVoxelChanged(MyVoxelBase.OperationType.Cut, voxelMap, sphereShape); ProfilerShort.End(); } ProfilerShort.End(); }
public static void CutOutShapeWithProperties( MyVoxelBase voxelMap, MyShape shape, out float voxelsCountInPercent, out MyVoxelMaterialDefinition voxelMaterial, Dictionary <MyVoxelMaterialDefinition, int> exactCutOutMaterials = null, bool updateSync = false, bool onlyCheck = false, bool applyDamageMaterial = false, bool onlyApplyMaterial = false) { if (MySession.Static.EnableVoxelDestruction == false) { voxelsCountInPercent = 0; voxelMaterial = null; return; } ProfilerShort.Begin("MyVoxelGenerator::CutOutShapeWithProperties()"); int originalSum = 0; int removedSum = 0; bool materials = exactCutOutMaterials != null; // Bring the shape into voxel space. var oldTranmsform = shape.Transformation; var newTransf = oldTranmsform * voxelMap.PositionComp.WorldMatrixInvScaled; newTransf.Translation += voxelMap.SizeInMetresHalf; shape.Transformation = newTransf; // This boundary should now be in our local space var bbox = shape.GetWorldBoundaries(); Vector3I minCorner, maxCorner; ComputeShapeBounds(voxelMap, ref bbox, Vector3.Zero, voxelMap.Storage.Size, out minCorner, out maxCorner); bool readMaterial = exactCutOutMaterials != null || applyDamageMaterial; var cacheMin = minCorner - 1; var cacheMax = maxCorner + 1; //try on making the read/write cell alligned see MyOctreeStorage.WriteRange - Micro octree leaf /*const int SHIFT = 4; * const int REM = (1 << SHIFT) - 1; * const int MASK = ~REM; * cacheMin &= MASK; * cacheMax = (cacheMax + REM) & MASK;*/ voxelMap.Storage.ClampVoxelCoord(ref cacheMin); voxelMap.Storage.ClampVoxelCoord(ref cacheMax); m_cache.Resize(cacheMin, cacheMax); m_cache.ClearMaterials(0); // Advise that the read content shall be cached MyVoxelRequestFlags flags = MyVoxelRequestFlags.AdviseCache; voxelMap.Storage.ReadRange(m_cache, readMaterial ? MyStorageDataTypeFlags.ContentAndMaterial : MyStorageDataTypeFlags.Content, 0, ref cacheMin, ref cacheMax, ref flags); Vector3I center; if (materials) { center = m_cache.Size3D / 2; voxelMaterial = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref center)); } else { center = (cacheMin + cacheMax) / 2; voxelMaterial = voxelMap.Storage.GetMaterialAt(ref center); } MyVoxelMaterialDefinition voxelMat = null; ProfilerShort.Begin("Main loop"); Vector3I pos; for (pos.X = minCorner.X; pos.X <= maxCorner.X; ++pos.X) { for (pos.Y = minCorner.Y; pos.Y <= maxCorner.Y; ++pos.Y) { for (pos.Z = minCorner.Z; pos.Z <= maxCorner.Z; ++pos.Z) { // get original amount var relPos = pos - cacheMin; var lin = m_cache.ComputeLinear(ref relPos); var original = m_cache.Content(lin); if (original == MyVoxelConstants.VOXEL_CONTENT_EMPTY) // if there is nothing to remove { continue; } Vector3D spos = (Vector3D)(pos - voxelMap.StorageMin) * MyVoxelConstants.VOXEL_SIZE_IN_METRES; var volume = shape.GetVolume(ref spos); if (volume == 0f) // if there is no intersection { continue; } var maxRemove = (int)(volume * MyVoxelConstants.VOXEL_CONTENT_FULL); var toRemove = maxRemove; // (int)(maxRemove * voxelMat.DamageRatio); var newVal = Math.Max(original - toRemove, 0); //MathHelper.Clamp(original - toRemove, 0, original-maxRemove); var removed = original - newVal; if (!onlyCheck && !onlyApplyMaterial) { m_cache.Content(lin, (byte)newVal); } originalSum += original; removedSum += removed; if (readMaterial) { voxelMat = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(lin)); } if (exactCutOutMaterials != null) { int value = 0; exactCutOutMaterials.TryGetValue(voxelMat, out value); value += (MyFakes.ENABLE_REMOVED_VOXEL_CONTENT_HACK ? (int)(removed * 3.9f) : removed); exactCutOutMaterials[voxelMat] = value; } if (applyDamageMaterial && voxelMat.HasDamageMaterial && !onlyCheck) { m_cache.Material(lin, voxelMat.DamagedMaterialId); } } } } if (removedSum > 0 && updateSync && Sync.IsServer) { shape.SendDrillCutOutRequest(voxelMap, applyDamageMaterial); } ProfilerShort.BeginNextBlock("Write"); if (removedSum > 0 && !onlyCheck) { // Clear all small voxel that may have been created during explosion. They can be created even outside the range of // explosion sphere, e.g. if you have three voxels in a row A, B, C, where A is 255, B is 60, and C is 255. During the // explosion you change C to 0, so now we have 255, 60, 0. Than another explosion that will change A to 0, so we // will have 0, 60, 0. But B was always outside the range of the explosion. So this is why we need to do -1/+1 and remove // B voxels too. //!! TODO AR & MK : check if this is needed !! //RemoveSmallVoxelsUsingChachedVoxels(); var dataTypeFlags = applyDamageMaterial ? MyStorageDataTypeFlags.ContentAndMaterial : MyStorageDataTypeFlags.Content; if (MyFakes.LOG_NAVMESH_GENERATION) { MyAIComponent.Static.Pathfinding.VoxelPathfinding.DebugLog.LogStorageWrite(voxelMap, m_cache, dataTypeFlags, cacheMin, cacheMax); } voxelMap.Storage.WriteRange(m_cache, dataTypeFlags, ref cacheMin, ref cacheMax); } ProfilerShort.End(); voxelsCountInPercent = (originalSum > 0f) ? (float)removedSum / (float)originalSum : 0f; shape.Transformation = oldTranmsform; if (removedSum > 0) { OnVoxelChanged(MyVoxelBase.OperationType.Cut, voxelMap, shape); } ProfilerShort.End(); }
// Sends input (keyboard/mouse) to screen which has focus (top-most) public static void HandleInput() { ProfilerShort.Begin("MyScreenManager.HandleInput"); try { // Forward input to screens only if there are screens and if game has focus (is active) if (m_screens.Count <= 0) { return; } // Get screen from top of the stack - that one has focus MyGuiScreenBase screenWithFocus = GetScreenWithFocus(); if (m_inputToNonFocusedScreens) { bool inputIsShared = false; for (int i = (m_screens.Count - 1); i >= 0; i--) { if (m_screens.Count <= i) { continue; } MyGuiScreenBase screen = m_screens[i]; ProfilerShort.Begin(screen.GetType().Name); if (screen.CanShareInput()) { screen.HandleInput(m_lastScreenWithFocus != screenWithFocus); inputIsShared = true; } else if (!inputIsShared && screen == screenWithFocus) { screen.HandleInput(m_lastScreenWithFocus != screenWithFocus); } ProfilerShort.End(); } m_inputToNonFocusedScreens &= inputIsShared; } else { foreach (var screen in m_screens) { if (screen != screenWithFocus) { screen.InputLost(); } } if (screenWithFocus != null) { switch (screenWithFocus.State) { case MyGuiScreenState.OPENED: case MyGuiScreenState.OPENING: case MyGuiScreenState.UNHIDING: ProfilerShort.Begin(screenWithFocus.GetType().Name); screenWithFocus.HandleInput(m_lastScreenWithFocus != screenWithFocus); ProfilerShort.End(); break; case MyGuiScreenState.CLOSING: case MyGuiScreenState.HIDING: break; default: Debug.Fail(string.Format("Focused screen in state {0}.", screenWithFocus.State)); break; } } } m_lastScreenWithFocus = screenWithFocus; } finally { ProfilerShort.End(); } }
public static void MakeCrater(MyVoxelBase voxelMap, BoundingSphereD sphere, Vector3 normal, MyVoxelMaterialDefinition material) { ProfilerShort.Begin("MakeCrater"); Vector3I minCorner, maxCorner; { Vector3D sphereMin = sphere.Center - (sphere.Radius - MyVoxelConstants.VOXEL_SIZE_IN_METRES); Vector3D sphereMax = sphere.Center + (sphere.Radius + MyVoxelConstants.VOXEL_SIZE_IN_METRES); MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMap.PositionLeftBottomCorner, ref sphereMin, out minCorner); MyVoxelCoordSystems.WorldPositionToVoxelCoord(voxelMap.PositionLeftBottomCorner, ref sphereMax, out maxCorner); } voxelMap.Storage.ClampVoxelCoord(ref minCorner); voxelMap.Storage.ClampVoxelCoord(ref maxCorner); // We are tracking which voxels were changed, so we can invalidate only needed cells in the cache bool changed = false; ProfilerShort.Begin("Reading cache"); m_cache.Resize(minCorner, maxCorner); voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, 0, ref minCorner, ref maxCorner); ProfilerShort.End(); ProfilerShort.Begin("Changing cache"); int removedVoxelContent = 0; Vector3I tempVoxelCoord; Vector3I cachePos; for (tempVoxelCoord.Z = minCorner.Z, cachePos.Z = 0; tempVoxelCoord.Z <= maxCorner.Z; tempVoxelCoord.Z++, ++cachePos.Z) { for (tempVoxelCoord.Y = minCorner.Y, cachePos.Y = 0; tempVoxelCoord.Y <= maxCorner.Y; tempVoxelCoord.Y++, ++cachePos.Y) { for (tempVoxelCoord.X = minCorner.X, cachePos.X = 0; tempVoxelCoord.X <= maxCorner.X; tempVoxelCoord.X++, ++cachePos.X) { Vector3D voxelPosition; MyVoxelCoordSystems.VoxelCoordToWorldPosition(voxelMap.PositionLeftBottomCorner, ref tempVoxelCoord, out voxelPosition); float addDist = (float)(voxelPosition - sphere.Center).Length(); float addDiff = (float)(addDist - sphere.Radius); byte newContent; if (addDiff > MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF) { newContent = MyVoxelConstants.VOXEL_CONTENT_EMPTY; } else if (addDiff < -MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF) { newContent = MyVoxelConstants.VOXEL_CONTENT_FULL; } else { // This formula will work even if diff is positive or negative newContent = (byte)(MyVoxelConstants.VOXEL_ISO_LEVEL - addDiff / MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * MyVoxelConstants.VOXEL_ISO_LEVEL); } byte originalContent = m_cache.Content(ref cachePos); if (newContent > originalContent && originalContent > 0) { if (material != null) { m_cache.Material(ref cachePos, material.Index); } changed = true; m_cache.Content(ref cachePos, newContent); } float delDist = (float)(voxelPosition - (sphere.Center + (float)sphere.Radius * 0.7f * normal)).Length(); float delDiff = (float)(delDist - sphere.Radius); byte contentToRemove; if (delDiff > MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF) { contentToRemove = MyVoxelConstants.VOXEL_CONTENT_EMPTY; } else if (delDiff < -MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF) { contentToRemove = MyVoxelConstants.VOXEL_CONTENT_FULL; } else { // This formula will work even if diff is positive or negative contentToRemove = (byte)(MyVoxelConstants.VOXEL_ISO_LEVEL - delDiff / MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * MyVoxelConstants.VOXEL_ISO_LEVEL); } originalContent = m_cache.Content(ref cachePos); if (originalContent > MyVoxelConstants.VOXEL_CONTENT_EMPTY && contentToRemove > MyVoxelConstants.VOXEL_CONTENT_EMPTY) { changed = true; int newVal = originalContent - contentToRemove; if (newVal < MyVoxelConstants.VOXEL_CONTENT_EMPTY) { newVal = MyVoxelConstants.VOXEL_CONTENT_EMPTY; } m_cache.Content(ref cachePos, (byte)newVal); removedVoxelContent += originalContent - newVal; } float setDist = (float)(voxelPosition - (sphere.Center - (float)sphere.Radius * 0.5f * normal)).Length(); float setDiff = (float)(setDist - sphere.Radius / 4f); if (setDiff <= MyVoxelConstants.VOXEL_SIZE_IN_METRES * 1.5f) // could be VOXEL_SIZE_IN_METRES_HALF, but we want to set material in empty cells correctly { byte indestructibleContentToSet = MyVoxelConstants.VOXEL_CONTENT_FULL; if (setDiff >= MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF) // outside { indestructibleContentToSet = MyVoxelConstants.VOXEL_CONTENT_EMPTY; } else if (setDiff >= -MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF) // boundary { indestructibleContentToSet = (byte)(MyVoxelConstants.VOXEL_ISO_LEVEL - setDiff / MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF * MyVoxelConstants.VOXEL_ISO_LEVEL); } MyVoxelMaterialDefinition originalMaterial = MyDefinitionManager.Static.GetVoxelMaterialDefinition(m_cache.Material(ref cachePos)); // Change the material: // - always on boundaries between material and nothing // - smoothly on inner boundaries MyVoxelMaterialDefinition newMaterial = material; if (setDiff > 0) { byte content = m_cache.Content(ref cachePos); if (content == MyVoxelConstants.VOXEL_CONTENT_FULL) { newMaterial = originalMaterial; } if (setDiff >= MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF && content != MyVoxelConstants.VOXEL_CONTENT_EMPTY) // set material behind boundary only for empty voxels { newMaterial = originalMaterial; } } if (originalMaterial == newMaterial) { continue; } m_cache.Material(ref cachePos, newMaterial.Index); changed = true; } float dist = (float)(voxelPosition - sphere.Center).Length(); float diff = (float)(dist - sphere.Radius); if (diff <= 0f) { originalContent = m_cache.Content(ref cachePos); if (originalContent > MyVoxelConstants.VOXEL_CONTENT_EMPTY) { bool wrinkled = m_cache.WrinkleVoxelContent(ref cachePos, MyVoxelConstants.DEFAULT_WRINKLE_WEIGHT_ADD, MyVoxelConstants.DEFAULT_WRINKLE_WEIGHT_REMOVE); if (wrinkled) { changed = true; } } } } } } ProfilerShort.End(); if (changed) { ProfilerShort.Begin("RemoveSmallVoxelsUsingChachedVoxels"); RemoveSmallVoxelsUsingChachedVoxels(); ProfilerShort.BeginNextBlock("Writing cache"); voxelMap.Storage.WriteRange(m_cache, MyStorageDataTypeFlags.ContentAndMaterial, ref minCorner, ref maxCorner); ProfilerShort.End(); } ProfilerShort.End(); }
public bool Drill(bool collectOre = true, bool performCutout = true) { ProfilerShort.Begin("MyDrillBase::Drill()"); bool drillingSuccess = false; MySoundPair sound = null; if ((m_drillEntity.Parent != null) && (m_drillEntity.Parent.Physics != null) && !m_drillEntity.Parent.Physics.Enabled) { return(false); } if (performCutout) { var entitiesInRange = m_sensor.EntitiesInRange; foreach (var entry in entitiesInRange) { drillingSuccess = false; var entity = entry.Value.Entity; if (entity.MarkedForClose) { continue; } if (entity is MyCubeGrid) { var grid = entity as MyCubeGrid; if (grid.Physics != null && grid.Physics.Enabled) { drillingSuccess = TryDrillBlocks(grid, entry.Value.DetectionPoint, !Sync.IsServer); } if (drillingSuccess) { m_initialHeatup = false; sound = m_sounds.MetalLoop; CreateParticles(entry.Value.DetectionPoint, false, true, false); } } else if (entity is MyVoxelMap) { ProfilerShort.Begin("Drill voxel map"); var voxels = entity as MyVoxelMap; drillingSuccess = TryDrillVoxels(voxels, entry.Value.DetectionPoint, collectOre, !Sync.IsServer); ProfilerShort.BeginNextBlock("Create particles"); if (drillingSuccess) { sound = m_sounds.RockLoop; CreateParticles(entry.Value.DetectionPoint, true, false, true); } ProfilerShort.End(); } else if (entity is MyFloatingObject) { var sphere = (BoundingSphereD)m_cutOut.Sphere; sphere.Radius *= 1.33f; if (entity.GetIntersectionWithSphere(ref sphere)) { MyFloatingObject flObj = entity as MyFloatingObject; if (Sync.IsServer) { if (flObj.Item.Content.TypeId == typeof(MyObjectBuilder_Ore)) { IMyInventoryOwner invOwn = m_drillEntity as IMyInventoryOwner; if (invOwn == null) { invOwn = (m_drillEntity as MyHandDrill).Owner as IMyInventoryOwner; } invOwn.GetInventory(0).TakeFloatingObject(flObj); } else { (entity as MyFloatingObject).DoDamage(70, MyDamageType.Drill, true); } } drillingSuccess = true; } } else if (entity is MyCharacter) { var sphere = (BoundingSphereD)m_cutOut.Sphere; sphere.Radius *= (4 / 5f); var character = entity as MyCharacter; if (entity.GetIntersectionWithSphere(ref sphere)) { //MyRenderProxy.DebugDrawSphere(sphere.Center, sphere.Radius, Color.Green.ToVector3(), 1, true); if (Sync.IsServer) { character.DoDamage(20, MyDamageType.Drill, true); } drillingSuccess = true; } else { BoundingSphereD headSphere = new BoundingSphereD(character.PositionComp.WorldMatrix.Translation + character.WorldMatrix.Up * 1.25f, 0.6f); //MyRenderProxy.DebugDrawSphere(headSphere.Center, headSphere.Radius, Color.Red.ToVector3(), 1, false); if (headSphere.Intersects(sphere)) { //MyRenderProxy.DebugDrawSphere(sphere.Center, sphere.Radius, Color.Green.ToVector3(), 1, true); if (Sync.IsServer) { character.DoDamage(20, MyDamageType.Drill, true); } drillingSuccess = true; } } } if (drillingSuccess) { m_lastContactTime = MySandboxGame.TotalGamePlayTimeInMilliseconds; } } } if (sound != null) { StartLoopSound(sound); } else { StartIdleSound(m_sounds.IdleLoop); } IsDrilling = true; m_animationLastUpdateTime = MySandboxGame.TotalGamePlayTimeInMilliseconds; ProfilerShort.End(); return(drillingSuccess); }
public void Update(int behaviorTicks) { m_stuckDetection.SetCurrentTicks(behaviorTicks); ProfilerShort.Begin("MyBotNavigation.Update"); AssertIsValid(); if (m_entity == null) { return; } ProfilerShort.Begin("UpdateMatrices"); UpdateMatrices(); ProfilerShort.End(); m_gravityDirection = MyGravityProviderSystem.CalculateTotalGravityInPoint(m_entity.PositionComp.WorldMatrix.Translation); if (!Vector3.IsZero(m_gravityDirection, 0.01f)) { m_gravityDirection = Vector3D.Normalize(m_gravityDirection); } if (MyPerGameSettings.NavmeshPresumesDownwardGravity) { m_upVector = Vector3.Up; } else { m_upVector = -m_gravityDirection; } if (!m_speed.IsValid()) { m_forwardVector = PositionAndOrientation.Forward; m_speed = 0.0f; m_rotationSpeedModifier = 1; } ProfilerShort.Begin("Steering update"); foreach (var steering in m_steerings) { ProfilerShort.Begin(steering.GetName()); steering.Update(); ProfilerShort.End(); } ProfilerShort.End(); ProfilerShort.Begin("Aiming"); m_aiming.Update(); ProfilerShort.End(); ProfilerShort.Begin("Steering accumulate correction"); CorrectMovement(m_aiming.RotationHint); ProfilerShort.End(); if (m_speed < 0.1f)// hotfix for flickering of animation from running left to running right { m_speed = 0; } ProfilerShort.Begin("MoveCharacter"); MoveCharacter(); ProfilerShort.End(); AssertIsValid(); ProfilerShort.End(); }
internal void UpdateAfterSimulation10() { ProfilerShort.Begin("Voxel Physics Prediction"); UpdateRigidBodyShape(); // Apply prediction based on movement of nearby entities. foreach (var entity in m_nearbyEntities) { Debug.Assert(m_bodiesInitialized, "Voxel map does not have physics!"); bool lod0 = entity is MyCharacter; if (!lod0) { var body = entity.Physics as MyPhysicsBody; if (body != null && body.RigidBody != null && (body.RigidBody.Layer == MyPhysics.CollisionLayers.FloatingObjectCollisionLayer || body.RigidBody.Layer == MyPhysics.CollisionLayers.LightFloatingObjectCollisionLayer)) { lod0 = true; } } if (!(entity is MyCubeGrid) && !lod0) { continue; } if (entity.MarkedForClose) { continue; } if (entity.Physics == null || entity.Physics.LinearVelocity.Length() < 2f) { continue; } BoundingBoxD aabb; GetPrediction(entity, out aabb); if (!aabb.Intersects(m_voxelMap.PositionComp.WorldAABB)) { continue; } int lod = lod0 ? 0 : 1; float lodSize = 1 << lod; Vector3I min, max; Vector3D localPositionMin, localPositionMax; aabb = aabb.Transform(m_voxelMap.PositionComp.WorldMatrixInvScaled); aabb.Translate(m_voxelMap.SizeInMetresHalf); localPositionMax = aabb.Max; localPositionMin = aabb.Min; MyVoxelCoordSystems.LocalPositionToVoxelCoord(ref localPositionMin, out min); MyVoxelCoordSystems.LocalPositionToVoxelCoord(ref localPositionMax, out max); m_voxelMap.Storage.ClampVoxelCoord(ref min); m_voxelMap.Storage.ClampVoxelCoord(ref max); MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref min, out min); MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref max, out max); min >>= lod; max >>= lod; { var size = (max - min + 1).Size; if (size >= m_cellsToGenerateBuffer.Length) { m_cellsToGenerateBuffer = new Vector3I[MathHelper.GetNearestBiggerPowerOfTwo(size)]; } } var shape = GetShape(lod); Debug.Assert(shape.Base.IsValid); int requiredCellsCount = shape.GetMissingCellsInRange(ref min, ref max, m_cellsToGenerateBuffer); if (requiredCellsCount == 0) { continue; } var bb = new BoundingBox(min * MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_METRES * lodSize, (max + 1) * MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_METRES * lodSize); bb.Translate(m_voxelMap.StorageMin); ProfilerShort.Begin("Storage Intersect"); if (requiredCellsCount > 0 && m_voxelMap.Storage.Intersect(ref bb, false) != ContainmentType.Intersects) { ProfilerShort.BeginNextBlock("Set Empty Shapes"); for (int i = 0; i < requiredCellsCount; ++i) { var cell = m_cellsToGenerateBuffer[i]; m_workTracker.Cancel(new MyCellCoord(lod, cell)); shape.SetChild(cell.X, cell.Y, cell.Z, (HkBvCompressedMeshShape)HkShape.Empty, HkReferencePolicy.TakeOwnership); } ProfilerShort.End(); continue; } ProfilerShort.BeginNextBlock("Start Jobs"); for (int i = 0; i < requiredCellsCount; ++i) { if (m_workTracker.Exists(new MyCellCoord(lod, m_cellsToGenerateBuffer[i]))) { continue; } MyPrecalcJobPhysicsPrefetch.Start(new MyPrecalcJobPhysicsPrefetch.Args { TargetPhysics = this, Tracker = m_workTracker, GeometryCell = new MyCellCoord(lod, m_cellsToGenerateBuffer[i]), Storage = m_voxelMap.Storage }); } ProfilerShort.End(); } if (m_bodiesInitialized) { CheckAndDiscardShapes(); } ProfilerShort.End(); }
public override void HandleInput() { ProfilerShort.Begin("MyToolbarComponent.HandleInput"); try { var context = MySession.Static.ControlledEntity != null ? MySession.Static.ControlledEntity.ControlContext : MyStringId.NullOrEmpty; var focusedScreen = MyScreenManager.GetScreenWithFocus(); if ((focusedScreen == MyGuiScreenGamePlay.Static || IsToolbarControlShown) && CurrentToolbar != null) { { for (int i = 0; i < m_slotControls.Length; i++) { if (MyControllerHelper.IsControl(context, m_slotControls[i], MyControlStateType.NEW_PRESSED)) { if (!MyInput.Static.IsAnyCtrlKeyPressed()) { if ((focusedScreen == MyGuiScreenGamePlay.Static || (focusedScreen is MyGuiScreenCubeBuilder || focusedScreen is MyGuiScreenToolbarConfigBase) && ((MyGuiScreenToolbarConfigBase)focusedScreen).AllowToolbarKeys()) && CurrentToolbar != null) { CurrentToolbar.ActivateItemAtSlot(i); } } else if (i < CurrentToolbar.PageCount) { MyGuiAudio.PlaySound(MyGuiSounds.HudClick); CurrentToolbar.SwitchToPage(i); } } } } if ((focusedScreen == MyGuiScreenGamePlay.Static || (focusedScreen is MyGuiScreenCubeBuilder || focusedScreen is MyGuiScreenToolbarConfigBase) && ((MyGuiScreenToolbarConfigBase)focusedScreen).AllowToolbarKeys()) && CurrentToolbar != null) { if (MyControllerHelper.IsControl(context, MyControlsSpace.TOOLBAR_NEXT_ITEM, MyControlStateType.NEW_PRESSED)) { CurrentToolbar.SelectNextSlot(); } else if (MyControllerHelper.IsControl(context, MyControlsSpace.TOOLBAR_PREV_ITEM, MyControlStateType.NEW_PRESSED)) { CurrentToolbar.SelectPreviousSlot(); } if (MyControllerHelper.IsControl(context, MyControlsSpace.TOOLBAR_UP, MyControlStateType.NEW_PRESSED)) { MyGuiAudio.PlaySound(MyGuiSounds.HudClick); CurrentToolbar.PageUp(); } if (MyControllerHelper.IsControl(context, MyControlsSpace.TOOLBAR_DOWN, MyControlStateType.NEW_PRESSED)) { MyGuiAudio.PlaySound(MyGuiSounds.HudClick); CurrentToolbar.PageDown(); } } } } finally { ProfilerShort.End(); } base.HandleInput(); }
public bool Disconnect(MyCubeGrid grid, MySlimBlock testBlock = null, bool testDisconnect = false) { ProfilerShort.Begin("Collect+IsInVoxels"); m_largestGroupWithPhysics = default(Group); m_groups.Clear(); m_sortedBlocks.Clear(); m_disconnectHelper.Clear(); foreach (var block in grid.GetBlocks()) { if (block == testBlock) { continue; } m_disconnectHelper.Add(block); } ProfilerShort.End(); ProfilerShort.Begin("GroupBy"); while (m_disconnectHelper.Count > 0) { Group group = default(Group); group.FirstBlockIndex = m_sortedBlocks.Count; AddNeighbours(m_disconnectHelper.FirstElement(), out group.IsValid, testBlock); group.BlockCount = m_sortedBlocks.Count - group.FirstBlockIndex; if (group.IsValid && group.BlockCount > m_largestGroupWithPhysics.BlockCount) { if (m_largestGroupWithPhysics.BlockCount > 0) // Is valid { // order matters, insert in correct place int i = 0; for (i = 0; i < m_groups.Count; i++) { if (m_groups[i].FirstBlockIndex > m_largestGroupWithPhysics.FirstBlockIndex) { m_groups.Insert(i, m_largestGroupWithPhysics); break; } } if (i == m_groups.Count) { m_groups.Add(m_largestGroupWithPhysics); } } m_largestGroupWithPhysics = group; } else { m_groups.Add(group); } } ProfilerShort.End(); ProfilerShort.Begin("RemoveLargestGroup"); m_sortedBlocks.RemoveRange(m_largestGroupWithPhysics.FirstBlockIndex, m_largestGroupWithPhysics.BlockCount); for (int i = 0; i < m_groups.Count; i++) { var g = m_groups[i]; if (g.FirstBlockIndex > m_largestGroupWithPhysics.FirstBlockIndex) { g.FirstBlockIndex -= m_largestGroupWithPhysics.BlockCount; m_groups[i] = g; } } ProfilerShort.End(); ProfilerShort.Begin("CreateSplits"); if (m_groups.Count > 0) { if (testDisconnect) { m_groups.Clear(); m_sortedBlocks.Clear(); m_disconnectHelper.Clear(); ProfilerShort.End(); return(true); } MyCubeGrid.CreateSplits(grid, m_sortedBlocks, m_groups); } else { if (!MySession.Static.Settings.StationVoxelSupport) { if (grid.IsStatic) { grid.TestDynamic = MyCubeGrid.MyTestDynamicReason.GridSplit; } } } ProfilerShort.End(); m_groups.Clear(); m_sortedBlocks.Clear(); m_disconnectHelper.Clear(); return(false); }
public override void Init(MyObjectBuilder_CubeBlock builder, MyCubeGrid cubeGrid) { base.Init(builder, cubeGrid); ProfilerShort.Begin("FP.Init"); CheckConnectionAllowed = true; var ob = builder as MyObjectBuilder_FracturedBlock; if (ob.Shapes.Count == 0) { ProfilerShort.End(); if (ob.CreatingFracturedBlock) { return; } Debug.Fail("No relevant shape was found for fractured block. It was probably reexported and names changed."); throw new Exception("No relevant shape was found for fractured block. It was probably reexported and names changed."); } OriginalBlocks = new List <MyDefinitionId>(); Orientations = new List <MyBlockOrientation>(); var lst = new List <HkdShapeInstanceInfo>(); foreach (var def in ob.BlockDefinitions) { var blockDef = MyDefinitionManager.Static.GetCubeBlockDefinition(def); var model = blockDef.Model; if (VRage.Game.Models.MyModels.GetModelOnlyData(model).HavokBreakableShapes == null) { MyDestructionData.Static.LoadModelDestruction(model, blockDef, Vector3.One); } var shape = VRage.Game.Models.MyModels.GetModelOnlyData(model).HavokBreakableShapes[0]; var si = new HkdShapeInstanceInfo(shape, null, null); lst.Add(si); m_children.Add(si); shape.GetChildren(m_children); if (blockDef.BuildProgressModels != null) { foreach (var progress in blockDef.BuildProgressModels) { model = progress.File; if (VRage.Game.Models.MyModels.GetModelOnlyData(model).HavokBreakableShapes == null) { MyDestructionData.Static.LoadModelDestruction(model, blockDef, Vector3.One); } shape = VRage.Game.Models.MyModels.GetModelOnlyData(model).HavokBreakableShapes[0]; si = new HkdShapeInstanceInfo(shape, null, null); lst.Add(si); m_children.Add(si); shape.GetChildren(m_children); } } OriginalBlocks.Add(def); } foreach (var or in ob.BlockOrientations) { Orientations.Add(or); } if (ob.MultiBlocks.Count > 0) { MultiBlocks = new List <MultiBlockPartInfo>(); foreach (var mbpart in ob.MultiBlocks) { if (mbpart != null) { MultiBlocks.Add(new MultiBlockPartInfo() { MultiBlockDefinition = mbpart.MultiBlockDefinition, MultiBlockId = mbpart.MultiBlockId }); } else { MultiBlocks.Add(null); } } } m_shapes.AddRange(ob.Shapes); for (int i = 0; i < m_children.Count; i++) { var child = m_children[i]; Func <MyObjectBuilder_FracturedBlock.ShapeB, bool> x = s => s.Name == child.ShapeName; var result = m_shapes.Where(x); if (result.Count() > 0) { var found = result.First(); var m = Matrix.CreateFromQuaternion(found.Orientation); m.Translation = child.GetTransform().Translation; var si = new HkdShapeInstanceInfo(child.Shape.Clone(), m); if (found.Fixed) { si.Shape.SetFlagRecursively(HkdBreakableShape.Flags.IS_FIXED); } lst.Add(si); m_shapeInfos.Add(si); m_shapes.Remove(found); } else { child.GetChildren(m_children); } } if (m_shapeInfos.Count == 0) { m_children.Clear(); ProfilerShort.End(); Debug.Fail("No relevant shape was found for fractured block. It was probably reexported and names changed."); throw new Exception("No relevant shape was found for fractured block. It was probably reexported and names changed."); } foreach (var shape in m_shapeInfos) { if (!string.IsNullOrEmpty(shape.Shape.Name)) { Render.AddPiece(shape.Shape.Name, Matrix.CreateFromQuaternion(Quaternion.CreateFromRotationMatrix(shape.GetTransform().GetOrientation()))); } } if (CubeGrid.CreatePhysics) { HkdBreakableShape compound = new HkdCompoundBreakableShape(null, m_shapeInfos); ((HkdCompoundBreakableShape)compound).RecalcMassPropsFromChildren(); Shape = compound; var mp = new HkMassProperties(); compound.BuildMassProperties(ref mp); Shape = new HkdBreakableShape(compound.GetShape(), ref mp); compound.RemoveReference(); foreach (var si in m_shapeInfos) { var siRef = si; Shape.AddShape(ref siRef); } Shape.SetStrenght(MyDestructionConstants.STRENGTH); CreateMountPoints(); } m_children.Clear(); foreach (var si in m_shapeInfos) { si.Shape.RemoveReference(); } foreach (var si in lst) { si.RemoveReference(); } m_shapeInfos.Clear(); ProfilerShort.End(); }
private void FindAndCaculateFromStatic() { HashSet <Node> closedList = new HashSet <Node>(); List <Node> tmpNodes = new List <Node>(); var cmp = new NodeDistanceComparer(); // For each dynamic block foreach (var stat in StaticBlocks) { // TODO: Clear nodes parent and is leaf closedList.Clear(); tmpNodes.Clear(); using (Stats.Timing.Measure("SI - Static.FindDistances", VRage.Stats.MyStatTypeEnum.Sum | VRage.Stats.MyStatTypeEnum.DontDisappearFlag)) { // Find shortest distance to each dynamic block ProfilerShort.Begin("FindDistances"); FindDistances(stat, closedList, tmpNodes); ProfilerShort.End(); } tmpNodes.Clear(); using (Stats.Timing.Measure("SI - Dynamic.Sort", VRage.Stats.MyStatTypeEnum.Sum | VRage.Stats.MyStatTypeEnum.DontDisappearFlag)) { foreach (var block in closedList) { if (!block.IsStatic) { // Reset transfer mass block.Ratio = 1.0f; block.TransferMass = block.Mass; tmpNodes.Add(block); } } // Sort dynamic blocks in range by distance, biggest distance first tmpNodes.Sort(cmp); } using (Stats.Timing.Measure("SI - Dynamic.Calculate", VRage.Stats.MyStatTypeEnum.Sum | VRage.Stats.MyStatTypeEnum.DontDisappearFlag)) { // For each dynamic block foreach (var node in tmpNodes) { if (node.IsStatic) { continue; } node.PathCount++; foreach (var parent in node.Parents) { var delta = parent.Pos - node.Pos; // Node to parent int index, parentIndex; if (delta.X + delta.Y + delta.Z > 0) { index = delta.Y + delta.Z * 2; // UnitX = 0, UnitY = 1, UnitZ = 2 parentIndex = index + 3; } else { index = -delta.X * 3 - delta.Y * 4 - delta.Z * 5; // // -UnitX = 3, -UnitY = 4, -UnitZ = 5 parentIndex = index - 3; } node.SupportingWeights[index] -= node.TransferMass / node.Parents.Count; parent.SupportingWeights[parentIndex] += node.TransferMass / node.Parents.Count; parent.TransferMass += node.TransferMass / node.Parents.Count; } } } } }
public static List <MyCubeBlockDefinition.MountPoint> AutogenerateMountpoints(HkShape[] shapes, float gridSize) { ProfilerShort.Begin("AutogenerateMountpoints"); HkShapeCutterUtil cutter = new HkShapeCutterUtil(); List <BoundingBox>[] aabbsPerDirection = new List <BoundingBox> [Base6Directions.EnumDirections.Length]; var newMountPoints = new List <MyCubeBlockDefinition.MountPoint>(); foreach (var directionEnum in Base6Directions.EnumDirections) { int dirEnum = (int)directionEnum; //int dirEnum = 2; Vector3 direction = Base6Directions.Directions[dirEnum]; foreach (var shape in shapes) { if (shape.ShapeType == HkShapeType.List) { var listShape = (HkListShape)shape; var iterator = listShape.GetIterator(); while (iterator.IsValid) { HkShape childShape = iterator.CurrentValue; if (childShape.ShapeType == HkShapeType.ConvexTransform) { HkConvexTransformShape transformShape = (HkConvexTransformShape)childShape; FindMountPoint(cutter, transformShape.Base, direction, gridSize, newMountPoints); } else if (childShape.ShapeType == HkShapeType.ConvexTranslate) { HkConvexTranslateShape translateShape = (HkConvexTranslateShape)childShape; FindMountPoint(cutter, translateShape.Base, direction, gridSize, newMountPoints); } else { FindMountPoint(cutter, childShape, direction, gridSize, newMountPoints); } iterator.Next(); } break; } else if (shape.ShapeType == HkShapeType.Mopp) { var compoundShape = (HkMoppBvTreeShape)shape; for (int s = 0; s < compoundShape.ShapeCollection.ShapeCount; s++) { HkShape childShape = compoundShape.ShapeCollection.GetShape((uint)s, null); if (childShape.ShapeType == HkShapeType.ConvexTranslate) { HkConvexTranslateShape translateShape = (HkConvexTranslateShape)childShape; FindMountPoint(cutter, translateShape.Base, direction, gridSize, newMountPoints); } } break; } else { FindMountPoint(cutter, shape, direction, gridSize, newMountPoints); } } } ProfilerShort.End(); return(newMountPoints); }
private void FindAndCaculateFromDynamic() { HashSet <Node> closedList = new HashSet <Node>(); List <Node> staticNodes = new List <Node>(); Queue <Node> tmpBranches = new Queue <Node>(); // For each dynamic block foreach (var dyn in DynamicBlocks) { // TODO: Clear nodes parent and is leaf closedList.Clear(); staticNodes.Clear(); dyn.PathCount = 1; using (Stats.Timing.Measure("SI - Dynamic.FindDistances", VRage.Stats.MyStatTypeEnum.Sum | VRage.Stats.MyStatTypeEnum.DontDisappearFlag)) { // Find shortest distance to each static block ProfilerShort.Begin("FindDistances"); FindDistances(dyn, closedList, staticNodes); ProfilerShort.End(); } int numPaths = staticNodes.Count; float contribution = dyn.Mass / numPaths; using (Stats.Timing.Measure("SI - Dynamic.Calculate", VRage.Stats.MyStatTypeEnum.Sum | VRage.Stats.MyStatTypeEnum.DontDisappearFlag)) { foreach (var s in staticNodes) { closedList.Clear(); tmpBranches.Clear(); s.Ratio = 1.0f; dyn.PathCount = 1; tmpBranches.Enqueue(s); while (tmpBranches.Count > 0) { var node = tmpBranches.Dequeue(); float ratio = node.Ratio / node.Parents.Count; foreach (var parent in node.Parents) { var delta = parent.Pos - node.Pos; // Node to parent int index, parentIndex; if (delta.X + delta.Y + delta.Z > 0) { index = delta.Y + delta.Z * 2; // UnitX = 0, UnitY = 1, UnitZ = 2 parentIndex = index + 3; } else { index = -delta.X * 3 - delta.Y * 4 - delta.Z * 5; // // -UnitX = 3, -UnitY = 4, -UnitZ = 5 parentIndex = index - 3; } node.SupportingWeights[index] -= contribution * ratio; parent.SupportingWeights[parentIndex] += contribution * ratio; if (closedList.Add(parent)) { parent.Ratio = ratio; tmpBranches.Enqueue(parent); } else { parent.Ratio += ratio; } } } } } } }
protected override void ProcessCullQueryResults(MyCullQuery cullQuery) { ProfilerShort.Begin("Reset"); foreach (MyFrustumCullQuery frustumQuery in cullQuery.FrustumCullQueries) { var cullProxies = frustumQuery.List; foreach (MyCullProxy cullProxy in cullProxies) { cullProxy.Updated = false; cullProxy.FirstFullyContainingCascadeIndex = uint.MaxValue; } } ProfilerShort.End(); foreach (var frustumQuery in cullQuery.FrustumCullQueries) { ProfilerShort.Begin("Distance cull and update"); var cullProxies = frustumQuery.List; bool isShadowFrustum = (frustumQuery.Type == MyFrustumEnum.ShadowCascade) || (frustumQuery.Type == MyFrustumEnum.ShadowProjection); for (int cullProxyIndex = 0; cullProxyIndex < cullProxies.Count; ++cullProxyIndex) { MyCullProxy cullProxy = cullProxies[cullProxyIndex]; if (cullProxy == null || cullProxy.RenderableProxies == null || cullProxy.RenderableProxies.Length == 0 || cullProxy.RenderableProxies[0].Parent == null || !cullProxy.RenderableProxies[0].Parent.IsVisible) { m_tmpIndicesToRemove.Add(cullProxyIndex); continue; } if (!cullProxy.Updated) { var renderableComponent = cullProxy.Parent; if (renderableComponent != null) { renderableComponent.OnFrameUpdate(); if (renderableComponent.IsCulled) { m_tmpIndicesToRemove.Add(cullProxyIndex); continue; } renderableComponent.UpdateInstanceLods(); } // Proxies can get removed in UpdateInstanceLods if (cullProxy.RenderableProxies == null) { m_tmpIndicesToRemove.Add(cullProxyIndex); continue; } foreach (MyRenderableProxy proxy in cullProxy.RenderableProxies) { bool shouldCastShadows = proxy.Flags.HasFlags(MyRenderableProxyFlags.CastShadows) && (proxy.Flags.HasFlags(MyRenderableProxyFlags.DrawOutsideViewDistance) || frustumQuery.CascadeIndex < 4); if (isShadowFrustum && !shouldCastShadows) { m_tmpIndicesToRemove.Add(cullProxyIndex); break; } var worldMat = proxy.WorldMatrix; worldMat.Translation -= MyEnvironment.CameraPosition; proxy.CommonObjectData.LocalMatrix = worldMat; proxy.CommonObjectData.MaterialIndex = MySceneMaterials.GetDrawMaterialIndex(proxy.PerMaterialIndex); } cullProxy.Updated = true; } } for (int removeIndex = m_tmpIndicesToRemove.Count - 1; removeIndex >= 0; --removeIndex) { cullProxies.RemoveAtFast(m_tmpIndicesToRemove[removeIndex]); frustumQuery.IsInsideList.RemoveAtFast(m_tmpIndicesToRemove[removeIndex]); } m_tmpIndicesToRemove.SetSize(0); ProfilerShort.BeginNextBlock("Culling by query type"); if (frustumQuery.Type == MyFrustumEnum.MainFrustum) { MyPerformanceCounter.PerCameraDraw11Write.ViewFrustumObjectsNum = frustumQuery.List.Count; } else if (frustumQuery.Type == MyFrustumEnum.ShadowCascade) { while (m_shadowCascadeProxies2.Count < MyRenderProxy.Settings.ShadowCascadeCount) { m_shadowCascadeProxies2.Add(new HashSet <MyCullProxy_2>()); } bool isHighCascade = frustumQuery.CascadeIndex < 3; if (cullProxies.Count == 0) { MyShadowCascades.ShadowCascadeObjectsCounter[frustumQuery.CascadeIndex] = 0; MyShadowCascades.ShadowCascadeTriangleCounter[frustumQuery.CascadeIndex] = 0; } // List 1 for (int cullProxyIndex = 0; cullProxyIndex < cullProxies.Count; ++cullProxyIndex) { var cullProxy = cullProxies[cullProxyIndex]; if ((isHighCascade && (cullProxy.FirstFullyContainingCascadeIndex < frustumQuery.CascadeIndex - 1)) || (!isHighCascade && cullProxy.FirstFullyContainingCascadeIndex < frustumQuery.CascadeIndex) || cullProxy.RenderableProxies == null) { cullProxies.RemoveAtFast(cullProxyIndex); frustumQuery.IsInsideList.RemoveAtFast(cullProxyIndex); --cullProxyIndex; continue; } else { foreach (var renderableProxy in cullProxy.RenderableProxies) { MyShadowCascades.ShadowCascadeTriangleCounter[frustumQuery.CascadeIndex] += (renderableProxy.InstanceCount > 0 ? renderableProxy.InstanceCount : 1) * renderableProxy.DrawSubmesh.IndexCount / 3; } if (frustumQuery.IsInsideList[cullProxyIndex]) { cullProxy.FirstFullyContainingCascadeIndex = (uint)frustumQuery.CascadeIndex; } } } // List 2 var cullProxies2 = frustumQuery.List2; m_shadowCascadeProxies2[frustumQuery.CascadeIndex].Clear(); for (int cullProxyIndex = 0; cullProxyIndex < cullProxies2.Count; ++cullProxyIndex) { var cullProxy2 = cullProxies2[cullProxyIndex]; bool containedInHigherCascade = false; // Cull items if they're fully contained in higher resolution cascades for (int hashSetIndex = 0; hashSetIndex < frustumQuery.CascadeIndex; ++hashSetIndex) { if (m_shadowCascadeProxies2[hashSetIndex].Contains(cullProxy2)) { cullProxies2.RemoveAtFast(cullProxyIndex); frustumQuery.IsInsideList2.RemoveAtFast(cullProxyIndex); --cullProxyIndex; containedInHigherCascade = true; break; } } if (!containedInHigherCascade && frustumQuery.IsInsideList2[cullProxyIndex]) { m_shadowCascadeProxies2[frustumQuery.CascadeIndex].Add(cullProxy2); } } MyShadowCascades.ShadowCascadeObjectsCounter[frustumQuery.CascadeIndex] = cullProxies.Count; } else if (frustumQuery.Type == MyFrustumEnum.ShadowProjection) { MyShadows.OtherShadowsTriangleCounter = 0; for (int cullProxyIndex = 0; cullProxyIndex < cullProxies.Count; ++cullProxyIndex) { var cullProxy = frustumQuery.List[cullProxyIndex]; if (cullProxy.RenderableProxies == null) { cullProxies.RemoveAtFast(cullProxyIndex); frustumQuery.IsInsideList.RemoveAtFast(cullProxyIndex); --cullProxyIndex; continue; } foreach (var proxy in cullProxy.RenderableProxies) { MyShadows.OtherShadowsTriangleCounter += Math.Max(proxy.InstanceCount, 1) * proxy.DrawSubmesh.IndexCount / 3; } } } ProfilerShort.End(); if (frustumQuery.Ignored != null) { for (int cullProxyIndex = 0; cullProxyIndex < cullProxies.Count; cullProxyIndex++) { if ((cullProxies[cullProxyIndex].RenderableProxies == null || cullProxies[cullProxyIndex].RenderableProxies.Length == 0 || cullProxies[cullProxyIndex].RenderableProxies[0] == null) || (frustumQuery.Ignored.Contains(cullProxies[cullProxyIndex].RenderableProxies[0].Parent.Owner.ID))) { cullProxies.RemoveAtFast(cullProxyIndex); frustumQuery.IsInsideList.RemoveAtFast(cullProxyIndex); --cullProxyIndex; continue; } } } } for (int cascadeIndex = 0; cascadeIndex < MyRenderProxy.Settings.ShadowCascadeCount; ++cascadeIndex) { if (MyShadowCascades.ShadowCascadeObjectsCounter[cascadeIndex] >= 0) { MyPerformanceCounter.PerCameraDraw11Write.ShadowCascadeObjectsNum[cascadeIndex] = MyShadowCascades.ShadowCascadeObjectsCounter[cascadeIndex]; MyShadowCascades.ShadowCascadeObjectsCounter[cascadeIndex] = -1; } if (MyShadowCascades.ShadowCascadeTriangleCounter[cascadeIndex] >= 0) { MyPerformanceCounter.PerCameraDraw11Write.ShadowCascadeTriangles[cascadeIndex] = MyShadowCascades.ShadowCascadeTriangleCounter[cascadeIndex]; MyShadowCascades.ShadowCascadeTriangleCounter[cascadeIndex] = -1; } } if (MyShadows.OtherShadowsTriangleCounter >= 0) { MyPerformanceCounter.PerCameraDraw11Write.OtherShadowTriangles = MyShadows.OtherShadowsTriangleCounter; MyShadows.OtherShadowsTriangleCounter = -1; } }
internal void ReadContentRange(MyStorageData target, ref Vector3I writeOffset, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod) { float lodVoxelSizeHalf; BoundingBox queryBox; BoundingSphere querySphere; SetupReading(lodIndex, ref minInLod, ref maxInLod, out lodVoxelSizeHalf, out queryBox, out querySphere); float lodVoxelSize = 2f * lodVoxelSizeHalf; ProfilerShort.Begin("Testing removed shapes"); var overlappedRemovedShapes = OverlappedRemovedShapes; overlappedRemovedShapes.Clear(); ContainmentType testRemove = ContainmentType.Disjoint; for (int i = 0; i < m_data.RemovedShapes.Length; ++i) { var test = m_data.RemovedShapes[i].Contains(ref queryBox, ref querySphere, lodVoxelSize); if (test == ContainmentType.Contains) { testRemove = ContainmentType.Contains; break; // completely empty so we can leave } else if (test == ContainmentType.Intersects) { testRemove = ContainmentType.Intersects; overlappedRemovedShapes.Add(m_data.RemovedShapes[i]); } } ProfilerShort.End(); if (testRemove == ContainmentType.Contains) { ProfilerShort.Begin("target.BlockFillContent"); target.BlockFillContent(writeOffset, writeOffset + (maxInLod - minInLod), MyVoxelConstants.VOXEL_CONTENT_EMPTY); ProfilerShort.End(); return; } ProfilerShort.Begin("Testing filled shapes"); var overlappedFilledShapes = OverlappedFilledShapes; overlappedFilledShapes.Clear(); ContainmentType testFill = ContainmentType.Disjoint; for (int i = 0; i < m_data.FilledShapes.Length; ++i) { var test = m_data.FilledShapes[i].Contains(ref queryBox, ref querySphere, lodVoxelSize); if (test == ContainmentType.Contains) { overlappedFilledShapes.Clear(); testFill = ContainmentType.Contains; break; } else if (test == ContainmentType.Intersects) { overlappedFilledShapes.Add(m_data.FilledShapes[i]); testFill = ContainmentType.Intersects; } } ProfilerShort.End(); if (testFill == ContainmentType.Disjoint) { ProfilerShort.Begin("target.BlockFillContent"); target.BlockFillContent(writeOffset, writeOffset + (maxInLod - minInLod), MyVoxelConstants.VOXEL_CONTENT_EMPTY); ProfilerShort.End(); return; } else if (testRemove == ContainmentType.Disjoint && testFill == ContainmentType.Contains) { ProfilerShort.Begin("target.BlockFillContent"); target.BlockFillContent(writeOffset, writeOffset + (maxInLod - minInLod), MyVoxelConstants.VOXEL_CONTENT_FULL); ProfilerShort.End(); return; } ProfilerShort.Begin("Distance field computation"); Vector3I v = minInLod; Vector3 localPos = v * lodVoxelSize; Vector3 localPosStart = v * lodVoxelSize; var writeOffsetLoc = writeOffset - minInLod; for (v.Z = minInLod.Z; v.Z <= maxInLod.Z; ++v.Z) { for (v.Y = minInLod.Y; v.Y <= maxInLod.Y; ++v.Y) { v.X = minInLod.X; var write2 = v + writeOffsetLoc; var write = target.ComputeLinear(ref write2); for (; v.X <= maxInLod.X; ++v.X) { //Vector3 localPos = v * lodVoxelSize; //ProfilerShort.Begin("Dist filled"); float distFill; if (testFill == ContainmentType.Contains) { distFill = -1f; } else { //ProfilerShort.Begin("shape distances"); distFill = 1f; foreach (var shape in overlappedFilledShapes) { distFill = Math.Min(distFill, shape.SignedDistance(ref localPos, lodVoxelSize, m_data.MacroModule, m_data.DetailModule)); if (distFill <= -1) { break; } } //ProfilerShort.End(); } //ProfilerShort.BeginNextBlock("Dist removed"); float distRemoved = 1f; if (testRemove != ContainmentType.Disjoint) { foreach (var shape in overlappedRemovedShapes) { distRemoved = Math.Min(distRemoved, shape.SignedDistance(ref localPos, lodVoxelSize, m_data.MacroModule, m_data.DetailModule)); if (distRemoved <= -1) { break; } } } //ProfilerShort.BeginNextBlock("content"); float signedDist = MathHelper.Max(distFill, -distRemoved); var fillRatio = MathHelper.Clamp(-signedDist, -1f, 1f) * 0.5f + 0.5f; byte content = (byte)(fillRatio * MyVoxelConstants.VOXEL_CONTENT_FULL); target.Content(write, content); Debug.Assert(Math.Abs((((float)content) / MyVoxelConstants.VOXEL_CONTENT_FULL) - fillRatio) <= 0.5f); //ProfilerShort.End(); write += target.StepLinear; localPos.X += lodVoxelSize; } localPos.Y += lodVoxelSize; localPos.X = localPosStart.X; } localPos.Z += lodVoxelSize; localPos.Y = localPosStart.Y; } ProfilerShort.End(); }
//collisions //sphere vs voxel volumetric test // mk:TODO Remove. This is not very accurate. public override bool DoOverlapSphereTest(float sphereRadius, Vector3D spherePos) { ProfilerShort.Begin("MyVoxelMap.DoOverlapSphereTest"); Vector3D body0Pos = spherePos; // sphere pos BoundingSphereD newSphere; newSphere.Center = body0Pos; newSphere.Radius = sphereRadius; // We will iterate only voxels contained in the bounding box of new sphere, so here we get min/max corned in voxel units Vector3I minCorner, maxCorner; { Vector3D sphereMin = newSphere.Center - newSphere.Radius - MyVoxelConstants.VOXEL_SIZE_IN_METRES; Vector3D sphereMax = newSphere.Center + newSphere.Radius + MyVoxelConstants.VOXEL_SIZE_IN_METRES; MyVoxelCoordSystems.WorldPositionToVoxelCoord(PositionLeftBottomCorner, ref sphereMin, out minCorner); MyVoxelCoordSystems.WorldPositionToVoxelCoord(PositionLeftBottomCorner, ref sphereMax, out maxCorner); } minCorner += StorageMin; maxCorner += StorageMin; Storage.ClampVoxelCoord(ref minCorner); Storage.ClampVoxelCoord(ref maxCorner); m_storageCache.Resize(minCorner, maxCorner); Storage.ReadRange(m_storageCache, MyStorageDataTypeFlags.Content, 0, ref minCorner, ref maxCorner); Vector3I tempVoxelCoord, cache; for (tempVoxelCoord.Z = minCorner.Z, cache.Z = 0; tempVoxelCoord.Z <= maxCorner.Z; tempVoxelCoord.Z++, cache.Z++) { for (tempVoxelCoord.Y = minCorner.Y, cache.Y = 0; tempVoxelCoord.Y <= maxCorner.Y; tempVoxelCoord.Y++, cache.Y++) { for (tempVoxelCoord.X = minCorner.X, cache.X = 0; tempVoxelCoord.X <= maxCorner.X; tempVoxelCoord.X++, cache.X++) { byte voxelContent = m_storageCache.Content(ref cache); // Ignore voxels bellow the ISO value (empty, partialy empty...) if (voxelContent < MyVoxelConstants.VOXEL_ISO_LEVEL) { continue; } Vector3D voxelPosition; MyVoxelCoordSystems.VoxelCoordToWorldPosition(PositionLeftBottomCorner - StorageMin * MyVoxelConstants.VOXEL_SIZE_IN_METRES, ref tempVoxelCoord, out voxelPosition); float voxelSize = (voxelContent / MyVoxelConstants.VOXEL_CONTENT_FULL_FLOAT) * MyVoxelConstants.VOXEL_RADIUS; // If distance to voxel border is less than sphere radius, we have a collision // So now we calculate normal vector and penetration depth but on OLD sphere float newDistanceToVoxel = Vector3.Distance(voxelPosition, newSphere.Center) - voxelSize; if (newDistanceToVoxel < (newSphere.Radius)) { ProfilerShort.End(); return(true); } } } } ProfilerShort.End(); return(false); }
internal void ReadMaterialRange(MyStorageData target, ref Vector3I writeOffset, int lodIndex, ref Vector3I minInLod, ref Vector3I maxInLod) { float lodVoxelSizeHalf; BoundingBox queryBox; BoundingSphere querySphere; SetupReading(lodIndex, ref minInLod, ref maxInLod, out lodVoxelSizeHalf, out queryBox, out querySphere); float lodVoxelSize = 2f * lodVoxelSizeHalf; var overlappedDeposits = OverlappedDeposits; { ProfilerShort.Begin("Testing deposit shapes"); overlappedDeposits.Clear(); ContainmentType testDeposits = ContainmentType.Disjoint; for (int i = 0; i < m_data.Deposits.Length; ++i) { var test = m_data.Deposits[i].Shape.Contains(ref queryBox, ref querySphere, lodVoxelSize); if (test != ContainmentType.Disjoint) { overlappedDeposits.Add(m_data.Deposits[i]); testDeposits = ContainmentType.Intersects; } } ProfilerShort.End(); if (testDeposits == ContainmentType.Disjoint) { ProfilerShort.Begin("target.BlockFillMaterial"); target.BlockFillMaterial(writeOffset, writeOffset + (maxInLod - minInLod), m_data.DefaultMaterial.Index); ProfilerShort.End(); return; } } ProfilerShort.Begin("Material computation"); Vector3I v; for (v.Z = minInLod.Z; v.Z <= maxInLod.Z; ++v.Z) { for (v.Y = minInLod.Y; v.Y <= maxInLod.Y; ++v.Y) { for (v.X = minInLod.X; v.X <= maxInLod.X; ++v.X) { Vector3 localPos = v * lodVoxelSize; float closestDistance = 1f; byte closestMaterialIdx = m_data.DefaultMaterial.Index; if (!MyFakes.DISABLE_COMPOSITE_MATERIAL) { foreach (var deposit in overlappedDeposits) { float distance = deposit.Shape.SignedDistance(ref localPos, MyVoxelConstants.VOXEL_SIZE_IN_METRES, m_data.MacroModule, m_data.DetailModule); if (distance < 0f && distance <= closestDistance) { closestDistance = distance; // DA: Pass default material to the layered deposit so only that does these if-s. var materialDef = deposit.GetMaterialForPosition(ref localPos, lodVoxelSize); closestMaterialIdx = materialDef == null ? m_data.DefaultMaterial.Index : materialDef.Index; } } } var write = v - minInLod + writeOffset; target.Material(ref write, closestMaterialIdx); } } } ProfilerShort.End(); }
public MyIsoMesh Precalc(IMyStorage storage, int lod, Vector3I voxelStart, Vector3I voxelEnd, bool generateMaterials, bool useAmbient, bool doNotCheck, bool adviceCache = false) { m_resultVerticesCounter = 0; m_resultTrianglesCounter = 0; m_edgeVertexCalcCounter++; m_temporaryVoxelsCounter++; CalcPolygCubeSize(lod, storage.Size); m_voxelStart = voxelStart; //voxelStart = voxelStart; //voxelEnd = voxelEnd; var ssize = storage.Size; m_cache.Resize(voxelStart, voxelEnd); // Load content first, check it if it contains isosurface, early exit if it doesn't. storage.ReadRange(m_cache, MyStorageDataTypeFlags.Content, lod, ref voxelStart, ref voxelEnd); if (!m_cache.ContainsIsoSurface()) { return(null); } storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, lod, ref voxelStart, ref voxelEnd); ProfilerShort.Begin("Marching cubes"); { // Size of voxel or cell (in meters) and size of voxel map / voxel cells ComputeSizeAndOrigin(lod, storage.Size); var start = Vector3I.Zero; var end = voxelEnd - voxelStart - 3; Vector3I coord0 = start; for (var it = new Vector3I_RangeIterator(ref start, ref end); it.IsValid(); it.GetNext(out coord0)) { int cubeIndex = 0; if (m_cache.Content(coord0.X + 0, coord0.Y + 0, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 1; } if (m_cache.Content(coord0.X + 1, coord0.Y + 0, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 2; } if (m_cache.Content(coord0.X + 1, coord0.Y + 0, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 4; } if (m_cache.Content(coord0.X + 0, coord0.Y + 0, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 8; } if (m_cache.Content(coord0.X + 0, coord0.Y + 1, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 16; } if (m_cache.Content(coord0.X + 1, coord0.Y + 1, coord0.Z + 0) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 32; } if (m_cache.Content(coord0.X + 1, coord0.Y + 1, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 64; } if (m_cache.Content(coord0.X + 0, coord0.Y + 1, coord0.Z + 1) < MyVoxelConstants.VOXEL_ISO_LEVEL) { cubeIndex |= 128; } // Cube is entirely in/out of the surface if (MyMarchingCubesConstants.EdgeTable[cubeIndex] == 0) { continue; } // We can get this voxel content right from cache (not using GetVoxelContent method), because after CopyVoxelContents these array must be filled. But only content, not material, normal, etc. Vector3I tempVoxelCoord0 = ComputeTemporaryVoxelData(m_cache, ref coord0, cubeIndex, lod); // Create the triangles CreateTriangles(ref coord0, cubeIndex, ref tempVoxelCoord0); } } ProfilerShort.End(); double numCellsHalf = 0.5f * (m_cache.Size3D.X); var voxelSize = MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << lod); var vertexCellOffset = voxelStart - AffectedRangeOffset; IMyIsoMesherOutputBuffer isomesh = new MyIsoMesh(); for (int i = 0; i < m_resultVerticesCounter; i++) { var pos = (m_resultVertices[i].Position - (Vector3)storage.Size / 2) / storage.Size; m_resultVertices[i].Position = pos; m_resultVertices[i].PositionMorph = pos; m_resultVertices[i].NormalMorph = m_resultVertices[i].Normal; m_resultVertices[i].MaterialMorph = m_resultVertices[i].Material; m_resultVertices[i].AmbientMorph = m_resultVertices[i].Ambient; } for (int i = 0; i < m_resultVerticesCounter; i++) { isomesh.WriteVertex(ref m_resultVertices[i].Cell, ref m_resultVertices[i].Position, ref m_resultVertices[i].Normal, (byte)m_resultVertices[i].Material, m_resultVertices[i].Ambient); } for (int i = 0; i < m_resultTrianglesCounter; i++) { isomesh.WriteTriangle(m_resultTriangles[i].VertexIndex0, m_resultTriangles[i].VertexIndex1, m_resultTriangles[i].VertexIndex2); } var mIsoMesh = (MyIsoMesh)isomesh; mIsoMesh.PositionOffset = storage.Size / 2; mIsoMesh.PositionScale = storage.Size; mIsoMesh.CellStart = voxelStart; mIsoMesh.CellEnd = voxelEnd; var vertexCells = mIsoMesh.Cells.GetInternalArray(); for (int i = 0; i < mIsoMesh.VerticesCount; i++) { vertexCells[i] += vertexCellOffset; } return((MyIsoMesh)isomesh); }
public void WriteRange(MyStorageData source, MyStorageDataTypeFlags dataToWrite, ref Vector3I voxelRangeMin, ref Vector3I voxelRangeMax) { MyPrecalcComponent.AssertUpdateThread(); ProfilerShort.Begin(GetType().Name + ".WriteRange"); try { m_compressedData = null; if (CachedWrites && m_pendingChunksToWrite.Count < WriteCacheCap) { bool enqueued = m_pendingChunksToWrite.Count > 0; var lodDiff = VoxelChunk.SizeBits; var chunkMin = voxelRangeMin >> lodDiff; var chunkMax = voxelRangeMax >> lodDiff; var pos = Vector3I.Zero; for (pos.Z = chunkMin.Z; pos.Z <= chunkMax.Z; ++pos.Z) { for (pos.Y = chunkMin.Y; pos.Y <= chunkMax.Y; ++pos.Y) { for (pos.X = chunkMin.X; pos.X <= chunkMax.X; ++pos.X) { var celPos = pos << lodDiff; var lodCkStart = pos << lodDiff; lodCkStart = Vector3I.Max(lodCkStart, voxelRangeMin); var lodCkEnd = ((pos + 1) << lodDiff) - 1; lodCkEnd = Vector3I.Min(lodCkEnd, voxelRangeMax); var targetOffset = lodCkStart - voxelRangeMin; VoxelChunk chunk; // Do not read the chunk if the range overlaps the whole chunk var toRead = (lodCkEnd - lodCkStart + 1).Size != VoxelChunk.Volume ? dataToWrite : 0; GetChunk(ref pos, out chunk, toRead); lodCkStart -= celPos; lodCkEnd -= celPos; using (chunk.Lock.AcquireExclusiveUsing()) { bool dirty = chunk.Dirty != 0; chunk.Write(source, dataToWrite, ref targetOffset, ref lodCkStart, ref lodCkEnd); if (!dirty) { m_pendingChunksToWrite.Enqueue(pos); } } } } } if (!enqueued) { OperationsComponent.Add(this); } } else { using (m_storageLock.AcquireExclusiveUsing()) WriteRangeInternal(source, dataToWrite, ref voxelRangeMin, ref voxelRangeMax); } ProfilerShort.BeginNextBlock(GetType().Name + ".OnRangeChanged"); OnRangeChanged(voxelRangeMin, voxelRangeMax, dataToWrite); } finally { ProfilerShort.End(); } }
private void UpdateRenderInstanceData(Dictionary <ModelId, Tuple <List <MyCubeInstanceMergedData>, MyInstanceInfo> > instanceParts, RenderFlags renderFlags) { if (m_parentCullObject == MyRenderProxy.RENDER_ID_UNASSIGNED) { m_parentCullObject = MyRenderProxy.CreateManualCullObject(m_gridRenderComponent.Container.Entity.GetFriendlyName() + " " + m_gridRenderComponent.Container.Entity.EntityId.ToString() + ", cull object", m_gridRenderComponent.Container.Entity.PositionComp.WorldMatrix); AddRenderObjectId(m_parentCullObject, true); } if (m_instanceBufferId == MyRenderProxy.RENDER_ID_UNASSIGNED) { m_instanceBufferId = MyRenderProxy.CreateRenderInstanceBuffer( m_gridRenderComponent.Container.Entity.GetFriendlyName() + " " + m_gridRenderComponent.Container.Entity.EntityId.ToString() + ", instance buffer " + DebugName, MyRenderInstanceBufferType.Cube, m_gridRenderComponent.GetRenderObjectID()); AddRenderObjectId(m_instanceBufferId, false); } ProfilerShort.Begin("Merge render parts"); // Merge data into one buffer Debug.Assert(InstanceData.Count == 0, "Instance data is not cleared"); m_instanceInfo.Clear(); m_tmpDecalData.Clear(); int instaceDataIndex = -1; foreach (var pair in instanceParts) { var modeId = pair.Key; var tuple = pair.Value; m_instanceInfo.Add(modeId, new MyRenderInstanceInfo(m_instanceBufferId, InstanceData.Count, tuple.Item1.Count, tuple.Item2.MaxViewDistance, tuple.Item2.Flags)); var instaceDatas = tuple.Item1; for (int it1 = 0; it1 < instaceDatas.Count; it1++) { instaceDataIndex++; InstanceData.Add(instaceDatas[it1].CubeInstanceData); var decals = instaceDatas[it1].Decals; if (decals == null) { continue; } for (int it2 = 0; it2 < decals.Count; it2++) { m_tmpDecalData.Add(new MyCubeInstanceDecalData() { DecalId = decals[it2], InstanceIndex = instaceDataIndex }); } } } ProfilerShort.End(); if (InstanceData.Count > 0) { ProfilerShort.Begin("Update instance buffer"); MyRenderProxy.UpdateRenderCubeInstanceBuffer(m_instanceBufferId, InstanceData, (int)(InstanceData.Count * 1.2f), m_tmpDecalData); ProfilerShort.End(); } InstanceData.Clear(); ProfilerShort.Begin("Update instance entitites"); UpdateRenderEntitiesInstanceData(renderFlags, m_parentCullObject); ProfilerShort.End(); }
public void ReadRange(MyStorageData target, MyStorageDataTypeFlags dataToRead, int lodIndex, ref Vector3I lodVoxelRangeMin, ref Vector3I lodVoxelRangeMax, ref MyVoxelRequestFlags requestFlags) { ProfilerShort.Begin(GetType().Name + ".ReadRange"); if ((dataToRead & MyStorageDataTypeFlags.Content) != 0) { target.ClearContent(0); } if (requestFlags.HasFlags(MyVoxelRequestFlags.AdviseCache) && lodIndex == 0 && CachedWrites) { ReadRangeAdviseCache(target, dataToRead, ref lodVoxelRangeMin, ref lodVoxelRangeMax); ProfilerShort.End(); return; } if (CachedWrites && lodIndex <= VoxelChunk.SizeBits && m_cachedChunks.Count > 0) { // read occlusion separate if (dataToRead.Requests(MyStorageDataTypeEnum.Occlusion)) { using (m_storageLock.AcquireSharedUsing()) ReadRangeInternal(target, ref Vector3I.Zero, MyStorageDataTypeFlags.Occlusion, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax, ref requestFlags); dataToRead ^= MyStorageDataTypeFlags.Occlusion; } if (m_tmpChunks == null) { m_tmpChunks = new List <VoxelChunk>(); } var lodDiff = VoxelChunk.SizeBits - lodIndex; // We fetch which chunks overlap our current range from the chunk tree, then we read all data from storage and apply those changes var querybb = new BoundingBox(lodVoxelRangeMin << lodIndex, lodVoxelRangeMax << lodIndex); using (m_cacheLock.AcquireSharedUsing()) m_cacheMap.OverlapAllBoundingBox(ref querybb, m_tmpChunks, 0, false); if (m_tmpChunks.Count > 0) { var chunkMin = lodVoxelRangeMin >> lodDiff; var chunkMax = lodVoxelRangeMax >> lodDiff; bool readFromStorage = false; if ((chunkMax - chunkMin + 1).Size > m_tmpChunks.Count) { using (m_storageLock.AcquireSharedUsing()) ReadRangeInternal(target, ref Vector3I.Zero, dataToRead, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax, ref requestFlags); readFromStorage = true; } for (int i = 0; i < m_tmpChunks.Count; ++i) { var chunk = m_tmpChunks[i]; var pos = chunk.Coords; var celPos = pos << lodDiff; var lodCkStart = pos << lodDiff; lodCkStart = Vector3I.Max(lodCkStart, lodVoxelRangeMin); var targetOffset = lodCkStart - lodVoxelRangeMin; var lodCkEnd = ((pos + 1) << lodDiff) - 1; lodCkEnd = Vector3I.Min(lodCkEnd, lodVoxelRangeMax); lodCkStart -= celPos; lodCkEnd -= celPos; if ((chunk.Cached & dataToRead) != dataToRead && !readFromStorage) { using (m_storageLock.AcquireSharedUsing()) using (chunk.Lock.AcquireExclusiveUsing()) if ((chunk.Cached & dataToRead) != dataToRead) { ReadDatForChunk(chunk, dataToRead); } } using (chunk.Lock.AcquireSharedUsing()) chunk.ReadLod(target, !readFromStorage ? dataToRead : dataToRead & chunk.Cached, ref targetOffset, lodIndex, ref lodCkStart, ref lodCkEnd); } m_tmpChunks.Clear(); ProfilerShort.End(); return; } } // all else using (m_storageLock.AcquireSharedUsing()) ReadRangeInternal(target, ref Vector3I.Zero, dataToRead, lodIndex, ref lodVoxelRangeMin, ref lodVoxelRangeMax, ref requestFlags); ProfilerShort.End(); }
private static void ProcessDrawMessage(MyRenderMessageBase drawMessage) { switch (drawMessage.MessageType) { case MyRenderMessageEnum.SpriteScissorPush: { var msg = drawMessage as MyRenderMessageSpriteScissorPush; MySpritesRenderer.ScissorStackPush(msg.ScreenRectangle); break; } case MyRenderMessageEnum.SpriteScissorPop: { MySpritesRenderer.ScissorStackPop(); break; } case MyRenderMessageEnum.DrawSprite: { MyRenderMessageDrawSprite sprite = (MyRenderMessageDrawSprite)drawMessage; MySpritesRenderer.AddSingleSprite(MyTextures.GetTexture(sprite.Texture, MyTextureEnum.GUI, waitTillLoaded: sprite.WaitTillLoaded), sprite.Color, sprite.Origin, sprite.RightVector, sprite.SourceRectangle, sprite.DestinationRectangle); break; } case MyRenderMessageEnum.DrawSpriteNormalized: { MyRenderMessageDrawSpriteNormalized sprite = (MyRenderMessageDrawSpriteNormalized)drawMessage; var rotation = sprite.Rotation; if (sprite.RotationSpeed != 0) { rotation += sprite.RotationSpeed * (float)(MyRender11.CurrentDrawTime - MyRender11.CurrentUpdateTime).Seconds; } Vector2 rightVector = rotation != 0f ? new Vector2((float)Math.Cos(rotation), (float)Math.Sin(rotation)) : sprite.RightVector; int safeGuiSizeY = MyRender11.ResolutionI.Y; int safeGuiSizeX = (int)(safeGuiSizeY * 1.3333f); // This will mantain same aspect ratio for GUI elements var safeGuiRectangle = new VRageMath.Rectangle(MyRender11.ResolutionI.X / 2 - safeGuiSizeX / 2, 0, safeGuiSizeX, safeGuiSizeY); var safeScreenScale = (float)safeGuiSizeY / MyRenderGuiConstants.REFERENCE_SCREEN_HEIGHT; float fixedScale = sprite.Scale * safeScreenScale; var tex = MyTextures.GetTexture(sprite.Texture, MyTextureEnum.GUI, true); var normalizedCoord = sprite.NormalizedCoord; var screenCoord = new Vector2(safeGuiRectangle.Left + safeGuiRectangle.Width * normalizedCoord.X, safeGuiRectangle.Top + safeGuiRectangle.Height * normalizedCoord.Y); var sizeInPixels = MyTextures.GetSize(tex); var sizeInPixelsScaled = sizeInPixels * fixedScale; Vector2 alignedScreenCoord = screenCoord; var drawAlign = sprite.DrawAlign; if (drawAlign == MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP) { // Nothing to do as position is already at this point } else if (drawAlign == MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER) { // Move position to the texture center alignedScreenCoord -= sizeInPixelsScaled / 2.0f; } else if (drawAlign == MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP) { alignedScreenCoord.X -= sizeInPixelsScaled.X / 2.0f; } else if (drawAlign == MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_BOTTOM) { alignedScreenCoord.X -= sizeInPixelsScaled.X / 2.0f; alignedScreenCoord.Y -= sizeInPixelsScaled.Y; } else if (drawAlign == MyGuiDrawAlignEnum.HORISONTAL_RIGHT_AND_VERTICAL_BOTTOM) { alignedScreenCoord -= sizeInPixelsScaled; } else if (drawAlign == MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_CENTER) { alignedScreenCoord.Y -= sizeInPixelsScaled.Y / 2.0f; } else if (drawAlign == MyGuiDrawAlignEnum.HORISONTAL_RIGHT_AND_VERTICAL_CENTER) { alignedScreenCoord.X -= sizeInPixelsScaled.X; alignedScreenCoord.Y -= sizeInPixelsScaled.Y / 2.0f; } else if (drawAlign == MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_BOTTOM) { alignedScreenCoord.Y -= sizeInPixelsScaled.Y; // *0.75f; } else if (drawAlign == MyGuiDrawAlignEnum.HORISONTAL_RIGHT_AND_VERTICAL_TOP) { alignedScreenCoord.X -= sizeInPixelsScaled.X; } screenCoord = alignedScreenCoord; var rect = new RectangleF(screenCoord.X, screenCoord.Y, fixedScale * sizeInPixels.X, fixedScale * sizeInPixels.Y); Vector2 origin; if (sprite.OriginNormalized.HasValue) { origin = sprite.OriginNormalized.Value * sizeInPixels; } else { origin = sizeInPixels / 2; } sprite.OriginNormalized = sprite.OriginNormalized ?? new Vector2(0.5f); MySpritesRenderer.AddSingleSprite(MyTextures.GetTexture(sprite.Texture, MyTextureEnum.GUI, waitTillLoaded: sprite.WaitTillLoaded), sprite.Color, origin, rightVector, null, rect); break; } case MyRenderMessageEnum.DrawSpriteAtlas: { MyRenderMessageDrawSpriteAtlas sprite = (MyRenderMessageDrawSpriteAtlas)drawMessage; var tex = MyTextures.GetTexture(sprite.Texture, MyTextureEnum.GUI, true); var textureSize = MyTextures.GetSize(tex); Rectangle?sourceRect = new Rectangle( (int)(textureSize.X * sprite.TextureOffset.X), (int)(textureSize.Y * sprite.TextureOffset.Y), (int)(textureSize.X * sprite.TextureSize.X), (int)(textureSize.Y * sprite.TextureSize.Y)); VRageMath.RectangleF destRect = new VRageMath.RectangleF( (sprite.Position.X) * sprite.Scale.X, (sprite.Position.Y) * sprite.Scale.Y, sprite.HalfSize.X * sprite.Scale.X * 2, sprite.HalfSize.Y * sprite.Scale.Y * 2); Vector2 origin = new Vector2(textureSize.X * sprite.TextureSize.X * 0.5f, textureSize.Y * sprite.TextureSize.Y * 0.5f); MySpritesRenderer.AddSingleSprite(MyTextures.GetTexture(sprite.Texture, MyTextureEnum.GUI, true), sprite.Color, origin, sprite.RightVector, sourceRect, destRect); break; } case MyRenderMessageEnum.DrawString: { var message = drawMessage as MyRenderMessageDrawString; var font = MyRender11.GetFont(message.FontIndex); font.DrawString( message.ScreenCoord, message.ColorMask, message.Text, message.ScreenScale, message.ScreenMaxWidth); break; } case MyRenderMessageEnum.DrawScene: { UpdateSceneFrame(); ProfilerShort.Begin("DrawScene"); DrawGameScene(Backbuffer); ProfilerShort.Begin("TransferPerformanceStats"); TransferPerformanceStats(); ProfilerShort.End(); ProfilerShort.End(); ProfilerShort.Begin("Draw scene debug"); MyGpuProfiler.IC_BeginBlock("Draw scene debug"); DrawSceneDebug(); MyGpuProfiler.IC_EndBlock(); ProfilerShort.End(); ProfilerShort.Begin("ProcessDebugMessages"); ProcessDebugMessages(); ProfilerShort.End(); ProfilerShort.Begin("MyDebugRenderer.Draw"); MyGpuProfiler.IC_BeginBlock("MyDebugRenderer.Draw"); MyDebugRenderer.Draw(MyRender11.Backbuffer); MyGpuProfiler.IC_EndBlock(); ProfilerShort.End(); var testingDepth = MyRender11.MultisamplingEnabled ? MyScreenDependants.m_resolvedDepth : MyGBuffer.Main.DepthStencil; ProfilerShort.Begin("MyPrimitivesRenderer.Draw"); MyGpuProfiler.IC_BeginBlock("MyPrimitivesRenderer.Draw"); MyPrimitivesRenderer.Draw(MyRender11.Backbuffer, testingDepth); MyGpuProfiler.IC_EndBlock(); ProfilerShort.End(); ProfilerShort.Begin("MyLinesRenderer.Draw"); MyGpuProfiler.IC_BeginBlock("MyLinesRenderer.Draw"); MyLinesRenderer.Draw(MyRender11.Backbuffer, testingDepth); MyGpuProfiler.IC_EndBlock(); ProfilerShort.End(); if (m_screenshot.HasValue && m_screenshot.Value.IgnoreSprites) { if (m_screenshot.Value.SizeMult == Vector2.One) { SaveScreenshotFromResource(Backbuffer.m_resource); } else { TakeCustomSizedScreenshot(m_screenshot.Value.SizeMult); } } ProfilerShort.Begin("MySpritesRenderer.Draw"); MyGpuProfiler.IC_BeginBlock("MySpritesRenderer.Draw"); MySpritesRenderer.Draw(MyRender11.Backbuffer.m_RTV, new MyViewport(MyRender11.ViewportResolution.X, MyRender11.ViewportResolution.Y)); MyGpuProfiler.IC_EndBlock(); ProfilerShort.End(); if (MyRenderProxy.DRAW_RENDER_STATS) { MyRender11.GetRenderProfiler().StartProfilingBlock("MyRenderStatsDraw.Draw"); MyRenderStatsDraw.Draw(MyRenderStats.m_stats, 0.6f, VRageMath.Color.Yellow); ProfilerShort.End(); } break; } } }
private void CreateRigidBodies() { if (Entity.MarkedForClose) { return; } ProfilerShort.Begin("MyVoxelPhysicsBody::CreateRigidBodies()"); try { if (m_bodiesInitialized) { Debug.Fail("Double rigid body intialization for voxel map!"); return; } Vector3I numCels = m_voxelMap.Size >> MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS; HkUniformGridShape shape; HkRigidBody lod1rb = null; if (MyFakes.USE_LOD1_VOXEL_PHYSICS) { shape = new HkUniformGridShape( new HkUniformGridShapeArgs { CellsCount = numCels >> 1, CellSize = MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_METRES * 2, CellOffset = MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF, CellExpand = MyVoxelConstants.VOXEL_SIZE_IN_METRES }); shape.SetShapeRequestHandler(RequestShapeBlockingLod1, QueryEmptyOrFull); CreateFromCollisionObject(shape, -m_voxelMap.SizeInMetresHalf, m_voxelMap.WorldMatrix, collisionFilter: MyPhysics.CollisionLayers.VoxelLod1CollisionLayer); shape.Base.RemoveReference(); lod1rb = RigidBody; RigidBody = null; } shape = new HkUniformGridShape( new HkUniformGridShapeArgs { CellsCount = numCels, CellSize = MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_METRES, CellOffset = MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF, CellExpand = MyVoxelConstants.VOXEL_SIZE_IN_METRES }); shape.SetShapeRequestHandler(RequestShapeBlocking, QueryEmptyOrFull); CreateFromCollisionObject(shape, -m_voxelMap.SizeInMetresHalf, m_voxelMap.WorldMatrix, collisionFilter: MyPhysics.CollisionLayers.VoxelCollisionLayer); shape.Base.RemoveReference(); if (MyFakes.USE_LOD1_VOXEL_PHYSICS) { RigidBody2 = lod1rb; } if (MyFakes.ENABLE_PHYSICS_HIGH_FRICTION) { Friction = 0.65f; } m_bodiesInitialized = true; // When doing the enable disable roundtrip we can mess up the ClusterTree because Activate() can end up calling this // if the phantom is immediatelly intersecting something. if (Enabled) { var matrix = GetRigidBodyMatrix(); RigidBody.SetWorldMatrix(matrix); m_world.AddRigidBody(RigidBody); if (MyFakes.USE_LOD1_VOXEL_PHYSICS) { RigidBody2.SetWorldMatrix(matrix); m_world.AddRigidBody(RigidBody2); } } } finally { ProfilerShort.End(); } }