public static void ShowDefaultModelMessage(UnityEngine.Object[] targetObjects)
        {
            if (!IsPartOfDefaultModel(targetObjects))
            {
                return;
            }

            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            EditorGUILayout.HelpBox(kDefaultModelContents, MessageType.Warning);
            if (GUILayout.Button(kCreateAndAddToModel))
            {
                // TODO: sort gameObjects by their siblingIndex / hierarchy position, pick top one

                var childTransform    = (targetObjects[0] as MonoBehaviour).transform;
                var childSiblingIndex = childTransform.GetSiblingIndex();
                var childParent       = childTransform.parent;

                var model           = ChiselModelManager.CreateNewModel(childParent);
                var modelGameObject = model.gameObject;
                var modelTransform  = model.transform;
                modelTransform.SetSiblingIndex(childSiblingIndex);
                Undo.RegisterCreatedObjectUndo(modelGameObject, "Create " + modelGameObject.name);
                MoveTargetsUnderModel(targetObjects, model);
            }
            if (ChiselModelManager.ActiveModel && GUILayout.Button(kAddToActiveModel))
            {
                // TODO: sort gameObjects by their siblingIndex / hierarchy position

                MoveTargetsUnderModel(targetObjects, ChiselModelManager.ActiveModel);
            }
            EditorGUILayout.EndVertical();
        }
Beispiel #2
0
        private static void ImportValveMapFormat2006()
        {
            GameObject go = null;

            try
            {
                string path = EditorUtility.OpenFilePanel("Import Source Engine Map", "", "vmf");
                if (path.Length != 0)
                {
                    EditorUtility.DisplayProgressBar("Chisel: Importing Source Engine Map", "Parsing Valve Map Format File (*.vmf)...", 0.0f);
                    var importer = new ValveMapFormat2006.VmfImporter();
                    var map      = importer.Import(path);

                    // create parent game object to store all of the imported content.
                    go = new GameObject("Source Map - " + Path.GetFileNameWithoutExtension(path));
                    go.SetActive(false);

                    // create chisel model and import all of the brushes.
                    EditorUtility.DisplayProgressBar("Chisel: Importing Source Engine Map", "Preparing Material Searcher...", 0.0f);
                    ValveMapFormat2006.VmfWorldConverter.Import(ChiselModelManager.CreateNewModel(go.transform), map);

#if COM_AETERNUMGAMES_CHISEL_DECALS // optional decals package: https://github.com/Henry00IS/Chisel.Decals
                    // rebuild the world as we need the collision mesh for decals.
                    EditorUtility.DisplayProgressBar("Chisel: Importing Source Engine Map", "Rebuilding the world...", 0.5f);
                    go.SetActive(true);
                    ChiselNodeHierarchyManager.Rebuild();
#endif
                    // begin converting hammer entities to unity objects.
                    ValveMapFormat2006.VmfEntityConverter.Import(go.transform, map);
                }
            }
            catch (Exception ex)
            {
                EditorUtility.ClearProgressBar();
                EditorUtility.DisplayDialog("Source Engine Map Import", "An exception occurred while importing the map:\r\n" + ex.Message, "Ohno!");
            }
            finally
            {
                EditorUtility.ClearProgressBar();
                if (go != null)
                {
                    go.SetActive(true);
                }
            }
        }
Beispiel #3
0
        /// <summary>
        /// Imports the specified world into the SabreCSG model.
        /// </summary>
        /// <param name="model">The model to import into.</param>
        /// <param name="world">The world to be imported.</param>
        /// <param name="scale">The scale modifier.</param>
        public static void Import(Transform rootTransform, MapWorld world)
        {
            _conversionScale = 1.0f / _Scale;

            // create a material searcher to associate materials automatically.
            MaterialSearcher materialSearcher = new MaterialSearcher();

            var mapTransform = CreateGameObjectWithUniqueName(world.mapName, rootTransform);

            mapTransform.position = Vector3.zero;

            // Index of entities by trenchbroom id
            var entitiesById = new Dictionary <int, EntityContainer>();

            var layers = new List <EntityContainer>();

            for (int e = 0; e < world.Entities.Count; e++)
            {
                var entity = world.Entities[e];

                //EntityContainer eContainer = null;

                if (entity.tbId >= 0)
                {
                    var name       = String.IsNullOrEmpty(entity.tbName) ? "Unnamed" : entity.tbName;
                    var t          = CreateGameObjectWithUniqueName(name, mapTransform);
                    var eContainer = new EntityContainer(t, entity);
                    entitiesById.Add(entity.tbId, eContainer);

                    if (entity.tbType == "_tb_layer")
                    {
                        layers.Add(eContainer);
                        eContainer.transform.SetParent(null); // unparent until layers are sorted by sort index
                    }
                }
            }

            var defaultLayer = CreateGameObjectWithUniqueName("Default Layer", mapTransform);

            layers = layers.OrderBy(l => l.entity.tbLayerSortIndex).ToList(); // sort layers by layer sort index

            foreach (var l in layers)
            {
                l.transform.SetParent(mapTransform); // parent layers to map in order
            }

            bool valveFormat = world.valveFormat;

            // iterate through all entities.
            for (int e = 0; e < world.Entities.Count; e++)
            {
#if UNITY_EDITOR
                UnityEditor.EditorUtility.DisplayProgressBar("Importing Quake 1 Map", "Converting Quake 1 Entities To Brushes (" + (e + 1) + " / " + world.Entities.Count + ")...", e / (float)world.Entities.Count);
#endif
                MapEntity entity = world.Entities[e];

                Transform brushParent = mapTransform;

                bool isLayer   = false;
                bool isTrigger = false;

                if (entity.ClassName == "worldspawn")
                {
                    brushParent = defaultLayer;
                }
                else if (entity.tbType == "_tb_layer")
                {
                    isLayer = true;
                    if (entitiesById.TryGetValue(entity.tbId, out EntityContainer eContainer))
                    {
                        brushParent = eContainer.transform;
                    }
                }
                else if (entity.tbType == "_tb_group")
                {
                    if (entitiesById.TryGetValue(entity.tbId, out EntityContainer eContainer))
                    {
                        brushParent = eContainer.transform;
                    }
                }
                else
                {
                    if (entity.ClassName.Contains("trigger"))
                    {
                        isTrigger = true;
                    }

                    brushParent = CreateGameObjectWithUniqueName(entity.ClassName, mapTransform);
                }

                if (brushParent != mapTransform && brushParent != defaultLayer)
                {
                    if (entity.tbGroup > 0)
                    {
                        if (entitiesById.TryGetValue(entity.tbGroup, out EntityContainer eContainer))
                        {
                            brushParent.SetParent(eContainer.transform);
                        }
                    }
                    else if (entity.tbLayer > 0)
                    {
                        if (entitiesById.TryGetValue(entity.tbLayer, out EntityContainer eContainer))
                        {
                            brushParent.SetParent(eContainer.transform);
                        }
                    }
                    else if (!isLayer)
                    {
                        brushParent.SetParent(defaultLayer);
                    }
                }

                //if(entity.)

                if (entity.Brushes.Count == 0)
                {
                    continue;
                }

                var model = ChiselModelManager.CreateNewModel(brushParent);
                // var model = OperationsUtility.CreateModelInstanceInScene(brushParent);
                var parent = model.transform;

                if (isTrigger)
                {
                    //model.Settings = (model.Settings | ModelSettingsFlags.IsTrigger | ModelSettingsFlags.SetColliderConvex | ModelSettingsFlags.DoNotRender);
                }

                // iterate through all entity brushes.
                for (int i = 0; i < entity.Brushes.Count; i++)
                {
                    MapBrush brush = entity.Brushes[i];


                    // build a very large cube brush.
                    ChiselBrush go = ChiselComponentFactory.Create <ChiselBrush>(model);
                    go.definition.surfaceDefinition = new ChiselSurfaceDefinition();
                    go.definition.surfaceDefinition.EnsureSize(6);
                    BrushMesh brushMesh = new BrushMesh();
                    go.definition.brushOutline = brushMesh;
                    BrushMeshFactory.CreateBox(ref brushMesh, new Vector3(-4096, -4096, -4096), new Vector3(4096, 4096, 4096), in go.definition.surfaceDefinition);

                    // prepare for uv calculations of clip planes after cutting.
                    var planes        = new float4[brush.Sides.Count];
                    var planeSurfaces = new ChiselSurface[brush.Sides.Count];

                    // compute all the sides of the brush that will be clipped.
                    for (int j = brush.Sides.Count; j-- > 0;)
                    {
                        MapBrushSide side = brush.Sides[j];

                        // detect excluded polygons.
                        //if (IsExcludedMaterial(side.Material))
                        //polygon.UserExcludeFromFinal = true;
                        // detect collision-only brushes.
                        //if (IsInvisibleMaterial(side.Material))
                        //pr.IsVisible = false;

                        // find the material in the unity project automatically.
                        Material material;

                        string materialName = side.Material.Replace("*", "#");
                        material = materialSearcher.FindMaterial(new string[] { materialName });
                        if (material == null)
                        {
                            material = ChiselMaterialManager.DefaultFloorMaterial;
                        }

                        // create chisel surface for the clip.
                        ChiselSurface surface = new ChiselSurface();
                        surface.brushMaterial      = ChiselBrushMaterial.CreateInstance(material, ChiselMaterialManager.DefaultPhysicsMaterial);
                        surface.surfaceDescription = SurfaceDescription.Default;

                        // detect collision-only polygons.
                        if (IsInvisibleMaterial(side.Material))
                        {
                            surface.brushMaterial.LayerUsage &= ~LayerUsageFlags.RenderReceiveCastShadows;
                        }
                        // detect excluded polygons.
                        if (IsExcludedMaterial(side.Material))
                        {
                            surface.brushMaterial.LayerUsage &= LayerUsageFlags.CastShadows;
                            surface.brushMaterial.LayerUsage |= LayerUsageFlags.Collidable;
                        }

                        // calculate the clipping planes.
                        Plane clip = new Plane(go.transform.InverseTransformPoint(new Vector3(side.Plane.P1.X, side.Plane.P1.Z, side.Plane.P1.Y) * _conversionScale), go.transform.InverseTransformPoint(new Vector3(side.Plane.P2.X, side.Plane.P2.Z, side.Plane.P2.Y) * _conversionScale), go.transform.InverseTransformPoint(new Vector3(side.Plane.P3.X, side.Plane.P3.Z, side.Plane.P3.Y) * _conversionScale));
                        planes[j]        = new float4(clip.normal, clip.distance);
                        planeSurfaces[j] = surface;
                    }

                    // cut all the clipping planes out of the brush in one go.
                    brushMesh.Cut(planes, planeSurfaces);

                    // now iterate over the planes to calculate UV coordinates.
                    int[] indices = new int[brush.Sides.Count];
                    for (int k = 0; k < planes.Length; k++)
                    {
                        var   plane           = planes[k];
                        int   closestIndex    = 0;
                        float closestDistance = math.lengthsq(plane - brushMesh.planes[0]);
                        for (int j = 1; j < brushMesh.planes.Length; j++)
                        {
                            float testDistance = math.lengthsq(plane - brushMesh.planes[j]);
                            if (testDistance < closestDistance)
                            {
                                closestIndex    = j;
                                closestDistance = testDistance;
                            }
                        }
                        indices[k] = closestIndex;
                    }

                    for (int j = 0; j < indices.Length; j++)
                    {
                        brushMesh.planes[indices[j]] = planes[j];
                    }

                    for (int j = brush.Sides.Count; j-- > 0;)
                    {
                        MapBrushSide side = brush.Sides[j];

                        var surface  = brushMesh.polygons[indices[j]].surface;
                        var material = surface.brushMaterial.RenderMaterial;

                        // calculate the texture coordinates.
                        int w = 256;
                        int h = 256;
                        if (material.mainTexture != null)
                        {
                            w = material.mainTexture.width;
                            h = material.mainTexture.height;
                        }
                        var clip = new Plane(planes[j].xyz, planes[j].w);

                        if (world.valveFormat)
                        {
                            var uAxis = new VmfAxis(side.t1, side.Offset.X, side.Scale.X);
                            var vAxis = new VmfAxis(side.t2, side.Offset.Y, side.Scale.Y);
                            CalculateTextureCoordinates(go, surface, clip, w, h, uAxis, vAxis);
                        }
                        else
                        {
                            if (GetTextureAxises(clip, out MapVector3 t1, out MapVector3 t2))
                            {
                                var uAxis = new VmfAxis(t1, side.Offset.X, side.Scale.X);
                                var vAxis = new VmfAxis(t2, side.Offset.Y, side.Scale.Y);
                                CalculateTextureCoordinates(go, surface, clip, w, h, uAxis, vAxis);
                            }
                        }
                    }

                    try
                    {
                        // finalize the brush by snapping planes and centering the pivot point.
                        go.transform.position += brushMesh.CenterAndSnapPlanes();
                    }
                    catch
                    {
                        // Brush failed, destroy brush
                        GameObject.DestroyImmediate(go);
                    }
                }
            }

#if UNITY_EDITOR
            UnityEditor.EditorUtility.ClearProgressBar();
#endif
        }
        // This method is used by Component specific classes (e.g. ChiselBoxEditor)
        // to create a menu Item that creates a gameObject with a specific component (e.g. ChiselBox)
        // Since MenuItems can only be created with attributes, and strings must be constant,
        // we can only do this from place where we specifically know which component the menu is for.
        protected static void CreateAsGameObjectMenuCommand(MenuCommand menuCommand, string name)
        {
            T component;
            // If we use the command object on a gameobject in the hierarchy, choose that gameobject
            // Otherwise: choose the activeModel (if available)
            var context          = (menuCommand.context as GameObject);
            var parentGameObject = (context != null) ? context : (ChiselModelManager.ActiveModel != null) ? ChiselModelManager.ActiveModel.gameObject : null;
            var parentTransform  = (parentGameObject == null) ? null : parentGameObject.transform;

            // If we used the command object on a generator, choose it's parent to prevent us from
            // adding a generator as a child to a generator
            if (parentTransform &&
                parentTransform.GetComponent <ChiselGeneratorComponent>())
            {
                parentTransform  = parentTransform.parent;
                parentGameObject = (parentTransform == null) ? null : parentTransform.gameObject;
            }

            // Create the gameobject
            if (parentTransform)
            {
                component = ChiselComponentFactory.Create <T>(name, parentTransform);
            }
            else
            {
                component = ChiselComponentFactory.Create <T>(name);
            }

            var gameObject = component.gameObject;

            GameObjectUtility.SetParentAndAlign(gameObject, parentGameObject);
            Undo.RegisterCreatedObjectUndo(gameObject, "Create " + gameObject.name);


            // Find the appropriate model to make active after we created the generator
            ChiselModel model;

            if (typeof(T) != typeof(ChiselModel))
            {
                model = gameObject.GetComponentInParent <ChiselModel>();
                // If we don't have a parent model, create one and put the generator underneath it
                if (!model)
                {
                    model = ChiselModelManager.CreateNewModel(gameObject.transform.parent);

                    // Make sure we create the model at the exact same location as the generator
                    var modelGameObject   = model.gameObject;
                    var modelTransform    = model.transform;
                    var childSiblingIndex = modelTransform.GetSiblingIndex();
                    modelTransform.SetSiblingIndex(childSiblingIndex);

                    Undo.RegisterCreatedObjectUndo(modelGameObject, "Create " + modelGameObject.name);
                    MoveTargetsUnderModel(new[] { component }, model);
                }
            }
            else
            {
                model = component as ChiselModel;
            }

            // Set the active model before we select the gameobject, otherwise we'll be selecting the model instead
            ChiselModelManager.ActiveModel = model;
            Selection.activeObject         = gameObject;
        }