public void AllocateForDefinition(string model, MyPhysicalModelDefinition definition, int count)
 {
     if (string.IsNullOrEmpty(model))
         return;
     ProfilerShort.Begin("Clone");
     var data = MyModels.GetModelOnlyData(model);
     if (MyFakes.LAZY_LOAD_DESTRUCTION && data.HavokBreakableShapes == null)
     {
         MyDestructionData.Static.LoadModelDestruction(model, definition, data.BoundingBoxSize);
     }               
     if (data.HavokBreakableShapes != null && data.HavokBreakableShapes.Length > 0)
     {
         if (!m_pools.ContainsKey(definition.Id))
             m_pools[definition.Id] = new Dictionary<string, ConcurrentQueue<HkdBreakableShape>>();
         if(!m_pools[definition.Id].ContainsKey(model))
             m_pools[definition.Id][model] = new ConcurrentQueue<HkdBreakableShape>();
         var queue = m_pools[definition.Id][model];
         for (int i = 0; i < count; i++)
         {
             var shape = data.HavokBreakableShapes[0].Clone();
             queue.Enqueue(shape);
             if (i == 0)
             {
                 var mp = new HkMassProperties();
                 shape.BuildMassProperties(ref mp);
                 if (!mp.InertiaTensor.IsValid())
                 {
                     MyLog.Default.WriteLine(string.Format("Block with wrong destruction! (q.isOk): {0}", definition.Model));
                     break;
                 }
             }
         }
     }
     ProfilerShort.End();
 }
        public short GetModelId(MyPhysicalModelDefinition def)
        {
            short id;
            if (!m_physicalModelToKey.TryGetValue(def, out id))
            {
                id = (short)m_physicalModels.Count;
                m_physicalModelToKey.Add(def, id);
                m_physicalModels.Add(def);
            }

            return id;
        }
        public static MyPhysicalMaterialDefinition GetPhysicalMaterial(MyPhysicalModelDefinition modelDef, string physicalMaterial)
        {
            if (m_physicalMaterials == null)
            {
                m_physicalMaterials = new Dictionary<string, MyPhysicalMaterialDefinition>();
                foreach (var physMat in MyDefinitionManager.Static.GetPhysicalMaterialDefinitions())
                {
                    m_physicalMaterials.Add(physMat.Id.SubtypeName, physMat);
                }

                m_physicalMaterials["Default"] = new MyPhysicalMaterialDefinition()
                {
                    Density = 1920,
                    HorisontalTransmissionMultiplier = 1,
                    HorisontalFragility = 2,
                    CollisionMultiplier = 1.4f,
                    SupportMultiplier = 1.5f             
                };
            }

            if(MyPerGameSettings.Destruction == false)
            {
              return m_physicalMaterials["Default"];
            }

            if (!string.IsNullOrEmpty(physicalMaterial))
            {
                if (m_physicalMaterials.ContainsKey(physicalMaterial))
                    return m_physicalMaterials[physicalMaterial];
                else
                {
                    string s = "ERROR: Physical material " + physicalMaterial + " does not exist!";
                    System.Diagnostics.Debug.Fail(s);
                    MyLog.Default.WriteLine(s);
                }
            }

            //MyLog.Default.WriteLine("WARNING: " + modelDef.Id.SubtypeName + " has no physical material specified, trying to autodetect from name");


            if (modelDef.Id.SubtypeName.Contains("Stone"))
            {
                return m_physicalMaterials["Stone"];
            }

            if (modelDef.Id.SubtypeName.Contains("Wood"))
            {
                return m_physicalMaterials["Wood"];
            }

            if (modelDef.Id.SubtypeName.Contains("Timber"))
            {
                return m_physicalMaterials["Wood"];
            }


            //MyLog.Default.WriteLine("WARNING: Unable to find proper physical material for " + modelDef.Id.SubtypeName + ", using Default");
            return m_physicalMaterials["Default"];
        }
        public void LoadModelDestruction(string modelName, MyPhysicalModelDefinition modelDef, bool dontCreateFracturePieces, Vector3 defaultSize, bool destructionRequired = true, bool useShapeVolume = false)
        {
            var model = MyModels.GetModelOnlyData(modelName);

            var material = modelDef.PhysicalMaterial;

            //var shapeName = modelDef.Id.SubtypeName;
            var shapeName = modelName;

            if (model != null)
            {
                bool forceCollisionsInsteadDestruction = false;

                //if (model.AssetName.Contains("StoneBattlementAdvancedStraightTop"))
                //{
                //}

                model.LoadUV = true;
                HkdBreakableShape bShape;
                bool createPieceData = false;
                bool recalculateMass = false;
                bool registerShape = false;

                //TODO: Dynamic fracturing is workaround. We need to find the way how to serialize fractured model directly into hkt
                //      and then load it from BreakableShapes.
                if (model.ModelFractures != null)
                {
                    if (model.HavokCollisionShapes != null && model.HavokCollisionShapes.Length > 0)
                    {
                        CreateBreakableShapeFromCollisionShapes(model, defaultSize, modelDef);

                        var physicsMesh = CreatePhysicsMesh(model);

                        Storage.RegisterShapeWithGraphics(physicsMesh, model.HavokBreakableShapes[0], shapeName);

                        string modPath = null;

                        if (Path.IsPathRooted(model.AssetName))
                            modPath = model.AssetName.Remove(model.AssetName.LastIndexOf("Models"));

                        FractureBreakableShape(model.HavokBreakableShapes[0], model.ModelFractures, modPath);

                        recalculateMass = true;
                        registerShape = true;
                        createPieceData = true;
                    }
                }
                else
                if (model.HavokDestructionData != null && !forceCollisionsInsteadDestruction)
                {
                    try
                    {
                        //string dump = Storage.DumpDestructionData(model.HavokDestructionData);
                        if (model.HavokBreakableShapes == null) //models are cached between sessions
                        {
                            model.HavokBreakableShapes = Storage.LoadDestructionDataFromBuffer(model.HavokDestructionData);
                            createPieceData = true;
                            recalculateMass = true;
                            registerShape = true;
                        }
                    }
                    catch
                    {
                        model.HavokBreakableShapes = null;
                    }
                }
                model.HavokDestructionData = null; //we dont need to hold the byte data after loading shape
                model.HavokData = null;

                if (model.HavokBreakableShapes == null && destructionRequired)
                {
                    MyLog.Default.WriteLine(model.AssetName + " does not have destruction data");

                    CreateBreakableShapeFromCollisionShapes(model, defaultSize, modelDef);

                    recalculateMass = true;
                    registerShape = true;

                    if (MyFakes.SHOW_MISSING_DESTRUCTION && destructionRequired)
                    {
                        //Show missing destructions in pink
                        VRageRender.MyRenderProxy.ChangeModelMaterial(model.AssetName, "Debug");
                    }
                }
                    
                if (model.HavokBreakableShapes == null)
                {
                    MyLog.Default.WriteLine(string.Format("Model {0} - Unable to load havok destruction data", model.AssetName), LoggingOptions.LOADING_MODELS);
                    return;
                }

                System.Diagnostics.Debug.Assert(model.HavokBreakableShapes.Length > 0, "Incomplete destruction data");
                bShape = model.HavokBreakableShapes[0];

                //bShape.GetChildren(m_tmpChildrenList);
                //if (m_tmpChildrenList.Count == 0)
                //    bShape.UserObject = (uint)HkdBreakableShape.Flags.FRACTURE_PIECE;

                if (dontCreateFracturePieces)
                    bShape.SetFlagRecursively(HkdBreakableShape.Flags.DONT_CREATE_FRACTURE_PIECE);
                    
                //m_tmpChildrenList.Clear();

                if (registerShape)
                {
                    bShape.AddReference();

                    Storage.RegisterShape(
                                bShape,
                                shapeName
                            );
                }

                // Necessary, otherwise materials on fractures would be missing
                VRageRender.MyRenderProxy.PreloadMaterials(model.AssetName);

                if (createPieceData)
                    CreatePieceData(model, bShape);

                if (recalculateMass)
                {
                    var volume = bShape.CalculateGeometryVolume();
                    if (volume <= 0 || useShapeVolume)
                        volume = bShape.Volume;
                    var realMass = volume * material.Density;

                    System.Diagnostics.Debug.Assert(realMass > 0, "Invalid mass data");

                    bShape.SetMassRecursively(MyDestructionHelper.MassToHavok(realMass));
                }

                if(modelDef.Mass > 0)
                {
                    bShape.SetMassRecursively(MyDestructionHelper.MassToHavok(modelDef.Mass));
                }
                //Debug.Assert(CheckVolumeMassRec(bShape, 0.00001f, 0.01f), "Low volume or mass." + bShape.Name);
                DisableRefCountRec(bShape);

                if (MyFakes.LAZY_LOAD_DESTRUCTION)
                    BlockShapePool.AllocateForDefinition(shapeName, modelDef, MyBlockShapePool.PREALLOCATE_COUNT);
            }
            else
            {
                //No armor in ME!
            }
        }
        void CreateBreakableShapeFromCollisionShapes(MyModel model, Vector3 defaultSize, MyPhysicalModelDefinition modelDef)
        {
            // Make box half edge length of the grid so fractured block is smaller than not fractured, also good for compounds
            HkShape shape;
            if (model.HavokCollisionShapes != null && model.HavokCollisionShapes.Length > 0)
            {
                if (model.HavokCollisionShapes.Length > 1)
                {
                    shape = HkListShape.Create(model.HavokCollisionShapes, model.HavokCollisionShapes.Length, HkReferencePolicy.None);
                }
                else
                {
                    shape = model.HavokCollisionShapes[0];
                    shape.AddReference();
                }
            }
            else
            {
                //modelDef.Size * (modelDef.CubeSize == MyCubeSize.Large ? 2.5f : 0.25f)
                shape = new HkBoxShape(defaultSize * 0.5f, MyPerGameSettings.PhysicsConvexRadius);
            }

            var boxBreakable = new HkdBreakableShape(shape);
            boxBreakable.Name = model.AssetName;
            boxBreakable.SetMass(modelDef.Mass);
            model.HavokBreakableShapes = new HkdBreakableShape[] { boxBreakable };
            shape.RemoveReference();
        }